jazelle/utils/generate-bazel-build-rules.js (83 lines of code) (raw):

// @flow const {relative, basename} = require('path'); const {exists, read, write} = require('./node-helpers.js'); const { getCallArgItems, addCallArgItem, removeCallArgItem, } = require('./starlark.js'); /*:: import type {Metadata} from './get-local-dependencies.js'; export type GenerateBazelBuildRulesArgs = { root: string, deps: Array<Metadata>, projects: Array<string>, dependencySyncRule: string, } export type GenerateBazelBuildRules = (GenerateBazelBuildRulesArgs) => Promise<void> export type TemplateArgs = { name: string, path: string, label: string, dependencies: Array<string>, } export type Template = (TemplateArgs) => Promise<string>; */ const generateBazelBuildRules /*: GenerateBazelBuildRules */ = async ({ root, deps, projects, dependencySyncRule, }) => { const depMap = deps.reduce((map, dep) => { map[dep.meta.name] = dep; return map; }, {}); await Promise.all( deps.map(async dep => { const build = `${dep.dir}/BUILD.bazel`; const dependencies = [ ...new Set([ ...getDepLabels(root, depMap, dep.meta.dependencies), ...getDepLabels(root, depMap, dep.meta.devDependencies), ]), ]; if (!(await exists(build))) { // generate BUILD.bazel file const path = relative(root, dep.dir); const name = basename(path); // $FlowFixMe const template /*: Template */ = (await require(`${root}/third_party/jazelle/scripts/build-file-template.js`)).template; // eslint-disable-line const rules = await template({ name, path, label: `//${path}:${name}`, dependencies, }); await write(build, rules.trim(), 'utf8'); } else { // sync web_library deps list in BUILD.bazel with local dependencies in package.json const src = await read(build, 'utf8'); let code = src; const items = getCallArgItems(code, dependencySyncRule, 'deps'); dependencies .map(d => `"${d}"`) .forEach(dependency => { // only add if no related target exists const [path] = dependency.split(':'); const paths = items.map(item => item.split(':').shift()); if (!paths.includes(path)) { code = addCallArgItem( code, dependencySyncRule, 'deps', `${dependency}` ); } }); items.forEach(item => { if (!dependencies.map(d => `"${d}"`).includes(item)) { const [, path, name] = item.match(/\/\/(.+?):([^"]+)/) || []; if (projects.includes(path) && basename(path) === name) { code = removeCallArgItem(code, dependencySyncRule, 'deps', item); } } }); if (src.trim() !== code.trim()) await write(build, code, 'utf8'); } }) ); }; const getDepLabels = (root, depMap, dependencies = {}) => { return Object.keys(dependencies) .map(name => { const {dir} = depMap[name] || {}; if (dir) { const path = relative(root, dir); const name = basename(path); return `//${path}:${name}`; } else { return null; } }) .filter(Boolean); }; module.exports = {generateBazelBuildRules};