diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1e6e5c1909..36b8c53a42 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -72,6 +72,12 @@ Use the `TEST_GREP` variable to run a subset of tests by name: $ TEST_GREP=transformation make test ``` +To test the code coverage, use: + +```sh +$ make test-cov +``` + #### Internals Please see [`/doc`](/doc) for internals documentation relevant to developing babel. diff --git a/packages/babel/src/generation/generators/flow.js b/packages/babel/src/generation/generators/flow.js index 80edc2cf1b..2721a84bfb 100644 --- a/packages/babel/src/generation/generators/flow.js +++ b/packages/babel/src/generation/generators/flow.js @@ -177,6 +177,12 @@ export function NullableTypeAnnotation(node, print) { print.plain(node.typeAnnotation); } +/** + * Prints NumberLiteralTypeAnnotation, prints value. + */ + +export { Literal as NumberLiteralTypeAnnotation } from "./types"; + /** * Prints NumberTypeAnnotation. */ diff --git a/packages/babel/src/transformation/file/index.js b/packages/babel/src/transformation/file/index.js index d7f4f4147a..536e21144f 100644 --- a/packages/babel/src/transformation/file/index.js +++ b/packages/babel/src/transformation/file/index.js @@ -407,6 +407,30 @@ export default class File { return uid; } + addTemplateObject(helperName: string, strings: Array, raw: Array): Object { + // Generate a unique name based on the string literals so we dedupe + // identical strings used in the program. + var stringIds = raw.elements.map(function(string) { + return string.value; + }); + var name = `${helperName}_${raw.elements.length}_${stringIds.join(",")}`; + + var declar = this.declarations[name]; + if (declar) return declar; + + var uid = this.declarations[name] = this.scope.generateUidIdentifier("templateObject"); + + var helperId = this.addHelper(helperName); + var init = t.callExpression(helperId, [strings, raw]); + init._compact = true; + this.scope.push({ + id: uid, + init: init, + _blockHoist: 1.9 // This ensures that we don't fail if not using function expression helpers + }); + return uid; + } + /** * [Please add a description.] */ diff --git a/packages/babel/src/transformation/pipeline.js b/packages/babel/src/transformation/pipeline.js index 0da9f4dff8..7e2444ddc7 100644 --- a/packages/babel/src/transformation/pipeline.js +++ b/packages/babel/src/transformation/pipeline.js @@ -110,7 +110,7 @@ export default class Pipeline { } /** - * [Please add a description.] + * Build dependency graph by recursing `metadata.modules`. WIP. */ pretransform(code: string, opts?: Object) { diff --git a/packages/babel/src/transformation/transformers/es6/template-literals.js b/packages/babel/src/transformation/transformers/es6/template-literals.js index 83f35c5e89..b561f64757 100644 --- a/packages/babel/src/transformation/transformers/es6/template-literals.js +++ b/packages/babel/src/transformation/transformers/es6/template-literals.js @@ -64,7 +64,9 @@ export var visitor = { var templateName = "tagged-template-literal"; if (file.isLoose("es6.templateLiterals")) templateName += "-loose"; - args.push(t.callExpression(file.addHelper(templateName), [strings, raw])); + + var templateObject = file.addTemplateObject(templateName, strings, raw); + args.push(templateObject); args = args.concat(quasi.expressions); diff --git a/packages/babel/src/traversal/scope/index.js b/packages/babel/src/traversal/scope/index.js index 2f65ce81b9..4a0145a135 100644 --- a/packages/babel/src/traversal/scope/index.js +++ b/packages/babel/src/traversal/scope/index.js @@ -834,14 +834,15 @@ export default class Scope { var unique = opts.unique; var kind = opts.kind || "var"; + var blockHoist = opts._blockHoist == null ? 2 : opts._blockHoist; - var dataKey = `declaration:${kind}`; + var dataKey = `declaration:${kind}:${blockHoist}`; var declar = !unique && path.getData(dataKey); if (!declar) { declar = t.variableDeclaration(kind, []); declar._generated = true; - declar._blockHoist = 2; + declar._blockHoist = blockHoist; this.hub.file.attachAuxiliaryComment(declar); diff --git a/packages/babel/src/types/definitions/flow.js b/packages/babel/src/types/definitions/flow.js index 448300e123..4380f13cf6 100644 --- a/packages/babel/src/types/definitions/flow.js +++ b/packages/babel/src/types/definitions/flow.js @@ -82,6 +82,10 @@ define("NullableTypeAnnotation", { aliases: ["Flow"] }); +define("NumberLiteralTypeAnnotation", { + aliases: ["Flow"] +}); + define("NumberTypeAnnotation", { aliases: ["Flow", "FlowBaseAnnotation"] }); diff --git a/packages/babel/test/api.js b/packages/babel/test/api.js index d553956d7a..f554f12c2e 100644 --- a/packages/babel/test/api.js +++ b/packages/babel/test/api.js @@ -4,6 +4,7 @@ var buildExternalHelpers = require("../lib/tools/build-external-helpers"); var PluginManager = require("../lib/transformation/file/plugin-manager"); var Transformer = require("../lib/transformation/transformer"); var transform = require("../lib/transformation"); +var Pipeline = require("../lib/transformation/pipeline"); var assert = require("assert"); var File = require("../lib/transformation/file"); @@ -422,6 +423,11 @@ suite("api", function () { assert.ok(file2.opts.extra !== file3.opts.extra); }); + // For now just signal that it's not cruft and shouldn't be deleted. + test("pretransform exists", function () { + assert.ok(Pipeline.prototype.pretransform); + }); + suite("buildExternalHelpers", function () { test("all", function () { var script = buildExternalHelpers(); diff --git a/packages/babel/test/fixtures/generation/flow/number-literal-types/actual.js b/packages/babel/test/fixtures/generation/flow/number-literal-types/actual.js new file mode 100644 index 0000000000..8aa0ffac4b --- /dev/null +++ b/packages/babel/test/fixtures/generation/flow/number-literal-types/actual.js @@ -0,0 +1,5 @@ +var a: 123; +var a: 123.0; +var a: 0x7B; +var a: 0b1111011; +var a: 0o173; diff --git a/packages/babel/test/fixtures/generation/flow/number-literal-types/expected.js b/packages/babel/test/fixtures/generation/flow/number-literal-types/expected.js new file mode 100644 index 0000000000..c8e24031f1 --- /dev/null +++ b/packages/babel/test/fixtures/generation/flow/number-literal-types/expected.js @@ -0,0 +1,5 @@ +var a: 123; +var a: 123.0; +var a: 0x7B; +var a: 123; +var a: 123; diff --git a/packages/babel/test/fixtures/transformation/es6.template-literals/tag-loose/actual.js b/packages/babel/test/fixtures/transformation/es6.template-literals/tag-loose/actual.js index 7fe1864736..52419bb505 100644 --- a/packages/babel/test/fixtures/transformation/es6.template-literals/tag-loose/actual.js +++ b/packages/babel/test/fixtures/transformation/es6.template-literals/tag-loose/actual.js @@ -1 +1,3 @@ var foo = bar`wow\na${ 42 }b ${_.foobar()}`; +var bar = bar`wow\nab${ 42 } ${_.foobar()}`; +var bar = bar`wow\naB${ 42 } ${_.baz()}`; diff --git a/packages/babel/test/fixtures/transformation/es6.template-literals/tag-loose/expected.js b/packages/babel/test/fixtures/transformation/es6.template-literals/tag-loose/expected.js index a2264017ba..9378680632 100644 --- a/packages/babel/test/fixtures/transformation/es6.template-literals/tag-loose/expected.js +++ b/packages/babel/test/fixtures/transformation/es6.template-literals/tag-loose/expected.js @@ -1,5 +1,11 @@ "use strict"; +var _templateObject = _taggedTemplateLiteralLoose(["wow\na", "b ", ""], ["wow\\na", "b ", ""]), + _templateObject2 = _taggedTemplateLiteralLoose(["wow\nab", " ", ""], ["wow\\nab", " ", ""]), + _templateObject3 = _taggedTemplateLiteralLoose(["wow\naB", " ", ""], ["wow\\naB", " ", ""]); + function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; } -var foo = bar(_taggedTemplateLiteralLoose(["wow\na", "b ", ""], ["wow\\na", "b ", ""]), 42, _.foobar()); \ No newline at end of file +var foo = bar(_templateObject, 42, _.foobar()); +var bar = bar(_templateObject2, 42, _.foobar()); +var bar = bar(_templateObject3, 42, _.baz()); \ No newline at end of file diff --git a/packages/babel/test/fixtures/transformation/es6.template-literals/tag/expected.js b/packages/babel/test/fixtures/transformation/es6.template-literals/tag/expected.js index db7bc65355..7749db566b 100644 --- a/packages/babel/test/fixtures/transformation/es6.template-literals/tag/expected.js +++ b/packages/babel/test/fixtures/transformation/es6.template-literals/tag/expected.js @@ -1,5 +1,7 @@ "use strict"; +var _templateObject = _taggedTemplateLiteral(["wow\na", "b ", ""], ["wow\\na", "b ", ""]); + function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } -var foo = bar(_taggedTemplateLiteral(["wow\na", "b ", ""], ["wow\\na", "b ", ""]), 42, _.foobar()); \ No newline at end of file +var foo = bar(_templateObject, 42, _.foobar()); diff --git a/packages/babylon/src/plugins/flow.js b/packages/babylon/src/plugins/flow.js index f361f10882..99f77cd93d 100644 --- a/packages/babylon/src/plugins/flow.js +++ b/packages/babylon/src/plugins/flow.js @@ -493,6 +493,12 @@ pp.flowParsePrimaryType = function () { this.next(); return this.finishNode(node, "StringLiteralTypeAnnotation"); + case tt.num: + node.value = this.value; + node.raw = this.input.slice(this.start, this.end); + this.next(); + return this.finishNode(node, "NumberLiteralTypeAnnotation"); + default: if (this.type.keyword === "typeof") { return this.flowParseTypeofType(); diff --git a/packages/babylon/test/tests-flow.js b/packages/babylon/test/tests-flow.js index 92fa91a17b..1afef5bcd0 100644 --- a/packages/babylon/test/tests-flow.js +++ b/packages/babylon/test/tests-flow.js @@ -10174,6 +10174,208 @@ var fbTestFixture = { } }, }, + 'Number Literal Types': { + 'var a: 123': { + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'a', + typeAnnotation: { + type: 'TypeAnnotation', + typeAnnotation: { + type: 'NumberLiteralTypeAnnotation', + value: 123, + raw: '123', + range: [7, 10], + loc: { + start: { line: 1, column: 7 }, + end: { line: 1, column: 10 } + } + }, + range: [5, 10], + loc: { + start: { line: 1, column: 5 }, + end: { line: 1, column: 10 } + } + } + }, + init: null, + range: [4, 10], + loc: { + start: { line: 1, column: 4 }, + end: { line: 1, column: 10 } + } + }], + kind: 'var', + range: [0, 10], + loc: { + start: { line: 1, column: 0 }, + end: { line: 1, column: 10 } + } + }, + 'var a: 123.0': { + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'a', + typeAnnotation: { + type: 'TypeAnnotation', + typeAnnotation: { + type: 'NumberLiteralTypeAnnotation', + value: 123, + raw: '123.0', + range: [7, 12], + loc: { + start: { line: 1, column: 7 }, + end: { line: 1, column: 12 } + } + }, + range: [5, 12], + loc: { + start: { line: 1, column: 5 }, + end: { line: 1, column: 12 } + } + } + }, + init: null, + range: [4, 12], + loc: { + start: { line: 1, column: 4 }, + end: { line: 1, column: 12 } + } + }], + kind: 'var', + range: [0, 12], + loc: { + start: { line: 1, column: 0 }, + end: { line: 1, column: 12 } + } + }, + 'var a: 0x7B': { + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'a', + typeAnnotation: { + type: 'TypeAnnotation', + typeAnnotation: { + type: 'NumberLiteralTypeAnnotation', + value: 123, + raw: '0x7B', + range: [7, 11], + loc: { + start: { line: 1, column: 7 }, + end: { line: 1, column: 11 } + } + }, + range: [5, 11], + loc: { + start: { line: 1, column: 5 }, + end: { line: 1, column: 11 } + } + } + }, + init: null, + range: [4, 11], + loc: { + start: { line: 1, column: 4 }, + end: { line: 1, column: 11 } + } + }], + kind: 'var', + range: [0, 11], + loc: { + start: { line: 1, column: 0 }, + end: { line: 1, column: 11 } + } + }, + 'var a: 0b1111011': { + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'a', + typeAnnotation: { + type: 'TypeAnnotation', + typeAnnotation: { + type: 'NumberLiteralTypeAnnotation', + value: 123, + raw: '0b1111011', + range: [7, 16], + loc: { + start: { line: 1, column: 7 }, + end: { line: 1, column: 16 } + } + }, + range: [5, 16], + loc: { + start: { line: 1, column: 5 }, + end: { line: 1, column: 16 } + } + } + }, + init: null, + range: [4, 16], + loc: { + start: { line: 1, column: 4 }, + end: { line: 1, column: 16 } + } + }], + kind: 'var', + range: [0, 16], + loc: { + start: { line: 1, column: 0 }, + end: { line: 1, column: 16 } + } + }, + 'var a: 0o173': { + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'a', + typeAnnotation: { + type: 'TypeAnnotation', + typeAnnotation: { + type: 'NumberLiteralTypeAnnotation', + value: 123, + raw: '0o173', + range: [7, 12], + loc: { + start: { line: 1, column: 7 }, + end: { line: 1, column: 12 } + } + }, + range: [5, 12], + loc: { + start: { line: 1, column: 5 }, + end: { line: 1, column: 12 } + } + } + }, + init: null, + range: [4, 12], + loc: { + start: { line: 1, column: 4 }, + end: { line: 1, column: 12 } + } + }], + kind: 'var', + range: [0, 12], + loc: { + start: { line: 1, column: 0 }, + end: { line: 1, column: 12 } + } + } + }, 'Qualified Generic Type': { 'var a : A.B': { type: 'VariableDeclaration',