UNPKG

cep-bundler-core

Version:

Core functionality for making bundler extensions to compile CEP

342 lines (320 loc) 10.9 kB
import os from 'os' import path from 'path' import { execSync } from 'child_process' import fs from 'fs-extra' import manifestTemplate from './templates/manifest' import panelTemplate from './templates/html' import debugTemplate from './templates/.debug' function templateDebug(formatter: any) { return [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16].map(formatter).join(os.EOL) } export function enablePlayerDebugMode() { // enable unsigned extensions if (process.platform === 'darwin') { execSync(templateDebug((i: number) => `defaults write com.adobe.CSXS.${i} PlayerDebugMode 1`)) } else { execSync( templateDebug((i: number) => `REG ADD HKCU\\Software\\Adobe\\CSXS.${i} /f /v PlayerDebugMode /t REG_SZ /d 1`), ) } } export function disablePlayerDebugMode() { // disable unsigned extensions if (process.platform === 'darwin') { execSync(templateDebug((i: number) => `defaults write com.adobe.CSXS.${i} PlayerDebugMode 0`)) } else { execSync(templateDebug((i: number) => `REG DELETE HKCU\\Software\\Adobe\\CSXS.${i} /f /v PlayerDebugMode`)) } } function camelToSnake(str: string) { return str.replace(/([A-Z])/g, (part) => `_${part.toLowerCase()}`) } function isTruthy(str: any) { return typeof str === 'string' && (str === '1' || str.toLowerCase() === 'true') } function getEnvConfig() { const debugPortEnvs = Object.keys(process.env).filter((key) => key.indexOf('CEP_DEBUG_PORT_') === 0) return { bundleName: process.env.CEP_NAME, bundleId: process.env.CEP_ID, bundleVersion: process.env.CEP_VERSION, cepVersion: process.env.CEP_CEP_VERSION, hosts: process.env.CEP_HOSTS, iconNormal: process.env.CEP_ICON_NORMAL, iconRollover: process.env.CEP_ICON_ROLLOVER, iconDarkNormal: process.env.CEP_ICON_DARK_NORMAL, iconDarkRollover: process.env.CEP_ICON_DARK_ROLLOVER, panelWidth: process.env.CEP_PANEL_WIDTH, panelHeight: process.env.CEP_PANEL_HEIGHT, panelMinWidth: process.env.CEP_PANEL_MIN_WIDTH, panelMinHeight: process.env.CEP_PANEL_MIN_HEIGHT, panelMaxWidth: process.env.CEP_PANEL_MAX_WIDTH, panelMaxHeight: process.env.CEP_PANEL_MAX_HEIGHT, devHost: process.env.CEP_DEV_HOST, devPort: !process.env.CEP_DEV_PORT ? undefined : Number(process.env.CEP_DEV_PORT), debugPorts: debugPortEnvs.length > 0 ? debugPortEnvs.reduce((obj, key) => { obj[key.replace('CEP_DEBUG_PORT_', '')] = parseInt(process.env[key] || '', 10) return obj }, {} as any) : undefined, debugInProduction: isTruthy(process.env.CEP_DEBUG_IN_PRODUCTION) || undefined, cefParams: !process.env.CEP_CEF_PARAMS ? undefined : process.env.CEP_CEF_PARAMS.split(','), } } function getPkgConfig(pkg: any, env?: string) { const pkgConfig = pkg.hasOwnProperty('cep') ? (env && pkg.cep.hasOwnProperty(env) ? pkg.cep[env] : pkg.cep) : {} return { bundleName: pkgConfig.name, bundleId: pkgConfig.id, bundleVersion: pkgConfig.version, cepVersion: pkgConfig.cepVersion, hosts: pkgConfig.hosts, iconNormal: pkgConfig.iconNormal, iconRollover: pkgConfig.iconRollover, iconDarkNormal: pkgConfig.iconDarkNormal, iconDarkRollover: pkgConfig.iconDarkRollover, panelWidth: pkgConfig.panelWidth, panelHeight: pkgConfig.panelHeight, panelMinWidth: pkgConfig.panelMinWidth, panelMinHeight: pkgConfig.panelMinHeight, panelMaxWidth: pkgConfig.panelMaxWidth, panelMaxHeight: pkgConfig.panelMaxHeight, debugPorts: pkgConfig.debugPorts, debugInProduction: pkgConfig.debugInProduction, lifecycle: pkgConfig.lifecycle, cefParams: pkgConfig.cefParams, htmlFilename: pkgConfig.htmlFilename, extensions: pkgConfig.extensions, devHost: pkgConfig.devHost, devPort: pkgConfig.devPort, } } function getConfigDefaults() { return { bundleName: 'CEP Extension', bundleId: 'com.mycompany.myextension', hosts: '*', debugInProduction: false, cepVersion: '8.0', panelWidth: 500, panelHeight: 500, htmlFilename: './index.html', devHost: 'localhost', devPort: 8080, lifecycle: { autoVisible: true, startOnEvents: [], }, cefParams: ['--allow-file-access-from-files', '--allow-file-access', '--enable-nodejs', '--mixed-context'], debugPorts: { PHXS: 3001, IDSN: 3002, AICY: 3003, ILST: 3004, PPRO: 3005, PRLD: 3006, AEFT: 3007, FLPR: 3008, AUDT: 3009, DRWV: 3010, MUST: 3011, KBRG: 3012, }, } } function assignDefined(target: any, ...sources: any) { for (const source of sources) { for (const key of Object.keys(source)) { const val = source[key] if (val !== undefined) { target[key] = val } } } return target } export function getConfig(pkg: any, env?: string) { const config = assignDefined({}, getConfigDefaults(), getPkgConfig(pkg, env), getEnvConfig()) // console.log('DEFAULTS', config) config.hosts = parseHosts(config.hosts) let extensions = [] if (Array.isArray(config.extensions)) { extensions = config.extensions.map((extension: any) => { return assignDefined({}, config, extension) }) } else { extensions.push({ id: config.bundleId, name: config.bundleName, ...config, }) } config.extensions = extensions // console.log('FINAL', config) return config } export function objectToProcessEnv(obj: any) { // assign object to process.env so they can be used in the code Object.keys(obj).forEach((key) => { const envKey = camelToSnake(key).toUpperCase() const value = typeof obj[key] === 'string' ? obj[key] : JSON.stringify(obj[key]) process.env[envKey] = value }) } export function writeExtensionTemplates(opts: any) { const manifestContents = manifestTemplate(opts) const { out, debugInProduction, isDev, extensions } = opts const manifestDir = path.join(out, 'CSXS') const manifestFile = path.join(manifestDir, 'manifest.xml') return Promise.resolve() .then(() => fs.ensureDir(manifestDir)) .then(() => fs.writeFile(manifestFile, manifestContents)) .then(() => { let chain = Promise.resolve() if (debugInProduction || isDev) { const debugContents = debugTemplate(opts) chain = chain.then(() => fs.writeFile(path.join(out, '.debug'), debugContents)) } if (isDev) { extensions.forEach((extension: any) => { const href = `http://${extension.devHost}:${extension.devPort}` const panelContents = panelTemplate({ title: extension.name, href, }) chain = chain.then(() => fs.writeFile(path.join(out, `dev.${extension.id}.html`), panelContents)) }) } return chain }) } export function parseHosts(hostsString: string) { if (hostsString == '*') hostsString = `PHXS, IDSN, AICY, ILST, PPRO, PRLD, AEFT, FLPR, AUDT, DRWV, MUST, KBRG` const hosts = hostsString .split(/(?![^)(]*\([^)(]*?\)\)),(?![^\[]*\])/) .map((host) => host.trim()) .map((host) => { // @ts-ignore let [name, version] = host.split('@') if (version == '*' || !version) { version = '[0.0,99.9]' } else if (version) { version = version } return { name, version, } }) return hosts } export function getExtensionPath() { if (process.platform == 'darwin') { return path.join(os.homedir(), '/Library/Application Support/Adobe/CEP/extensions') } else { return path.join(process.env.APPDATA || '', 'Adobe/CEP/extensions') } } function getSymlinkExtensionPath({ bundleId }: { bundleId: string }) { const extensionPath = getExtensionPath() return path.join(extensionPath, bundleId) } export function symlinkExtension({ bundleId, out }: { bundleId: string; out: string }) { const target = getSymlinkExtensionPath({ bundleId }) return Promise.resolve() .then(() => fs.ensureDir(getExtensionPath())) .then(() => fs.remove(target)) .then(() => { if (process.platform === 'win32') { return fs.symlink(path.join(out, '/'), target, 'junction') } else { return fs.symlink(path.join(out, '/'), target) } }) } export function copyDependencies({ root, out, pkg }: { root: string; out: string; pkg: any }) { const deps = pkg.dependencies || {} return Object.keys(deps).reduce((chain, dep) => { if (dep.indexOf('/') !== -1) { dep = dep.split('/')[0] } const src = path.join(root, 'node_modules', dep) const dest = path.join(out, 'node_modules', dep) let exists = false try { exists = fs.statSync(dest).isFile() } catch (err) {} if (!exists) { chain = chain .then(() => fs.copy(src, dest)) .catch(() => { console.error(`Could not copy ${src} to ${dest}. Ensure the path is correct.`) }) .then(() => { try { const packageJson = fs.readJsonSync(path.join(root, 'node_modules', dep, 'package.json')) return copyDependencies({ root, out, pkg: packageJson, }) } catch (err) { return } }) return chain } return chain }, Promise.resolve()) } export function copyIcons({ root, out, iconNormal, iconRollover, iconDarkNormal, iconDarkRollover }: any) { const iconPaths = [iconNormal, iconRollover, iconDarkNormal, iconDarkRollover] .filter((icon) => icon !== undefined) .map((icon) => ({ source: path.resolve(root, icon), output: path.join(out, path.relative(root, icon)), })) return Promise.all( iconPaths.map((icon) => { return fs.copy(icon.source, icon.output).catch(() => { console.error(`Could not copy ${icon.source}. Ensure the path is correct.`) }) }), ) } interface CompileOptions { env?: string root?: string htmlFilename?: string isDev?: boolean pkg?: any } export function compile(opts: CompileOptions) { opts.env = opts.env ? opts.env : process.env.NODE_ENV opts.root = opts.root ? opts.root : process.cwd() opts.htmlFilename = opts.htmlFilename ? opts.htmlFilename : './index.html' opts.pkg = opts.pkg ? opts.pkg : require(path.join(opts.root, '/package.json')) opts.isDev = opts.hasOwnProperty('isDev') ? opts.isDev : false const config = getConfig(opts.pkg, opts.env) const allOpts = { ...opts, ...config, } let chain = Promise.resolve() if (opts.isDev) { enablePlayerDebugMode() if (!config.noSymlink) { chain = chain.then(() => symlinkExtension(allOpts)) } } chain = chain .then(() => copyDependencies(allOpts)) .then(() => writeExtensionTemplates(allOpts)) .then(() => copyIcons(allOpts)) .then(() => { // noop }) return chain }