hugo & tasks init
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
/node_modules
|
||||
/coverage
|
||||
*.log
|
||||
.DS_Store
|
||||
@@ -0,0 +1,102 @@
|
||||
import * as path from 'path'
|
||||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
|
||||
import { logger as _logger } from '@plastichub/core/debug'
|
||||
export const logger = _logger('ph-site')
|
||||
import { createContent, ICompileTaskOptions } from '@plastichub/osr-tasks/tasks/compile'
|
||||
import { productHugoTask, readProducts, registerProductTasks } from './product'
|
||||
import { OSRL_MODULE_NAME, LANGUAGES, I18N_STORE, OSR_ROOT, TRANSLATE_CONTENT, TASK_COMPILE_CONTENT_CACHE, RETAIL_DEFAULT_BRANCH, I18N_SOURCE_LANGUAGE, REGISTER_RETAIL_TASKS, TASK_COMPILE_CONTENT } from './config'
|
||||
import { writeTaskConfig } from './log'
|
||||
import * as pMap from 'p-map'
|
||||
|
||||
// const _logger = createSubLogger(logger, logLevel, 'compile:content')
|
||||
|
||||
export const grunt = (grunt) => {
|
||||
grunt.loadNpmTasks("grunt-extend-config")
|
||||
const logLevel = grunt.option('logLevel') || 'warn'
|
||||
logger.setSettings({ minLevel: logLevel })
|
||||
const watch = grunt.option('watchContent')
|
||||
// Pages - src/content/lang/**/*.md
|
||||
|
||||
const contentTask = (sourceLanguage, options: any = {}) => {
|
||||
const config = {}
|
||||
const src = `src/content/${sourceLanguage}/**/*.md`
|
||||
const cwd = process.cwd()
|
||||
const dst = path.resolve(`${cwd}/content/${sourceLanguage}`)
|
||||
const profile = path.resolve(`./.osrl.json`)
|
||||
const root = path.resolve(`./src/content/${sourceLanguage}`)
|
||||
const compilerOptions: ICompileTaskOptions = {
|
||||
output: dst,
|
||||
debug: false,
|
||||
cache: !!grunt.option('cache') || TASK_COMPILE_CONTENT_CACHE,
|
||||
watchContent: watch,
|
||||
module: OSRL_MODULE_NAME,
|
||||
profile,
|
||||
root,
|
||||
...(options || {}),
|
||||
env: 'library',
|
||||
language: 'osr',
|
||||
format: 'html',
|
||||
sourceLanguage: sourceLanguage,
|
||||
logLevel: logLevel,
|
||||
variables: {
|
||||
cwd,
|
||||
targetLanguage: sourceLanguage,
|
||||
sourceLanguage: sourceLanguage,
|
||||
i18n: I18N_STORE(OSR_ROOT(), sourceLanguage)
|
||||
}
|
||||
}
|
||||
let defaultOptions = {
|
||||
src: [src],
|
||||
options: compilerOptions
|
||||
}
|
||||
const onCompiled = (src, dst, content) => content
|
||||
const onCompiledDone = async (src, dst, options, content) => {
|
||||
return await pMap(LANGUAGES, async (dstLanguage) => {
|
||||
const opts: ICompileTaskOptions = {
|
||||
...defaultOptions.options,
|
||||
output: path.resolve(`${process.cwd()}/content/${dstLanguage}/`),
|
||||
sourceLanguage: sourceLanguage,
|
||||
targetLanguage: dstLanguage,
|
||||
variables: {
|
||||
...defaultOptions.options.variables,
|
||||
cwd: process.cwd(),
|
||||
i18n: I18N_STORE(OSR_ROOT(), dstLanguage),
|
||||
sourceLanguage: sourceLanguage,
|
||||
targetLanguage: dstLanguage,
|
||||
}
|
||||
};
|
||||
const content = await createContent(src, opts)
|
||||
return content
|
||||
}, { concurrency: 1 })
|
||||
}
|
||||
config[`content-${sourceLanguage}`] = {
|
||||
...defaultOptions,
|
||||
options: {
|
||||
...defaultOptions.options,
|
||||
onCompiled: TRANSLATE_CONTENT ? onCompiled : undefined,
|
||||
onCompileDone: TRANSLATE_CONTENT ? onCompiledDone : undefined
|
||||
}
|
||||
}
|
||||
grunt.extendConfig({ compile: config })
|
||||
grunt.registerTask(`content-${sourceLanguage}`, `compile:content-${sourceLanguage}`)
|
||||
writeTaskConfig(`compile_content-${sourceLanguage}`, config)
|
||||
}
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON("package.json"),
|
||||
compile: {}
|
||||
})
|
||||
contentTask(I18N_SOURCE_LANGUAGE)
|
||||
grunt.registerTask('content', ['compile:content-en'])
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Products
|
||||
const product_item_tasks = []
|
||||
const productTasks = (items) =>
|
||||
items.forEach((i) => productHugoTask(grunt, i, {}, product_item_tasks))
|
||||
|
||||
const _products = readProducts(grunt.option('branch') || RETAIL_DEFAULT_BRANCH)
|
||||
TASK_COMPILE_CONTENT && productTasks(_products)
|
||||
REGISTER_RETAIL_TASKS && registerProductTasks(grunt)
|
||||
require("@plastichub/osr-tasks").initConfig(grunt, {})
|
||||
}
|
||||
module.exports = grunt
|
||||
@@ -0,0 +1,60 @@
|
||||
import * as path from 'path'
|
||||
import { resolve } from '@plastichub/osr-cli-commons/fs'
|
||||
|
||||
export const OSR_ROOT = () => path.resolve(resolve("${OSR_ROOT}"))
|
||||
|
||||
// Supported languages
|
||||
export const TRANSLATE_CONTENT = true // translate regular pages
|
||||
export const LANGUAGES = ['de']
|
||||
|
||||
// i18n constants
|
||||
export const I18N_STORE = (root, lang) => `${root}/i18n-store/store-${lang}.json`
|
||||
export const I18N_SOURCE_LANGUAGE = 'en'
|
||||
|
||||
// Product compiler
|
||||
export const PRODUCT_ROOT = () => path.resolve(resolve("${OSR_ROOT}/products"))
|
||||
export const PRODUCT_CONFIG = (product) =>
|
||||
path.resolve(resolve("${OSR_ROOT}/products/${product}/config.json", false,
|
||||
{
|
||||
product
|
||||
}))
|
||||
export const PRODUCT_DIR = (product) =>
|
||||
path.resolve(resolve("${OSR_ROOT}/products/${product}", false,
|
||||
{
|
||||
product
|
||||
}))
|
||||
export const IS_DEV = true
|
||||
export const OSRL_ENV = 'bazar-release'
|
||||
export const OSRL_ENV_DEV = 'hugo-debug'
|
||||
export const OSRL_ENVIRONMENT = IS_DEV ? OSRL_ENV_DEV : OSRL_ENV
|
||||
export const PRODUCT_HUGO_TEMPLATE = './osr/hugo/root.html'
|
||||
export const PRODUCTS_TARGET_SRC = './src/content/en/retail'
|
||||
|
||||
// OSRL - Language
|
||||
export const OSRL_MODULE_NAME = 'osr-site'
|
||||
export const OSRL_PRODUCT_PROFILE = '${root}/.osrl.json'
|
||||
export const OSRL_LANG_FLAVOR = 'osr'
|
||||
|
||||
// Products
|
||||
export const ENABLED_PRODUCTS = "./config/machines.json"
|
||||
|
||||
// Tasks
|
||||
export const TASK_CONFIG_LOG_DIRECTORY = './config/'
|
||||
|
||||
// Task: compile:content
|
||||
export const TASK_COMPILE_CONTENT = false
|
||||
export const TASK_COMPILE_CONTENT_CACHE = true
|
||||
|
||||
// Task - Logging
|
||||
export const TASK_LOG_DIRECTORY = './logs/'
|
||||
|
||||
// Task - Retail Config
|
||||
export const REGISTER_RETAIL_TASKS = true
|
||||
export const RETAIL_DEFAULT_BRANCH = 'current'
|
||||
export const RETAIL_COMPILE_CACHE = false
|
||||
export const RETAIL_MEDIA_CACHE = true
|
||||
export const RETAIL_LOG_LEVEL_I18N_PRODUCT_ASSETS = 'info'
|
||||
|
||||
export const ConvertProductMedia = false
|
||||
export const TranslateProductAssets = false
|
||||
export const PopulateProductDefaults = false
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
import {
|
||||
I18N_SOURCE_LANGUAGE, I18N_STORE,
|
||||
OSR_ROOT
|
||||
} from './config'
|
||||
|
||||
import { IOptions as IOptionsI18n } from '@plastichub/osr-i18n/types'
|
||||
|
||||
import { CONFIG_DEFAULT } from '@plastichub/osr-cli-commons'
|
||||
|
||||
import { translateDeepL, getTranslation, translate } from '@plastichub/osr-i18n/lib/translate'
|
||||
import { sync as read } from '@plastichub/fs/read'
|
||||
import { sync as write } from '@plastichub/fs/write'
|
||||
|
||||
import { sanitize } from '@plastichub/osr-i18n/_cli'
|
||||
|
||||
import { createHash } from 'crypto'
|
||||
|
||||
const removeNonPrintableCharacters = (text: string): string => text.replace(/[^\x20-\x7E]/g, '')
|
||||
|
||||
export const clean = (text: string = "") => text.trim()
|
||||
export const hash = (text: string) => createHash('md5').update(clean(text)).digest('base64')
|
||||
|
||||
export const store = (storePath: string, text: string, file: string = '') => {
|
||||
const _hash: string = hash(text)
|
||||
const store = read(storePath, 'json') || {}
|
||||
store[_hash] = clean(text)
|
||||
write(storePath, store)
|
||||
}
|
||||
|
||||
export const translateText = async (text: string, srcLang: string, dstLang: string, storePath: string) => {
|
||||
if (text.length === 0) {
|
||||
return ''
|
||||
}
|
||||
if (srcLang === dstLang) {
|
||||
store(storePath, text)
|
||||
return
|
||||
}
|
||||
const config: any = CONFIG_DEFAULT()
|
||||
text = clean(text)
|
||||
const _hash: string = hash(text)
|
||||
const db = read(storePath, 'json') || {}
|
||||
if (db[text]) {
|
||||
return db[text]
|
||||
}
|
||||
const out = await translateDeepL(
|
||||
text,
|
||||
srcLang,
|
||||
dstLang,
|
||||
{
|
||||
...config.deepl
|
||||
}, {
|
||||
|
||||
}, "")
|
||||
|
||||
const translation = getTranslation((out as any), false)
|
||||
|
||||
if (translation) {
|
||||
db[text] = translation
|
||||
write(storePath, db)
|
||||
return translation
|
||||
}
|
||||
}
|
||||
|
||||
export const translateString = (str: string, srcLang: string, dstLanguage: string) => {
|
||||
|
||||
const translateProductAssets = async () => {
|
||||
const config: any = CONFIG_DEFAULT()
|
||||
if (dstLanguage === I18N_SOURCE_LANGUAGE) {
|
||||
return
|
||||
}
|
||||
const i18nOptions: IOptionsI18n = {
|
||||
srcLang: I18N_SOURCE_LANGUAGE,
|
||||
dstLang: dstLanguage,
|
||||
store: I18N_STORE(OSR_ROOT(), dstLanguage),
|
||||
noCache: true,
|
||||
api_key: config.deepl.auth_key,
|
||||
logLevel: 'warn'
|
||||
}
|
||||
const ret = await translate(sanitize(i18nOptions) as any)
|
||||
return ret
|
||||
}
|
||||
}
|
||||
+499
@@ -0,0 +1,499 @@
|
||||
export interface ExifData {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface ImageSEOData {
|
||||
src: string;
|
||||
alt: string;
|
||||
title: string;
|
||||
caption?: string;
|
||||
fileName: string;
|
||||
format: string;
|
||||
size: string;
|
||||
metadata: {
|
||||
location?: string;
|
||||
camera?: string;
|
||||
keywords: string[];
|
||||
exifData: ExifData[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface GalleryImage
|
||||
{
|
||||
name: string
|
||||
url: string
|
||||
thumb: string
|
||||
responsive: string
|
||||
meta: Meta
|
||||
keywords: string[]
|
||||
description: string
|
||||
alt?: string
|
||||
title?: string
|
||||
height?: number
|
||||
width?: number
|
||||
}
|
||||
|
||||
export interface Meta {
|
||||
format: string
|
||||
width: number
|
||||
height: number
|
||||
space: string
|
||||
channels: number
|
||||
depth: string
|
||||
density: number
|
||||
chromaSubsampling: string
|
||||
isProgressive: boolean
|
||||
resolutionUnit: string
|
||||
hasProfile: boolean
|
||||
hasAlpha: boolean
|
||||
orientation: number
|
||||
exif: Exif
|
||||
}
|
||||
|
||||
export interface Exif {
|
||||
file: File
|
||||
jfif: Jfif
|
||||
exif: Exif2
|
||||
gps: Gps
|
||||
}
|
||||
|
||||
export interface File {
|
||||
"Bits Per Sample": BitsPerSample
|
||||
"Image Height": ImageHeight
|
||||
"Image Width": ImageWidth
|
||||
"Color Components": ColorComponents
|
||||
Subsampling: Subsampling
|
||||
FileType: FileType
|
||||
}
|
||||
|
||||
export interface BitsPerSample {
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ImageHeight {
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ImageWidth {
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ColorComponents {
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Subsampling {
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface FileType {
|
||||
value: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Jfif {
|
||||
"JFIF Version": JfifVersion
|
||||
"Resolution Unit": ResolutionUnit
|
||||
XResolution: Xresolution
|
||||
YResolution: Yresolution
|
||||
"JFIF Thumbnail Width": JfifThumbnailWidth
|
||||
"JFIF Thumbnail Height": JfifThumbnailHeight
|
||||
}
|
||||
|
||||
export interface JfifVersion {
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ResolutionUnit {
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Xresolution {
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Yresolution {
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface JfifThumbnailWidth {
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface JfifThumbnailHeight {
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Exif2 {
|
||||
ImageDescription: ImageDescription
|
||||
Make: Make
|
||||
Model: Model
|
||||
Orientation: Orientation
|
||||
XResolution: Xresolution2
|
||||
YResolution: Yresolution2
|
||||
ResolutionUnit: ResolutionUnit2
|
||||
Software: Software
|
||||
DateTime: DateTime
|
||||
YCbCrPositioning: YcbCrPositioning
|
||||
"Exif IFD Pointer": ExifIfdPointer
|
||||
"GPS Info IFD Pointer": GpsInfoIfdPointer
|
||||
XPTitle: Xptitle
|
||||
XPSubject: Xpsubject
|
||||
Padding: Padding
|
||||
ExposureTime: ExposureTime
|
||||
FNumber: Fnumber
|
||||
ExposureProgram: ExposureProgram
|
||||
ISOSpeedRatings: IsospeedRatings
|
||||
ExifVersion: ExifVersion
|
||||
DateTimeOriginal: DateTimeOriginal
|
||||
DateTimeDigitized: DateTimeDigitized
|
||||
ComponentsConfiguration: ComponentsConfiguration
|
||||
ExposureBiasValue: ExposureBiasValue
|
||||
MeteringMode: MeteringMode
|
||||
LightSource: LightSource
|
||||
Flash: Flash
|
||||
FocalLength: FocalLength
|
||||
SubSecTime: SubSecTime
|
||||
SubSecTimeOriginal: SubSecTimeOriginal
|
||||
SubSecTimeDigitized: SubSecTimeDigitized
|
||||
FlashpixVersion: FlashpixVersion
|
||||
ColorSpace: ColorSpace
|
||||
PixelXDimension: PixelXdimension
|
||||
PixelYDimension: PixelYdimension
|
||||
ExposureMode: ExposureMode
|
||||
WhiteBalance: WhiteBalance
|
||||
DigitalZoomRatio: DigitalZoomRatio
|
||||
FocalLengthIn35mmFilm: FocalLengthIn35mmFilm
|
||||
SceneCaptureType: SceneCaptureType
|
||||
GPSLatitudeRef: GpslatitudeRef
|
||||
GPSLatitude: Gpslatitude
|
||||
GPSLongitudeRef: GpslongitudeRef
|
||||
GPSLongitude: Gpslongitude
|
||||
GPSAltitude: Gpsaltitude
|
||||
}
|
||||
|
||||
export interface ImageDescription {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Make {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Model {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Orientation {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Xresolution2 {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Yresolution2 {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ResolutionUnit2 {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Software {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface DateTime {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface YcbCrPositioning {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ExifIfdPointer {
|
||||
id: number
|
||||
value: number
|
||||
description: number
|
||||
}
|
||||
|
||||
export interface GpsInfoIfdPointer {
|
||||
id: number
|
||||
value: number
|
||||
description: number
|
||||
}
|
||||
|
||||
export interface Xptitle {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Xpsubject {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Padding {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ExposureTime {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Fnumber {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ExposureProgram {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface IsospeedRatings {
|
||||
id: number
|
||||
value: number
|
||||
description: number
|
||||
}
|
||||
|
||||
export interface ExifVersion {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface DateTimeOriginal {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface DateTimeDigitized {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ComponentsConfiguration {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ExposureBiasValue {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface MeteringMode {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface LightSource {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Flash {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface FocalLength {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface SubSecTime {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface SubSecTimeOriginal {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface SubSecTimeDigitized {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface FlashpixVersion {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ColorSpace {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface PixelXdimension {
|
||||
id: number
|
||||
value: number
|
||||
description: number
|
||||
}
|
||||
|
||||
export interface PixelYdimension {
|
||||
id: number
|
||||
value: number
|
||||
description: number
|
||||
}
|
||||
|
||||
export interface ExposureMode {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface WhiteBalance {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface DigitalZoomRatio {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface FocalLengthIn35mmFilm {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface SceneCaptureType {
|
||||
id: number
|
||||
value: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface GpslatitudeRef {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Gpslatitude {
|
||||
id: number
|
||||
description: number
|
||||
}
|
||||
|
||||
export interface GpslongitudeRef {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Gpslongitude {
|
||||
id: number
|
||||
description: number
|
||||
}
|
||||
|
||||
export interface Gpsaltitude {
|
||||
id: number
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface Gps {
|
||||
Latitude: number
|
||||
Longitude: number
|
||||
}
|
||||
|
||||
export const generateDefaultImageJSONLD = (imageData: ImageSEOData) =>{
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ImageObject",
|
||||
"contentUrl": imageData.src,
|
||||
"name": imageData.title,
|
||||
"description": imageData.caption || imageData.alt,
|
||||
"width": parseInt(imageData.size.split('x')[0]),
|
||||
"height": parseInt(imageData.size.split('x')[1]),
|
||||
"thumbnail": `https://example.com/thumbnails/${imageData.fileName}`,
|
||||
"license": "https://example.com/license",
|
||||
"acquireLicensePage": "https://example.com/buy-license",
|
||||
"copyrightNotice": `© ${new Date().getFullYear()} Default Organization`,
|
||||
"creator": {
|
||||
"@type": "Person",
|
||||
"name": "Default Creator Name"
|
||||
},
|
||||
"copyrightHolder": {
|
||||
"@type": "Organization",
|
||||
"name": "Default Organization Name"
|
||||
},
|
||||
"contentLocation": imageData.metadata.location || "Unknown location",
|
||||
"datePublished": new Date().toISOString().split('T')[0],
|
||||
"exifData": imageData.metadata.exifData.length > 0 ? imageData.metadata.exifData : [
|
||||
{
|
||||
"@type": "PropertyValue",
|
||||
"name": "Camera",
|
||||
"value": imageData.metadata.camera || "Unknown camera"
|
||||
},
|
||||
{
|
||||
"@type": "PropertyValue",
|
||||
"name": "Keywords",
|
||||
"value": imageData.metadata.keywords.join(', ')
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
// Example usage
|
||||
const imageData: ImageSEOData = {
|
||||
src: "https://example.com/image.jpg",
|
||||
alt: "A beautiful scenery",
|
||||
title: "Beautiful Scenery",
|
||||
caption: "A beautiful scenery with mountains and a lake.",
|
||||
fileName: "scenery.jpg",
|
||||
format: "image/jpeg",
|
||||
size: "1200x800",
|
||||
metadata: {
|
||||
location: "Mountain Lake",
|
||||
camera: "Canon EOS 5D Mark IV",
|
||||
keywords: ["scenery", "mountain", "lake"],
|
||||
exifData: [
|
||||
{
|
||||
name: "Exposure Time",
|
||||
value: "1/659 sec."
|
||||
},
|
||||
{
|
||||
name: "FNumber",
|
||||
value: "f/4.0"
|
||||
},
|
||||
{
|
||||
name: "ISO",
|
||||
value: "100"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
import * as path from 'path'
|
||||
import * as pMap from 'p-map'
|
||||
import { CONFIG_DEFAULT } from '@plastichub/osr-cli-commons'
|
||||
import { resolve } from '@plastichub/osr-cli-commons/fs'
|
||||
import { files } from '@plastichub/osr-cli-commons/glob'
|
||||
|
||||
import { sync as cp } from '@plastichub/fs/copy'
|
||||
import { sync as exists } from '@plastichub/fs/exists'
|
||||
import { sync as rm } from '@plastichub/fs/remove'
|
||||
import { sync as read } from '@plastichub/fs/read'
|
||||
import { sync as write } from '@plastichub/fs/write'
|
||||
|
||||
import { logger as _logger } from '@plastichub/core/debug'
|
||||
import * as ExifReader from 'exifreader'
|
||||
import { Logger, TTransportLogger, ILogObject } from 'tslog'
|
||||
import { createStream } from "rotating-file-stream"
|
||||
import { sanitize } from '@plastichub/osr-i18n/_cli'
|
||||
import { translateText } from '@plastichub/osr-i18n/lib/translate'
|
||||
import { IOptions as IOptionsI18n } from '@plastichub/osr-i18n/types'
|
||||
import { translate } from '@plastichub/osr-i18n/lib/translate'
|
||||
import { resize, getResizePatterns, format, getFormats, meta } from '@plastichub/osr-media/lib/media/images'
|
||||
|
||||
import {
|
||||
ENABLED_PRODUCTS, I18N_SOURCE_LANGUAGE, I18N_STORE,
|
||||
LANGUAGES,
|
||||
OSRL_ENV, OSRL_LANG_FLAVOR,
|
||||
OSRL_MODULE_NAME, OSR_ROOT, PRODUCTS_TARGET_SRC, PRODUCT_CONFIG, PRODUCT_HUGO_TEMPLATE, OSRL_PRODUCT_PROFILE, PRODUCT_ROOT, PRODUCT_DIR,
|
||||
OSRL_ENVIRONMENT,
|
||||
RETAIL_LOG_LEVEL_I18N_PRODUCT_ASSETS,
|
||||
TASK_CONFIG_LOG_DIRECTORY
|
||||
} from './config'
|
||||
|
||||
|
||||
import { GalleryImage } from './images'
|
||||
|
||||
const debug = false
|
||||
const verbose = true
|
||||
|
||||
const logger = _logger('ph-site')
|
||||
const IMAGES_GLOB = '*.+(JPG|jpg|png|PNG|gif)'
|
||||
|
||||
const _convertProductMedia = true
|
||||
const _translateProductAssets = true
|
||||
const _populateProductDefaults = true
|
||||
|
||||
|
||||
export const createSubLogger = (root: Logger, level: string, name: string): Logger => {
|
||||
|
||||
const ret = root.getChildLogger({
|
||||
name,
|
||||
type: "pretty",
|
||||
displayInstanceName: true,
|
||||
displayFilePath: 'hidden',
|
||||
instanceName: name,
|
||||
displayFunctionName: true,
|
||||
displayRequestId: true,
|
||||
displayLogLevel: true,
|
||||
colorizePrettyLogs: true,
|
||||
hostname: "osr-cli",
|
||||
displayLoggerName: true,
|
||||
displayTypes: false,
|
||||
prefix: ["\n\t "],
|
||||
})
|
||||
|
||||
const logFile = path.resolve(resolve(`${TASK_CONFIG_LOG_DIRECTORY}/${name}.log`))
|
||||
const stream = createStream(logFile,
|
||||
{
|
||||
size: "10M", // rotate every 10 MegaBytes written
|
||||
interval: "1d", // rotate daily
|
||||
compress: "gzip", // compress rotated files
|
||||
});
|
||||
|
||||
const transport = {
|
||||
minLevel: level,
|
||||
transportLogger: {
|
||||
info: (logObject: ILogObject) => {
|
||||
stream.write(JSON.stringify(logObject, null, 2) + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.attachTransport(transport.transportLogger as any, level as any)
|
||||
return logger
|
||||
}
|
||||
|
||||
export const writeTaskConfig = (taskName, config: any) => {
|
||||
const file = path.resolve(resolve(`${TASK_CONFIG_LOG_DIRECTORY}/${taskName}.json`))
|
||||
write(file, JSON.stringify(config, null, 2))
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
export const item = (rel) => `machines/${rel}`
|
||||
|
||||
export const injectors = [
|
||||
|
||||
item('injection/elena'),
|
||||
item('injection/elena-xmax'),
|
||||
item('injection/lever'),
|
||||
item('injection/lever-laser-cut'),
|
||||
item('injection/myriad'),
|
||||
item('injection/components/304_Valve-40mm')
|
||||
]
|
||||
|
||||
export const shredders = [
|
||||
item('shredder/pp-v2.1'),
|
||||
item('shredder/pp-v3.3'),
|
||||
item('shredder/asterix-pp'),
|
||||
item('shredder/asterix-sm-morren'),
|
||||
item('shredder/pp-v4'),
|
||||
item('shredder/pp-v42'),
|
||||
item('shredder/obelix'),
|
||||
item('shredder/idefix'),
|
||||
item('shredder/components/shredder_v31-light'),
|
||||
item('shredder/bicycle-shredder'),
|
||||
item('zoe')
|
||||
]
|
||||
export const extruders = [
|
||||
item('extrusion/lydia-mini'),
|
||||
item('extrusion/lydia-v3.5'),
|
||||
item('extrusion/lydia-v4.5'),
|
||||
item('extrusion/pp-v3'),
|
||||
item('extrusion/pp-v4-extruder'),
|
||||
item('extrusion/pp-v42-extruder'),
|
||||
item('extrusion/lydia-print-head'),
|
||||
item('extrusion/components/202_FilamentHousing'),
|
||||
item('extrusion/components/102_lucy-mini')
|
||||
]
|
||||
|
||||
export const sheetpresses = [
|
||||
item('sheetpress/100cm'),
|
||||
item('sheetpress/110cm-fiction-factory'),
|
||||
item('sheetpress/150cm'),
|
||||
item('sheetpress/cassandra'),
|
||||
item('sheetpress/cassandra-light'),
|
||||
item('sheetpress/sheetpress-cell')
|
||||
]
|
||||
|
||||
export const test_items = [
|
||||
//item('sheetpress/100cm'),
|
||||
// item('sheetpress/110cm-fiction-factory')
|
||||
// item('extrusion/plastic-odyssey'),
|
||||
item('injection/elena'),
|
||||
//item('injection/lever')
|
||||
//'products/zoe',
|
||||
// 'products/sheetpress/cassandra-light',
|
||||
// 'products/sheetpress/sheetpress-cell',
|
||||
//'products/components/700_UniversalHousing'
|
||||
//'products/shredder/components/shredder_v33',
|
||||
//'products/shredder/asterix-sm'
|
||||
];
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
|
||||
import * as path from 'path'
|
||||
import * as pMap from 'p-map'
|
||||
import { resolve } from '@plastichub/osr-cli-commons/fs'
|
||||
import { files } from '@plastichub/osr-cli-commons/glob'
|
||||
|
||||
import { sync as exists } from '@plastichub/fs/exists'
|
||||
import { sync as read } from '@plastichub/fs/read'
|
||||
|
||||
import { logger as _logger } from '@plastichub/core/debug'
|
||||
import * as ExifReader from 'exifreader'
|
||||
|
||||
import { translateText } from '@plastichub/osr-i18n/lib/translate'
|
||||
import { resize, getResizePatterns, format, getFormats, meta } from '@plastichub/osr-media/lib/media/images'
|
||||
|
||||
import {
|
||||
I18N_STORE,
|
||||
|
||||
OSR_ROOT, PRODUCT_CONFIG, PRODUCT_ROOT,
|
||||
RETAIL_MEDIA_CACHE
|
||||
} from './config'
|
||||
import { GalleryImage } from './images'
|
||||
|
||||
const logger = _logger('ph-site')
|
||||
const IMAGES_GLOB = '*.+(JPG|jpg|png|PNG|gif)'
|
||||
|
||||
export const productGallery = async (grunt, assetPath, product, lang, dstLanguage): Promise<GalleryImage[]> => {
|
||||
product = '' + product
|
||||
const root = resolve(PRODUCT_ROOT())
|
||||
const productConfig: any = read(PRODUCT_CONFIG(product), "json")
|
||||
if (!productConfig) {
|
||||
logger.error('Product config not found !' + product)
|
||||
return
|
||||
}
|
||||
const mediaPath = `${root}/${product}/${assetPath}/`
|
||||
if (!exists(mediaPath)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const galleryFiles = files(mediaPath, IMAGES_GLOB, {
|
||||
cwd: mediaPath,
|
||||
absolute: false
|
||||
})
|
||||
|
||||
if (!galleryFiles) {
|
||||
return
|
||||
}
|
||||
const removeBufferValues = (obj: any): any => {
|
||||
for (const key in obj) {
|
||||
const val = obj[key]
|
||||
if (Buffer.isBuffer(val)) {
|
||||
}
|
||||
if (Buffer.isBuffer(val)) {
|
||||
delete obj[key];
|
||||
} else if (typeof val === 'object') {
|
||||
removeBufferValues(val);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
const removeArrayValues = (obj: any): any => {
|
||||
for (const key in obj) {
|
||||
if (key == 'id') {
|
||||
delete obj[key]
|
||||
}
|
||||
if (Array.isArray(obj[key]) || Buffer.isBuffer(obj[key])) {
|
||||
delete obj[key];
|
||||
} else if (typeof obj[key] === 'object') {
|
||||
removeArrayValues(obj[key]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
const removeEmptyObjects = (obj: any): any => {
|
||||
for (const key in obj) {
|
||||
if (typeof obj[key] === 'object' ||
|
||||
(key == 'value' && typeof obj[key] === 'number' && obj[key] === 0 ||
|
||||
key == 'base64')
|
||||
) {
|
||||
obj[key] = removeEmptyObjects(obj[key]);
|
||||
if (Object.keys(obj[key]).length === 0) {
|
||||
delete obj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
const removeArrays = (obj: any): any => {
|
||||
for (const key in obj) {
|
||||
if (key == 'description' && typeof obj[key] === 'string' && obj[key].split(',').length > 2) {
|
||||
try {
|
||||
if (Buffer.isBuffer(Buffer.from(obj[key].split(','))))
|
||||
delete obj[key]
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
} else if (typeof obj[key] === 'object') {
|
||||
removeArrays(obj[key]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
return await pMap(galleryFiles, async (file: string) => {
|
||||
const parts = path.parse(file)
|
||||
const filePath = path.join(mediaPath, file)
|
||||
let imageMeta: any = await meta(filePath)
|
||||
const exifRaw: any = await ExifReader.load(filePath)
|
||||
const title = exifRaw?.title?.description || ''
|
||||
const keywords = exifRaw?.['LastKeywordXMP']?.description || exifRaw?.iptc?.Keywords?.description || ''
|
||||
const exifDescription = exifRaw?.['ImageDescription']?.description || ''
|
||||
const width = exifRaw?.['Image Width']?.value
|
||||
const height = exifRaw?.['Image Height']?.value
|
||||
const lon = exifRaw?.['GPSLongitude']?.description
|
||||
const lat = exifRaw?.['GPSLatitude']?.description
|
||||
const description = exifDescription || exifRaw?.iptc?.['Caption/Abstract'].description || ''
|
||||
imageMeta.exif = exifRaw
|
||||
imageMeta = removeBufferValues(imageMeta)
|
||||
imageMeta = removeArrayValues(imageMeta)
|
||||
imageMeta = removeArrays(imageMeta)
|
||||
imageMeta = removeEmptyObjects(imageMeta)
|
||||
delete imageMeta.xmp
|
||||
delete imageMeta.icc
|
||||
delete imageMeta.exif.icc
|
||||
delete imageMeta.exif.xmp
|
||||
delete imageMeta.exif.iptc
|
||||
const keywordsTranslated = await translateText(keywords || '', lang, dstLanguage,{
|
||||
store: I18N_STORE(OSR_ROOT(), dstLanguage)
|
||||
})
|
||||
const assetUrl = (filePath) => `[[OSR_MACHINES_ASSETS_URL]]/[[product_relative]]/${assetPath}/${filePath}`
|
||||
const ret: GalleryImage =
|
||||
{
|
||||
name: path.parse(file).name,
|
||||
url: assetUrl(file),
|
||||
thumb: assetUrl(`/20/webp/${parts.name}.webp`),
|
||||
responsive: assetUrl(`/webp/${parts.name}.webp`),
|
||||
meta: imageMeta || "",
|
||||
keywords: keywords.split(',').map((k) => k.trim()),
|
||||
description,
|
||||
alt: `${description} - ${keywordsTranslated || ''}`,
|
||||
width,
|
||||
height,
|
||||
title
|
||||
}
|
||||
return ret
|
||||
})
|
||||
}
|
||||
export const compileProductAssets = async (grunt, product_root, srcLang, dstLanguage) => {
|
||||
logger.info('Resize Product Media Assets ', product_root);
|
||||
|
||||
await resize(getResizePatterns(product_root, 'drawings'))
|
||||
await format(getFormats(product_root, 'drawings'), { png: false, cache: RETAIL_MEDIA_CACHE })
|
||||
|
||||
await resize(getResizePatterns(product_root, 'renderings'))
|
||||
await format(getFormats(product_root, 'renderings'), { png: false, cache: RETAIL_MEDIA_CACHE })
|
||||
|
||||
await resize(getResizePatterns(product_root, 'renderings/20'))
|
||||
await format(getFormats(product_root, 'renderings/20'), { png: false, cache: RETAIL_MEDIA_CACHE })
|
||||
|
||||
await resize(getResizePatterns(product_root, 'media/gallery'))
|
||||
await format(getFormats(product_root, 'media/gallery'), { png: false, cache: RETAIL_MEDIA_CACHE })
|
||||
await resize(getResizePatterns(product_root, 'media/gallery/20'))
|
||||
await format(getFormats(product_root, 'media/gallery/20'), { png: false, cache: RETAIL_MEDIA_CACHE })
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
|
||||
import * as path from 'path'
|
||||
import { CONFIG_DEFAULT } from '@plastichub/osr-cli-commons'
|
||||
import { resolve } from '@plastichub/osr-cli-commons/fs'
|
||||
|
||||
import { sync as exists } from '@plastichub/fs/exists'
|
||||
import { sync as read } from '@plastichub/fs/read'
|
||||
import { sync as write } from '@plastichub/fs/write'
|
||||
|
||||
import { logger as _logger } from '@plastichub/core/debug'
|
||||
|
||||
import { sanitize } from '@plastichub/osr-i18n/_cli'
|
||||
import { IOptions as IOptionsI18n } from '@plastichub/osr-i18n/types'
|
||||
import { translate } from '@plastichub/osr-i18n/lib/translate'
|
||||
|
||||
import { compileProductAssets, productGallery } from './media'
|
||||
import { writeTaskConfig } from './log'
|
||||
|
||||
import {
|
||||
ENABLED_PRODUCTS, I18N_SOURCE_LANGUAGE, I18N_STORE,
|
||||
LANGUAGES,
|
||||
OSRL_ENV, OSRL_LANG_FLAVOR,
|
||||
OSRL_MODULE_NAME, OSR_ROOT, PRODUCTS_TARGET_SRC, PRODUCT_CONFIG, PRODUCT_HUGO_TEMPLATE, OSRL_PRODUCT_PROFILE, PRODUCT_ROOT, PRODUCT_DIR,
|
||||
OSRL_ENVIRONMENT,
|
||||
RETAIL_LOG_LEVEL_I18N_PRODUCT_ASSETS,
|
||||
TranslateProductAssets,
|
||||
ConvertProductMedia,
|
||||
PopulateProductDefaults,
|
||||
RETAIL_COMPILE_CACHE
|
||||
} from './config'
|
||||
import { ICompileTaskOptions } from '@plastichub/osr-tasks/tasks/compile'
|
||||
const logger = _logger('ph-site')
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Product Multi Task products[product] -> content/retail/product
|
||||
export const populateProductDefaults = async (grunt, product_root, srcLang, dstLanguage) => {
|
||||
const _createFile = (file: string) => {
|
||||
file = path.resolve(path.join(product_root, file))
|
||||
if (!exists(file)) {
|
||||
write(file, '')
|
||||
}
|
||||
}
|
||||
_createFile('templates/shared/product_features.md')
|
||||
}
|
||||
export const compileProductTask = async (grunt, product, lang, dstLanguage, target, options: any = {}) => {
|
||||
const config = {}
|
||||
product = '' + product
|
||||
const logLevel = grunt.option('logLevel') || 'warn'
|
||||
const product_rel = product.replace('products/', '')
|
||||
const root = resolve(PRODUCT_ROOT())
|
||||
const slug = path.parse(product).base
|
||||
const debug = grunt.option('debug')
|
||||
const productConfig: any = read(PRODUCT_CONFIG(product), "json")
|
||||
if (!productConfig) {
|
||||
logger.error('Product config not found !' + product)
|
||||
return
|
||||
}
|
||||
productConfig.description = productConfig.description || ''
|
||||
if (!productConfig) {
|
||||
logger.error('Product config not found !' + product)
|
||||
return
|
||||
}
|
||||
const translateProductAssets = async () => {
|
||||
logger.info('Translate Product Assets ' + slug + ' ' + dstLanguage + ' ' + product_rel)
|
||||
const config: any = CONFIG_DEFAULT()
|
||||
if (dstLanguage === I18N_SOURCE_LANGUAGE) {
|
||||
return
|
||||
}
|
||||
//const _logger = createSubLogger(logger, logLevel, 'i18n')
|
||||
logger.setSettings({ minLevel: RETAIL_LOG_LEVEL_I18N_PRODUCT_ASSETS })
|
||||
const i18nOptions: IOptionsI18n = {
|
||||
srcLang: I18N_SOURCE_LANGUAGE,
|
||||
dstLang: dstLanguage,
|
||||
src: `${PRODUCT_DIR(product)}/specs.xlsx`,
|
||||
store: I18N_STORE(OSR_ROOT(), dstLanguage),
|
||||
dst: "${SRC_DIR}/${SRC_NAME}-${DST_LANG}${SRC_EXT}",
|
||||
query: "$[*][0,1]",
|
||||
cache: true,
|
||||
api_key: config.deepl.auth_key,
|
||||
logLevel: RETAIL_LOG_LEVEL_I18N_PRODUCT_ASSETS
|
||||
}
|
||||
const ret = await translate(sanitize(i18nOptions) as any)
|
||||
return ret
|
||||
}
|
||||
|
||||
const onCompiled = async (src, dst, options, content) => {
|
||||
// translate specs
|
||||
if (TranslateProductAssets || grunt.option('translateProductAssets')) {
|
||||
await translateProductAssets()
|
||||
}
|
||||
if (ConvertProductMedia || grunt.option('convertProductMedia')) {
|
||||
await compileProductAssets(grunt, PRODUCT_DIR(product), lang, dstLanguage)
|
||||
}
|
||||
if (PopulateProductDefaults) {
|
||||
await populateProductDefaults(grunt, PRODUCT_DIR(product), lang, dstLanguage)
|
||||
}
|
||||
// logger.warn('On Compiled Product ' + product + ' ' + dstLanguage)
|
||||
}
|
||||
|
||||
let defaultOptions: any = {
|
||||
src: [path.resolve(path.join(root, PRODUCT_HUGO_TEMPLATE))],
|
||||
options: {
|
||||
cache: RETAIL_COMPILE_CACHE,
|
||||
debug,
|
||||
env: OSRL_ENVIRONMENT,
|
||||
format: 'html',
|
||||
language: OSRL_LANG_FLAVOR,
|
||||
module: OSRL_MODULE_NAME,
|
||||
output: `${target}/${product_rel}/_index.md`,
|
||||
profile: OSRL_PRODUCT_PROFILE,
|
||||
root,
|
||||
cwd: root,
|
||||
watchContent: false,
|
||||
logLevel,
|
||||
store: I18N_STORE(OSR_ROOT(), dstLanguage),
|
||||
sourceLanguage: I18N_SOURCE_LANGUAGE,
|
||||
targetLanguage: dstLanguage,
|
||||
variables: {
|
||||
root,
|
||||
product,
|
||||
product_rel,
|
||||
product_relative: '' + product_rel,
|
||||
sourceLanguage: I18N_SOURCE_LANGUAGE,
|
||||
targetLanguage: dstLanguage,
|
||||
language: dstLanguage,
|
||||
i18n: I18N_STORE(OSR_ROOT(), dstLanguage),
|
||||
...productConfig,
|
||||
fm: {
|
||||
keywords: (productConfig.keywords || "").split(',').map((k) => k.trim())
|
||||
}
|
||||
},
|
||||
...options,
|
||||
onCompileDone: onCompiled,
|
||||
onCompile: async (options) => {
|
||||
const gallery = await productGallery(grunt, 'media/gallery', product, lang, dstLanguage)
|
||||
const galleryRenderings = await productGallery(grunt, 'renderings', product, lang, dstLanguage)
|
||||
options.variables.fm.rGallery = gallery
|
||||
options.variables.fm.rGalleryRenderings = galleryRenderings
|
||||
return options
|
||||
}
|
||||
} as ICompileTaskOptions
|
||||
}
|
||||
debug && logger.debug('Create product compile options for ' + product, defaultOptions.options)
|
||||
config[`content-${dstLanguage}-${slug}`] = {
|
||||
...defaultOptions,
|
||||
}
|
||||
grunt.extendConfig({ compile: config })
|
||||
grunt.registerTask(`content-${dstLanguage}-${slug}`, `compile:content-${dstLanguage}-${slug}`)
|
||||
}
|
||||
export const registerProductTasks = (grunt) => {
|
||||
const logLevel = grunt.option('logLevel') || 'warn'
|
||||
logger.setSettings({ minLevel: logLevel })
|
||||
const product_compile_tasks = []
|
||||
const productTasks = (items) => {
|
||||
items.forEach((product) => {
|
||||
const slug = path.parse(product).base
|
||||
compileProductTask(grunt, product, I18N_SOURCE_LANGUAGE, I18N_SOURCE_LANGUAGE, "./content/en/retail")
|
||||
product_compile_tasks.push(`compile:content-en-${slug}`)
|
||||
LANGUAGES.forEach((lang) => {
|
||||
product_compile_tasks.push(`compile:content-${lang}-${slug}`)
|
||||
compileProductTask(grunt, product, I18N_SOURCE_LANGUAGE, lang, `./content/${lang}/retail`)
|
||||
})
|
||||
})
|
||||
}
|
||||
productTasks(readProducts(grunt.option('branch') || 'test'))
|
||||
grunt.registerTask(`content-all`, product_compile_tasks)
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Product Single Test Task products[product] -> src/retail/product
|
||||
export const productContentOptions = (target, product) => {
|
||||
product = '' + product
|
||||
const product_rel = product.replace('products/', '')
|
||||
const root = resolve(PRODUCT_ROOT())
|
||||
const productConfig: any = read(PRODUCT_CONFIG(product), "json")
|
||||
if (!productConfig) {
|
||||
logger.error('Product config not found !' + product)
|
||||
}
|
||||
|
||||
return {
|
||||
debug: false,
|
||||
watch: false,
|
||||
root,
|
||||
cwd: root,
|
||||
env: OSRL_ENV,
|
||||
profile: '${root}/.osrl.json',
|
||||
output: `${target}/${product_rel}/_index.md`,
|
||||
// format: 'html',
|
||||
module: OSRL_MODULE_NAME,
|
||||
cache: true,
|
||||
variables: {
|
||||
product,
|
||||
product_rel,
|
||||
root,
|
||||
product_relative: '' + product_rel,
|
||||
...productConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
export const productHugoTask = (grunt, product, options: any = {}, product_item_tasks) => {
|
||||
if (!product) {
|
||||
logger.error('Invalid product')
|
||||
}
|
||||
const config = {}
|
||||
const slug = path.parse(product).base
|
||||
const target = path.resolve(PRODUCTS_TARGET_SRC)
|
||||
const productOptions = productContentOptions(target, product)
|
||||
config[`product-${slug}`] = {
|
||||
src: [PRODUCT_HUGO_TEMPLATE],
|
||||
options: productOptions
|
||||
}
|
||||
grunt.extendConfig({
|
||||
compile: config
|
||||
})
|
||||
grunt.registerTask(`product-${slug}`, `compile:product-${slug}`)
|
||||
product_item_tasks.push(`compile:product-${slug}`)
|
||||
grunt.registerTask(`products-hugo`, product_item_tasks)
|
||||
writeTaskConfig(`compile_product-${slug}`, config)
|
||||
}
|
||||
export const readProducts = (branch: string = 'test') => {
|
||||
const conf = read(ENABLED_PRODUCTS, "json") || {}
|
||||
if (branch) {
|
||||
conf['all'] = [...conf["sheetpress"], ...conf["injectors"], ...conf["extruders"], ...conf["shredders"]]
|
||||
return conf[branch] || []
|
||||
} else {
|
||||
return Object.values(conf).flat()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user