diff --git a/packages/babel-plugin-proposal-record-and-tuple/.npmignore b/packages/babel-plugin-proposal-record-and-tuple/.npmignore new file mode 100644 index 0000000000..f980694583 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/.npmignore @@ -0,0 +1,3 @@ +src +test +*.log diff --git a/packages/babel-plugin-proposal-record-and-tuple/package.json b/packages/babel-plugin-proposal-record-and-tuple/package.json new file mode 100644 index 0000000000..7d82bcb4ab --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/package.json @@ -0,0 +1,32 @@ +{ + "name": "@babel/plugin-proposal-record-and-tuple", + "version": "7.12.0", + "description": "A transform for Record and Tuple syntax.", + "repository": { + "type": "git", + "url": "https://github.com/babel/babel.git", + "directory": "packages/babel-plugin-proposal-record-and-tuple" + }, + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "main": "./lib/index.js", + "exports": "./lib/index.js", + "keywords": [ + "babel-plugin" + ], + "dependencies": { + "@babel/helper-module-imports": "workspace:^7.12.13", + "@babel/helper-plugin-utils": "workspace:^7.12.13", + "@babel/helper-validator-option": "workspace:^7.12.17", + "@babel/plugin-syntax-record-and-tuple": "workspace:^7.12.1" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + }, + "devDependencies": { + "@babel/core": "workspace:*", + "@babel/helper-plugin-test-runner": "workspace:*" + } +} diff --git a/packages/babel-plugin-proposal-record-and-tuple/src/index.js b/packages/babel-plugin-proposal-record-and-tuple/src/index.js new file mode 100644 index 0000000000..0a63de2e31 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/src/index.js @@ -0,0 +1,88 @@ +/* + ** Copyright 2020 Bloomberg Finance L.P. + ** + ** Licensed under the MIT License (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** https://opensource.org/licenses/MIT + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +import { declare } from "@babel/helper-plugin-utils"; +import syntaxRecordAndTuple from "@babel/plugin-syntax-record-and-tuple"; +import { types as t } from "@babel/core"; +import { addNamed, isModule } from "@babel/helper-module-imports"; +import { OptionValidator } from "@babel/helper-validator-option"; + +const v = new OptionValidator(PACKAGE_JSON.name); + +export default declare((api, options) => { + api.assertVersion(7); + + const polyfillModuleName = v.validateStringOption( + "polyfillModuleName", + options.polyfillModuleName, + "@bloomberg/record-tuple-polyfill", + ); + const shouldImportPolyfill = v.validateBooleanOption( + "importPolyfill", + options.importPolyfill, + !!options.polyfillModuleName, + ); + + // program -> cacheKey -> localBindingName + const importCaches = new WeakMap(); + + function getOr(map, key, getDefault) { + let value = map.get(key); + if (!value) map.set(key, (value = getDefault())); + return value; + } + + function getBuiltIn(name, path, programPath) { + if (!shouldImportPolyfill) return t.identifier(name); + if (!programPath) { + throw new Error("Internal error: unable to find the Program node."); + } + + const cacheKey = `${name}:${isModule(programPath)}`; + + const cache = getOr(importCaches, programPath.node, () => new Map()); + const localBindingName = getOr(cache, cacheKey, () => { + return addNamed(programPath, name, polyfillModuleName, { + importedInterop: "uncompiled", + }).name; + }); + + return t.identifier(localBindingName); + } + + return { + name: "proposal-record-and-tuple", + inherits: syntaxRecordAndTuple, + visitor: { + Program(path, state) { + state.programPath = path; + }, + RecordExpression(path, state) { + const record = getBuiltIn("Record", path, state.programPath); + + const object = t.objectExpression(path.node.properties); + const wrapped = t.callExpression(record, [object]); + path.replaceWith(wrapped); + }, + TupleExpression(path, state) { + const tuple = getBuiltIn("Tuple", path, state.programPath); + + const wrapped = t.callExpression(tuple, path.node.elements); + path.replaceWith(wrapped); + }, + }, + }; +}); diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/commonjs/input.js b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/commonjs/input.js new file mode 100644 index 0000000000..f23d5c75b2 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/commonjs/input.js @@ -0,0 +1,8 @@ +const r2 = #{ + a: #{ + b: 456, + }, + e: 789, +}; + +const t2 = #[1, #[2, 3, #[4], 5], 6]; diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/commonjs/options.json b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/commonjs/options.json new file mode 100644 index 0000000000..8142c14cc1 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/commonjs/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [["../../../../", { + "syntaxType": "hash", + "importPolyfill": true + }]] +} diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/commonjs/output.js b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/commonjs/output.js new file mode 100644 index 0000000000..6c403a10cc --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/commonjs/output.js @@ -0,0 +1,12 @@ +var _Tuple = require("@bloomberg/record-tuple-polyfill").Tuple; + +var _Record = require("@bloomberg/record-tuple-polyfill").Record; + +const r2 = _Record({ + a: _Record({ + b: 456 + }), + e: 789 +}); + +const t2 = _Tuple(1, _Tuple(2, 3, _Tuple(4), 5), 6); diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name-implies-should-import/input.mjs b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name-implies-should-import/input.mjs new file mode 100644 index 0000000000..f23d5c75b2 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name-implies-should-import/input.mjs @@ -0,0 +1,8 @@ +const r2 = #{ + a: #{ + b: 456, + }, + e: 789, +}; + +const t2 = #[1, #[2, 3, #[4], 5], 6]; diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name-implies-should-import/options.json b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name-implies-should-import/options.json new file mode 100644 index 0000000000..ef8b0013a1 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name-implies-should-import/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [["../../../../", { + "syntaxType": "hash", + "polyfillModuleName": "my-polyfill" + }]] +} diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name-implies-should-import/output.mjs b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name-implies-should-import/output.mjs new file mode 100644 index 0000000000..c681193271 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name-implies-should-import/output.mjs @@ -0,0 +1,11 @@ +import { Tuple as _Tuple } from "my-polyfill"; +import { Record as _Record } from "my-polyfill"; + +const r2 = _Record({ + a: _Record({ + b: 456 + }), + e: 789 +}); + +const t2 = _Tuple(1, _Tuple(2, 3, _Tuple(4), 5), 6); diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name/input.mjs b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name/input.mjs new file mode 100644 index 0000000000..f23d5c75b2 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name/input.mjs @@ -0,0 +1,8 @@ +const r2 = #{ + a: #{ + b: 456, + }, + e: 789, +}; + +const t2 = #[1, #[2, 3, #[4], 5], 6]; diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name/options.json b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name/options.json new file mode 100644 index 0000000000..d93f3394f7 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [["../../../../", { + "syntaxType": "hash", + "importPolyfill": true, + "polyfillModuleName": "my-polyfill" + }]] +} diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name/output.mjs b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name/output.mjs new file mode 100644 index 0000000000..c681193271 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/custom-name/output.mjs @@ -0,0 +1,11 @@ +import { Tuple as _Tuple } from "my-polyfill"; +import { Record as _Record } from "my-polyfill"; + +const r2 = _Record({ + a: _Record({ + b: 456 + }), + e: 789 +}); + +const t2 = _Tuple(1, _Tuple(2, 3, _Tuple(4), 5), 6); diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/default-name/input.mjs b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/default-name/input.mjs new file mode 100644 index 0000000000..f23d5c75b2 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/default-name/input.mjs @@ -0,0 +1,8 @@ +const r2 = #{ + a: #{ + b: 456, + }, + e: 789, +}; + +const t2 = #[1, #[2, 3, #[4], 5], 6]; diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/default-name/options.json b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/default-name/options.json new file mode 100644 index 0000000000..8142c14cc1 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/default-name/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [["../../../../", { + "syntaxType": "hash", + "importPolyfill": true + }]] +} diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/default-name/output.mjs b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/default-name/output.mjs new file mode 100644 index 0000000000..08e4128efd --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/import-polyfill/default-name/output.mjs @@ -0,0 +1,11 @@ +import { Tuple as _Tuple } from "@bloomberg/record-tuple-polyfill"; +import { Record as _Record } from "@bloomberg/record-tuple-polyfill"; + +const r2 = _Record({ + a: _Record({ + b: 456 + }), + e: 789 +}); + +const t2 = _Tuple(1, _Tuple(2, 3, _Tuple(4), 5), 6); diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/bar/input.js b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/bar/input.js new file mode 100644 index 0000000000..4a2296f0b5 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/bar/input.js @@ -0,0 +1,23 @@ +"use strict"; + +const r1 = {| + a: 1, + b: 2, + c: 3, +|}; + +const r2 = {| + a: {| + b: {| + c: 123, + |}, + d: 456, + |}, + e: 789, +|}; + +const t1 = [||]; + +const t2 = [|1,2,3|]; + +const t3 = [|1, [|2, 3, [|4|], 5|], 6|]; diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/bar/options.json b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/bar/options.json new file mode 100644 index 0000000000..647b9ef87a --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/bar/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["../../../../", { "syntaxType": "bar" }]] +} diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/bar/output.js b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/bar/output.js new file mode 100644 index 0000000000..7574318c03 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/bar/output.js @@ -0,0 +1,19 @@ +"use strict"; + +const r1 = Record({ + a: 1, + b: 2, + c: 3 +}); +const r2 = Record({ + a: Record({ + b: Record({ + c: 123 + }), + d: 456 + }), + e: 789 +}); +const t1 = Tuple(); +const t2 = Tuple(1, 2, 3); +const t3 = Tuple(1, Tuple(2, 3, Tuple(4), 5), 6); diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/hash/input.js b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/hash/input.js new file mode 100644 index 0000000000..a280a50faf --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/hash/input.js @@ -0,0 +1,21 @@ +"use strict"; + +const r1 = #{ + a: 1, + b: 2, + c: 3, +}; + +const r2 = #{ + a: #{ + b: #{ + c: 123, + }, + d: 456, + }, + e: 789, +}; + +const t1 = #[1,2,3]; + +const t2 = #[1, #[2, 3, #[4], 5], 6]; diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/hash/options.json b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/hash/options.json new file mode 100644 index 0000000000..30fa6b7cca --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/hash/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["../../../../", { "syntaxType": "hash" }]] +} diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/hash/output.js b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/hash/output.js new file mode 100644 index 0000000000..f3676e85dc --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/fixtures/syntax/hash/output.js @@ -0,0 +1,18 @@ +"use strict"; + +const r1 = Record({ + a: 1, + b: 2, + c: 3 +}); +const r2 = Record({ + a: Record({ + b: Record({ + c: 123 + }), + d: 456 + }), + e: 789 +}); +const t1 = Tuple(1, 2, 3); +const t2 = Tuple(1, Tuple(2, 3, Tuple(4), 5), 6); diff --git a/packages/babel-plugin-proposal-record-and-tuple/test/index.js b/packages/babel-plugin-proposal-record-and-tuple/test/index.js new file mode 100644 index 0000000000..1b534b8fc6 --- /dev/null +++ b/packages/babel-plugin-proposal-record-and-tuple/test/index.js @@ -0,0 +1,3 @@ +import runner from "@babel/helper-plugin-test-runner"; + +runner(__dirname); diff --git a/yarn.lock b/yarn.lock index eceeda271f..59efd04ebb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1385,6 +1385,21 @@ __metadata: languageName: unknown linkType: soft +"@babel/plugin-proposal-record-and-tuple@workspace:packages/babel-plugin-proposal-record-and-tuple": + version: 0.0.0-use.local + resolution: "@babel/plugin-proposal-record-and-tuple@workspace:packages/babel-plugin-proposal-record-and-tuple" + dependencies: + "@babel/core": "workspace:*" + "@babel/helper-module-imports": "workspace:^7.12.13" + "@babel/helper-plugin-test-runner": "workspace:*" + "@babel/helper-plugin-utils": "workspace:^7.12.13" + "@babel/helper-validator-option": "workspace:^7.12.17" + "@babel/plugin-syntax-record-and-tuple": "workspace:^7.12.1" + peerDependencies: + "@babel/core": ^7.12.0 + languageName: unknown + linkType: soft + "@babel/plugin-proposal-throw-expressions@workspace:*, @babel/plugin-proposal-throw-expressions@workspace:packages/babel-plugin-proposal-throw-expressions": version: 0.0.0-use.local resolution: "@babel/plugin-proposal-throw-expressions@workspace:packages/babel-plugin-proposal-throw-expressions" @@ -1729,7 +1744,7 @@ __metadata: languageName: unknown linkType: soft -"@babel/plugin-syntax-record-and-tuple@workspace:*, @babel/plugin-syntax-record-and-tuple@workspace:packages/babel-plugin-syntax-record-and-tuple": +"@babel/plugin-syntax-record-and-tuple@workspace:*, @babel/plugin-syntax-record-and-tuple@workspace:^7.12.1, @babel/plugin-syntax-record-and-tuple@workspace:packages/babel-plugin-syntax-record-and-tuple": version: 0.0.0-use.local resolution: "@babel/plugin-syntax-record-and-tuple@workspace:packages/babel-plugin-syntax-record-and-tuple" dependencies: