diff --git a/packages/babel-cli/src/_babel-node.js b/packages/babel-cli/src/_babel-node.js index ee6e340c31..28b62dd2c0 100644 --- a/packages/babel-cli/src/_babel-node.js +++ b/packages/babel-cli/src/_babel-node.js @@ -3,7 +3,6 @@ import Module from "module"; import { inspect } from "util"; import path from "path"; import repl from "repl"; -import { util } from "babel-core"; import * as babel from "babel-core"; import vm from "vm"; import "babel-polyfill"; @@ -13,13 +12,24 @@ import pkg from "../package.json"; const program = new commander.Command("babel-node"); +function collect(value, previousValue): Array { + // If the user passed the option with no value, like "babel-node file.js --presets", do nothing. + if (typeof value !== "string") return previousValue; + + const values = value.split(","); + + return previousValue ? previousValue.concat(values) : values; +} + +/* eslint-disable max-len */ program.option("-e, --eval [script]", "Evaluate script"); program.option("-p, --print [code]", "Evaluate script and print result"); -program.option("-o, --only [globs]", ""); -program.option("-i, --ignore [globs]", ""); -program.option("-x, --extensions [extensions]", "List of extensions to hook into [.es6,.js,.es,.jsx]"); -program.option("-w, --plugins [string]", "", util.list); -program.option("-b, --presets [string]", "", util.list); +program.option("-o, --only [globs]", "A comma-separated list of glob patterns to compile", collect); +program.option("-i, --ignore [globs]", "A comma-separated list of glob patterns to skip compiling", collect); +program.option("-x, --extensions [extensions]", "List of extensions to hook into [.es6,.js,.es,.jsx]", collect); +program.option("-w, --plugins [string]", "", collect); +program.option("-b, --presets [string]", "", collect); +/* eslint-enable max-len */ program.version(pkg.version); program.usage("[options] [ -e script | script.js ] [arguments]"); diff --git a/packages/babel-cli/src/babel-external-helpers.js b/packages/babel-cli/src/babel-external-helpers.js index 76552a3a71..6624b64d65 100755 --- a/packages/babel-cli/src/babel-external-helpers.js +++ b/packages/babel-cli/src/babel-external-helpers.js @@ -1,7 +1,16 @@ import commander from "commander"; -import { util, buildExternalHelpers } from "babel-core"; +import { buildExternalHelpers } from "babel-core"; -commander.option("-l, --whitelist [whitelist]", "Whitelist of helpers to ONLY include", util.list); +function collect(value, previousValue): Array { + // If the user passed the option with no value, like "babel-external-helpers --whitelist", do nothing. + if (typeof value !== "string") return previousValue; + + const values = value.split(","); + + return previousValue ? previousValue.concat(values) : values; +} + +commander.option("-l, --whitelist [whitelist]", "Whitelist of helpers to ONLY include", collect); commander.option("-t, --output-type [type]", "Type of output (global|umd|var)", "global"); commander.usage("[options]"); diff --git a/packages/babel-cli/src/babel/dir.js b/packages/babel-cli/src/babel/dir.js index 7a19148bd7..1113fd9afc 100644 --- a/packages/babel-cli/src/babel/dir.js +++ b/packages/babel-cli/src/babel/dir.js @@ -8,6 +8,8 @@ import * as util from "./util"; export default function (commander, filenames, opts) { function write(src, relative) { + if (!util.isCompilableExtension(relative, commander.extensions)) return false; + // remove extension and then append back on .js relative = relative.replace(/\.(\w*?)$/, "") + ".js"; @@ -17,7 +19,8 @@ export default function (commander, filenames, opts) { sourceFileName: slash(path.relative(dest + "/..", src)), sourceMapTarget: path.basename(relative), }, opts)); - if (!commander.copyFiles && data.ignored) return; + + if (!data) return false; // we've requested explicit sourcemaps to be written to disk if (data.map && commander.sourceMaps && commander.sourceMaps !== "inline") { @@ -30,14 +33,14 @@ export default function (commander, filenames, opts) { util.chmod(src, dest); util.log(src + " -> " + dest); + + return true; } function handleFile(src, filename) { - if (util.shouldIgnore(src, opts)) return; + const didWrite = write(src, filename); - if (util.canCompile(filename, commander.extensions)) { - write(src, filename); - } else if (commander.copyFiles) { + if (!didWrite && commander.copyFiles) { const dest = path.join(commander.outDir, filename); outputFileSync(dest, fs.readFileSync(src)); util.chmod(src, dest); diff --git a/packages/babel-cli/src/babel/file.js b/packages/babel-cli/src/babel/file.js index 181432c1e6..689f8f9353 100644 --- a/packages/babel-cli/src/babel/file.js +++ b/packages/babel-cli/src/babel/file.js @@ -124,8 +124,6 @@ export default function (commander, filenames, opts) { }); _filenames.forEach(function (filename) { - if (util.shouldIgnore(filename, opts)) return; - let sourceFilename = filename; if (commander.outFile) { sourceFilename = path.relative(path.dirname(commander.outFile), sourceFilename); @@ -136,7 +134,8 @@ export default function (commander, filenames, opts) { sourceFileName: sourceFilename, }, opts)); - if (data.ignored) return; + if (!data) return; + results.push(data); }); @@ -159,7 +158,7 @@ export default function (commander, filenames, opts) { pollInterval: 10, }, }).on("all", function (type, filename) { - if (util.shouldIgnore(filename, opts) || !util.canCompile(filename, commander.extensions)) return; + if (!util.isCompilableExtension(filename, commander.extensions)) return; if (type === "add" || type === "change") { util.log(type + " " + filename); diff --git a/packages/babel-cli/src/babel/index.js b/packages/babel-cli/src/babel/index.js index 99da42c6df..732ba1b011 100755 --- a/packages/babel-cli/src/babel/index.js +++ b/packages/babel-cli/src/babel/index.js @@ -2,7 +2,7 @@ import fs from "fs"; import commander from "commander"; -import { util, version } from "babel-core"; +import { version } from "babel-core"; import uniq from "lodash/uniq"; import glob from "glob"; @@ -11,17 +11,38 @@ import fileCommand from "./file"; import pkg from "../../package.json"; +function booleanify(val: any): boolean | any { + if (val === "true" || val == 1) { + return true; + } + + if (val === "false" || val == 0 || !val) { + return false; + } + + return val; +} + +function collect(value, previousValue): Array { + // If the user passed the option with no value, like "babel file.js --presets", do nothing. + if (typeof value !== "string") return previousValue; + + const values = value.split(","); + + return previousValue ? previousValue.concat(values) : values; +} + /* eslint-disable max-len */ // Standard Babel input configs. commander.option("-f, --filename [filename]", "filename to use when reading from stdin - this will be used in source-maps, errors etc"); -commander.option("--presets [list]", "comma-separated list of preset names"); -commander.option("--plugins [list]", "comma-separated list of plugin names"); +commander.option("--presets [list]", "comma-separated list of preset names", collect); +commander.option("--plugins [list]", "comma-separated list of plugin names", collect); // Basic file input configuration. commander.option("--source-type [script|module]", ""); commander.option("--no-babelrc", "Whether or not to look up .babelrc and .babelignore files"); -commander.option("--ignore [list]", "list of glob paths to **not** compile"); -commander.option("--only [list]", "list of glob paths to **only** compile"); +commander.option("--ignore [list]", "list of glob paths to **not** compile", collect); +commander.option("--only [list]", "list of glob paths to **only** compile", collect); // Misc babel config. commander.option("--no-highlight-code", "enable/disable ANSI syntax highlighting of code frames (on by default)"); @@ -29,13 +50,13 @@ commander.option("--no-highlight-code", "enable/disable ANSI syntax highlighting // General output formatting. commander.option("--no-comments", "write comments to generated output (true by default)"); commander.option("--retain-lines", "retain line numbers - will result in really ugly code"); -commander.option("--compact [true|false|auto]", "do not include superfluous whitespace characters and line terminators"); +commander.option("--compact [true|false|auto]", "do not include superfluous whitespace characters and line terminators", booleanify); commander.option("--minified", "save as much bytes when printing [true|false]"); commander.option("--auxiliary-comment-before [string]", "print a comment before any injected non-user code"); commander.option("--auxiliary-comment-after [string]", "print a comment after any injected non-user code"); // General soucemap formatting. -commander.option("-s, --source-maps [true|false|inline|both]", ""); +commander.option("-s, --source-maps [true|false|inline|both]", "", booleanify); commander.option("--source-map-target [string]", "set `file` on returned source map"); commander.option("--source-file-name [string]", "set `sources[0]` on returned source map"); commander.option("--source-root [filename]", "the root from which all sources are relative"); @@ -46,7 +67,7 @@ commander.option("-M, --module-ids", "insert an explicit id for modules"); commander.option("--module-id [string]", "specify a custom name for module ids"); // "babel" command specific arguments that are not passed to babel-core. -commander.option("-x, --extensions [extensions]", "List of extensions to compile when a directory has been input [.es6,.js,.es,.jsx]"); +commander.option("-x, --extensions [extensions]", "List of extensions to compile when a directory has been input [.es6,.js,.es,.jsx]", collect); commander.option("-w, --watch", "Recompile files on changes"); commander.option("--skip-initial-build", "Do not compile files before watching"); commander.option("-o, --out-file [out]", "Compile all input files into a single file"); @@ -61,12 +82,6 @@ commander.parse(process.argv); // -if (commander.extensions) { - commander.extensions = util.arrayify(commander.extensions); -} - -// - const errors = []; let filenames = commander.args.reduce(function (globbed, input) { @@ -130,16 +145,5 @@ if (opts.babelrc === true) opts.babelrc = undefined; if (opts.comments === true) opts.comments = undefined; if (opts.highlightCode === true) opts.highlightCode = undefined; -opts.ignore = util.arrayify(opts.ignore, util.regexify); - -if (opts.only) { - opts.only = util.arrayify(opts.only, util.regexify); -} - -if (opts.sourceMaps) opts.sourceMaps = util.booleanify(opts.sourceMaps); -if (opts.compact) opts.compact = util.booleanify(opts.compact); -if (opts.presets) opts.presets = util.list(opts.presets); -if (opts.plugins) opts.plugins = util.list(opts.plugins); - const fn = commander.outDir ? dirCommand : fileCommand; fn(commander, filenames, opts); diff --git a/packages/babel-cli/src/babel/util.js b/packages/babel-cli/src/babel/util.js index d95555ae1d..ef99088537 100644 --- a/packages/babel-cli/src/babel/util.js +++ b/packages/babel-cli/src/babel/util.js @@ -1,6 +1,7 @@ import commander from "commander"; import readdir from "fs-readdir-recursive"; import * as babel from "babel-core"; +import includes from "lodash/includes"; import path from "path"; import fs from "fs"; @@ -10,16 +11,19 @@ export function chmod(src, dest) { export function readdirFilter(filename) { return readdir(filename).filter(function (filename) { - return babel.util.canCompile(filename); + return babel.util.isCompilableExtension(filename); }); } export { readdir }; -export const canCompile = babel.util.canCompile; - -export function shouldIgnore(loc, opts) { - return babel.util.shouldIgnore(loc, opts.ignore, opts.only); +/** + * Test if a filename ends with a compilable extension. + */ +export function isCompilableExtension(filename: string, altExts?: Array): boolean { + const exts = altExts || babel.DEFAULT_EXTENSIONS; + const ext = path.extname(filename); + return includes(exts, ext); } export function addSourceMappingUrl(code, loc) { @@ -35,16 +39,12 @@ export function transform(filename, code, opts) { filename, }); - const result = babel.transform(code, opts); - result.filename = filename; - result.actual = code; - return result; + return babel.transform(code, opts); } export function compile(filename, opts) { try { - const code = fs.readFileSync(filename, "utf8"); - return transform(filename, code, opts); + return babel.transformFileSync(filename, opts); } catch (err) { if (commander.watch) { console.error(toErrorStack(err)); diff --git a/packages/babel-cli/test/fixtures/babel/--ignore complete/options.json b/packages/babel-cli/test/fixtures/babel/--ignore complete/options.json index c013d5d4da..b4c4db71f3 100644 --- a/packages/babel-cli/test/fixtures/babel/--ignore complete/options.json +++ b/packages/babel-cli/test/fixtures/babel/--ignore complete/options.json @@ -1,3 +1,3 @@ { - "args": ["src", "--out-dir", "lib", "--ignore", "/bar/*"] + "args": ["src", "--out-dir", "lib", "--ignore", "src/bar"] } diff --git a/packages/babel-cli/test/index.js b/packages/babel-cli/test/index.js index c2bda15c4c..bb9746be70 100644 --- a/packages/babel-cli/test/index.js +++ b/packages/babel-cli/test/index.js @@ -91,7 +91,7 @@ const buildTest = function (binName, testName, opts) { } if (binName === "babel-node") { - args.push("--only", "packages/*/test"); + args.push("--only", "../../../../packages/*/test"); } args = args.concat(opts.args); @@ -119,7 +119,7 @@ const buildTest = function (binName, testName, opts) { } if (err) { - err.message = args.join(" ") + ": " + err.message; + err.message = args.map((arg) => `"${ arg }"`).join(" ") + ": " + err.message; } callback(err); diff --git a/packages/babel-core/package.json b/packages/babel-core/package.json index 0c99b59385..2beae71fa0 100644 --- a/packages/babel-core/package.json +++ b/packages/babel-core/package.json @@ -39,7 +39,7 @@ "debug": "^2.1.1", "json5": "^0.5.0", "lodash": "^4.2.0", - "minimatch": "^3.0.2", + "micromatch": "^2.3.11", "private": "^0.1.6", "resolve": "^1.3.2", "slash": "^1.0.0", diff --git a/packages/babel-core/src/index.js b/packages/babel-core/src/index.js index 164ccc21a9..f3fa340eb5 100644 --- a/packages/babel-core/src/index.js +++ b/packages/babel-core/src/index.js @@ -6,8 +6,6 @@ export resolvePreset from "./helpers/resolve-preset"; export { version } from "../package"; export { getEnv } from "./helpers/environment"; -export * as util from "./util"; - export * as messages from "babel-messages"; export * as types from "babel-types"; export traverse from "babel-traverse"; @@ -27,3 +25,8 @@ export { transformFileSync, } from "./transformation/pipeline"; +/** + * Recommended set of compilable extensions. Not used in babel-core directly, but meant as + * as an easy source for tooling making use of babel-core. + */ +export const DEFAULT_EXTENSIONS = Object.freeze([".js", ".jsx", ".es6", ".es"]); diff --git a/packages/babel-core/src/transformation/file/index.js b/packages/babel-core/src/transformation/file/index.js index 3eddf03235..9d5af49ff0 100644 --- a/packages/babel-core/src/transformation/file/index.js +++ b/packages/babel-core/src/transformation/file/index.js @@ -415,11 +415,7 @@ export default class File extends Store { code = code + ""; try { - if (this.shouldIgnore()) { - return this.makeResult({ code, ignored: true }); - } else { - return callback(); - } + return callback(); } catch (err) { if (err._babel) { throw err; @@ -462,11 +458,6 @@ export default class File extends Store { this.addAst(ast); } - shouldIgnore() { - const opts = this.opts; - return util.shouldIgnore(opts.filename, opts.ignore, opts.only); - } - call(key: "pre" | "post", pluginPasses: Array) { for (const pass of pluginPasses) { const plugin = pass.plugin; diff --git a/packages/babel-core/src/transformation/file/options/build-config-chain.js b/packages/babel-core/src/transformation/file/options/build-config-chain.js index 11930db2cd..df05a06443 100644 --- a/packages/babel-core/src/transformation/file/options/build-config-chain.js +++ b/packages/babel-core/src/transformation/file/options/build-config-chain.js @@ -3,6 +3,7 @@ import resolve from "../../../helpers/resolve"; import json5 from "json5"; import path from "path"; import fs from "fs"; +import micromatch from "micromatch"; const existsCache = {}; const jsonCache = {}; @@ -22,27 +23,104 @@ function exists(filename) { } export default function buildConfigChain(opts: Object = {}) { - const filename = opts.filename; - const builder = new ConfigChainBuilder(); + const filename = opts.filename ? path.resolve(opts.filename) : null; + const builder = new ConfigChainBuilder(filename); - builder.mergeConfig({ - options: opts, - alias: "base", - dirname: process.cwd(), - }); + try { + builder.mergeConfig({ + options: opts, + alias: "base", + dirname: process.cwd(), + }); - // resolve all .babelrc files - if (opts.babelrc !== false) { - builder.findConfigs(filename); + // resolve all .babelrc files + if (opts.babelrc !== false) { + builder.findConfigs(filename); + } + } catch (e) { + if (e.code !== "BABEL_IGNORED_FILE") throw e; + + return null; } return builder.configs.reverse(); } class ConfigChainBuilder { - constructor() { + constructor(filename) { this.resolvedConfigs = []; this.configs = []; + this.filename = filename; + this.possibleDirs = null; + } + + /** + * Tests if a filename should be ignored based on "ignore" and "only" options. + */ + shouldIgnore( + ignore: Array, + only?: Array, + dirname: string, + ): boolean { + if (!this.filename) return false; + + if (ignore) { + if (!Array.isArray(ignore)) { + throw new Error(`.ignore should be an array, was ${JSON.stringify(ignore)}`); + } + + for (const pattern of ignore) { + if (this.matchesPattern(pattern, dirname)) return true; + } + } + + if (only) { + if (!Array.isArray(only)) { + throw new Error(`.only should be an array, was ${JSON.stringify(only)}`); + } + + for (const pattern of only) { + if (this.matchesPattern(pattern, dirname)) return false; + } + return true; + } + + return false; + } + + /** + * Returns result of calling function with filename if pattern is a function. + * Otherwise returns result of matching pattern Regex with filename. + */ + matchesPattern(pattern: string | Function | RegExp, dirname: string) { + if (typeof pattern === "string") { + // Lazy-init so we don't initialize this for files that have no glob patterns. + if (!this.possibleDirs) { + this.possibleDirs = []; + + if (this.filename) { + this.possibleDirs.push(this.filename); + + let current = this.filename; + while (true) { + const previous = current; + current = path.dirname(current); + if (previous === current) break; + + this.possibleDirs.push(current); + } + } + } + + return this.possibleDirs.some(micromatch.filter(path.resolve(dirname, pattern), { + nocase: true, + nonegate: true, + })); + } else if (typeof pattern === "function") { + return pattern(this.filename); + } else { + return pattern.test(this.filename); + } } errorMultipleConfigs(loc1: string, loc2: string) { @@ -171,6 +249,12 @@ class ConfigChainBuilder { return false; } + // Bail out ASAP if this file is ignored so that we run as little logic as possible on ignored files. + if (this.filename && this.shouldIgnore(options.ignore, options.only, dirname)) { + // TODO(logan): This is a really cross way to bail out. Avoid this in rewrite. + throw Object.assign(new Error("This file has been ignored."), { code: "BABEL_IGNORED_FILE" }); + } + options = Object.assign({}, options); loc = loc || alias; diff --git a/packages/babel-core/src/transformation/file/options/option-manager.js b/packages/babel-core/src/transformation/file/options/option-manager.js index 0eedbe8345..df43555c5f 100644 --- a/packages/babel-core/src/transformation/file/options/option-manager.js +++ b/packages/babel-core/src/transformation/file/options/option-manager.js @@ -236,17 +236,6 @@ export default class OptionManager { } } - if (opts.ignore) { - if (!Array.isArray(rawOpts.ignore)) throw new Error(`${alias}.ignore should be an array`); - - opts.ignore = opts.ignore.map(util.regexify); - } - if (opts.only) { - if (!Array.isArray(rawOpts.only)) throw new Error(`${alias}.only should be an array`); - - opts.only = opts.only.map(util.regexify); - } - // resolve plugins if (opts.plugins) { if (!Array.isArray(rawOpts.plugins)) throw new Error(`${alias}.plugins should be an array`); @@ -373,8 +362,11 @@ export default class OptionManager { } init(opts: Object = {}): Object { + const configChain = buildConfigChain(opts); + if (!configChain) return null; + try { - for (const config of buildConfigChain(opts)) { + for (const config of configChain) { this.mergeOptions(config); } } catch (e) { diff --git a/packages/babel-core/src/transformation/pipeline.js b/packages/babel-core/src/transformation/pipeline.js index 367e1efede..9bf718a47e 100644 --- a/packages/babel-core/src/transformation/pipeline.js +++ b/packages/babel-core/src/transformation/pipeline.js @@ -17,6 +17,7 @@ export function analyse(code: string, opts: Object = {}, visitor?: Object): ?Bab export function transform(code: string, opts?: Object): BabelFileResult { opts = new OptionManager().init(opts); + if (opts === null) return null; const file = new File(opts); return file.wrap(code, function () { @@ -28,6 +29,7 @@ export function transform(code: string, opts?: Object): BabelFileResult { export function transformFromAst(ast: Object, code: string, opts: Object): BabelFileResult { opts = new OptionManager().init(opts); + if (opts === null) return null; ast = normalizeAst(ast); @@ -47,6 +49,7 @@ export function transformFile(filename: string, opts?: Object, callback: Functio opts.filename = filename; opts = new OptionManager().init(opts); + if (opts === null) return callback(null, null); fs.readFile(filename, function (err, code) { let result; @@ -75,6 +78,7 @@ export function transformFile(filename: string, opts?: Object, callback: Functio export function transformFileSync(filename: string, opts?: Object = {}): string { opts.filename = filename; opts = new OptionManager().init(opts); + if (opts === null) return null; const code = fs.readFileSync(filename, "utf8"); const file = new File(opts); diff --git a/packages/babel-core/src/util.js b/packages/babel-core/src/util.js index 51d42086c0..3caa4be75e 100644 --- a/packages/babel-core/src/util.js +++ b/packages/babel-core/src/util.js @@ -1,10 +1,3 @@ -import escapeRegExp from "lodash/escapeRegExp"; -import startsWith from "lodash/startsWith"; -import minimatch from "minimatch"; -import includes from "lodash/includes"; -import isRegExp from "lodash/isRegExp"; -import path from "path"; -import slash from "slash"; import buildDebug from "debug"; export { inherits, inspect } from "util"; @@ -22,140 +15,3 @@ export function message(opts: Object, msg: string) { return `[BABEL] ${opts.filename || "unknown"}: ${msg}`; } - -/** - * Test if a filename ends with a compilable extension. - */ - -export function canCompile(filename: string, altExts?: Array): boolean { - const exts = altExts || canCompile.EXTENSIONS; - const ext = path.extname(filename); - return includes(exts, ext); -} - -/** - * Default set of compilable extensions. - */ - -canCompile.EXTENSIONS = [".js", ".jsx", ".es6", ".es"]; - -/** - * Create an array from any value, splitting strings by ",". - */ - -export function list(val?: string): Array { - if (!val) { - return []; - } else if (Array.isArray(val)) { - return val; - } else if (typeof val === "string") { - return val.split(","); - } else { - return [val]; - } -} - -/** - * Create a RegExp from a string, array, or regexp. - */ - -export function regexify(val: any): RegExp { - if (!val) { - return new RegExp(/.^/); - } - - if (Array.isArray(val)) { - val = new RegExp(val.map(escapeRegExp).join("|"), "i"); - } - - if (typeof val === "string") { - // normalise path separators - val = slash(val); - - // remove starting wildcards or relative separator if present - if (startsWith(val, "./") || startsWith(val, "*/")) val = val.slice(2); - if (startsWith(val, "**/")) val = val.slice(3); - - const regex = minimatch.makeRe(val, { nocase: true }); - return new RegExp(regex.source.slice(1, -1), "i"); - } - - if (isRegExp(val)) { - return val; - } - - throw new TypeError("illegal type for regexify"); -} - -/** - * Create an array from a boolean, string, or array, mapped by and optional function. - */ - -export function arrayify(val: any, mapFn?: Function): Array { - if (!val) return []; - if (typeof val === "boolean") return arrayify([val], mapFn); - if (typeof val === "string") return arrayify(list(val), mapFn); - - if (Array.isArray(val)) { - if (mapFn) val = val.map(mapFn); - return val; - } - - return [val]; -} - -/** - * Makes boolean-like strings into booleans. - */ - -export function booleanify(val: any): boolean | any { - if (val === "true" || val == 1) { - return true; - } - - if (val === "false" || val == 0 || !val) { - return false; - } - - return val; -} - -/** - * Tests if a filename should be ignored based on "ignore" and "only" options. - */ - -export function shouldIgnore( - filename: string, - ignore: Array, - only?: Array, -): boolean { - filename = filename.replace(/\\/g, "/"); - - if (ignore && ignore.length) { - for (const pattern of ignore) { - if (matchesPattern(pattern, filename)) return true; - } - } - - if (only) { - for (const pattern of only) { - if (matchesPattern(pattern, filename)) return false; - } - return true; - } - - return false; -} - -/** - * Returns result of calling function with filename if pattern is a function. - * Otherwise returns result of matching pattern Regex with filename. - */ - -function matchesPattern(pattern: Function | RegExp, filename: string) { - if (typeof pattern === "function") { - return pattern(filename); - } else { - return pattern.test(filename); - } -} diff --git a/packages/babel-core/test/api.js b/packages/babel-core/test/api.js index 3d181488c3..6f345592c5 100644 --- a/packages/babel-core/test/api.js +++ b/packages/babel-core/test/api.js @@ -6,7 +6,7 @@ import Plugin from "../lib/transformation/plugin"; import generator from "babel-generator"; function assertIgnored(result) { - assert.ok(result.ignored); + assert.ok(!result); } function assertNotIgnored(result) { @@ -496,51 +496,76 @@ describe("api", function () { it("ignore option", function () { return Promise.all([ transformAsync("", { - ignore: ["node_modules"], + ignore: ["/foo"], filename: "/foo/node_modules/bar", }).then(assertIgnored), transformAsync("", { - ignore: ["foo/node_modules"], + ignore: ["/foo/node_modules"], filename: "/foo/node_modules/bar", }).then(assertIgnored), transformAsync("", { - ignore: ["foo/node_modules/*.bar"], + ignore: ["/foo/node_modules/*"], + filename: "/foo/node_modules/bar", + }).then(assertIgnored), + + transformAsync("", { + ignore: ["/foo/**/*"], + filename: "/foo/node_modules/bar", + }).then(assertIgnored), + + transformAsync("", { + ignore: ["/foo/node_modules/*.bar"], filename: "/foo/node_modules/foo.bar", }).then(assertIgnored), + + transformAsync("", { + ignore: ["/foo/node_modules/*.foo"], + filename: "/foo/node_modules/foo.bar", + }).then(assertNotIgnored), + + transformAsync("", { + ignore: ["/bar/**/*"], + filename: "/foo/node_modules/foo.bar", + }).then(assertNotIgnored), ]); }); it("only option", function () { return Promise.all([ transformAsync("", { - only: ["node_modules"], + only: ["/foo"], filename: "/foo/node_modules/bar", }).then(assertNotIgnored), transformAsync("", { - only: ["foo/node_modules"], + only: ["/foo/*"], filename: "/foo/node_modules/bar", }).then(assertNotIgnored), transformAsync("", { - only: ["foo/node_modules/*.bar"], + only: ["/foo/node_modules"], + filename: "/foo/node_modules/bar", + }).then(assertNotIgnored), + + transformAsync("", { + only: ["/foo/node_modules/*.bar"], filename: "/foo/node_modules/foo.bar", }).then(assertNotIgnored), transformAsync("", { - only: ["node_modules"], + only: ["/foo/node_modules"], filename: "/foo/node_module/bar", }).then(assertIgnored), transformAsync("", { - only: ["foo/node_modules"], + only: ["/foo/node_modules"], filename: "/bar/node_modules/foo", }).then(assertIgnored), transformAsync("", { - only: ["foo/node_modules/*.bar"], + only: ["/foo/node_modules/*.bar"], filename: "/foo/node_modules/bar.foo", }).then(assertIgnored), ]); diff --git a/packages/babel-core/test/config-chain.js b/packages/babel-core/test/config-chain.js index 0185c783bb..a9cc6bd2e9 100644 --- a/packages/babel-core/test/config-chain.js +++ b/packages/babel-core/test/config-chain.js @@ -31,6 +31,8 @@ describe("buildConfigChain", function () { process.env.NODE_ENV = oldNodeEnv; }); + // TODO: Tests for ignore and only + it("dir1", function () { const chain = buildConfigChain({ filename: fixture("dir1", "src.js"), diff --git a/packages/babel-core/test/util.js b/packages/babel-core/test/util.js deleted file mode 100644 index 5d84ad41f6..0000000000 --- a/packages/babel-core/test/util.js +++ /dev/null @@ -1,107 +0,0 @@ -import assert from "assert"; -import * as util from "../lib/util"; -import * as t from "babel-types"; - -describe("util", function () { - it("canCompile", function () { - assert.ok(util.canCompile("test.js")); - assert.ok(util.canCompile("/test.js")); - assert.ok(util.canCompile("/scripts/test.js")); - - assert.ok(util.canCompile("test.es6")); - assert.ok(util.canCompile("/test.es6")); - assert.ok(util.canCompile("/scripts/test.es6")); - - assert.ok(util.canCompile("test.es")); - assert.ok(util.canCompile("/test.es")); - assert.ok(util.canCompile("/scripts/test.es")); - - assert.ok(util.canCompile("test.jsx")); - assert.ok(util.canCompile("/test.jsx")); - assert.ok(util.canCompile("/scripts/test.jsx")); - - assert.ok(!util.canCompile("test")); - assert.ok(!util.canCompile("test.css")); - assert.ok(!util.canCompile("/test.css")); - assert.ok(!util.canCompile("/scripts/test.css")); - }); - - it("list", function () { - assert.deepEqual(util.list(undefined), []); - assert.deepEqual(util.list(false), []); - assert.deepEqual(util.list(null), []); - assert.deepEqual(util.list(""), []); - assert.deepEqual(util.list("foo"), ["foo"]); - assert.deepEqual(util.list("foo,bar"), ["foo", "bar"]); - assert.deepEqual(util.list(["foo", "bar"]), ["foo", "bar"]); - assert.deepEqual(util.list(/foo/), [/foo/]); - - const date = new Date; - assert.deepEqual(util.list(date), [date]); - }); - - it("arrayify", function () { - assert.deepEqual(util.arrayify(undefined), []); - assert.deepEqual(util.arrayify(false), []); - assert.deepEqual(util.arrayify(null), []); - assert.deepEqual(util.arrayify(""), []); - assert.deepEqual(util.arrayify("foo"), ["foo"]); - assert.deepEqual(util.arrayify("foo,bar"), ["foo", "bar"]); - assert.deepEqual(util.arrayify(["foo", "bar"]), ["foo", "bar"]); - assert.deepEqual(util.arrayify({ foo: "bar" }), [{ foo: "bar" }]); - assert.deepEqual(util.arrayify(function () { return "foo"; })[0](), "foo"); - }); - - it("regexify", function () { - assert.deepEqual(util.regexify(undefined), /.^/); - assert.deepEqual(util.regexify(false), /.^/); - assert.deepEqual(util.regexify(null), /.^/); - assert.deepEqual(util.regexify(""), /.^/); - assert.deepEqual(util.regexify(["foo", "bar"]), /foo|bar/i); - assert.deepEqual(util.regexify("foobar"), /(?:(?=.)foobar)/i); - assert.deepEqual(util.regexify(/foobar/), /foobar/); - - assert.ok(util.regexify("foo/bar").test("bar/foo/bar")); - assert.ok(util.regexify("foo/*").test("foo/bar.js")); - assert.ok(util.regexify("*.js").test("bar.js")); - assert.ok(util.regexify("./foo").test("foo")); - assert.ok(util.regexify("./foo/bar.js").test("foo/bar.js")); - assert.ok(util.regexify("foobar").test("foobar")); - - assert.throws(function () { - util.regexify({}); - }, /illegal type for regexify/); - }); - - it("booleanify", function () { - assert.strictEqual(util.booleanify("true"), true); - assert.strictEqual(util.booleanify("false"), false); - assert.strictEqual(util.booleanify("inline"), "inline"); - }); - - it("toIdentifier", function () { - assert.equal(t.toIdentifier("swag-lord"), "swagLord"); - }); - - it("shouldIgnore", function () { - const reIgnore = /\-reIgnore\.js/; - const fnIgnore = function (src) { - if (src.indexOf("fnIgnore") > 0) { - return true; - } - }; - - assert.equal(util.shouldIgnore("test.js", []), false); - assert.equal(util.shouldIgnore("test-reIgnore.js", [fnIgnore]), false); - assert.equal(util.shouldIgnore("test-reIgnore.js", [reIgnore]), true); - - assert.equal(util.shouldIgnore("test-fnIgnore.js", [fnIgnore]), true); - assert.equal(util.shouldIgnore("test-fnIgnore.js", [reIgnore]), false); - - assert.equal(util.shouldIgnore("test-reIgnore.js", [], [fnIgnore]), true); - assert.equal(util.shouldIgnore("test-reIgnore.js", [], [reIgnore]), false); - - assert.equal(util.shouldIgnore("test-fnIgnore.js", [], [fnIgnore]), false); - assert.equal(util.shouldIgnore("test-fnIgnore.js", [], [reIgnore]), true); - }); -}); diff --git a/packages/babel-register/src/node.js b/packages/babel-register/src/node.js index 229ecb3475..3ae82ad886 100644 --- a/packages/babel-register/src/node.js +++ b/packages/babel-register/src/node.js @@ -1,9 +1,10 @@ import deepClone from "lodash/cloneDeep"; import sourceMapSupport from "source-map-support"; import * as registerCache from "./cache"; +import escapeRegExp from "lodash/escapeRegExp"; import extend from "lodash/extend"; import * as babel from "babel-core"; -import { util, OptionManager } from "babel-core"; +import { OptionManager, DEFAULT_EXTENSIONS } from "babel-core"; import fs from "fs"; import path from "path"; @@ -28,18 +29,9 @@ let cache = registerCache.get(); const transformOpts = {}; -let ignore; -let only; - let oldHandlers = {}; const maps = {}; -const cwd = process.cwd(); - -function getRelativePath(filename) { - return path.relative(cwd, filename); -} - function mtime(filename) { return +fs.statSync(filename).mtime; } @@ -54,6 +46,9 @@ function compile(filename) { { filename } )); + // Bail out ASAP if the file has been ignored. + if (opts === null) return null; + let cacheKey = `${JSON.stringify(opts)}:${babel.version}`; const env = babel.getEnv(false); @@ -87,27 +82,14 @@ function compile(filename) { return result.code; } -function shouldIgnore(filename) { - if (!ignore && !only) { - return getRelativePath(filename).split(path.sep).indexOf("node_modules") >= 0; - } else { - return util.shouldIgnore(filename, ignore || [], only); - } -} - -function loader(m, filename) { - m._compile(compile(filename), filename); -} - function registerExtension(ext) { const old = oldHandlers[ext] || oldHandlers[".js"] || require.extensions[".js"]; require.extensions[ext] = function (m, filename) { - if (shouldIgnore(filename)) { - old(m, filename); - } else { - loader(m, filename, old); - } + const result = compile(filename); + + if (result === null) old(m, filename); + else m._compile(result, filename); }; } @@ -129,20 +111,27 @@ function hookExtensions(_exts) { }); } -hookExtensions(util.canCompile.EXTENSIONS); +hookExtensions(DEFAULT_EXTENSIONS); export default function (opts?: Object = {}) { - if (opts.only != null) only = util.arrayify(opts.only, util.regexify); - if (opts.ignore != null) ignore = util.arrayify(opts.ignore, util.regexify); - - if (opts.extensions) hookExtensions(util.arrayify(opts.extensions)); + if (opts.extensions) hookExtensions(opts.extensions); if (opts.cache === false) cache = null; delete opts.extensions; - delete opts.ignore; delete opts.cache; - delete opts.only; extend(transformOpts, opts); + + if (!transformOpts.ignore && !transformOpts.only) { + // By default, ignore files inside the node_modules relative to the current working directory. + transformOpts.ignore = [ + new RegExp( + "^" + + escapeRegExp(process.cwd() + path.sep) + + ".*" + + escapeRegExp(path.sep + "node_modules" + path.sep) + , "i"), + ]; + } } diff --git a/packages/babel-types/test/converters.js b/packages/babel-types/test/converters.js index d787265a7f..43e1e887a7 100644 --- a/packages/babel-types/test/converters.js +++ b/packages/babel-types/test/converters.js @@ -2,6 +2,10 @@ import * as t from "../lib"; import { assert } from "chai"; describe("converters", function () { + it("toIdentifier", function () { + assert.equal(t.toIdentifier("swag-lord"), "swagLord"); + }); + describe("valueToNode", function () { it("number", function () { assert.deepEqual(t.valueToNode(Math.PI), t.numericLiteral(Math.PI));