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;
|
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": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.0.0",
|
"@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"
|
"@babel/plugin-syntax-decorators": "^7.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@ -6,20 +6,21 @@ import legacyVisitor from "./transformer-legacy";
|
|||||||
export default declare((api, options) => {
|
export default declare((api, options) => {
|
||||||
api.assertVersion(7);
|
api.assertVersion(7);
|
||||||
|
|
||||||
const { legacy = false, decoratorsBeforeExport } = options;
|
const { legacy = false } = options;
|
||||||
if (typeof legacy !== "boolean") {
|
if (typeof legacy !== "boolean") {
|
||||||
throw new Error("'legacy' must be a boolean.");
|
throw new Error("'legacy' must be a boolean.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (legacy !== true) {
|
const { decoratorsBeforeExport } = options;
|
||||||
throw new Error(
|
if (decoratorsBeforeExport === undefined) {
|
||||||
"The new decorators proposal is not supported yet." +
|
if (!legacy) {
|
||||||
' You must pass the `"legacy": true` option to' +
|
throw new Error(
|
||||||
" @babel/plugin-proposal-decorators",
|
"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.",
|
||||||
|
);
|
||||||
if (decoratorsBeforeExport !== undefined) {
|
}
|
||||||
|
} else {
|
||||||
if (legacy) {
|
if (legacy) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'decoratorsBeforeExport' can't be used with legacy decorators.",
|
"'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.");
|
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;
|
const { decoratorsBeforeExport } = options;
|
||||||
if (decoratorsBeforeExport === undefined) {
|
if (decoratorsBeforeExport === undefined) {
|
||||||
if (!legacy) {
|
if (!legacy) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"The '@babel/plugin-syntax-decorators' plugin requires a" +
|
"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 {
|
} else {
|
||||||
|
|||||||
@ -15,7 +15,7 @@ describe("'legacy' option", function() {
|
|||||||
expect(makeParser("", { legacy: "legacy" })).toThrow();
|
expect(makeParser("", { legacy: "legacy" })).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip("'legacy': false", function() {
|
test("'legacy': false", function() {
|
||||||
expect(makeParser("({ @dec fn() {} })", { legacy: false })).toThrow();
|
expect(makeParser("({ @dec fn() {} })", { legacy: false })).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -23,17 +23,13 @@ describe("'legacy' option", function() {
|
|||||||
expect(makeParser("({ @dec fn() {} })", { legacy: true })).not.toThrow();
|
expect(makeParser("({ @dec fn() {} })", { legacy: true })).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip("defaults to 'false'", function() {
|
test("defaults to 'false'", function() {
|
||||||
expect(makeParser("({ @dec fn() {} })", {})).toThrow();
|
expect(makeParser("({ @dec fn() {} })", {})).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("it must be true", function() {
|
|
||||||
expect(makeParser("", { legacy: false })).toThrow();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("'decoratorsBeforeExport' option", function() {
|
describe("'decoratorsBeforeExport' option", function() {
|
||||||
test.skip("must be boolean", function() {
|
test("must be boolean", function() {
|
||||||
expect(makeParser("", { decoratorsBeforeExport: "before" })).toThrow();
|
expect(makeParser("", { decoratorsBeforeExport: "before" })).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -63,7 +59,7 @@ describe("'decoratorsBeforeExport' option", function() {
|
|||||||
(code === BEFORE ? "before" : "after") +
|
(code === BEFORE ? "before" : "after") +
|
||||||
"export";
|
"export";
|
||||||
|
|
||||||
test.skip(name, function() {
|
test(name, function() {
|
||||||
const expectTheParser = expect(
|
const expectTheParser = expect(
|
||||||
makeParser(code, { decoratorsBeforeExport: before }),
|
makeParser(code, { decoratorsBeforeExport: before }),
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user