diff --git a/packages/babel-plugin-transform-decorators/README.md b/packages/babel-plugin-transform-decorators/README.md index 71fee789b4..a19335dfdc 100644 --- a/packages/babel-plugin-transform-decorators/README.md +++ b/packages/babel-plugin-transform-decorators/README.md @@ -54,9 +54,7 @@ npm install --save-dev babel-plugin-transform-decorators ## Usage -### Via `.babelrc` (Recommended) - -**.babelrc** +Add the following line to your .babelrc file: ```json { @@ -64,6 +62,32 @@ npm install --save-dev babel-plugin-transform-decorators } ``` +#### NOTE: Order of Plugins Matters! + +If you are including your plugins manually and using `transform-class-properties`, make sure that `transform-decorators` comes *before* `transform-class-properties`. + +Wrong: + +```json +{ + "plugins": [ + "transform-class-properties", + "transform-decorators" + ] +} +``` + +Right: + +```json +{ + "plugins": [ + "transform-decorators", + "transform-class-properties" + ] +} +``` + ### Via CLI ```sh diff --git a/packages/babel-plugin-transform-decorators/package.json b/packages/babel-plugin-transform-decorators/package.json index 0264dc7052..a061cc2632 100644 --- a/packages/babel-plugin-transform-decorators/package.json +++ b/packages/babel-plugin-transform-decorators/package.json @@ -1,17 +1,19 @@ { "name": "babel-plugin-transform-decorators", - "version": "6.22.0", + "version": "1.3.4", + "author": "Logan Smyth ", + "license": "MIT", "description": "Compile class and object decorators to ES5", "repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-decorators", - "license": "MIT", "main": "lib/index.js", "keywords": [ - "babel-plugin" + "babel", + "babel-plugin", + "decorators" ], "dependencies": { - "babel-types": "^6.22.0", "babel-plugin-syntax-decorators": "^6.13.0", - "babel-helper-explode-class": "^6.22.0", + "babel-runtime": "^6.2.0", "babel-template": "^6.22.0" }, "devDependencies": { diff --git a/packages/babel-plugin-transform-decorators/src/index.js b/packages/babel-plugin-transform-decorators/src/index.js index e1156b6903..e05a53e798 100644 --- a/packages/babel-plugin-transform-decorators/src/index.js +++ b/packages/babel-plugin-transform-decorators/src/index.js @@ -1,132 +1,341 @@ +// Fork of https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy + import template from "babel-template"; -import explodeClass from "babel-helper-explode-class"; const buildClassDecorator = template(` - CLASS_REF = DECORATOR(CLASS_REF) || CLASS_REF; + DECORATOR(CLASS_REF = INNER) || CLASS_REF; `); -export default function ({ types: t }) { - function cleanDecorators(decorators) { - return decorators.reverse().map((dec) => dec.expression); - } +const buildClassPrototype = template(` + CLASS_REF.prototype; +`); - function transformClass(path, ref, state) { - const nodes = []; +const buildGetDescriptor = template(` + Object.getOwnPropertyDescriptor(TARGET, PROPERTY); +`); - state; - let classDecorators = path.node.decorators; - if (classDecorators) { - path.node.decorators = null; - classDecorators = cleanDecorators(classDecorators); - - for (const decorator of classDecorators) { - nodes.push(buildClassDecorator({ - CLASS_REF: ref, - DECORATOR: decorator - })); - } - } - - const map = Object.create(null); - - for (const method of path.get("body.body")) { - const decorators = method.node.decorators; - if (!decorators) continue; - - const alias = t.toKeyAlias(method.node); - map[alias] = map[alias] || []; - map[alias].push(method.node); - - method.remove(); - } - - for (const alias in map) { - const items = map[alias]; - - items; - } - - return nodes; - } - - function hasDecorators(path) { - if (path.isClass()) { - if (path.node.decorators) return true; - - for (const method of (path.node.body.body: Array)) { - if (method.decorators) { - return true; +const buildGetObjectInitializer = template(` + (TEMP = Object.getOwnPropertyDescriptor(TARGET, PROPERTY), (TEMP = TEMP ? TEMP.value : undefined), { + enumerable: true, + configurable: true, + writable: true, + initializer: function(){ + return TEMP; } - } - } else if (path.isObjectExpression()) { - for (const prop of (path.node.properties: Array)) { - if (prop.decorators) { - return true; + }) +`); + +const buildInitializerWarningHelper = template(` + function NAME(descriptor, context){ + throw new Error( + 'Decorating class property failed. Please ensure that ' + + 'transform-class-properties is enabled.' + ); + } +`); + +const buildInitializerDefineProperty = template(` + function NAME(target, property, descriptor, context){ + if (!descriptor) return; + + Object.defineProperty(target, property, { + enumerable: descriptor.enumerable, + configurable: descriptor.configurable, + writable: descriptor.writable, + value: descriptor.initializer ? descriptor.initializer.call(context) : void 0, + }); + } +`); + +const buildApplyDecoratedDescriptor = template(` + function NAME(target, property, decorators, descriptor, context){ + var desc = {}; + Object['ke' + 'ys'](descriptor).forEach(function(key){ + desc[key] = descriptor[key]; + }); + desc.enumerable = !!desc.enumerable; + desc.configurable = !!desc.configurable; + if ('value' in desc || desc.initializer){ + desc.writable = true; } - } + + desc = decorators.slice().reverse().reduce(function(desc, decorator){ + return decorator(target, property, desc) || desc; + }, desc); + + if (context && desc.initializer !== void 0){ + desc.value = desc.initializer ? desc.initializer.call(context) : void 0; + desc.initializer = undefined; + } + + if (desc.initializer === void 0){ + // This is a hack to avoid this being processed by 'transform-runtime'. + // See issue #9. + Object['define' + 'Property'](target, property, desc); + desc = null; + } + + return desc; + } +`); + +export default function({ types: t }) { + /** + * Add a helper to take an initial descriptor, apply some decorators to it, and optionally + * define the property. + */ + function ensureApplyDecoratedDescriptorHelper(path, state) { + if (!state.applyDecoratedDescriptor) { + state.applyDecoratedDescriptor = path.scope.generateUidIdentifier("applyDecoratedDescriptor"); + const helper = buildApplyDecoratedDescriptor({ + NAME: state.applyDecoratedDescriptor, + }); + path.scope.getProgramParent().path.unshiftContainer("body", helper); } - return false; + return state.applyDecoratedDescriptor; } - function doError(path) { - throw path.buildCodeFrameError( -`Decorators are not officially supported yet in 6.x pending a proposal update. -However, if you need to use them you can install the legacy decorators transform with: + /** + * Add a helper to call as a replacement for class property definition. + */ + function ensureInitializerDefineProp(path, state) { + if (!state.initializerDefineProp) { + state.initializerDefineProp = path.scope.generateUidIdentifier("initDefineProp"); + const helper = buildInitializerDefineProperty({ + NAME: state.initializerDefineProp, + }); + path.scope.getProgramParent().path.unshiftContainer("body", helper); + } -npm install babel-plugin-transform-decorators-legacy --save-dev + return state.initializerDefineProp; + } -and add the following line to your .babelrc file: + /** + * Add a helper that will throw a useful error if the transform fails to detect the class + * property assignment, so users know something failed. + */ + function ensureInitializerWarning(path, state) { + if (!state.initializerWarningHelper) { + state.initializerWarningHelper = path.scope.generateUidIdentifier("initializerWarningHelper"); + const helper = buildInitializerWarningHelper({ + NAME: state.initializerWarningHelper, + }); + path.scope.getProgramParent().path.unshiftContainer("body", helper); + } -{ - "plugins": ["transform-decorators-legacy"] -} + return state.initializerWarningHelper; + } -The repo url is: https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy. - `); + /** + * If the decorator expressions are non-identifiers, hoist them to before the class so we can be sure + * that they are evaluated in order. + */ + function applyEnsureOrdering(path) { + // TODO: This should probably also hoist computed properties. + const decorators = ( + path.isClass() + ? [path].concat(path.get("body.body")) + : path.get("properties") + ).reduce((acc, prop) => acc.concat(prop.node.decorators || []), []); + + const identDecorators = decorators.filter((decorator) => !t.isIdentifier(decorator.expression)); + if (identDecorators.length === 0) return; + + return t.sequenceExpression(identDecorators.map((decorator) => { + const expression = decorator.expression; + const id = decorator.expression = path.scope.generateDeclaredUidIdentifier("dec"); + return t.assignmentExpression("=", id, expression); + }).concat([path.node])); + } + + /** + * Given a class expression with class-level decorators, create a new expression + * with the proper decorated behavior. + */ + function applyClassDecorators(classPath) { + const decorators = classPath.node.decorators || []; + classPath.node.decorators = null; + + if (decorators.length === 0) return; + + const name = classPath.scope.generateDeclaredUidIdentifier("class"); + + return decorators + .map((dec) => dec.expression) + .reverse() + .reduce(function(acc, decorator) { + return buildClassDecorator({ + CLASS_REF: name, + DECORATOR: decorator, + INNER: acc, + }).expression; + }, classPath.node); + } + + /** + * Given a class expression with method-level decorators, create a new expression + * with the proper decorated behavior. + */ + function applyMethodDecorators(path, state) { + const hasMethodDecorators = path.node.body.body.some(function(node) { + return (node.decorators || []).length > 0; + }); + + if (!hasMethodDecorators) return; + + return applyTargetDecorators(path, state, path.node.body.body); + } + + /** + * Given an object expression with property decorators, create a new expression + * with the proper decorated behavior. + */ + function applyObjectDecorators(path, state) { + const hasMethodDecorators = path.node.properties.some(function(node) { + return (node.decorators || []).length > 0; + }); + + if (!hasMethodDecorators) return; + + return applyTargetDecorators(path, state, path.node.properties); + } + + /** + * A helper to pull out property decorators into a sequence expression. + */ + function applyTargetDecorators(path, state, decoratedProps) { + const name = path.scope.generateDeclaredUidIdentifier(path.isClass() ? "class" : "obj"); + + const exprs = decoratedProps.reduce(function(acc, node) { + const decorators = node.decorators || []; + node.decorators = null; + + if (decorators.length === 0) return acc; + + if (node.computed) { + throw path.buildCodeFrameError("Computed method/property decorators are not yet supported."); + } + + const property = t.isLiteral(node.key) ? node.key : t.stringLiteral(node.key.name); + + const target = (path.isClass() && !node.static) ? buildClassPrototype({ + CLASS_REF: name, + }).expression : name; + + if (t.isClassProperty(node, { static: false })) { + const descriptor = path.scope.generateDeclaredUidIdentifier("descriptor"); + + const initializer = node.value ? + t.functionExpression(null, [], t.blockStatement([t.returnStatement(node.value)])) : + t.nullLiteral(); + node.value = t.callExpression( + ensureInitializerWarning(path, state), [descriptor, t.thisExpression()] + ); + + acc = acc.concat([ + t.assignmentExpression( + "=", descriptor, t.callExpression(ensureApplyDecoratedDescriptorHelper(path, state), [ + target, + property, + t.arrayExpression(decorators.map((dec) => dec.expression)), + t.objectExpression([ + t.objectProperty(t.identifier("enumerable"), t.booleanLiteral(true)), + t.objectProperty(t.identifier("initializer"), initializer), + ]), + ]) + ), + ]); + } else { + acc = acc.concat( + t.callExpression(ensureApplyDecoratedDescriptorHelper(path, state), [ + target, + property, + t.arrayExpression(decorators.map((dec) => dec.expression)), + ( + t.isObjectProperty(node) || + t.isClassProperty(node, { static: true })) ? + buildGetObjectInitializer({ + TEMP: path.scope.generateDeclaredUidIdentifier("init"), + TARGET: target, + PROPERTY: property, + }).expression : buildGetDescriptor({ + TARGET: target, + PROPERTY: property, + } + ).expression, + target, + ]) + ); + } + + return acc; + }, []); + + return t.sequenceExpression([ + t.assignmentExpression("=", name, path.node), + t.sequenceExpression(exprs), + name, + ]); } return { inherits: require("babel-plugin-syntax-decorators"), visitor: { - ClassExpression(path) { - if (!hasDecorators(path)) return; - doError(path); + ExportDefaultDeclaration(path) { + if (!path.get("declaration").isClassDeclaration()) return; - explodeClass(path); + const { node } = path; + const ref = node.declaration.id || path.scope.generateUidIdentifier("default"); + node.declaration.id = ref; - const ref = path.scope.generateDeclaredUidIdentifier("ref"); - let nodes = []; - - nodes.push(t.assignmentExpression("=", ref, path.node)); - - nodes = nodes.concat(transformClass(path, ref, this)); - - nodes.push(ref); - - path.replaceWith(t.sequenceExpression(nodes)); + // Split the class declaration and the export into two separate statements. + path.replaceWith(node.declaration); + path.insertAfter(t.exportNamedDeclaration(null, [t.exportSpecifier(ref, t.identifier("default"))])); }, - ClassDeclaration(path) { - if (!hasDecorators(path)) return; - doError(path); - explodeClass(path); + const { node } = path; - const ref = path.node.id; - let nodes = []; + const ref = node.id || path.scope.generateUidIdentifier("class"); - nodes = nodes.concat(transformClass(path, ref, this).map((expr) => t.expressionStatement(expr))); - nodes.push(t.expressionStatement(ref)); + path.replaceWith(t.variableDeclaration("let", [ + t.variableDeclarator(ref, t.toExpression(node)) + ])); + }, + ClassExpression(path, state) { + // Create a replacement for the class node if there is one. We do one pass to replace classes with + // class decorators, and a second pass to process method decorators. + const decoratedClass = ( + applyEnsureOrdering(path) || + applyClassDecorators(path, state) || + applyMethodDecorators(path, state) + ); - path.insertAfter(nodes); + if (decoratedClass) path.replaceWith(decoratedClass); + }, + ObjectExpression(path, state) { + const decoratedObject = applyEnsureOrdering(path) || applyObjectDecorators(path, state); + + if (decoratedObject) path.replaceWith(decoratedObject); }, - ObjectExpression(path) { - if (!hasDecorators(path)) return; - doError(path); - } + AssignmentExpression(path, state) { + if (!state.initializerWarningHelper) return; + + if (!path.get("left").isMemberExpression()) return; + if (!path.get("left.property").isIdentifier()) return; + if (!path.get("right").isCallExpression()) return; + if (!path.get("right.callee").isIdentifier({ name: state.initializerWarningHelper.name })) return; + + path.replaceWith(t.callExpression(ensureInitializerDefineProp(path, state), [ + path.get("left.object").node, + t.stringLiteral(path.get("left.property").node.name), + path.get("right.arguments")[0].node, + path.get("right.arguments")[1].node, + ])); + }, } }; } diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-constructors/mutate-existing-constructor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-constructors/mutate-existing-constructor/exec.js new file mode 100644 index 0000000000..22fc0fdfc6 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-constructors/mutate-existing-constructor/exec.js @@ -0,0 +1,10 @@ +function dec(cls){ + cls.staticProp = "prop"; +} + +@dec +class Parent { + parent() {}; +} + +assert.equal(Parent.staticProp, "prop"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-constructors/return-new-constructor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-constructors/return-new-constructor/exec.js new file mode 100644 index 0000000000..e0471eb47f --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-constructors/return-new-constructor/exec.js @@ -0,0 +1,13 @@ +function dec(cls){ + return class Child extends cls { + child(){} + }; +} + +@dec +class Parent { + parent(){} +} + +assert.equal(typeof Parent.prototype.parent, "function") +assert.equal(typeof Parent.prototype.child, "function") diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-ordering/order/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-ordering/order/exec.js new file mode 100644 index 0000000000..c31dd400aa --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-ordering/order/exec.js @@ -0,0 +1,28 @@ +const calls = []; + +function dec(id){ + calls.push(id); + return function() {}; +} + +@dec(1) +@dec(2) +class Example { + @dec(3) + @dec(4) + method1() {}; + + @dec(5) + @dec(6) + prop1 = 1; + + @dec(7) + @dec(8) + method2() {}; + + @dec(9) + @dec(10) + prop2 = 2; +} + +assert.deepEqual(calls, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-ordering/reverse-order/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-ordering/reverse-order/exec.js new file mode 100644 index 0000000000..0edd5a76e5 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-ordering/reverse-order/exec.js @@ -0,0 +1,29 @@ +const calls = []; + +function dec(id){ + return function(){ + calls.push(id); + }; +} + +@dec(10) +@dec(9) +class Example2 { + @dec(2) + @dec(1) + method1() {}; + + @dec(4) + @dec(3) + prop1 = 1; + + @dec(6) + @dec(5) + method2() {}; + + @dec(8) + @dec(7) + prop2 = 2; +} + +assert.deepEqual(calls, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/mutate-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/mutate-descriptor/exec.js new file mode 100644 index 0000000000..16b5ee6f52 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/mutate-descriptor/exec.js @@ -0,0 +1,115 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let value = descriptor.value; + Object.assign(descriptor, { + enumerable: name.indexOf("enum") !== -1, + configurable: name.indexOf("conf") !== -1, + writable: name.indexOf("write") !== -1, + value: function(...args) { + return "__" + value.apply(this, args) + "__"; + }, + }); +} + +class Example { + @dec + enumconfwrite(){ + return 1; + } + + @dec + enumconf(){ + return 2; + } + + @dec + enumwrite(){ + return 3; + } + + @dec + enum(){ + return 4; + } + + @dec + confwrite(){ + return 5; + } + + @dec + conf(){ + return 6; + } + + @dec + write(){ + return 7; + } + + @dec + _(){ + return 8; + } +} + +assert(Example.prototype.hasOwnProperty('decoratedProps')); +assert.deepEqual(Example.prototype.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const inst = new Example(); + +const descs = Object.getOwnPropertyDescriptors(Example.prototype); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(inst.enumconfwrite(), "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(inst.enumconf(), "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(inst.enumwrite(), "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(inst.enum(), "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(inst.confwrite(), "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(inst.conf(), "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(inst.write(), "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(inst._(), "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/numeric-props/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/numeric-props/exec.js new file mode 100644 index 0000000000..1955a25ee8 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/numeric-props/exec.js @@ -0,0 +1,10 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(name, 4); + assert.equal(typeof descriptor, "object"); +} + +class Example { + @dec + 4() {}; +} diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/return-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/return-descriptor/exec.js new file mode 100644 index 0000000000..7d614d16a3 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/return-descriptor/exec.js @@ -0,0 +1,117 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let value = descriptor.value; + return { + enumerable: name.indexOf('enum') !== -1, + configurable: name.indexOf('conf') !== -1, + writable: name.indexOf('write') !== -1, + value: function(...args){ + return '__' + value.apply(this, args) + '__'; + }, + }; +} + +class Example { + @dec + enumconfwrite() { + return 1; + } + + @dec + enumconf() { + return 2; + } + + @dec + enumwrite() { + return 3; + } + + @dec + enum() { + return 4; + } + + @dec + confwrite() { + return 5; + } + + @dec + conf() { + return 6; + } + + @dec + write() { + return 7; + } + + @dec + _() { + return 8; + } +} + + +assert(Example.prototype.hasOwnProperty('decoratedProps')); +assert.deepEqual(Example.prototype.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + + +const inst = new Example(); + +const descs = Object.getOwnPropertyDescriptors(Example.prototype); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(inst.enumconfwrite(), "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(inst.enumconf(), "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(inst.enumwrite(), "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(inst.enum(), "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(inst.confwrite(), "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(inst.conf(), "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(inst.write(), "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(inst._(), "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/string-props/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/string-props/exec.js new file mode 100644 index 0000000000..46d76bd73a --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-methods/string-props/exec.js @@ -0,0 +1,10 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(name, "str"); + assert.equal(typeof descriptor, "object"); +} + +class Example { + @dec + "str"() {}; +} diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/child-classes-properties/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/child-classes-properties/exec.js new file mode 100644 index 0000000000..7d843bdc9f --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/child-classes-properties/exec.js @@ -0,0 +1,27 @@ +function dec(target, name, descriptor){ + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let initializer = descriptor.initializer; + descriptor.initializer = function(...args){ + return "__" + initializer.apply(this, args) + "__"; + }; +} + +class Base { + @dec + prop2 = 4; +} + +class Example extends Base { + @dec + prop = 3; +} + +let inst = new Example(); + +assert.equal(inst.prop, "__3__"); +assert.equal(inst.prop2, "__4__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/mutate-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/mutate-descriptor/exec.js new file mode 100644 index 0000000000..e0baa17081 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/mutate-descriptor/exec.js @@ -0,0 +1,99 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let initializer = descriptor.initializer; + Object.assign(descriptor, { + enumerable: name.indexOf('enum') !== -1, + configurable: name.indexOf('conf') !== -1, + writable: name.indexOf('write') !== -1, + initializer: function(...args){ + return '__' + initializer.apply(this, args) + '__'; + }, + }); +} + +class Example { + @dec + enumconfwrite = 1; + + @dec + enumconf = 2; + + @dec + enumwrite = 3; + + @dec + enum = 4; + + @dec + confwrite = 5; + + @dec + conf = 6; + + @dec + write = 7; + + @dec + _ = 8; +} + +const inst = new Example(); + +assert(Example.prototype.hasOwnProperty("decoratedProps")); +assert.deepEqual(inst.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const descs = Object.getOwnPropertyDescriptors(inst); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(inst.enumconfwrite, "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(inst.enumconf, "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(inst.enumwrite, "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(inst.enum, "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(inst.confwrite, "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(inst.conf, "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(inst.write, "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(inst._, "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/mutate-initialzer/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/mutate-initialzer/exec.js new file mode 100644 index 0000000000..e5bd2bf933 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/mutate-initialzer/exec.js @@ -0,0 +1,27 @@ +function dec(target, name, descriptor){ + assert(target); + assert.equal(name, "prop"); + assert.equal(typeof descriptor, "object"); + + let {initializer} = descriptor; + delete descriptor.initializer; + delete descriptor.writable; + + let value; + descriptor.get = function(){ + if (initializer){ + value = '__' + initializer.call(this) + '__'; + initializer = null; + } + return value; + }; +} + +class Example { + @dec + prop = 3; +} + +let inst = new Example(); + +assert.equal(inst.prop, "__3__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/properties-without-initializer/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/properties-without-initializer/exec.js new file mode 100644 index 0000000000..3031f7b3cd --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/properties-without-initializer/exec.js @@ -0,0 +1,11 @@ +function dec(target, name, descriptor) { + +} + +class Example { + @dec prop; +} + +let inst = new Example(); +assert(inst.hasOwnProperty("prop")); +assert.equal(inst.prop, undefined); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/return-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/return-descriptor/exec.js new file mode 100644 index 0000000000..b98c219651 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-prototype-properties/return-descriptor/exec.js @@ -0,0 +1,99 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let initializer = descriptor.initializer; + return { + enumerable: name.indexOf('enum') !== -1, + configurable: name.indexOf('conf') !== -1, + writable: name.indexOf('write') !== -1, + initializer: function(...args){ + return '__' + initializer.apply(this, args) + '__'; + }, + }; +} + +class Example { + @dec + enumconfwrite = 1; + + @dec + enumconf = 2; + + @dec + enumwrite = 3; + + @dec + enum = 4; + + @dec + confwrite = 5; + + @dec + conf = 6; + + @dec + write = 7; + + @dec + _ = 8; +} + +const inst = new Example(); + +assert(Example.prototype.hasOwnProperty("decoratedProps")); +assert.deepEqual(inst.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const descs = Object.getOwnPropertyDescriptors(inst); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(inst.enumconfwrite, "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(inst.enumconf, "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(inst.enumwrite, "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(inst.enum, "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(inst.confwrite, "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(inst.conf, "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(inst.write, "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(inst._, "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/mutate-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/mutate-descriptor/exec.js new file mode 100644 index 0000000000..63c53284bc --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/mutate-descriptor/exec.js @@ -0,0 +1,113 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let value = descriptor.value; + Object.assign(descriptor, { + enumerable: name.indexOf("enum") !== -1, + configurable: name.indexOf("conf") !== -1, + writable: name.indexOf("write") !== -1, + value: function(...args) { + return "__" + value.apply(this, args) + "__"; + }, + }); +} + +class Example { + @dec + static enumconfwrite(){ + return 1; + } + + @dec + static enumconf(){ + return 2; + } + + @dec + static enumwrite(){ + return 3; + } + + @dec + static enum(){ + return 4; + } + + @dec + static confwrite(){ + return 5; + } + + @dec + static conf(){ + return 6; + } + + @dec + static write(){ + return 7; + } + + @dec + static _(){ + return 8; + } +} + +assert(Example.hasOwnProperty("decoratedProps")); +assert.deepEqual(Example.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const descs = Object.getOwnPropertyDescriptors(Example); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(Example.enumconfwrite(), "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(Example.enumconf(), "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(Example.enumwrite(), "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(Example.enum(), "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(Example.confwrite(), "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(Example.conf(), "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(Example.write(), "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(Example._(), "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/numeric-props/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/numeric-props/exec.js new file mode 100644 index 0000000000..61c7b3fc18 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/numeric-props/exec.js @@ -0,0 +1,10 @@ +function dec(target, name, descriptor){ + assert(target); + assert.equal(name, 4); + assert.equal(typeof descriptor, "object"); +} + +class Example { + @dec + static 4() {} +} diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/return-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/return-descriptor/exec.js new file mode 100644 index 0000000000..fc117a5166 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/return-descriptor/exec.js @@ -0,0 +1,114 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let value = descriptor.value; + return { + enumerable: name.indexOf('enum') !== -1, + configurable: name.indexOf('conf') !== -1, + writable: name.indexOf('write') !== -1, + value: function(...args){ + return '__' + value.apply(this, args) + '__'; + }, + }; +} + +class Example { + @dec + static enumconfwrite() { + return 1; + } + + @dec + static enumconf() { + return 2; + } + + @dec + static enumwrite() { + return 3; + } + + @dec + static enum() { + return 4; + } + + @dec + static confwrite() { + return 5; + } + + @dec + static conf() { + return 6; + } + + @dec + static write() { + return 7; + } + + @dec + static _() { + return 8; + } +} + + +assert(Example.hasOwnProperty("decoratedProps")); +assert.deepEqual(Example.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const descs = Object.getOwnPropertyDescriptors(Example); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(Example.enumconfwrite(), "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(Example.enumconf(), "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(Example.enumwrite(), "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(Example.enum(), "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(Example.confwrite(), "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(Example.conf(), "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(Example.write(), "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(Example._(), "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/string-props/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/string-props/exec.js new file mode 100644 index 0000000000..2e20b5dbce --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-methods/string-props/exec.js @@ -0,0 +1,10 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(name, "str"); + assert.equal(typeof descriptor, "object"); +} + +class Example { + @dec + static "str"() {}; +} diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/mutate-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/mutate-descriptor/exec.js new file mode 100644 index 0000000000..e936af3d7d --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/mutate-descriptor/exec.js @@ -0,0 +1,99 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let initializer = descriptor.initializer; + Object.assign(descriptor, { + enumerable: name.indexOf("enum") !== -1, + configurable: name.indexOf("conf") !== -1, + writable: name.indexOf("write") !== -1, + initializer: function(...args){ + return '__' + initializer.apply(this, args) + '__'; + }, + }); +} + +class Example { + @dec + static enumconfwrite = 1; + + @dec + static enumconf = 2; + + @dec + static enumwrite = 3; + + @dec + static enum = 4; + + @dec + static confwrite = 5; + + @dec + static conf = 6; + + @dec + static write = 7; + + @dec + static _ = 8; +} + +const inst = new Example(); + +assert(Example.hasOwnProperty("decoratedProps")); +assert.deepEqual(Example.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const descs = Object.getOwnPropertyDescriptors(Example); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(Example.enumconfwrite, "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(Example.enumconf, "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(Example.enumwrite, "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(Example.enum, "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(Example.confwrite, "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(Example.conf, "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(Example.write, "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(Example._, "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/mutate-initialzer/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/mutate-initialzer/exec.js new file mode 100644 index 0000000000..e9d60ef728 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/mutate-initialzer/exec.js @@ -0,0 +1,25 @@ +function dec(target, name, descriptor){ + assert(target); + assert.equal(name, "prop"); + assert.equal(typeof descriptor, "object"); + + let {initializer} = descriptor; + delete descriptor.initializer; + delete descriptor.writable; + + let value; + descriptor.get = function(){ + if (initializer){ + value = '__' + initializer.call(this) + '__'; + initializer = null; + } + return value; + }; +} + +class Example { + @dec + static prop = 3; +} + +assert.equal(Example.prop, "__3__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/properties-without-initializer/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/properties-without-initializer/exec.js new file mode 100644 index 0000000000..94b5a6ce32 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/properties-without-initializer/exec.js @@ -0,0 +1,10 @@ +function dec(target, name, descriptor) { + +} + +class Example { + @dec static prop; +} + +assert(Example.hasOwnProperty("prop")); +assert.equal(Example.prop, undefined); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/return-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/return-descriptor/exec.js new file mode 100644 index 0000000000..8aa17ef0bd --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/class-static-properties/return-descriptor/exec.js @@ -0,0 +1,99 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let initializer = descriptor.initializer; + return { + enumerable: name.indexOf('enum') !== -1, + configurable: name.indexOf('conf') !== -1, + writable: name.indexOf('write') !== -1, + initializer: function(...args){ + return '__' + initializer.apply(this, args) + '__'; + }, + }; +} + +class Example { + @dec + static enumconfwrite = 1; + + @dec + static enumconf = 2; + + @dec + static enumwrite = 3; + + @dec + static enum = 4; + + @dec + static confwrite = 5; + + @dec + static conf = 6; + + @dec + static write = 7; + + @dec + static _ = 8; +} + +const inst = new Example(); + +assert(Example.hasOwnProperty("decoratedProps")); +assert.deepEqual(Example.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const descs = Object.getOwnPropertyDescriptors(Example); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(Example.enumconfwrite, "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(Example.enumconf, "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(Example.enumwrite, "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(Example.enum, "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(Example.confwrite, "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(Example.conf, "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(Example.write, "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(Example._, "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/exec/options.json b/packages/babel-plugin-transform-decorators/test/fixtures/exec/options.json deleted file mode 100644 index 0c91a1a362..0000000000 --- a/packages/babel-plugin-transform-decorators/test/fixtures/exec/options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plugins": ["external-helpers", "transform-es2015-destructuring", "transform-es2015-block-scoping", "transform-decorators", "transform-es2015-classes", "transform-class-properties"] -} diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/mutate-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/mutate-descriptor/exec.js new file mode 100644 index 0000000000..f6392e0aea --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/mutate-descriptor/exec.js @@ -0,0 +1,113 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let value = descriptor.value; + Object.assign(descriptor, { + enumerable: name.indexOf("enum") !== -1, + configurable: name.indexOf("conf") !== -1, + writable: name.indexOf("write") !== -1, + value: function(...args) { + return "__" + value.apply(this, args) + "__"; + }, + }); +} + +const inst = { + @dec + enumconfwrite(){ + return 1; + }, + + @dec + enumconf(){ + return 2; + }, + + @dec + enumwrite(){ + return 3; + }, + + @dec + enum(){ + return 4; + }, + + @dec + confwrite(){ + return 5; + }, + + @dec + conf(){ + return 6; + }, + + @dec + write(){ + return 7; + }, + + @dec + _(){ + return 8; + }, +} + +assert(inst.hasOwnProperty('decoratedProps')); +assert.deepEqual(inst.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const descs = Object.getOwnPropertyDescriptors(inst); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(inst.enumconfwrite(), "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(inst.enumconf(), "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(inst.enumwrite(), "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(inst.enum(), "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(inst.confwrite(), "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(inst.conf(), "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(inst.write(), "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(inst._(), "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/numeric-props/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/numeric-props/exec.js new file mode 100644 index 0000000000..5474eb7dec --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/numeric-props/exec.js @@ -0,0 +1,11 @@ +function dec(target, name, descriptor){ + assert(target); + assert.equal(name, 4); + assert.equal(typeof descriptor, "object"); +} + +const inst = { + @dec + 4(){ + } +}; diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/return-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/return-descriptor/exec.js new file mode 100644 index 0000000000..a1ed774df0 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/return-descriptor/exec.js @@ -0,0 +1,113 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let value = descriptor.value; + return { + enumerable: name.indexOf('enum') !== -1, + configurable: name.indexOf('conf') !== -1, + writable: name.indexOf('write') !== -1, + value: function(...args){ + return '__' + value.apply(this, args) + '__'; + }, + }; +} + +const inst = { + @dec + enumconfwrite(){ + return 1; + }, + + @dec + enumconf(){ + return 2; + }, + + @dec + enumwrite(){ + return 3; + }, + + @dec + enum(){ + return 4; + }, + + @dec + confwrite(){ + return 5; + }, + + @dec + conf(){ + return 6; + }, + + @dec + write(){ + return 7; + }, + + @dec + _(){ + return 8; + }, +} + +assert(inst.hasOwnProperty('decoratedProps')); +assert.deepEqual(inst.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const descs = Object.getOwnPropertyDescriptors(inst); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(inst.enumconfwrite(), "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(inst.enumconf(), "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(inst.enumwrite(), "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(inst.enum(), "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(inst.confwrite(), "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(inst.conf(), "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(inst.write(), "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(inst._(), "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/string-props/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/string-props/exec.js new file mode 100644 index 0000000000..d20b0c8096 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-methods/string-props/exec.js @@ -0,0 +1,12 @@ +function dec(target, name, descriptor){ + assert(target); + assert.equal(name, "str"); + assert.equal(typeof descriptor, "object"); +} + +const inst = { + @dec + "str"(){ + + } +}; diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-ordering/order/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-ordering/order/exec.js new file mode 100644 index 0000000000..129a19ef6a --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-ordering/order/exec.js @@ -0,0 +1,25 @@ +const calls = []; +function dec(id){ + calls.push(id); + return function(){}; +} + +const obj = { + @dec(1) + @dec(2) + method1(){}, + + @dec(3) + @dec(4) + prop1: 1, + + @dec(5) + @dec(6) + method2(){}, + + @dec(7) + @dec(8) + prop2: 2, +} + +assert.deepEqual(calls, [1, 2, 3, 4, 5, 6, 7, 8]); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-ordering/reverse-order/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-ordering/reverse-order/exec.js new file mode 100644 index 0000000000..fc6066b196 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-ordering/reverse-order/exec.js @@ -0,0 +1,26 @@ +const calls = []; +function dec(id){ + return function(){ + calls.push(id); + }; +} + +const obj = { + @dec(2) + @dec(1) + method1(){}, + + @dec(4) + @dec(3) + prop1: 1, + + @dec(6) + @dec(5) + method2(){}, + + @dec(8) + @dec(7) + prop2: 2, +} + +assert.deepEqual(calls, [1, 2, 3, 4, 5, 6, 7, 8]); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/mutate-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/mutate-descriptor/exec.js new file mode 100644 index 0000000000..4ff3fc269b --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/mutate-descriptor/exec.js @@ -0,0 +1,98 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let initializer = descriptor.initializer; + Object.assign(descriptor, { + enumerable: name.indexOf("enum") !== -1, + configurable: name.indexOf("conf") !== -1, + writable: name.indexOf("write") !== -1, + initializer: function(...args){ + return '__' + initializer.apply(this, args) + '__'; + }, + }); +} + +const inst = { + @dec + enumconfwrite: 1, + + @dec + enumconf: 2, + + @dec + enumwrite: 3, + + @dec + enum: 4, + + @dec + confwrite: 5, + + @dec + conf: 6, + + @dec + write: 7, + + @dec + _: 8, +}; + + +assert(inst.hasOwnProperty("decoratedProps")); +assert.deepEqual(inst.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const descs = Object.getOwnPropertyDescriptors(inst); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(inst.enumconfwrite, "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(inst.enumconf, "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(inst.enumwrite, "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(inst.enum, "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(inst.confwrite, "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(inst.conf, "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(inst.write, "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(inst._, "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/mutate-initialzer/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/mutate-initialzer/exec.js new file mode 100644 index 0000000000..1c046d4a7d --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/mutate-initialzer/exec.js @@ -0,0 +1,25 @@ +function dec(target, name, descriptor){ + assert(target); + assert.equal(name, "prop"); + assert.equal(typeof descriptor, "object"); + + let {initializer} = descriptor; + delete descriptor.initializer; + delete descriptor.writable; + + let value; + descriptor.get = function(){ + if (initializer){ + value = '__' + initializer.call(this) + '__'; + initializer = null; + } + return value; + }; +} + +let inst = { + @dec + prop: 3 +}; + +assert.equal(inst.prop, "__3__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/numeric-props/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/numeric-props/exec.js new file mode 100644 index 0000000000..fd0c328a29 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/numeric-props/exec.js @@ -0,0 +1,10 @@ +function dec(target, name, descriptor){ + assert(target); + assert.equal(name, 4); + assert.equal(typeof descriptor, "object"); +} + +const inst = { + @dec + 4: 1 +}; diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/return-descriptor/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/return-descriptor/exec.js new file mode 100644 index 0000000000..3b79d92dcf --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/return-descriptor/exec.js @@ -0,0 +1,97 @@ +function dec(target, name, descriptor) { + assert(target); + assert.equal(typeof name, "string"); + assert.equal(typeof descriptor, "object"); + + target.decoratedProps = (target.decoratedProps || []).concat([name]); + + let initializer = descriptor.initializer; + return { + enumerable: name.indexOf('enum') !== -1, + configurable: name.indexOf('conf') !== -1, + writable: name.indexOf('write') !== -1, + initializer: function(...args){ + return '__' + initializer.apply(this, args) + '__'; + }, + }; +} + +const inst = { + @dec + enumconfwrite: 1, + + @dec + enumconf: 2, + + @dec + enumwrite: 3, + + @dec + enum: 4, + + @dec + confwrite: 5, + + @dec + conf: 6, + + @dec + write: 7, + + @dec + _: 8, +}; + +assert(inst.hasOwnProperty("decoratedProps")); +assert.deepEqual(inst.decoratedProps, [ + "enumconfwrite", + "enumconf", + "enumwrite", + "enum", + "confwrite", + "conf", + "write", + "_", +]); + +const descs = Object.getOwnPropertyDescriptors(inst); + +assert(descs.enumconfwrite.enumerable); +assert(descs.enumconfwrite.writable); +assert(descs.enumconfwrite.configurable); +assert.equal(inst.enumconfwrite, "__1__"); + +assert(descs.enumconf.enumerable); +assert.equal(descs.enumconf.writable, false); +assert(descs.enumconf.configurable); +assert.equal(inst.enumconf, "__2__"); + +assert(descs.enumwrite.enumerable); +assert(descs.enumwrite.writable); +assert.equal(descs.enumwrite.configurable, false); +assert.equal(inst.enumwrite, "__3__"); + +assert(descs.enum.enumerable); +assert.equal(descs.enum.writable, false); +assert.equal(descs.enum.configurable, false); +assert.equal(inst.enum, "__4__"); + +assert.equal(descs.confwrite.enumerable, false); +assert(descs.confwrite.writable); +assert(descs.confwrite.configurable); +assert.equal(inst.confwrite, "__5__"); + +assert.equal(descs.conf.enumerable, false); +assert.equal(descs.conf.writable, false); +assert(descs.conf.configurable); +assert.equal(inst.conf, "__6__"); + +assert.equal(descs.write.enumerable, false); +assert(descs.write.writable); +assert.equal(descs.write.configurable, false); +assert.equal(inst.write, "__7__"); + +assert.equal(descs._.enumerable, false); +assert.equal(descs._.writable, false); +assert.equal(descs._.configurable, false); +assert.equal(inst._, "__8__"); diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/string-props/exec.js b/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/string-props/exec.js new file mode 100644 index 0000000000..8dec1d5e54 --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/object-properties/string-props/exec.js @@ -0,0 +1,10 @@ +function dec(target, name, descriptor){ + assert(target); + assert.equal(name, "str"); + assert.equal(typeof descriptor, "object"); +} + +const inst = { + @dec + "str": 1 +}; diff --git a/packages/babel-plugin-transform-decorators/test/fixtures/options.json b/packages/babel-plugin-transform-decorators/test/fixtures/options.json new file mode 100644 index 0000000000..f2aac002ac --- /dev/null +++ b/packages/babel-plugin-transform-decorators/test/fixtures/options.json @@ -0,0 +1,4 @@ +{ + "presets": ["es2015"], + "plugins": ["transform-decorators", "transform-class-properties"] +}