Add support for the new decorators proposal (#7976)
This commit is contained in:
parent
29a2878973
commit
9aec4ad159
@ -1078,3 +1078,642 @@ helpers.classStaticPrivateFieldSpecSet = helper("7.0.1")`
|
||||
return value;
|
||||
}
|
||||
`;
|
||||
|
||||
helpers.decorate = helper("7.0.1")`
|
||||
import toArray from "toArray";
|
||||
|
||||
// These comments are stripped by @babel/template
|
||||
/*::
|
||||
type PropertyDescriptor =
|
||||
| {
|
||||
value: any,
|
||||
writable: boolean,
|
||||
configurable: boolean,
|
||||
enumerable: boolean,
|
||||
}
|
||||
| {
|
||||
get?: () => any,
|
||||
set?: (v: any) => void,
|
||||
configurable: boolean,
|
||||
enumerable: boolean,
|
||||
};
|
||||
|
||||
type FieldDescriptor ={
|
||||
writable: boolean,
|
||||
configurable: boolean,
|
||||
enumerable: boolean,
|
||||
};
|
||||
|
||||
type Placement = "static" | "prototype" | "own";
|
||||
type Key = string | symbol; // PrivateName is not supported yet.
|
||||
|
||||
type ElementDescriptor =
|
||||
| {
|
||||
kind: "method",
|
||||
key: Key,
|
||||
placement: Placement,
|
||||
descriptor: PropertyDescriptor
|
||||
}
|
||||
| {
|
||||
kind: "field",
|
||||
key: Key,
|
||||
placement: Placement,
|
||||
descriptor: FieldDescriptor,
|
||||
initializer?: () => any,
|
||||
};
|
||||
|
||||
// This is exposed to the user code
|
||||
type ElementObjectInput = ElementDescriptor & {
|
||||
[@@toStringTag]?: "Descriptor"
|
||||
};
|
||||
|
||||
// This is exposed to the user code
|
||||
type ElementObjectOutput = ElementDescriptor & {
|
||||
[@@toStringTag]?: "Descriptor"
|
||||
extras?: ElementDescriptor[],
|
||||
finisher?: ClassFinisher,
|
||||
};
|
||||
|
||||
// This is exposed to the user code
|
||||
type ClassObject = {
|
||||
[@@toStringTag]?: "Descriptor",
|
||||
kind: "class",
|
||||
elements: ElementDescriptor[],
|
||||
};
|
||||
|
||||
type ElementDecorator = (descriptor: ElementObjectInput) => ?ElementObjectOutput;
|
||||
type ClassDecorator = (descriptor: ClassObject) => ?ClassObject;
|
||||
type ClassFinisher = <A, B>(cl: Class<A>) => Class<B>;
|
||||
|
||||
// Only used by Babel in the transform output, not part of the spec.
|
||||
type ElementDefinition =
|
||||
| {
|
||||
kind: "method",
|
||||
value: any,
|
||||
key: Key,
|
||||
static?: boolean,
|
||||
decorators?: ElementDecorator[],
|
||||
}
|
||||
| {
|
||||
kind: "field",
|
||||
value: () => any,
|
||||
key: Key,
|
||||
static?: boolean,
|
||||
decorators?: ElementDecorator[],
|
||||
};
|
||||
|
||||
declare function ClassFactory<C>(initialize: (instance: C) => void): {
|
||||
F: Class<C>,
|
||||
d: ElementDefinition[]
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/*::
|
||||
// Various combinations with/without extras and with one or many finishers
|
||||
|
||||
type ElementFinisherExtras = {
|
||||
element: ElementDescriptor,
|
||||
finisher?: ClassFinisher,
|
||||
extras?: ElementDescriptor[],
|
||||
};
|
||||
|
||||
type ElementFinishersExtras = {
|
||||
element: ElementDescriptor,
|
||||
finishers: ClassFinisher[],
|
||||
extras: ElementDescriptor[],
|
||||
};
|
||||
|
||||
type ElementsFinisher = {
|
||||
elements: ElementDescriptor[],
|
||||
finisher?: ClassFinisher,
|
||||
};
|
||||
|
||||
type ElementsFinishers = {
|
||||
elements: ElementDescriptor[],
|
||||
finishers: ClassFinisher[],
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
// ClassDefinitionEvaluation (Steps 26-*)
|
||||
export default function _decorate(
|
||||
decorators /*: ClassDecorator[] */,
|
||||
factory /*: ClassFactory */,
|
||||
superClass /*: ?Class<*> */,
|
||||
) /*: Class<*> */ {
|
||||
var r = factory(function initialize(O) {
|
||||
_initializeInstanceElements(O, decorated.elements);
|
||||
}, superClass);
|
||||
var decorated = _decorateClass(
|
||||
_coalesceClassElements(r.d.map(_createElementDescriptor)),
|
||||
decorators,
|
||||
);
|
||||
|
||||
_initializeClassElements(r.F, decorated.elements);
|
||||
|
||||
return _runClassFinishers(r.F, decorated.finishers);
|
||||
}
|
||||
|
||||
// ClassElementEvaluation
|
||||
function _createElementDescriptor(
|
||||
def /*: ElementDefinition */,
|
||||
) /*: ElementDescriptor */ {
|
||||
var descriptor /*: PropertyDescriptor */;
|
||||
if (def.kind === "method") {
|
||||
descriptor = {
|
||||
value: def.value,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
};
|
||||
} else if (def.kind === "get") {
|
||||
descriptor = { get: def.value, configurable: true, enumerable: false };
|
||||
} else if (def.kind === "set") {
|
||||
descriptor = { set: def.value, configurable: true, enumerable: false };
|
||||
} else if (def.kind === "field") {
|
||||
descriptor = { configurable: true, writable: true, enumerable: false };
|
||||
}
|
||||
|
||||
var element /*: ElementDescriptor */ = {
|
||||
kind: def.kind === "field" ? "field" : "method",
|
||||
key: def.key,
|
||||
placement: def.static
|
||||
? "static"
|
||||
: def.kind === "field"
|
||||
? "own"
|
||||
: "prototype",
|
||||
descriptor: descriptor,
|
||||
};
|
||||
if (def.decorators) element.decorators = def.decorators;
|
||||
if (def.kind === "field") element.initializer = def.value;
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
// CoalesceGetterSetter
|
||||
function _coalesceGetterSetter(
|
||||
element /*: ElementDescriptor */,
|
||||
other /*: ElementDescriptor */,
|
||||
) {
|
||||
if (element.descriptor.get !== undefined) {
|
||||
other.descriptor.get = element.descriptor.get;
|
||||
} else {
|
||||
other.descriptor.set = element.descriptor.set;
|
||||
}
|
||||
}
|
||||
|
||||
// CoalesceClassElements
|
||||
function _coalesceClassElements(
|
||||
elements /*: ElementDescriptor[] */,
|
||||
) /*: ElementDescriptor[] */ {
|
||||
var newElements /*: ElementDescriptor[] */ = [];
|
||||
|
||||
var isSameElement = function(other /*: ElementDescriptor */) /*: boolean */ {
|
||||
return (
|
||||
other.kind === "method" &&
|
||||
other.key === element.key &&
|
||||
other.placement === element.placement
|
||||
);
|
||||
};
|
||||
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
var element /*: ElementDescriptor */ = elements[i];
|
||||
var other /*: ElementDescriptor */;
|
||||
|
||||
if (
|
||||
element.kind === "method" &&
|
||||
(other = newElements.find(isSameElement))
|
||||
) {
|
||||
if (
|
||||
_isDataDescriptor(element.descriptor) ||
|
||||
_isDataDescriptor(other.descriptor)
|
||||
) {
|
||||
if (_hasDecorators(element) || _hasDecorators(other)) {
|
||||
throw new ReferenceError(
|
||||
"Duplicated methods (" + element.key + ") can't be decorated.",
|
||||
);
|
||||
}
|
||||
other.descriptor = element.descriptor;
|
||||
} else {
|
||||
if (_hasDecorators(element)) {
|
||||
if (_hasDecorators(other)) {
|
||||
throw new ReferenceError(
|
||||
"Decorators can't be placed on different accessors with for " +
|
||||
"the same property (" +
|
||||
element.key +
|
||||
").",
|
||||
);
|
||||
}
|
||||
other.decorators = element.decorators;
|
||||
}
|
||||
_coalesceGetterSetter(element, other);
|
||||
}
|
||||
} else {
|
||||
newElements.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
return newElements;
|
||||
}
|
||||
|
||||
function _hasDecorators(element /*: ElementDescriptor */) /*: boolean */ {
|
||||
return element.decorators && element.decorators.length;
|
||||
}
|
||||
|
||||
function _isDataDescriptor(desc /*: PropertyDescriptor */) /*: boolean */ {
|
||||
return (
|
||||
desc !== undefined &&
|
||||
!(desc.value === undefined && desc.writable === undefined)
|
||||
);
|
||||
}
|
||||
|
||||
// InitializeClassElements
|
||||
function _initializeClassElements /*::<C>*/(
|
||||
F /*: Class<C> */,
|
||||
elements /*: ElementDescriptor[] */,
|
||||
) {
|
||||
var proto = F.prototype;
|
||||
|
||||
["method", "field"].forEach(function(kind) {
|
||||
elements.forEach(function(element /*: ElementDescriptor */) {
|
||||
var placement = element.placement;
|
||||
if (
|
||||
element.kind === kind &&
|
||||
(placement === "static" || placement === "prototype")
|
||||
) {
|
||||
var receiver = placement === "static" ? F : proto;
|
||||
_defineClassElement(receiver, element);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// InitializeInstanceElements
|
||||
function _initializeInstanceElements /*::<C>*/(
|
||||
O /*: C */,
|
||||
elements /*: ElementDescriptor[] */,
|
||||
) {
|
||||
["method", "field"].forEach(function(kind) {
|
||||
elements.forEach(function(element /*: ElementDescriptor */) {
|
||||
if (element.kind === kind && element.placement === "own") {
|
||||
_defineClassElement(O, element);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// DefineClassElement
|
||||
function _defineClassElement /*::<C>*/(
|
||||
receiver /*: C | Class<C> */,
|
||||
element /*: ElementDescriptor */,
|
||||
) {
|
||||
var descriptor /*: PropertyDescriptor */ = element.descriptor;
|
||||
if (element.kind === "field") {
|
||||
var initializer = element.initializer;
|
||||
descriptor = {
|
||||
enumerable: descriptor.enumerable,
|
||||
writable: descriptor.writable,
|
||||
configurable: descriptor.configurable,
|
||||
value: initializer === void 0 ? void 0 : initializer.call(receiver),
|
||||
};
|
||||
}
|
||||
Object.defineProperty(receiver, element.key, descriptor);
|
||||
}
|
||||
|
||||
/*::
|
||||
|
||||
type Placements = {
|
||||
static: Key[],
|
||||
prototype: Key[],
|
||||
own: Key[],
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
// DecorateClass
|
||||
function _decorateClass(
|
||||
elements /*: ElementDescriptor[] */,
|
||||
decorators /*: ClassDecorator[] */,
|
||||
) /*: ElementsFinishers */ {
|
||||
var newElements /*: ElementDescriptor[] */ = [];
|
||||
var finishers /*: ClassFinisher[] */ = [];
|
||||
var placements /*: Placements */ = { static: [], prototype: [], own: [] };
|
||||
|
||||
elements.forEach(function(element /*: ElementDescriptor */) {
|
||||
_addElementPlacement(element, placements);
|
||||
});
|
||||
|
||||
elements.forEach(function(element /*: ElementDescriptor */) {
|
||||
if (!_hasDecorators(element)) return newElements.push(element);
|
||||
|
||||
var elementFinishersExtras /*: ElementFinishersExtras */ = _decorateElement(
|
||||
element,
|
||||
placements,
|
||||
);
|
||||
newElements.push(elementFinishersExtras.element);
|
||||
newElements.push.apply(newElements, elementFinishersExtras.extras);
|
||||
finishers.push.apply(finishers, elementFinishersExtras.finishers);
|
||||
});
|
||||
|
||||
if (!decorators) {
|
||||
return { elements: newElements, finishers: finishers };
|
||||
}
|
||||
|
||||
var result /*: ElementsFinishers */ = _decorateConstructor(
|
||||
newElements,
|
||||
decorators,
|
||||
);
|
||||
finishers.push.apply(finishers, result.finishers);
|
||||
result.finishers = finishers;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// AddElementPlacement
|
||||
function _addElementPlacement(
|
||||
element /*: ElementDescriptor */,
|
||||
placements /*: Placements */,
|
||||
silent /*: boolean */,
|
||||
) {
|
||||
var keys = placements[element.placement];
|
||||
if (!silent && keys.indexOf(element.key) !== -1) {
|
||||
throw new TypeError("Duplicated element (" + element.key + ")");
|
||||
}
|
||||
keys.push(element.key);
|
||||
}
|
||||
|
||||
// DecorateElement
|
||||
function _decorateElement(
|
||||
element /*: ElementDescriptor */,
|
||||
placements /*: Placements */,
|
||||
) /*: ElementFinishersExtras */ {
|
||||
var extras /*: ElementDescriptor[] */ = [];
|
||||
var finishers /*: ClassFinisher[] */ = [];
|
||||
|
||||
for (
|
||||
var decorators = element.decorators, i = decorators.length - 1;
|
||||
i >= 0;
|
||||
i--
|
||||
) {
|
||||
// (inlined) RemoveElementPlacement
|
||||
var keys = placements[element.placement];
|
||||
keys.splice(keys.indexOf(element.key), 1);
|
||||
|
||||
var elementObject /*: ElementObjectInput */ = _fromElementDescriptor(
|
||||
element,
|
||||
);
|
||||
var elementFinisherExtras /*: ElementFinisherExtras */ = _toElementFinisherExtras(
|
||||
(0, decorators[i])(elementObject) /*: ElementObjectOutput */ ||
|
||||
elementObject,
|
||||
);
|
||||
|
||||
element = elementFinisherExtras.element;
|
||||
_addElementPlacement(element, placements);
|
||||
|
||||
if (elementFinisherExtras.finisher) {
|
||||
finishers.push(elementFinisherExtras.finisher);
|
||||
}
|
||||
|
||||
var newExtras /*: ElementDescriptor[] | void */ =
|
||||
elementFinisherExtras.extras;
|
||||
if (newExtras) {
|
||||
for (var j = 0; j < newExtras.length; j++) {
|
||||
_addElementPlacement(newExtras[j], placements);
|
||||
}
|
||||
extras.push.apply(extras, newExtras);
|
||||
}
|
||||
}
|
||||
|
||||
return { element: element, finishers: finishers, extras: extras };
|
||||
}
|
||||
|
||||
// DecorateConstructor
|
||||
function _decorateConstructor(
|
||||
elements /*: ElementDescriptor[] */,
|
||||
decorators /*: ClassDecorator[] */,
|
||||
) /*: ElementsFinishers */ {
|
||||
var finishers /*: ClassFinisher[] */ = [];
|
||||
|
||||
for (var i = decorators.length - 1; i >= 0; i--) {
|
||||
var obj /*: ClassObject */ = _fromClassDescriptor(elements);
|
||||
var elementsAndFinisher /*: ElementsFinisher */ = _toClassDescriptor(
|
||||
(0, decorators[i])(obj) /*: ClassObject */ || obj,
|
||||
);
|
||||
|
||||
if (elementsAndFinisher.finisher !== undefined) {
|
||||
finishers.push(elementsAndFinisher.finisher);
|
||||
}
|
||||
|
||||
if (elementsAndFinisher.elements !== undefined) {
|
||||
elements = elementsAndFinisher.elements;
|
||||
|
||||
for (var j = 0; j < elements.length - 1; j++) {
|
||||
for (var k = j + 1; k < elements.length; k++) {
|
||||
if (
|
||||
elements[j].key === elements[k].key &&
|
||||
elements[j].placement === elements[k].placement
|
||||
) {
|
||||
throw new TypeError("Duplicated element (" + elements[j].key + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { elements: elements, finishers: finishers };
|
||||
}
|
||||
|
||||
// FromElementDescriptor
|
||||
function _fromElementDescriptor(
|
||||
element /*: ElementDescriptor */,
|
||||
) /*: ElementObject */ {
|
||||
var obj /*: ElementObject */ = {
|
||||
kind: element.kind,
|
||||
key: element.key,
|
||||
placement: element.placement,
|
||||
descriptor: element.descriptor,
|
||||
};
|
||||
|
||||
var desc = {
|
||||
value: "Descriptor",
|
||||
configurable: true,
|
||||
};
|
||||
Object.defineProperty(obj, Symbol.toStringTag, desc);
|
||||
|
||||
if (element.kind === "field") obj.initializer = element.initializer;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
// ToElementDescriptors
|
||||
function _toElementDescriptors(
|
||||
elementObjects /*: ElementObject[] */,
|
||||
) /*: ElementDescriptor[] */ {
|
||||
if (elementObjects === undefined) return;
|
||||
return toArray(elementObjects).map(function(elementObject) {
|
||||
var element = _toElementDescriptor(elementObject);
|
||||
_disallowProperty(elementObject, "finisher", "An element descriptor");
|
||||
_disallowProperty(elementObject, "extras", "An element descriptor");
|
||||
return element;
|
||||
});
|
||||
}
|
||||
|
||||
// ToElementDescriptor
|
||||
function _toElementDescriptor(
|
||||
elementObject /*: ElementObject */,
|
||||
) /*: ElementDescriptor */ {
|
||||
var kind = String(elementObject.kind);
|
||||
if (kind !== "method" && kind !== "field") {
|
||||
throw new TypeError(
|
||||
'An element descriptor\\'s .kind property must be either "method" or' +
|
||||
' "field", but a decorator created an element descriptor with' +
|
||||
' .kind "' +
|
||||
kind +
|
||||
'"',
|
||||
);
|
||||
}
|
||||
|
||||
var key = elementObject.key;
|
||||
if (typeof key !== "string" && typeof key !== "symbol") key = String(key);
|
||||
|
||||
var placement = String(elementObject.placement);
|
||||
if (
|
||||
placement !== "static" &&
|
||||
placement !== "prototype" &&
|
||||
placement !== "own"
|
||||
) {
|
||||
throw new TypeError(
|
||||
'An element descriptor\\'s .placement property must be one of "static",' +
|
||||
' "prototype" or "own", but a decorator created an element descriptor' +
|
||||
' with .placement "' +
|
||||
placement +
|
||||
'"',
|
||||
);
|
||||
}
|
||||
|
||||
var descriptor /*: PropertyDescriptor */ = elementObject.descriptor;
|
||||
|
||||
_disallowProperty(elementObject, "elements", "An element descriptor");
|
||||
|
||||
var element /*: ElementDescriptor */ = {
|
||||
kind: kind,
|
||||
key: key,
|
||||
placement: placement,
|
||||
descriptor: Object.assign({}, descriptor),
|
||||
};
|
||||
|
||||
if (kind !== "field") {
|
||||
_disallowProperty(elementObject, "initializer", "A method descriptor");
|
||||
} else {
|
||||
_disallowProperty(
|
||||
descriptor,
|
||||
"get",
|
||||
"The property descriptor of a field descriptor",
|
||||
);
|
||||
_disallowProperty(
|
||||
descriptor,
|
||||
"set",
|
||||
"The property descriptor of a field descriptor",
|
||||
);
|
||||
_disallowProperty(
|
||||
descriptor,
|
||||
"value",
|
||||
"The property descriptor of a field descriptor",
|
||||
);
|
||||
|
||||
element.initializer = elementObject.initializer;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
function _toElementFinisherExtras(
|
||||
elementObject /*: ElementObject */,
|
||||
) /*: ElementFinisherExtras */ {
|
||||
var element /*: ElementDescriptor */ = _toElementDescriptor(elementObject);
|
||||
var finisher /*: ClassFinisher */ = _optionalCallableProperty(
|
||||
elementObject,
|
||||
"finisher",
|
||||
);
|
||||
var extras /*: ElementDescriptors[] */ = _toElementDescriptors(
|
||||
elementObject.extras,
|
||||
);
|
||||
|
||||
return { element: element, finisher: finisher, extras: extras };
|
||||
}
|
||||
|
||||
// FromClassDescriptor
|
||||
function _fromClassDescriptor(
|
||||
elements /*: ElementDescriptor[] */,
|
||||
) /*: ClassObject */ {
|
||||
var obj = {
|
||||
kind: "class",
|
||||
elements: elements.map(_fromElementDescriptor),
|
||||
};
|
||||
|
||||
var desc = { value: "Descriptor", configurable: true };
|
||||
Object.defineProperty(obj, Symbol.toStringTag, desc);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
// ToClassDescriptor
|
||||
function _toClassDescriptor(obj /*: ClassObject */) /*: ElementsFinisher */ {
|
||||
var kind = String(obj.kind);
|
||||
if (kind !== "class") {
|
||||
throw new TypeError(
|
||||
'A class descriptor\\'s .kind property must be "class", but a decorator' +
|
||||
' created a class descriptor with .kind "' +
|
||||
kind +
|
||||
'"',
|
||||
);
|
||||
}
|
||||
|
||||
_disallowProperty(obj, "key", "A class descriptor");
|
||||
_disallowProperty(obj, "placement", "A class descriptor");
|
||||
_disallowProperty(obj, "descriptor", "A class descriptor");
|
||||
_disallowProperty(obj, "initializer", "A class descriptor");
|
||||
_disallowProperty(obj, "extras", "A class descriptor");
|
||||
|
||||
var finisher = _optionalCallableProperty(obj, "finisher");
|
||||
var elements = _toElementDescriptors(obj.elements);
|
||||
|
||||
return { elements: elements, finisher: finisher };
|
||||
}
|
||||
|
||||
function _disallowProperty(obj, name, objectType) {
|
||||
if (obj[name] !== undefined) {
|
||||
throw new TypeError(objectType + " can't have a ." + name + " property.");
|
||||
}
|
||||
}
|
||||
|
||||
function _optionalCallableProperty /*::<T>*/(
|
||||
obj /*: T */,
|
||||
name /*: $Keys<T> */,
|
||||
) /*: ?Function */ {
|
||||
var value = obj[name];
|
||||
if (value !== undefined && typeof value !== "function") {
|
||||
throw new TypeError("Expected '" + name + "' to be a function");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// RunClassFinishers
|
||||
function _runClassFinishers(
|
||||
constructor /*: Class<*> */,
|
||||
finishers /*: ClassFinisher[] */,
|
||||
) /*: Class<*> */ {
|
||||
for (var i = 0; i < finishers.length; i++) {
|
||||
var newConstructor /*: ?Class<*> */ = (0, finishers[i])(constructor);
|
||||
if (newConstructor !== undefined) {
|
||||
// NOTE: This should check if IsConstructor(newConstructor) is false.
|
||||
if (typeof newConstructor !== "function") {
|
||||
throw new TypeError("Finishers must return a constructor.");
|
||||
}
|
||||
constructor = newConstructor;
|
||||
}
|
||||
}
|
||||
return constructor;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.0.0",
|
||||
"@babel/helper-replace-supers": "^7.0.0",
|
||||
"@babel/helper-split-export-declaration": "^7.0.0",
|
||||
"@babel/plugin-syntax-decorators": "^7.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@ -6,20 +6,21 @@ import legacyVisitor from "./transformer-legacy";
|
||||
export default declare((api, options) => {
|
||||
api.assertVersion(7);
|
||||
|
||||
const { legacy = false, decoratorsBeforeExport } = options;
|
||||
const { legacy = false } = options;
|
||||
if (typeof legacy !== "boolean") {
|
||||
throw new Error("'legacy' must be a boolean.");
|
||||
}
|
||||
|
||||
if (legacy !== true) {
|
||||
throw new Error(
|
||||
"The new decorators proposal is not supported yet." +
|
||||
' You must pass the `"legacy": true` option to' +
|
||||
" @babel/plugin-proposal-decorators",
|
||||
);
|
||||
}
|
||||
|
||||
if (decoratorsBeforeExport !== undefined) {
|
||||
const { decoratorsBeforeExport } = options;
|
||||
if (decoratorsBeforeExport === undefined) {
|
||||
if (!legacy) {
|
||||
throw new Error(
|
||||
"The decorators plugin requires a 'decoratorsBeforeExport' option," +
|
||||
" whose value must be a boolean. If you want to use the legacy" +
|
||||
" decorators semantics, you can set the 'legacy: true' option.",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (legacy) {
|
||||
throw new Error(
|
||||
"'decoratorsBeforeExport' can't be used with legacy decorators.",
|
||||
|
||||
@ -1,3 +1,232 @@
|
||||
// Not implemented yet
|
||||
import { types as t, template } from "@babel/core";
|
||||
import splitExportDeclaration from "@babel/helper-split-export-declaration";
|
||||
import ReplaceSupers from "@babel/helper-replace-supers";
|
||||
|
||||
export default {};
|
||||
function prop(key, value) {
|
||||
if (!value) return null;
|
||||
return t.objectProperty(t.identifier(key), value);
|
||||
}
|
||||
|
||||
function value(body, params = []) {
|
||||
return t.objectMethod("method", t.identifier("value"), params, body);
|
||||
}
|
||||
|
||||
function hasDecorators({ node }) {
|
||||
if (node.decorators && node.decorators.length > 0) return true;
|
||||
|
||||
const body = node.body.body;
|
||||
for (let i = 0; i < body.length; i++) {
|
||||
const method = body[i];
|
||||
if (method.decorators && method.decorators.length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function takeDecorators({ node }) {
|
||||
let result;
|
||||
if (node.decorators && node.decorators.length > 0) {
|
||||
result = t.arrayExpression(
|
||||
node.decorators.map(decorator => decorator.expression),
|
||||
);
|
||||
}
|
||||
node.decorators = undefined;
|
||||
return result;
|
||||
}
|
||||
|
||||
function getKey(node) {
|
||||
if (node.computed) {
|
||||
return node.key;
|
||||
} else if (t.isIdentifier(node.key)) {
|
||||
return t.stringLiteral(node.key.name);
|
||||
} else {
|
||||
return t.stringLiteral(String(node.key.value));
|
||||
}
|
||||
}
|
||||
|
||||
function getSingleElementDefinition(path, superRef, classRef, file) {
|
||||
const { node, scope } = path;
|
||||
const isMethod = path.isClassMethod();
|
||||
|
||||
if (path.isPrivate()) {
|
||||
throw path.buildCodeFrameError(
|
||||
`Private ${
|
||||
isMethod ? "methods" : "fields"
|
||||
} in decorated classes are not supported yet.`,
|
||||
);
|
||||
}
|
||||
|
||||
new ReplaceSupers(
|
||||
{
|
||||
methodPath: path,
|
||||
methodNode: node,
|
||||
objectRef: classRef,
|
||||
isStatic: node.static,
|
||||
superRef,
|
||||
scope,
|
||||
file,
|
||||
},
|
||||
true,
|
||||
).replace();
|
||||
|
||||
const properties = [
|
||||
prop("kind", t.stringLiteral(isMethod ? node.kind : "field")),
|
||||
prop("decorators", takeDecorators(path)),
|
||||
prop("static", node.static && t.booleanLiteral(true)),
|
||||
prop("key", getKey(node)),
|
||||
isMethod
|
||||
? value(node.body, node.params)
|
||||
: node.value
|
||||
? value(template.ast`{ return ${node.value} }`)
|
||||
: prop("value", scope.buildUndefinedNode()),
|
||||
].filter(Boolean);
|
||||
|
||||
return t.objectExpression(properties);
|
||||
}
|
||||
|
||||
function getElementsDefinitions(path, fId, file) {
|
||||
const elements = [];
|
||||
for (const p of path.get("body.body")) {
|
||||
if (!p.isClassMethod({ kind: "constructor" })) {
|
||||
elements.push(
|
||||
getSingleElementDefinition(p, path.node.superClass, fId, file),
|
||||
);
|
||||
p.remove();
|
||||
}
|
||||
}
|
||||
|
||||
return t.arrayExpression(elements);
|
||||
}
|
||||
|
||||
function getConstructorPath(path) {
|
||||
return path
|
||||
.get("body.body")
|
||||
.find(path => path.isClassMethod({ kind: "constructor" }));
|
||||
}
|
||||
|
||||
const bareSupersVisitor = {
|
||||
CallExpression(path, { initializeInstanceElements }) {
|
||||
if (path.get("callee").isSuper()) {
|
||||
path.insertAfter(t.cloneNode(initializeInstanceElements));
|
||||
}
|
||||
},
|
||||
Function(path) {
|
||||
if (!path.isArrowFunctionExpression()) path.skip();
|
||||
},
|
||||
};
|
||||
|
||||
function insertInitializeInstanceElements(path, initializeInstanceId) {
|
||||
const isBase = !path.node.superClass;
|
||||
const initializeInstanceElements = t.callExpression(initializeInstanceId, [
|
||||
t.thisExpression(),
|
||||
]);
|
||||
|
||||
const constructorPath = getConstructorPath(path);
|
||||
if (constructorPath) {
|
||||
if (isBase) {
|
||||
constructorPath
|
||||
.get("body")
|
||||
.unshiftContainer("body", [
|
||||
t.expressionStatement(initializeInstanceElements),
|
||||
]);
|
||||
} else {
|
||||
constructorPath.traverse(bareSupersVisitor, {
|
||||
initializeInstanceElements,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const constructor = isBase
|
||||
? t.classMethod(
|
||||
"constructor",
|
||||
t.identifier("constructor"),
|
||||
[],
|
||||
t.blockStatement([t.expressionStatement(initializeInstanceElements)]),
|
||||
)
|
||||
: t.classMethod(
|
||||
"constructor",
|
||||
t.identifier("constructor"),
|
||||
[t.restElement(t.identifier("args"))],
|
||||
t.blockStatement([
|
||||
t.expressionStatement(
|
||||
t.callExpression(t.Super(), [
|
||||
t.spreadElement(t.identifier("args")),
|
||||
]),
|
||||
),
|
||||
t.expressionStatement(initializeInstanceElements),
|
||||
]),
|
||||
);
|
||||
path.node.body.body.push(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
function transformClass(path, file) {
|
||||
const isDeclaration = path.node.id && path.isDeclaration();
|
||||
const isStrict = path.isInStrictMode();
|
||||
const { superClass } = path.node;
|
||||
|
||||
path.node.type = "ClassDeclaration";
|
||||
if (!path.node.id) path.node.id = path.scope.generateUidIdentifier("class");
|
||||
|
||||
const initializeId = path.scope.generateUidIdentifier("initialize");
|
||||
const superId =
|
||||
superClass &&
|
||||
path.scope.generateUidIdentifierBasedOnNode(path.node.superClass, "super");
|
||||
|
||||
if (superClass) path.node.superClass = superId;
|
||||
|
||||
const classDecorators = takeDecorators(path);
|
||||
const definitions = getElementsDefinitions(path, path.node.id, file);
|
||||
|
||||
insertInitializeInstanceElements(path, initializeId);
|
||||
|
||||
const expr = template.expression.ast`
|
||||
${addDecorateHelper(file)}(
|
||||
${classDecorators || t.nullLiteral()},
|
||||
function (${initializeId}, ${superClass ? superId : null}) {
|
||||
${path.node}
|
||||
return { F: ${t.cloneNode(path.node.id)}, d: ${definitions} };
|
||||
},
|
||||
${superClass}
|
||||
)
|
||||
`;
|
||||
if (!isStrict) {
|
||||
expr.arguments[1].body.directives.push(
|
||||
t.directive(t.directiveLiteral("use strict")),
|
||||
);
|
||||
}
|
||||
|
||||
return isDeclaration ? template.ast`let ${path.node.id} = ${expr}` : expr;
|
||||
}
|
||||
|
||||
function addDecorateHelper(file) {
|
||||
try {
|
||||
return file.addHelper("decorate");
|
||||
} catch (err) {
|
||||
if (err.code === "BABEL_HELPER_UNKNOWN") {
|
||||
err.message +=
|
||||
"\n '@babel/plugin-transform-decorators' in non-legacy mode" +
|
||||
" requires '@babel/core' version ^7.0.1 and you appear to be using" +
|
||||
" an older version.";
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
ExportDefaultDeclaration(path) {
|
||||
let decl = path.get("declaration");
|
||||
if (!decl.isClassDeclaration() || !hasDecorators(decl)) return;
|
||||
|
||||
if (decl.node.id) decl = splitExportDeclaration(path);
|
||||
|
||||
decl.replaceWith(transformClass(decl, this.file));
|
||||
},
|
||||
|
||||
Class(path) {
|
||||
if (hasDecorators(path)) {
|
||||
path.replaceWith(transformClass(path, this.file));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
22
packages/babel-plugin-proposal-decorators/test/fixtures/duplicated-keys/coalesce-get-set/exec.js
vendored
Normal file
22
packages/babel-plugin-proposal-decorators/test/fixtures/duplicated-keys/coalesce-get-set/exec.js
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
var el, el1;
|
||||
|
||||
@(_ => el = _)
|
||||
class A {
|
||||
@(_ => el1 = _)
|
||||
get foo() { return 1; }
|
||||
|
||||
set foo(x) { return 2; }
|
||||
}
|
||||
|
||||
expect(el.elements).toHaveLength(1);
|
||||
|
||||
expect(el1).toEqual(expect.objectContaining({
|
||||
descriptor: expect.objectContaining({
|
||||
get: expect.any(Function),
|
||||
set: expect.any(Function)
|
||||
})
|
||||
}));
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(A.prototype, "foo");
|
||||
expect(desc.get()).toBe(1);
|
||||
expect(desc.set()).toBe(2);
|
||||
@ -0,0 +1,28 @@
|
||||
var i = 0;
|
||||
|
||||
function getKey() {
|
||||
return (i++).toString();
|
||||
}
|
||||
|
||||
var desc;
|
||||
|
||||
@(_ => desc = _)
|
||||
class Foo {
|
||||
[getKey()]() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
[getKey()]() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
expect(desc.elements).toHaveLength(2);
|
||||
|
||||
expect(desc.elements[0].key).toBe("0");
|
||||
expect(desc.elements[0].descriptor.value()).toBe(1);
|
||||
|
||||
expect(desc.elements[1].key).toBe("1");
|
||||
expect(desc.elements[1].descriptor.value()).toBe(2);
|
||||
|
||||
expect(i).toBe(2);
|
||||
@ -0,0 +1,10 @@
|
||||
@(_ => desc = _)
|
||||
class Foo {
|
||||
[getKey()]() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
[getKey()]() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
let Foo = babelHelpers.decorate([_ => desc = _], function (_initialize) {
|
||||
"use strict";
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: Foo,
|
||||
d: [{
|
||||
kind: "method",
|
||||
key: getKey(),
|
||||
|
||||
value() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}, {
|
||||
kind: "method",
|
||||
key: getKey(),
|
||||
|
||||
value() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
}]
|
||||
};
|
||||
});
|
||||
@ -0,0 +1,30 @@
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
|
||||
function getKeyI() {
|
||||
return (i++).toString();
|
||||
}
|
||||
function getKeyJ() {
|
||||
return (j++).toString();
|
||||
}
|
||||
|
||||
var desc;
|
||||
|
||||
@(_ => desc = _)
|
||||
class Foo {
|
||||
[getKeyI()]() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
[getKeyJ()]() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
expect(desc.elements).toHaveLength(1);
|
||||
|
||||
expect(desc.elements[0].key).toBe("0");
|
||||
expect(desc.elements[0].descriptor.value()).toBe(2);
|
||||
|
||||
expect(i).toBe(1);
|
||||
expect(j).toBe(1);
|
||||
@ -0,0 +1,10 @@
|
||||
@(_ => desc = _)
|
||||
class Foo {
|
||||
[getKeyI()]() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
[getKeyJ()]() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
let Foo = babelHelpers.decorate([_ => desc = _], function (_initialize) {
|
||||
"use strict";
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: Foo,
|
||||
d: [{
|
||||
kind: "method",
|
||||
key: getKeyI(),
|
||||
|
||||
value() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}, {
|
||||
kind: "method",
|
||||
key: getKeyJ(),
|
||||
|
||||
value() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
}]
|
||||
};
|
||||
});
|
||||
@ -0,0 +1,21 @@
|
||||
function pushElement(e) {
|
||||
return function (c) { c.elements.push(e); return c };
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
@pushElement({
|
||||
kind: "method",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function() {},
|
||||
}
|
||||
})
|
||||
class A {
|
||||
foo() {}
|
||||
}
|
||||
}).toThrow(TypeError);
|
||||
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
function decorate() {
|
||||
return {
|
||||
kind: "method",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function() {},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
class A {
|
||||
@decorate
|
||||
bar() {}
|
||||
|
||||
foo() {}
|
||||
}
|
||||
}).toThrow(TypeError);
|
||||
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
function decorate(el) {
|
||||
el.extras = [{
|
||||
kind: "method",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function() {},
|
||||
}
|
||||
}];
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
class A {
|
||||
@decorate
|
||||
bar() {}
|
||||
|
||||
foo() {}
|
||||
}
|
||||
}).toThrow(TypeError);
|
||||
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
function decorate(el) {
|
||||
el.extras = [{
|
||||
kind: "method",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function() {},
|
||||
}
|
||||
}, {
|
||||
kind: "method",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function() {},
|
||||
}
|
||||
}];
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
class A {
|
||||
@decorate
|
||||
method() {}
|
||||
}
|
||||
}).toThrow(TypeError);
|
||||
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
function decorate(el) {
|
||||
return {
|
||||
kind: "method",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function() {},
|
||||
},
|
||||
extras: [{
|
||||
kind: "method",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function() {},
|
||||
}
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
class A {
|
||||
@decorate
|
||||
method() {}
|
||||
}
|
||||
}).toThrow(TypeError);
|
||||
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
function dec(el) { return el }
|
||||
|
||||
expect(() => {
|
||||
class A {
|
||||
@dec
|
||||
get foo() {}
|
||||
|
||||
@dec
|
||||
set foo(x) {}
|
||||
}
|
||||
}).toThrow(ReferenceError);
|
||||
@ -0,0 +1,33 @@
|
||||
var value1, value2 = {};
|
||||
|
||||
function makeStatic(el) {
|
||||
el.placement = "static";
|
||||
return el;
|
||||
}
|
||||
|
||||
function defineBar(el) {
|
||||
el.extras = [{
|
||||
key: "bar",
|
||||
kind: "method",
|
||||
placement: "prototype",
|
||||
descriptor: {
|
||||
value: value2,
|
||||
},
|
||||
}];
|
||||
return el;
|
||||
}
|
||||
|
||||
function storeValue(el) {
|
||||
value1 = el.descriptor.value;
|
||||
return el;
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@defineBar
|
||||
@makeStatic
|
||||
@storeValue
|
||||
bar() {}
|
||||
}
|
||||
|
||||
expect(Foo.bar).toBe(value1);
|
||||
expect(Foo.prototype.bar).toBe(value2);
|
||||
7
packages/babel-plugin-proposal-decorators/test/fixtures/duplicated-keys/options.json
vendored
Normal file
7
packages/babel-plugin-proposal-decorators/test/fixtures/duplicated-keys/options.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"plugins": [
|
||||
["proposal-decorators", { "decoratorsBeforeExport": false }],
|
||||
"proposal-class-properties",
|
||||
"external-helpers"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
expect(() => {
|
||||
class A {
|
||||
@(el => el)
|
||||
method() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@(el => el)
|
||||
method() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}).toThrow(ReferenceError);
|
||||
@ -0,0 +1,12 @@
|
||||
expect(() => {
|
||||
class A {
|
||||
method() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@(el => el)
|
||||
method() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}).toThrow(ReferenceError);
|
||||
@ -0,0 +1,16 @@
|
||||
var el;
|
||||
|
||||
@(_ => el = _)
|
||||
class A {
|
||||
method() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
method() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
expect(el.elements).toHaveLength(1);
|
||||
|
||||
expect(A.prototype.method()).toBe(2);
|
||||
@ -0,0 +1,12 @@
|
||||
expect(() => {
|
||||
class A {
|
||||
@(el => el)
|
||||
method() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
method() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}).toThrow(ReferenceError);
|
||||
@ -0,0 +1,17 @@
|
||||
var el;
|
||||
|
||||
@(_ => el = _)
|
||||
class A {
|
||||
method() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static method() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
expect(el.elements).toHaveLength(2);
|
||||
|
||||
expect(A.prototype.method()).toBe(1);
|
||||
expect(A.method()).toBe(2);
|
||||
@ -0,0 +1,30 @@
|
||||
function pushElement(e) {
|
||||
return function (c) { c.elements.push(e); return c };
|
||||
}
|
||||
|
||||
var value = {};
|
||||
|
||||
@pushElement({
|
||||
kind: "field",
|
||||
placement: "own",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
},
|
||||
initializer() {
|
||||
return value;
|
||||
}
|
||||
})
|
||||
class A {}
|
||||
|
||||
expect(A).not.toHaveProperty("foo");
|
||||
expect(A.prototype).not.toHaveProperty("foo");
|
||||
|
||||
expect(Object.getOwnPropertyDescriptor(new A(), "foo")).toEqual({
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: value,
|
||||
});
|
||||
@ -0,0 +1,28 @@
|
||||
function pushElement(e) {
|
||||
return function (c) { c.elements.push(e); return c };
|
||||
}
|
||||
|
||||
function method() {}
|
||||
|
||||
@pushElement({
|
||||
kind: "method",
|
||||
placement: "own",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: method,
|
||||
}
|
||||
})
|
||||
class A {}
|
||||
|
||||
expect(A).not.toHaveProperty("foo");
|
||||
expect(A.prototype).not.toHaveProperty("foo");
|
||||
|
||||
expect(Object.getOwnPropertyDescriptor(new A(), "foo")).toEqual({
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: method,
|
||||
});
|
||||
@ -0,0 +1,29 @@
|
||||
function pushElement(e) {
|
||||
return function (c) { c.elements.push(e); return c };
|
||||
}
|
||||
|
||||
var value = {};
|
||||
|
||||
@pushElement({
|
||||
kind: "field",
|
||||
placement: "prototype",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
},
|
||||
initializer() {
|
||||
return value;
|
||||
}
|
||||
})
|
||||
class A {}
|
||||
|
||||
expect(A).not.toHaveProperty("foo");
|
||||
|
||||
expect(Object.getOwnPropertyDescriptor(A.prototype, "foo")).toEqual({
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: value,
|
||||
});
|
||||
@ -0,0 +1,27 @@
|
||||
function pushElement(e) {
|
||||
return function (c) { c.elements.push(e); return c };
|
||||
}
|
||||
|
||||
function method() {}
|
||||
|
||||
@pushElement({
|
||||
kind: "method",
|
||||
placement: "prototype",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: method,
|
||||
}
|
||||
})
|
||||
class A {}
|
||||
|
||||
expect(A).not.toHaveProperty("foo");
|
||||
|
||||
expect(Object.getOwnPropertyDescriptor(A.prototype, "foo")).toEqual({
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: method,
|
||||
});
|
||||
@ -0,0 +1,30 @@
|
||||
function pushElement(e) {
|
||||
return function (c) { c.elements.push(e); return c };
|
||||
}
|
||||
|
||||
var value = {};
|
||||
|
||||
@pushElement({
|
||||
kind: "field",
|
||||
placement: "static",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
},
|
||||
initializer() {
|
||||
return value;
|
||||
}
|
||||
})
|
||||
class A {}
|
||||
|
||||
expect(A.prototype).not.toHaveProperty("foo");
|
||||
expect(new A()).not.toHaveProperty("foo");
|
||||
|
||||
expect(Object.getOwnPropertyDescriptor(A, "foo")).toEqual({
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: value,
|
||||
});
|
||||
@ -0,0 +1,28 @@
|
||||
function pushElement(e) {
|
||||
return function (c) { c.elements.push(e); return c };
|
||||
}
|
||||
|
||||
function method() {}
|
||||
|
||||
@pushElement({
|
||||
kind: "method",
|
||||
placement: "static",
|
||||
key: "foo",
|
||||
descriptor: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: method,
|
||||
}
|
||||
})
|
||||
class A {}
|
||||
|
||||
expect(A.prototype).not.toHaveProperty("foo");
|
||||
expect(new A()).not.toHaveProperty("foo");
|
||||
|
||||
expect(Object.getOwnPropertyDescriptor(A, "foo")).toEqual({
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: method,
|
||||
});
|
||||
14
packages/babel-plugin-proposal-decorators/test/fixtures/element-descriptors/default/exec.js
vendored
Normal file
14
packages/babel-plugin-proposal-decorators/test/fixtures/element-descriptors/default/exec.js
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
function decorate(el) {
|
||||
el.descriptor.value = 2;
|
||||
}
|
||||
|
||||
var Foo;
|
||||
|
||||
expect(() => {
|
||||
Foo = @(() => void 0) class Foo {
|
||||
@decorate
|
||||
bar() {}
|
||||
}
|
||||
}).not.toThrow();
|
||||
|
||||
expect(Foo.prototype.bar).toBe(2);
|
||||
@ -0,0 +1,8 @@
|
||||
var dec1, dec2;
|
||||
|
||||
@(_ => dec1 = _)
|
||||
@(_ => dec2 = _)
|
||||
class A {}
|
||||
|
||||
expect(dec1).toEqual(dec2);
|
||||
expect(dec1).not.toBe(dec2);
|
||||
@ -0,0 +1,13 @@
|
||||
var dec1, dec2;
|
||||
|
||||
class A {
|
||||
@(_ => dec1 = _)
|
||||
@(_ => dec2 = _)
|
||||
field = {}
|
||||
}
|
||||
|
||||
expect(dec1).toEqual(dec2);
|
||||
expect(dec1).not.toBe(dec2);
|
||||
expect(dec1.descriptor).toEqual(dec2.descriptor);
|
||||
expect(dec1.descriptor).not.toBe(dec2.descriptor);
|
||||
expect(dec1.initializer).toBe(dec2.initializer);
|
||||
@ -0,0 +1,13 @@
|
||||
var dec1, dec2;
|
||||
|
||||
class A {
|
||||
@(_ => dec1 = _)
|
||||
@(_ => dec2 = _)
|
||||
fn() {}
|
||||
}
|
||||
|
||||
expect(dec1).toEqual(dec2);
|
||||
expect(dec1).not.toBe(dec2);
|
||||
expect(dec1.descriptor).toEqual(dec2.descriptor);
|
||||
expect(dec1.descriptor).not.toBe(dec2.descriptor);
|
||||
expect(dec1.descriptor.value).toBe(dec2.descriptor.value);
|
||||
7
packages/babel-plugin-proposal-decorators/test/fixtures/element-descriptors/options.json
vendored
Normal file
7
packages/babel-plugin-proposal-decorators/test/fixtures/element-descriptors/options.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"plugins": [
|
||||
["proposal-decorators", { "decoratorsBeforeExport": false }],
|
||||
"proposal-class-properties",
|
||||
"external-helpers"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
var el = null;
|
||||
|
||||
@(_ => el = _)
|
||||
class A {}
|
||||
|
||||
expect(el).toEqual(Object.defineProperty({
|
||||
kind: "class",
|
||||
elements: []
|
||||
}, Symbol.toStringTag, { value: "Descriptor" }));
|
||||
|
||||
@(_ => el = _)
|
||||
class B {
|
||||
foo = 2;
|
||||
static bar() {}
|
||||
get baz() {}
|
||||
set baz(x) {}
|
||||
}
|
||||
|
||||
expect(el.elements).toHaveLength(3);
|
||||
@ -0,0 +1,18 @@
|
||||
var el = null;
|
||||
|
||||
class A {
|
||||
@(_ => el = _)
|
||||
foo;
|
||||
}
|
||||
|
||||
expect(el).toEqual(Object.defineProperty({
|
||||
kind: "field",
|
||||
key: "foo",
|
||||
placement: "own",
|
||||
descriptor: {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
},
|
||||
initializer: undefined,
|
||||
}, Symbol.toStringTag, { value: "Descriptor" }));
|
||||
@ -0,0 +1,21 @@
|
||||
var el = null;
|
||||
var val = {};
|
||||
|
||||
class A {
|
||||
@(_ => el = _)
|
||||
foo = val;
|
||||
}
|
||||
|
||||
expect(el).toEqual(Object.defineProperty({
|
||||
kind: "field",
|
||||
key: "foo",
|
||||
placement: "own",
|
||||
descriptor: {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
},
|
||||
initializer: expect.any(Function),
|
||||
}, Symbol.toStringTag, { value: "Descriptor" }));
|
||||
|
||||
expect(el.initializer()).toBe(val);
|
||||
@ -0,0 +1,18 @@
|
||||
var el = null;
|
||||
|
||||
class A {
|
||||
@(_ => el = _)
|
||||
foo() {}
|
||||
}
|
||||
|
||||
expect(el).toEqual(Object.defineProperty({
|
||||
kind: "method",
|
||||
key: "foo",
|
||||
placement: "prototype",
|
||||
descriptor: {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: A.prototype.foo,
|
||||
},
|
||||
}, Symbol.toStringTag, { value: "Descriptor" }));
|
||||
@ -0,0 +1,21 @@
|
||||
var el = null;
|
||||
var val = { foo: 2 };
|
||||
|
||||
class A {
|
||||
@(_ => el = _)
|
||||
static foo = val;
|
||||
}
|
||||
|
||||
expect(el).toEqual(Object.defineProperty({
|
||||
kind: "field",
|
||||
key: "foo",
|
||||
placement: "static",
|
||||
descriptor: {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
},
|
||||
initializer: expect.any(Function),
|
||||
}, Symbol.toStringTag, { value: "Descriptor" }));
|
||||
|
||||
expect(el.initializer()).toBe(val);
|
||||
@ -0,0 +1,18 @@
|
||||
var el = null;
|
||||
|
||||
class A {
|
||||
@(_ => el = _)
|
||||
static foo() {}
|
||||
}
|
||||
|
||||
expect(el).toEqual(Object.defineProperty({
|
||||
kind: "method",
|
||||
key: "foo",
|
||||
placement: "static",
|
||||
descriptor: {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: A.foo,
|
||||
},
|
||||
}, Symbol.toStringTag, { value: "Descriptor" }));
|
||||
16
packages/babel-plugin-proposal-decorators/test/fixtures/finishers/class-as-parameter/exec.js
vendored
Normal file
16
packages/babel-plugin-proposal-decorators/test/fixtures/finishers/class-as-parameter/exec.js
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
var C;
|
||||
|
||||
function decorator(el) {
|
||||
return Object.assign(el, {
|
||||
finisher(Class) {
|
||||
C = Class;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
class A {
|
||||
@decorator
|
||||
foo() {}
|
||||
}
|
||||
|
||||
expect(C).toBe(A);
|
||||
21
packages/babel-plugin-proposal-decorators/test/fixtures/finishers/no-in-extras/exec.js
vendored
Normal file
21
packages/babel-plugin-proposal-decorators/test/fixtures/finishers/no-in-extras/exec.js
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
class C {}
|
||||
|
||||
function decorator(el) {
|
||||
return Object.assign(el, {
|
||||
extras: [
|
||||
Object.assign({}, el, {
|
||||
key: "bar",
|
||||
finisher() {
|
||||
return C;
|
||||
}
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
class A {
|
||||
@decorator
|
||||
foo() {}
|
||||
}
|
||||
}).toThrow();
|
||||
7
packages/babel-plugin-proposal-decorators/test/fixtures/finishers/options.json
vendored
Normal file
7
packages/babel-plugin-proposal-decorators/test/fixtures/finishers/options.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"plugins": [
|
||||
["proposal-decorators", { "decoratorsBeforeExport": false }],
|
||||
"proposal-class-properties",
|
||||
"external-helpers"
|
||||
]
|
||||
}
|
||||
16
packages/babel-plugin-proposal-decorators/test/fixtures/finishers/return-class/exec.js
vendored
Normal file
16
packages/babel-plugin-proposal-decorators/test/fixtures/finishers/return-class/exec.js
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
class C {}
|
||||
|
||||
function decorator(el) {
|
||||
return Object.assign(el, {
|
||||
finisher() {
|
||||
return C;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
class A {
|
||||
@decorator
|
||||
foo() {}
|
||||
}
|
||||
|
||||
expect(A).toBe(C);
|
||||
31
packages/babel-plugin-proposal-decorators/test/fixtures/ordering/decorators/exec.js
vendored
Normal file
31
packages/babel-plugin-proposal-decorators/test/fixtures/ordering/decorators/exec.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
var log = [];
|
||||
|
||||
function push(x) { log.push(x); return x; }
|
||||
|
||||
function logDecoratorRun(a, b) {
|
||||
push(a);
|
||||
return function (el) { push(b); return el; };
|
||||
}
|
||||
|
||||
@logDecoratorRun(0, 23)
|
||||
@logDecoratorRun(1, 22)
|
||||
class A {
|
||||
@logDecoratorRun(2, 15)
|
||||
@logDecoratorRun(3, 14)
|
||||
[push(4)] = "4";
|
||||
|
||||
@logDecoratorRun(5, 17)
|
||||
@logDecoratorRun(6, 16)
|
||||
static [push(7)]() {}
|
||||
|
||||
@logDecoratorRun(8, 19)
|
||||
@logDecoratorRun(9, 18)
|
||||
static [push(10)] = "10";
|
||||
|
||||
@logDecoratorRun(11, 21)
|
||||
@logDecoratorRun(12, 20)
|
||||
[push(13)]() {}
|
||||
}
|
||||
|
||||
var numsFrom0to23 = Array.from({ length: 24 }, (_, i) => i);
|
||||
expect(log).toEqual(numsFrom0to23);
|
||||
@ -0,0 +1,27 @@
|
||||
var counter = 0;
|
||||
|
||||
@(x => x)
|
||||
class A {
|
||||
foo = (() => {
|
||||
counter++;
|
||||
expect(typeof this.method).toBe("function");
|
||||
expect(this.foo).toBeUndefined();
|
||||
expect(this.bar).toBeUndefined();
|
||||
return "foo";
|
||||
})();
|
||||
|
||||
method() {}
|
||||
|
||||
bar = (() => {
|
||||
counter++;
|
||||
expect(typeof this.method).toBe("function");
|
||||
expect(this.foo).toBe("foo");
|
||||
expect(this.bar).toBeUndefined();
|
||||
})();
|
||||
}
|
||||
|
||||
expect(counter).toBe(0);
|
||||
|
||||
new A();
|
||||
|
||||
expect(counter).toBe(2);
|
||||
34
packages/babel-plugin-proposal-decorators/test/fixtures/ordering/finishers/exec.js
vendored
Normal file
34
packages/babel-plugin-proposal-decorators/test/fixtures/ordering/finishers/exec.js
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
var log = [];
|
||||
|
||||
function push(x) { log.push(x); return x; }
|
||||
|
||||
function logFinisher(x) {
|
||||
return function (el) {
|
||||
return Object.assign(el, {
|
||||
finisher() { push(x); }
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@logFinisher(9)
|
||||
@logFinisher(8)
|
||||
class A {
|
||||
@logFinisher(1)
|
||||
@logFinisher(0)
|
||||
foo;
|
||||
|
||||
@logFinisher(3)
|
||||
@logFinisher(2)
|
||||
static bar() {}
|
||||
|
||||
@logFinisher(5)
|
||||
@logFinisher(4)
|
||||
static baz;
|
||||
|
||||
@logFinisher(7)
|
||||
@logFinisher(6)
|
||||
asd() {}
|
||||
}
|
||||
|
||||
var numsFrom0to9 = Array.from({ length: 10 }, (_, i) => i);
|
||||
expect(log).toEqual(numsFrom0to9);
|
||||
7
packages/babel-plugin-proposal-decorators/test/fixtures/ordering/options.json
vendored
Normal file
7
packages/babel-plugin-proposal-decorators/test/fixtures/ordering/options.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"plugins": [
|
||||
["proposal-decorators", { "decoratorsBeforeExport": false }],
|
||||
"proposal-class-properties",
|
||||
"external-helpers"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
var counter = 0;
|
||||
|
||||
@(x => x)
|
||||
class A {
|
||||
static foo = (() => {
|
||||
counter++;
|
||||
expect(typeof this.method).toBe("function");
|
||||
expect(this.foo).toBeUndefined();
|
||||
expect(this.bar).toBeUndefined();
|
||||
return "foo";
|
||||
})();
|
||||
|
||||
static method() {}
|
||||
|
||||
static bar = (() => {
|
||||
counter++;
|
||||
expect(typeof this.method).toBe("function");
|
||||
expect(this.foo).toBe("foo");
|
||||
expect(this.bar).toBeUndefined();
|
||||
})();
|
||||
}
|
||||
|
||||
expect(counter).toBe(2);
|
||||
4
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/arguments/input.js
vendored
Normal file
4
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/arguments/input.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
@dec(a, b, ...c)
|
||||
class A {
|
||||
@dec(a, b, ...c) method() {}
|
||||
}
|
||||
22
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/arguments/output.js
vendored
Normal file
22
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/arguments/output.js
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
let A = babelHelpers.decorate([dec(a, b, ...c)], function (_initialize) {
|
||||
"use strict";
|
||||
|
||||
class A {
|
||||
constructor() {
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: A,
|
||||
d: [{
|
||||
kind: "method",
|
||||
decorators: [dec(a, b, ...c)],
|
||||
key: "method",
|
||||
|
||||
value() {}
|
||||
|
||||
}]
|
||||
};
|
||||
});
|
||||
@ -0,0 +1,5 @@
|
||||
async function* f() {
|
||||
@(yield dec1)
|
||||
@(await dec2)
|
||||
class A {}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
{
|
||||
"plugins": [
|
||||
["proposal-decorators", { "decoratorsBeforeExport": false }],
|
||||
"proposal-class-properties",
|
||||
"external-helpers",
|
||||
"syntax-async-generators"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
async function* f() {
|
||||
let A = babelHelpers.decorate([yield dec1, await dec2], function (_initialize) {
|
||||
"use strict";
|
||||
|
||||
class A {
|
||||
constructor() {
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: A,
|
||||
d: []
|
||||
};
|
||||
});
|
||||
}
|
||||
2
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/declaration/input.js
vendored
Normal file
2
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/declaration/input.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
@dec()
|
||||
class A {}
|
||||
15
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/declaration/output.js
vendored
Normal file
15
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/declaration/output.js
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
let A = babelHelpers.decorate([dec()], function (_initialize) {
|
||||
"use strict";
|
||||
|
||||
class A {
|
||||
constructor() {
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: A,
|
||||
d: []
|
||||
};
|
||||
});
|
||||
@ -0,0 +1 @@
|
||||
export default @dec() class {}
|
||||
@ -0,0 +1,13 @@
|
||||
export default babelHelpers.decorate([dec()], function (_initialize) {
|
||||
class _class {
|
||||
constructor() {
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: _class,
|
||||
d: []
|
||||
};
|
||||
});
|
||||
@ -0,0 +1 @@
|
||||
export default @dec() class Foo {}
|
||||
@ -0,0 +1,14 @@
|
||||
let Foo = babelHelpers.decorate([dec()], function (_initialize) {
|
||||
class Foo {
|
||||
constructor() {
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: Foo,
|
||||
d: []
|
||||
};
|
||||
});
|
||||
export { Foo as default };
|
||||
1
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/expression/input.js
vendored
Normal file
1
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/expression/input.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
(@dec() class {});
|
||||
15
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/expression/output.js
vendored
Normal file
15
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/expression/output.js
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
babelHelpers.decorate([dec()], function (_initialize) {
|
||||
"use strict";
|
||||
|
||||
class _class {
|
||||
constructor() {
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: _class,
|
||||
d: []
|
||||
};
|
||||
});
|
||||
@ -0,0 +1,3 @@
|
||||
async function g() {
|
||||
@dec class A extends (await B) {}
|
||||
}
|
||||
19
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/extends-await/output.js
vendored
Normal file
19
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/extends-await/output.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
async function g() {
|
||||
let A = babelHelpers.decorate([dec], function (_initialize, _super) {
|
||||
"use strict";
|
||||
|
||||
class A extends _super {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: A,
|
||||
d: []
|
||||
};
|
||||
}, (await B));
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
function* g() {
|
||||
@dec class A extends (yield B) {}
|
||||
}
|
||||
19
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/extends-yield/output.js
vendored
Normal file
19
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/extends-yield/output.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
function* g() {
|
||||
let A = babelHelpers.decorate([dec], function (_initialize, _super) {
|
||||
"use strict";
|
||||
|
||||
class A extends _super {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: A,
|
||||
d: []
|
||||
};
|
||||
}, (yield B));
|
||||
}
|
||||
7
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/extends/exec.js
vendored
Normal file
7
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/extends/exec.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
class B {}
|
||||
|
||||
@(_ => _)
|
||||
class A extends B {}
|
||||
|
||||
expect(new A).toBeInstanceOf(A);
|
||||
expect(new A).toBeInstanceOf(B);
|
||||
1
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/extends/input.js
vendored
Normal file
1
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/extends/input.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
@dec class A extends B {}
|
||||
17
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/extends/output.js
vendored
Normal file
17
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/extends/output.js
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
let A = babelHelpers.decorate([dec], function (_initialize, _B) {
|
||||
"use strict";
|
||||
|
||||
class A extends _B {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: A,
|
||||
d: []
|
||||
};
|
||||
}, B);
|
||||
@ -0,0 +1,4 @@
|
||||
class B {
|
||||
foo = 2;
|
||||
bar() {}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
class B {
|
||||
constructor() {
|
||||
babelHelpers.defineProperty(this, "foo", 2);
|
||||
}
|
||||
|
||||
bar() {}
|
||||
|
||||
}
|
||||
7
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/options.json
vendored
Normal file
7
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/options.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"plugins": [
|
||||
["proposal-decorators", { "decoratorsBeforeExport": false }],
|
||||
"proposal-class-properties",
|
||||
"external-helpers"
|
||||
]
|
||||
}
|
||||
15
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/strict-directive/input.js
vendored
Normal file
15
packages/babel-plugin-proposal-decorators/test/fixtures/transformation/strict-directive/input.js
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
(() => {
|
||||
"use strict";
|
||||
|
||||
@dec
|
||||
class Foo {
|
||||
method() {}
|
||||
}
|
||||
});
|
||||
|
||||
(() => {
|
||||
@dec
|
||||
class Foo {
|
||||
method() {}
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,47 @@
|
||||
() => {
|
||||
"use strict";
|
||||
|
||||
let Foo = babelHelpers.decorate([dec], function (_initialize) {
|
||||
class Foo {
|
||||
constructor() {
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: Foo,
|
||||
d: [{
|
||||
kind: "method",
|
||||
key: "method",
|
||||
|
||||
value() {}
|
||||
|
||||
}]
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
() => {
|
||||
let Foo = babelHelpers.decorate([dec], function (_initialize2) {
|
||||
"use strict";
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
_initialize2(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: Foo,
|
||||
d: [{
|
||||
kind: "method",
|
||||
key: "method",
|
||||
|
||||
value() {}
|
||||
|
||||
}]
|
||||
};
|
||||
});
|
||||
};
|
||||
@ -8,20 +8,14 @@ export default declare((api, options) => {
|
||||
throw new Error("'legacy' must be a boolean.");
|
||||
}
|
||||
|
||||
if (legacy !== true) {
|
||||
throw new Error(
|
||||
"The new decorators proposal is not supported yet." +
|
||||
' You must pass the `"legacy": true` option to' +
|
||||
" @babel/plugin-syntax-decorators",
|
||||
);
|
||||
}
|
||||
|
||||
const { decoratorsBeforeExport } = options;
|
||||
if (decoratorsBeforeExport === undefined) {
|
||||
if (!legacy) {
|
||||
throw new Error(
|
||||
"The '@babel/plugin-syntax-decorators' plugin requires a" +
|
||||
" 'decoratorsBeforeExport' option, whose value must be a boolean.",
|
||||
" 'decoratorsBeforeExport' option, whose value must be a boolean." +
|
||||
" If you want to use the legacy decorators semantics, you can set" +
|
||||
" the 'legacy: true' option.",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -15,7 +15,7 @@ describe("'legacy' option", function() {
|
||||
expect(makeParser("", { legacy: "legacy" })).toThrow();
|
||||
});
|
||||
|
||||
test.skip("'legacy': false", function() {
|
||||
test("'legacy': false", function() {
|
||||
expect(makeParser("({ @dec fn() {} })", { legacy: false })).toThrow();
|
||||
});
|
||||
|
||||
@ -23,17 +23,13 @@ describe("'legacy' option", function() {
|
||||
expect(makeParser("({ @dec fn() {} })", { legacy: true })).not.toThrow();
|
||||
});
|
||||
|
||||
test.skip("defaults to 'false'", function() {
|
||||
test("defaults to 'false'", function() {
|
||||
expect(makeParser("({ @dec fn() {} })", {})).toThrow();
|
||||
});
|
||||
|
||||
test("it must be true", function() {
|
||||
expect(makeParser("", { legacy: false })).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("'decoratorsBeforeExport' option", function() {
|
||||
test.skip("must be boolean", function() {
|
||||
test("must be boolean", function() {
|
||||
expect(makeParser("", { decoratorsBeforeExport: "before" })).toThrow();
|
||||
});
|
||||
|
||||
@ -63,7 +59,7 @@ describe("'decoratorsBeforeExport' option", function() {
|
||||
(code === BEFORE ? "before" : "after") +
|
||||
"export";
|
||||
|
||||
test.skip(name, function() {
|
||||
test(name, function() {
|
||||
const expectTheParser = expect(
|
||||
makeParser(code, { decoratorsBeforeExport: before }),
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user