UNPKG

@bolt/build-utils

Version:

Build-related utilities and helper scripts used in the Bolt Design System

201 lines (184 loc) 6.23 kB
/* eslint-disable no-await-in-loop */ const fs = require('fs'); const path = require('path'); const $RefParser = require('json-schema-ref-parser'); const { ensureFileExists } = require('./general'); const { getDataFile } = require('./yaml'); const { validateSchemaSchema } = require('./schemas'); const { getConfig } = require('./config-store'); let config; // cached Bolt config // don't automatically include these Bolt packages as extra (undeclared) dependencies const missingBoltPkgsWhitelist = [ '@bolt/core-v3.x', '@bolt/polyfills', '@bolt/element', '@bolt/lazy-queue', '@bolt/components-icons', ]; /** * Get information about a components assets * @param {string|object} pkgName - Name of a component i.e. `@bolt/button` * OR object - see `config.schema.yml` under `definitions.components.items` * @returns {{name, basicName: string | * | void}} - Asset info + an array of missing dependencies (if any) */ async function getPkgInfo(pkgName) { const missingBoltPkgs = []; config = config || (await getConfig()); if (typeof pkgName === 'object') { const info = { name: pkgName.name, basicName: pkgName.name, assets: {}, }; if (pkgName.scss) { info.assets.style = pkgName.scss; info.dir = path.dirname(pkgName.scss); ensureFileExists(pkgName.scss); } if (pkgName.js) { info.assets.main = pkgName.js; // yeah I know we're overwriting `dir`... got to have something though... and it's only used by PL to watch Twig info.dir = path.dirname(pkgName.js); ensureFileExists(pkgName.js); } return info; } if (pkgName.endsWith('.scss') || pkgName.endsWith('.js')) { const pathInfo = path.parse(pkgName); const name = pathInfo.name + pathInfo.ext.replace('.', '-'); const info = { name, basicName: name, dir: path.dirname(pkgName), assets: {}, }; if (pkgName.endsWith('.scss')) { info.assets.style = pkgName; } if (pkgName.endsWith('.js')) { info.assets.main = pkgName; } ensureFileExists(pkgName); return { processedPkg: info, missingPkgs: missingBoltPkgs, }; } else { // package name const pkgJsonPath = require.resolve(`${pkgName}/package.json`); const dir = path.dirname(pkgJsonPath); const pkg = require(pkgJsonPath); // automatically convert scoped package names into Twig namespaces // match NPM scoped package names // borrowed from https://github.com/sindresorhus/scoped-regex const regex = '@[a-z\\d][\\w-.]+/[a-z\\d][\\w-.]*'; const scopedRegex = options => options && options.exact ? new RegExp(`^${regex}$`, 'i') : new RegExp(regex, 'gi'); /** * Strip out @ signs and the first dash in the package name. * * For example: * @bolt/ -> bolt- * @pegawww/ -> pegawww- */ let normalizedPkgName; if (pkg.name.match(scopedRegex())) { const matchedName = pkg.name.match(scopedRegex())[0]; const pkgNamePrefix = matchedName.split('/')[0].replace('@', ''); const pkgNameSuffix = matchedName.split('/')[1]; normalizedPkgName = `${pkgNamePrefix}-${pkgNameSuffix}`; } else { normalizedPkgName = pkg.name.replace('@bolt/', 'bolt-'); } const info = { name: pkg.name, basicName: normalizedPkgName, dir, assets: {}, deps: [], }; config.components.individual = config.components.individual || []; config.components.global = config.components.global || []; // combine pkg.dependencies and pkg.peerDependencies let deps = {}; if (pkg.dependencies) { deps = { ...deps, ...pkg.dependencies }; } if (pkg.peerDependencies) { deps = { ...deps, ...pkg.peerDependencies }; } if (Object.keys(deps).length > 0) { for (const dependency in deps) { if ( dependency.includes('@bolt/') && !missingBoltPkgs.includes(dependency) && missingBoltPkgsWhitelist.indexOf(dependency) === -1 && !config.components.global.includes(dependency) && !config.components.individual.includes(dependency) ) { missingBoltPkgs.push(dependency); } // @todo: remove with v3.0 if (dependency.includes('bolt')) { info.deps.push(dependency); } } } info.twigNamespace = `@${info.basicName}`; if (pkg.style) { info.assets.style = path.join(dir, pkg.style); ensureFileExists(info.assets.style); } if (pkg.main) { info.assets.main = path.join(dir, pkg.main); ensureFileExists(info.assets.main); } if (pkg.schema) { if (typeof pkg.schema === 'object') { if (info.schema === undefined) { info.schema = {}; } const schemas = pkg.schema; for (const schemaPath of schemas) { let schema; const schemaFilePath = path.join(dir, schemaPath); // eslint-disable-next-line if (schemaFilePath.endsWith('.js')) { schema = require(schemaFilePath); } else { schema = await getDataFile(schemaFilePath); } validateSchemaSchema( schema, `Schema not valid for: ${schemaFilePath}`, ); const schemaMachineName = schema.title .replace(/ /g, '-') .toLowerCase(); const dereferencedSchema = await $RefParser.dereference(schema); info.schema[schemaMachineName] = dereferencedSchema; } } else { let schema; const schemaFilePath = path.join(dir, pkg.schema); if (schemaFilePath.endsWith('.js')) { schema = require(schemaFilePath); } else { schema = await getDataFile(schemaFilePath); } validateSchemaSchema(schema, `Schema not valid for: ${schemaFilePath}`); const dereferencedSchema = await $RefParser.dereference(schema); info.schema = dereferencedSchema; } } // @todo Allow verbosity settings // console.log(assets); return { processedPkg: info, missingPkgs: missingBoltPkgs, }; } } module.exports = getPkgInfo;