UNPKG

patternplate-server

Version:

Programmatically serve atomic patterns via a REST API

491 lines (364 loc) 19.7 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; let exportAsCommonjs = (() => { var _ref = _asyncToGenerator(function* (application, settings) { (0, _assert2.default)(typeof settings.patterns === 'object', `build-commonjs needs a valid patterns configuration. ${where} build-commonjs.patterns`); (0, _assert2.default)(typeof settings.patterns.formats === 'object', `build-commonjs needs a valid patterns.formats configuration. ${where} build-commonjs.patterns.formats`); (0, _assert2.default)(typeof settings.transforms === 'object', `build-commonjs needs a valid transforms configuration. ${where} build-commonjs.transforms`); let spinner = (0, _ora2.default)().start(); const debug = (0, _util.debuglog)('commonjs'); debug('calling commonjs with'); debug(settings); const cwd = application.runtime.patterncwd || application.runtime.cwd; const patternRoot = (0, _path.resolve)(cwd, 'patterns'); const commonjsRoot = (0, _path.resolve)(cwd, settings.out || (0, _path.join)('build', 'build-commonjs')); const manifestPath = (0, _path.resolve)(commonjsRoot, 'package.json'); const filters = _extends({}, settings.filters || {}, { baseNames: ['index'] }); const warnings = []; const warn = application.log.warn; application.log.warn = function () { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } if (args.some(function (arg) { return arg.includes('Deprecation'); })) { warnings.push(args); return; } warn.apply(undefined, args); }; // Override pattern config settings.patterns.formats = (0, _pattern.normalizeFormats)(settings.patterns.formats); application.configuration.patterns = settings.patterns; // Reinitialize transforms application.configuration.transforms = settings.transforms || {}; application.transforms = (yield (0, _transforms.loadTransforms)(settings.transforms || {}))(application); // start reading pattern mtimes, ignore dependencies const mtimesStart = new Date(); application.log.debug(_decorations.wait`Obtaining pattern modification times`); const readingPatternMtimes = (0, _getPatternMtimes2.default)('./patterns', { resolveDependencies: false, filters: filters }); // start reading artifact mtimes const artifactMtimesStart = new Date(); const readingArtifactMtimes = (0, _getArtifactMtimes2.default)(commonjsRoot, application.configuration.patterns, application.configuration.transforms); // wait for all mtimes to trickle in const patternMtimes = yield readingPatternMtimes; application.log.debug(_decorations.ok`Read pattern modification times ${mtimesStart}`); // wait for all artifact mtimes const artifactMtimes = yield readingArtifactMtimes; application.log.debug(_decorations.ok`Read artifact modification times ${artifactMtimesStart}`); // check if package.json is in distribution const hasManifest = yield (0, _pathExists2.default)((0, _path.resolve)(commonjsRoot, 'package.json')); const previousPkgString = hasManifest ? (yield readFile(manifestPath)).toString('utf-8') : null; const pkgConfig = settings.pkg || {}; const previousPkg = hasManifest ? parseJSON(previousPkgString) : fallbackManifest; const previousPkgConfig = previousPkg.ppcommonjs || {}; const previousDependencies = previousPkg.ppDependencies || {}; const previousDevdependencies = previousPkg.ppDevdependencies || {}; const pkgConfigChanged = !(0, _lodash.isEqual)(previousPkgConfig, pkgConfig) || !(0, _lodash.isEqual)(previousDependencies, pkg.dependencies || {}) || !(0, _lodash.isEqual)(previousDevdependencies, pkg.devDependencies || {}); // obtain patterns we have to build application.log.debug(_decorations.wait`Calculating pattern collection to build`); let buildCount = 1; const patternFilter = pkgConfigChanged ? function (i) { return i; } : (0, _getPatternsToBuild2.default)(artifactMtimes, application.configuration.patterns); const patternsToBuild = patternMtimes.filter(patternFilter).sort(function (a, b) { return b.mtime.getTime() - a.mtime.getTime(); }); const padMaxBuild = (0, _fp.padEnd)(patternsToBuild.map(function (pattern) { return pattern.id.length; }).reduce(function (a, b) { return a > b ? a : b; }, 0) + 1); if (pkgConfigChanged) { application.log.debug(_decorations.ok`Manifest or pkg config change, building all ${patternMtimes.length} patterns`); } const pruneDetectionStart = new Date(); application.log.debug(_decorations.wait`Searching for artifacts to prune`); let pruneCount = 1; const artifactsToPrune = (0, _getArtifactsToPrune2.default)(commonjsRoot, patternMtimes, artifactMtimes, { resolve: pathFormatString, formats: settings.patterns.formats, transforms: settings.transforms }); const padMaxPrune = (0, _fp.padEnd)(artifactsToPrune.map(function (artifact) { return artifact.length; }).reduce(function (a, b) { return a > b ? a : b; }, 0) + 1); application.log.debug(_decorations.ok`Detected ${artifactsToPrune.length} artifacts to prune ${pruneDetectionStart}`); const pruneStart = new Date(); application.log.debug(_decorations.wait`Pruning ${artifactsToPrune.length} artifacts`); const pruning = Promise.all(artifactsToPrune.map((0, _throat2.default)(1, (() => { var _ref2 = _asyncToGenerator(function* (path) { if (settings['dry-run']) { return Promise.resolve(); } spinner.text = `prune ${padMaxPrune(path)} ${pruneCount}/${artifactsToPrune.length}`; yield (0, _removeFile2.default)((0, _path.dirname)(path)); pruneCount += 1; }); return function (_x3) { return _ref2.apply(this, arguments); }; })()))); const pruned = yield pruning; application.log.debug(_decorations.ready`Pruned ${pruned.length} artifact files ${pruneStart}`); spinner.text = `${pruned.length}/${artifactsToPrune.length} pruned`; spinner.succeed(); spinner.stop(); spinner = (0, _ora2.default)().start(); // build patterns in parallel const buildStart = new Date(); const building = Promise.all(patternsToBuild.map((0, _throat2.default)(1, (() => { var _ref3 = _asyncToGenerator(function* (pattern) { const filterStart = new Date(); application.log.debug(_decorations.wait`Checking for files of ${pattern.id} to exclude from transform.`); let changedFiles = []; // enhance filters config to build only files that are modified const artifact = (0, _lodash.find)(artifactMtimes, { id: pattern.id }); if (artifact) { // build up mtime registry for pattern files const filesMtimes = pattern.files.reduce(function (results, file, index) { return _extends({}, results, { [file]: pattern.mtimes[index] }); }, {}); // build up registry for artifact files const artifactFilesMtimes = artifact.files.reduce(function (results, file, index) { const path = (0, _path.relative)(commonjsRoot, file); return _extends({}, results, { [path]: artifact.mtimes[index] }); }, {}); // find pattern files with newer mtime than // - their artifact // - their folder // - their pattern.json changedFiles = pattern.files.filter(function (file) { const formatKey = (0, _path.extname)(file).slice(1); const format = application.configuration.patterns.formats[formatKey]; if (!format) { return false; } const transformNames = format.transforms || []; const lastTransformName = transformNames[transformNames.length - 1]; const lastTransform = application.configuration.transforms[lastTransformName] || {}; const targetExtension = lastTransform.outFormat || formatKey; const targetFile = (0, _patternplateTransformsCore.resolvePathFormatString)(pathFormatString, pattern.id, format.name.toLowerCase(), targetExtension); const targetFileMtime = artifactFilesMtimes[targetFile] || 0; const fileMtime = filesMtimes[file]; const dirMtime = filesMtimes[(0, _path.dirname)(file)]; const metaMtime = filesMtimes[(0, _path.join)((0, _path.dirname)(file), 'pattern.json')]; return fileMtime > targetFileMtime || dirMtime > targetFileMtime || metaMtime > targetFileMtime; }).filter(Boolean); } if (artifact) { filters.in3 = changedFiles.map(function (file) { return (0, _path.extname)(file).slice(1); }); const formats = _chalk2.default.grey(`[${filters.inFormats.join(', ')}]`); application.log.debug(_decorations.ok`Building ${filters.inFormats.length} files for ${pattern.id} ${formats} ${filterStart}`); } else { application.log.debug(_decorations.ok`Building all files for ${pattern.id} ${filterStart}`); } if (settings['dry-run']) { return Promise.resolve({}); } const transformStart = new Date(); application.log.debug(_decorations.wait`Transforming pattern ${pattern.id}`); spinner.text = `build ${padMaxBuild(pattern.id)} ${buildCount}/${patternsToBuild.length}`; buildCount += 1; // obtain transformed pattern by id const patternList = yield (0, _getPatterns2.default)({ id: pattern.id, base: patternRoot, config: application.configuration, factory: application.pattern.factory, transforms: application.transforms, log: application.log, filters: filters }, application.cache); application.log.debug(_decorations.ok`Transformed pattern ${pattern.id} ${transformStart}`); const writeStart = new Date(); application.log.debug(_decorations.ok`Writing artifacts of ${pattern.id}`); // Write results to disk const writingArtifacts = Promise.all(patternList.map((() => { var _ref4 = _asyncToGenerator(function* (patternItem) { const writingPatternItems = Promise.all(Object.entries(patternItem.results).map((() => { var _ref5 = _asyncToGenerator(function* (resultsEntry) { var _resultsEntry = _slicedToArray(resultsEntry, 2); const resultName = _resultsEntry[0]; const result = _resultsEntry[1]; const relativePath = (0, _patternplateTransformsCore.resolvePathFormatString)(pathFormatString, patternItem.id, resultName.toLowerCase(), result.out); const resultPath = (0, _path.join)(commonjsRoot, relativePath); return (0, _writeSafe2.default)(resultPath, result.buffer); }); return function (_x6) { return _ref5.apply(this, arguments); }; })())); return yield writingPatternItems; }); return function (_x5) { return _ref4.apply(this, arguments); }; })())); const written = yield writingArtifacts; application.log.debug(_decorations.ok`Wrote ${written.length} artifacts for ${pattern.id} ${writeStart}`); return patternList; }); return function (_x4) { return _ref3.apply(this, arguments); }; })()))); const built = yield building; application.log.debug(_decorations.ready`Built ${built.length} from ${patternsToBuild.length} planned and ${patternMtimes.length} artifacts overall ${buildStart}`); spinner.text = `${built.length}/${patternsToBuild.length} built`; spinner.succeed(); if (settings['dry-run']) { yield building; spinner.text = `Dry-run executed successfully ${buildStart}`; spinner.succeed(); return; } if (application.resources) { const resources = application.resources.filter(function (r) { return Boolean(r.pattern); }).filter(function (r) { return Boolean(r.file); }); yield Promise.all(resources.map((() => { var _ref6 = _asyncToGenerator(function* (resource) { const format = resource.file.format; const formatConfig = application.configuration.patterns.formats[format]; const resourcePath = (0, _patternplateTransformsCore.resolvePathFormatString)(pathFormatString, resource.pattern, formatConfig.name, resource.type); const artifactPath = (0, _path.join)(commonjsRoot, resourcePath); return (0, _writeSafe2.default)(artifactPath, (yield resource.content)); }); return function (_x7) { return _ref6.apply(this, arguments); }; })())); } const copyStart = new Date(); application.log.debug(_decorations.wait`Copying static files`); yield (0, _copyStatic2.default)(cwd, commonjsRoot); application.log.debug(_decorations.ready`Copied static files. ${copyStart}`); spinner.text = `static files copied`; spinner.succeed(); // Extract dependency information const dependencyLists = (0, _lodash.flatten)(built).reduce(function (registry, patternItem) { var _patternItem$meta = patternItem.meta; const dependencies = _patternItem$meta.dependencies; const devDependencies = _patternItem$meta.devDependencies; return { dependencies: [].concat(_toConsumableArray(registry.dependencies), _toConsumableArray(dependencies || [])), devDependencies: [].concat(_toConsumableArray(registry.devDependencies), _toConsumableArray(devDependencies || [])) }; }, { dependencies: [], devDependencies: [] }); const deps = pkg.dependencies || {}; const devDeps = pkg.devDependencies || {}; const dependencies = dependencyLists.dependencies.reduce(function (results, dependencyName) { return _extends({}, results, { [dependencyName]: deps[dependencyName] || devDeps[dependencyName] || '*' }); }, previousPkg.dependencies); const devDependencies = dependencyLists.devDependencies.reduce(function (results, dependencyName) { return _extends({}, results, { [dependencyName]: deps[dependencyName] || devDeps[dependencyName] || '*' }); }, previousPkg.devDependencies); const prunedDependencies = (0, _lodash.omit)(dependencies, [].concat(_toConsumableArray(settings.ignoredDependencies || []), [_nodeCoreModuleNames2.default])); const prunedDevDependencies = (0, _lodash.omit)(devDependencies, [].concat(_toConsumableArray(settings.ignoredDevDependencies || []), [_nodeCoreModuleNames2.default], _toConsumableArray(Object.keys(dependencies)))); const updatedPackageString = (0, _getPackageString2.default)(prunedDependencies, previousPkg, { devDependencies: prunedDevDependencies, ppcommonjs: pkgConfig, ppDependencies: pkg.dependencies, ppDevdependencies: pkg.devDependencies }, (0, _lodash.omit)(pkg, ['dependencies', 'devDependencies', 'scripts', 'config', 'main']), settings.pkg); if (updatedPackageString !== previousPkgString) { const pkgStart = new Date(); application.log.debug(_decorations.wait`Writing package.json`); yield (0, _writeSafe2.default)(manifestPath, updatedPackageString); application.log.debug(_decorations.ready`Wrote package.json ${pkgStart}`); } const messages = (0, _lodash.uniq)(warnings).map(function (warning) { return warning.join(' '); }); messages.forEach(function (message) { console.log((0, _boxen2.default)(message, { borderColor: 'yellow', padding: 1 })); }); }); return function exportAsCommonjs(_x, _x2) { return _ref.apply(this, arguments); }; })(); var _assert = require('assert'); var _assert2 = _interopRequireDefault(_assert); var _util = require('util'); var _denodeify = require('denodeify'); var _denodeify2 = _interopRequireDefault(_denodeify); var _path = require('path'); var _fs = require('fs'); var _boxen = require('boxen'); var _boxen2 = _interopRequireDefault(_boxen); var _lodash = require('lodash'); var _fp = require('lodash/fp'); var _throat = require('throat'); var _throat2 = _interopRequireDefault(_throat); var _chalk = require('chalk'); var _chalk2 = _interopRequireDefault(_chalk); var _pathExists = require('path-exists'); var _pathExists2 = _interopRequireDefault(_pathExists); var _nodeCoreModuleNames = require('node-core-module-names'); var _nodeCoreModuleNames2 = _interopRequireDefault(_nodeCoreModuleNames); var _patternplateTransformsCore = require('patternplate-transforms-core'); var _ora = require('ora'); var _ora2 = _interopRequireDefault(_ora); var _decorations = require('../../../library/log/decorations'); var _transforms = require('../../../library/transforms'); var _pattern = require('../../../library/pattern'); var _copyStatic = require('../common/copy-static'); var _copyStatic2 = _interopRequireDefault(_copyStatic); var _getArtifactMtimes = require('../../../library/utilities/get-artifact-mtimes'); var _getArtifactMtimes2 = _interopRequireDefault(_getArtifactMtimes); var _getArtifactsToPrune = require('../../../library/utilities/get-artifacts-to-prune'); var _getArtifactsToPrune2 = _interopRequireDefault(_getArtifactsToPrune); var _getPackageString = require('./get-package-string'); var _getPackageString2 = _interopRequireDefault(_getPackageString); var _getPatternMtimes = require('../../../library/utilities/get-pattern-mtimes'); var _getPatternMtimes2 = _interopRequireDefault(_getPatternMtimes); var _getPatterns = require('../../../library/utilities/get-patterns'); var _getPatterns2 = _interopRequireDefault(_getPatterns); var _getPatternsToBuild = require('../../../library/utilities/get-patterns-to-build'); var _getPatternsToBuild2 = _interopRequireDefault(_getPatternsToBuild); var _removeFile = require('../../../library/filesystem/remove-file'); var _removeFile2 = _interopRequireDefault(_removeFile); var _writeSafe = require('../../../library/filesystem/write-safe'); var _writeSafe2 = _interopRequireDefault(_writeSafe); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } const pkg = require((0, _path.resolve)(process.cwd(), 'package.json')); const readFile = (0, _denodeify2.default)(_fs.readFile); const pathFormatString = '%(outputName)s/%(patternId)s/index.%(extension)s'; const where = `Configure it at configuration/patternplate-server/tasks.js.`; const fallbackManifest = { dependencies: {}, devDependencies: {}, ppcommonjs: {}, ppDependencies: {}, ppDevdependencies: {} }; exports.default = exportAsCommonjs; function parseJSON(jsonString) { try { return JSON.parse(jsonString); } catch (error) { return fallbackManifest; } } module.exports = exports['default'];