diff --git a/packages/babel-plugin-transform-property-literals/__tests__/transform-property-literals-test.js b/packages/babel-plugin-transform-property-literals/__tests__/transform-property-literals-test.js index 10b91648b..5cd2fe843 100644 --- a/packages/babel-plugin-transform-property-literals/__tests__/transform-property-literals-test.js +++ b/packages/babel-plugin-transform-property-literals/__tests__/transform-property-literals-test.js @@ -81,15 +81,31 @@ describe("transform-property-literals-plugin", () => { const source = unpad(` ({ "ಠ_ಠ": "bar", - "12e34": "wut" + "12e34": "wut", + "\u01FC": "AE" }) `); const expected = unpad(` ({ ಠ_ಠ: "bar", - 12e34: "wut" + "12e34": "wut" }); `); expect(transform(source)).toBe(expected); }); + + it("should transform computed properties which are strings", () => { + const source = unpad(` + ({ + [ಠ_ಠ]: "foo", + ["ಠ_ಠ"]: "bar" + }); + `); + const expected = unpad(` + ({ + [ಠ_ಠ]: "foo", + ಠ_ಠ: "bar" + }); + `); + }); }); diff --git a/packages/babel-plugin-transform-property-literals/src/escape-string-literal.js b/packages/babel-plugin-transform-property-literals/src/escape-string-literal.js new file mode 100644 index 000000000..916879dac --- /dev/null +++ b/packages/babel-plugin-transform-property-literals/src/escape-string-literal.js @@ -0,0 +1,67 @@ +"use strict"; + +/** + * Original Source: + * https://github.com/shapesecurity/shift-codegen-js/blob/0d09bd8a/src/coderep.js#L122 + * + * The following function is an exact copy of the original implementation + * + * LICENSE + +Copyright 2014 Shape Security, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +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. + + */ +module.exports = function escapeStringLiteral(stringValue) { + let result = ""; + let nSingle = 0, nDouble = 0; + for (let i = 0, l = stringValue.length; i < l; ++i) { + let ch = stringValue[i]; + if (ch === '"') { + ++nDouble; + } else if (ch === "'") { + ++nSingle; + } + } + let delim = nDouble > nSingle ? "'" : '"'; + result += delim; + for (let i = 0; i < stringValue.length; i++) { + let ch = stringValue.charAt(i); + switch (ch) { + case delim: + result += "\\" + delim; + break; + case "\n": + result += "\\n"; + break; + case "\r": + result += "\\r"; + break; + case "\\": + result += "\\\\"; + break; + case "\u2028": + result += "\\u2028"; + break; + case "\u2029": + result += "\\u2029"; + break; + default: + result += ch; + break; + } + } + result += delim; + return result; +}; diff --git a/packages/babel-plugin-transform-property-literals/src/index.js b/packages/babel-plugin-transform-property-literals/src/index.js index c028b09df..74e4f6796 100644 --- a/packages/babel-plugin-transform-property-literals/src/index.js +++ b/packages/babel-plugin-transform-property-literals/src/index.js @@ -1,6 +1,6 @@ "use strict"; -const esutils = require("esutils"); +const { reduceStaticPropertyNameES5 } = require("./property-name"); module.exports = function({ types: t }) { return { @@ -8,41 +8,15 @@ module.exports = function({ types: t }) { visitor: { // { 'foo': 'bar' } -> { foo: 'bar' } ObjectProperty: { - exit({ node }) { - const key = node.key; - if (!t.isStringLiteral(key)) { + exit(path) { + const key = path.get("key"); + if (!key.isStringLiteral()) { return; } - if (key.value.match(/^\d+$/)) { - const newProp = parseInt(node.key.value, 10); - if (newProp.toString() === node.key.value) { - node.key = t.numericLiteral(newProp); - node.computed = false; - } - } else if (isValidPropertyName(key.value)) { - node.key = t.identifier(key.value); - node.computed = false; - } + key.replaceWith(reduceStaticPropertyNameES5(t, key.node)); } } } }; }; - -// This currently targets es5 now. -// TODO: -// Target es6 after integration with babel-preset-env -function isValidPropertyName(name) { - if (typeof name !== "string") { - return false; - } - - for (const char of name) { - if (!esutils.code.isIdentifierPartES5(char.charCodeAt(0))) { - return false; - } - } - - return true; -} diff --git a/packages/babel-plugin-transform-property-literals/src/property-name.js b/packages/babel-plugin-transform-property-literals/src/property-name.js new file mode 100644 index 000000000..45ad6956d --- /dev/null +++ b/packages/babel-plugin-transform-property-literals/src/property-name.js @@ -0,0 +1,45 @@ +"use strict"; + +const { keyword } = require("esutils"); +const escapeStringLiteral = require("./escape-string-literal"); + +module.exports = { + reduceStaticPropertyNameES5 +}; + +/** + * + * Original Source: + * https://github.com/shapesecurity/shift-codegen-js/blob/0d09bd8a/src/minimal-codegen.js#L635 + * + * This implementation modifies the original source in the following ways + * + Check for ES5 Identifier name instead of ES6 Identifier name + * + Use Babel-Types & Babel's AST instead of ShiftAST + * + * LICENSE + +Copyright 2014 Shape Security, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +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. + + */ +function reduceStaticPropertyNameES5(t, node) { + if (keyword.isIdentifierNameES5(node.value)) { + return t.Identifier(node.value); + } + let n = parseFloat(node.value); + if (n >= 0 && n.toString() === node.value) { + return t.NumericLiteral(n); + } + return t.Identifier(escapeStringLiteral(node.value)); +}