From 56516c5f30e8294a01989b0b76cf536d4228757f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Mon, 15 Jun 2020 16:10:32 -0400 Subject: [PATCH] refactor: add createLogger to makeChainWalker --- .../fixtures/babel/--show-config/stdout.txt | 114 ++++++----------- packages/babel-cli/test/index.js | 17 +-- .../babel-core/src/config/config-chain.js | 120 ++++++++++-------- packages/babel-core/src/config/printer.js | 96 ++++++++++++++ 4 files changed, 216 insertions(+), 131 deletions(-) create mode 100644 packages/babel-core/src/config/printer.js diff --git a/packages/babel-cli/test/fixtures/babel/--show-config/stdout.txt b/packages/babel-cli/test/fixtures/babel/--show-config/stdout.txt index 1dfeac851686..9c89462f1bf7 100644 --- a/packages/babel-cli/test/fixtures/babel/--show-config/stdout.txt +++ b/packages/babel-cli/test/fixtures/babel/--show-config/stdout.txt @@ -1,77 +1,45 @@ programmatic options from @babel/cli -[ - { - "sourceFileName": "stdin", - "presets": [ - "/Users/jh/code/babel/packages/babel-preset-react" - ], - "plugins": [ - "/Users/jh/code/babel/packages/babel-plugin-transform-arrow-functions", - "/Users/jh/code/babel/packages/babel-plugin-transform-strict-mode", - "/Users/jh/code/babel/packages/babel-plugin-transform-modules-commonjs" - ], - "configFile": "./my-config.js", - "showConfig": true, - "caller": { - "name": "@babel/cli" - }, - "filename": "./src/index.js" - } -] +{ + "sourceFileName": "stdin", + "presets": [ + "/packages/babel-preset-react" + ], + "plugins": [ + "/packages/babel-plugin-transform-arrow-functions", + "/packages/babel-plugin-transform-strict-mode", + "/packages/babel-plugin-transform-modules-commonjs" + ], + "configFile": "./my-config.js", + "showConfig": true, + "caller": { + "name": "@babel/cli" + }, + "filename": "./src/index.js" +} config /my-config.js -[ - { - "babelrc": false, - "plugins": [ - null - ], - "overrides": [ - { - "test": "src/index.js", - "plugins": [ - "@foo/babel-plugin-2", - { - "noDocumentAll": true - } - ] - } - ], - "env": { - "test": { - "plugins": [ - [ - "@foo/babel-plugin-3", - { - "noDocumentAll": true - } - ] - ] - }, - "development": { - "plugins": [ - "@foo/babel-plugin-4" - ] - } +{ + "babelrc": false, + "plugins": [ + null + ] +} + +config /my-config.js .env["test"] +{ + "babelrc": false, + "plugins": [ + null + ] +} + +config /my-config.js .overrides[0] +{ + "test": "src/index.js", + "plugins": [ + "@foo/babel-plugin-2", + { + "noDocumentAll": true } - }, - { - "plugins": [ - [ - "@foo/babel-plugin-3", - { - "noDocumentAll": true - } - ] - ] - }, - { - "test": "src/index.js", - "plugins": [ - "@foo/babel-plugin-2", - { - "noDocumentAll": true - } - ] - } -] + ] +} diff --git a/packages/babel-cli/test/index.js b/packages/babel-cli/test/index.js index 0debf8a29414..94ac5c9be4c6 100644 --- a/packages/babel-cli/test/index.js +++ b/packages/babel-cli/test/index.js @@ -9,6 +9,7 @@ const fs = require("fs"); const fixtureLoc = path.join(__dirname, "fixtures"); const tmpLoc = path.join(__dirname, "tmp"); +const rootDir = path.resolve(__dirname, "../../.."); const fileFilter = function (x) { return x !== ".DS_Store"; @@ -19,12 +20,12 @@ const outputFileSync = function (filePath, data) { fs.writeFileSync(filePath, data); }; -const presetLocs = [path.join(__dirname, "../../babel-preset-react")]; +const presetLocs = [path.join(rootDir, "./packages/babel-preset-react")]; const pluginLocs = [ - path.join(__dirname, "/../../babel-plugin-transform-arrow-functions"), - path.join(__dirname, "/../../babel-plugin-transform-strict-mode"), - path.join(__dirname, "/../../babel-plugin-transform-modules-commonjs"), + path.join(rootDir, "./packages/babel-plugin-transform-arrow-functions"), + path.join(rootDir, "./packages/babel-plugin-transform-strict-mode"), + path.join(rootDir, "./packages/babel-plugin-transform-modules-commonjs"), ].join(","); const readDir = function (loc, filter) { @@ -49,19 +50,19 @@ const saveInFiles = function (files) { }); }; -const normalizeOutput = function (str, cwd) { +const normalizeOutput = function (str, cwd, root) { let prev; do { prev = str; - str = str.replace(cwd, ""); + str = str.replace(cwd, "").replace(root, ""); } while (str !== prev); return str.replace(/\(\d+ms\)/g, "(123ms)"); }; const assertTest = function (stdout, stderr, opts, cwd) { - stdout = normalizeOutput(stdout, cwd); - stderr = normalizeOutput(stderr, cwd); + stdout = normalizeOutput(stdout, cwd, rootDir); + stderr = normalizeOutput(stderr, cwd, rootDir); const expectStderr = opts.stderr.trim(); stderr = stderr.trim(); diff --git a/packages/babel-core/src/config/config-chain.js b/packages/babel-core/src/config/config-chain.js index d3cffc17d0da..99c859dfd117 100644 --- a/packages/babel-core/src/config/config-chain.js +++ b/packages/babel-core/src/config/config-chain.js @@ -12,6 +12,7 @@ import { type CallerMetadata, } from "./validation/options"; import pathPatternToRegex from "./pattern-to-regex"; +import { ConfigPrinter } from "./printer"; const debug = buildDebug("babel:config:config-chain"); @@ -88,6 +89,7 @@ export const buildPresetChainWalker: ( overrides: (preset, index) => loadPresetOverridesDescriptors(preset)(index), overridesEnv: (preset, index, envName) => loadPresetOverridesEnvDescriptors(preset)(index)(envName), + createLogger: () => () => {}, // Currently we don't support logging how preset is expanded }); const loadPresetDescriptors = makeWeakCacheSync((preset: PresetInstance) => buildRootDescriptors(preset, preset.alias, createUncachedDescriptors), @@ -142,19 +144,18 @@ export function* buildRootChain( context: ConfigContext, ): Handler { let configReport, babelRcReport; + const programmaticLogger = new ConfigPrinter(); const programmaticChain = yield* loadProgrammaticChain( { options: opts, dirname: context.cwd, }, context, + undefined, + programmaticLogger, ); if (!programmaticChain) return null; - const programmaticReport = printChain( - programmaticChain, - ChainFormatter.Programmatic, - context, - ); + const programmaticReport = programmaticLogger.output(); let configFile; if (typeof opts.configFile === "string") { @@ -176,16 +177,17 @@ export function* buildRootChain( let babelrcRootsDirectory = context.cwd; const configFileChain = emptyChain(); + const configFileLogger = new ConfigPrinter(); if (configFile) { const validatedFile = validateConfigFile(configFile); - const result = yield* loadFileChain(validatedFile, context); - if (!result) return null; - configReport = printChain( - result, - ChainFormatter.Config, - context, + const result = yield* loadFileChain( validatedFile, + context, + undefined, + configFileLogger, ); + if (!result) return null; + configReport = configFileLogger.output(); // Allow config files to toggle `.babelrc` resolution on and off and // specify where the roots are. @@ -228,14 +230,15 @@ export function* buildRootChain( if (babelrcFile) { const validatedFile = validateBabelrcFile(babelrcFile); - const result = yield* loadFileChain(validatedFile, context); - if (!result) return null; - babelRcReport = printChain( - result, - ChainFormatter.Config, - context, + const babelrcLogger = new ConfigPrinter(); + const result = yield* loadFileChain( validatedFile, + context, + undefined, + babelrcLogger, ); + if (!result) return null; + babelRcReport = babelrcLogger.output(); mergeChain(fileChain, result); } @@ -349,6 +352,8 @@ const loadProgrammaticChain = makeChainWalker({ index, envName, ), + createLogger: (input, context, baseLogger) => + buildProgrammaticLogger(input, context, baseLogger), }); /** @@ -360,6 +365,8 @@ const loadFileChain = makeChainWalker({ overrides: (file, index) => loadFileOverridesDescriptors(file)(index), overridesEnv: (file, index, envName) => loadFileOverridesEnvDescriptors(file)(index)(envName), + createLogger: (file, context, baseLogger) => + buildFileLogger(file.filepath, context, baseLogger), }); const loadFileDescriptors = makeWeakCacheSync((file: ValidatedFile) => buildRootDescriptors(file, file.filepath, createUncachedDescriptors), @@ -399,10 +406,32 @@ const loadFileOverridesEnvDescriptors = makeWeakCacheSync( ), ); +function buildFileLogger( + filepath: string, + context: ConfigContext, + baseLogger: ?ConfigPrinter, +) { + if (!baseLogger) { + return () => {}; + } + return baseLogger.configure(context.showConfig, ChainFormatter.Config, { + filepath, + }); +} + function buildRootDescriptors({ dirname, options }, alias, descriptors) { return descriptors(dirname, options, alias); } +function buildProgrammaticLogger(_, context, baseLogger: ?ConfigPrinter) { + if (!baseLogger) { + return () => {}; + } + return baseLogger.configure(context.showConfig, ChainFormatter.Programmatic, { + callerName: context.caller?.name, + }); +} + function buildEnvDescriptors( { dirname, options }, alias, @@ -450,34 +479,45 @@ function makeChainWalker({ env, overrides, overridesEnv, + createLogger, }: {| root: ArgT => OptionsAndDescriptors, env: (ArgT, string) => OptionsAndDescriptors | null, overrides: (ArgT, number) => OptionsAndDescriptors, overridesEnv: (ArgT, number, string) => OptionsAndDescriptors | null, + createLogger: ( + ArgT, + ConfigContext, + ?ConfigPrinter, + ) => (OptionsAndDescriptors, ?number, ?string) => void, |}): ( ArgT, ConfigContext, - Set | void, + files?: Set | void, + baseLogger?: ConfigPrinter, ) => Handler { - return function* (input, context, files = new Set()) { + return function* (input, context, files = new Set(), baseLogger) { const { dirname } = input; const flattenedConfigs = []; + const logger = createLogger(input, context, baseLogger); const rootOpts = root(input); if (configIsApplicable(rootOpts, dirname, context)) { flattenedConfigs.push(rootOpts); + logger(rootOpts); const envOpts = env(input, context.envName); if (envOpts && configIsApplicable(envOpts, dirname, context)) { flattenedConfigs.push(envOpts); + logger(rootOpts, undefined, context.envName); } (rootOpts.options.overrides || []).forEach((_, index) => { const overrideOps = overrides(input, index); if (configIsApplicable(overrideOps, dirname, context)) { flattenedConfigs.push(overrideOps); + logger(overrideOps, index); const overrideEnvOpts = overridesEnv(input, index, context.envName); if ( @@ -485,6 +525,7 @@ function makeChainWalker({ configIsApplicable(overrideEnvOpts, dirname, context) ) { flattenedConfigs.push(overrideEnvOpts); + logger(overrideEnvOpts, index, context.envName); } } }); @@ -505,7 +546,14 @@ function makeChainWalker({ for (const op of flattenedConfigs) { if ( - !(yield* mergeExtendsChain(chain, op.options, dirname, context, files)) + !(yield* mergeExtendsChain( + chain, + op.options, + dirname, + context, + files, + baseLogger, + )) ) { return null; } @@ -522,6 +570,7 @@ function* mergeExtendsChain( dirname: string, context: ConfigContext, files: Set, + baseLogger: ?ConfigPrinter, ): Handler { if (opts.extends === undefined) return true; @@ -545,6 +594,7 @@ function* mergeExtendsChain( validateExtendFile(file), context, files, + baseLogger, ); files.delete(file); @@ -743,33 +793,3 @@ function matchPattern( } return pattern.test(pathToTest); } - -function printChain( - chain: ConfigChain, - formatter: $Values, - context: ConfigContext, - validatedFile?: ValidatedFile, -): string { - function formatHeading(type, context, validatedFile) { - let heading = ""; - if (type === ChainFormatter.Programmatic) { - heading = "programmatic options"; - if (context.caller?.name) { - heading += " from " + context.caller.name; - } - } else { - // $FlowIgnore - heading = "config " + validatedFile.filepath; - } - return heading; - } - function formatChain(chain: ConfigChain) { - return JSON.stringify(chain.options, undefined, 2); - } - if (!context.showConfig) { - return ""; - } - return ( - formatHeading(formatter, context, validatedFile) + "\n" + formatChain(chain) - ); -} diff --git a/packages/babel-core/src/config/printer.js b/packages/babel-core/src/config/printer.js new file mode 100644 index 000000000000..113b16e932a5 --- /dev/null +++ b/packages/babel-core/src/config/printer.js @@ -0,0 +1,96 @@ +// @flow + +import type { OptionsAndDescriptors } from "./config-descriptors"; + +// todo: Use flow enums when @babel/transform-flow-types supports it +export const ChainFormatter = { + Programmatic: 0, + Config: 1, +}; + +type PrintableConfig = { + content: OptionsAndDescriptors, + type: $Values, + callerName: ?string, + filepath: ?string, + index: ?number, + envName: ?string, +}; + +const Formatter = { + title( + type: $Values, + callerName: ?string, + filepath: ?string, + ): string { + let title = ""; + if (type === ChainFormatter.Programmatic) { + title = "programmatic options"; + if (callerName) { + title += " from " + callerName; + } + } else { + // $FlowIgnore + title = "config " + filepath; + } + return title; + }, + loc(index: ?number, envName: ?string): string { + let loc = ""; + if (index != null) { + loc += `.overrides[${index}]`; + } + if (envName != null) { + loc += `.env["${envName}"]`; + } + return loc; + }, + optionsAndDescriptors(opt: OptionsAndDescriptors) { + const content = { ...opt.options }; + // overrides and env will be printed as separated config items + delete content.overrides; + delete content.env; + return JSON.stringify(content, undefined, 2); + }, +}; + +export class ConfigPrinter { + _stack: Array = []; + configure( + enabled: boolean, + type: $Values, + { callerName, filepath }: { callerName?: string, filepath?: string }, + ) { + if (!enabled) return () => {}; + return ( + content: OptionsAndDescriptors, + index: ?number, + envName: ?string, + ) => { + this._stack.push({ + type, + callerName, + filepath, + content, + index, + envName, + }); + }; + } + static format(config: PrintableConfig): string { + let title = Formatter.title( + config.type, + config.callerName, + config.filepath, + ); + const loc = Formatter.loc(config.index, config.envName); + if (loc) title += ` ${loc}`; + const content = Formatter.optionsAndDescriptors(config.content); + return `${title}\n${content}`; + } + + output(): string { + if (this._stack.length === 0) return ""; + return this._stack.map(s => ConfigPrinter.format(s)).join("\n\n"); + } +}