Implement assumptions defined in the babel/rfcs#5 RFC
- `mutableTemplateObject` and `ignoreToPrimitiveHint` (#12408) - `setClassMethods` (#12407) - `setComputedProperties` (#12490) - `ignoreFunctionLength` (#12491) - `noDocumentAll` (#12481) - `iterableIsArray` and `arrayLikeIsIterable` (#12489) - `pureGetters` (#12504) - `skipForOfIteratorClosing` (#12496) - `objectRestNoSymbols`, `setSpreadProperties` and `pureGetters` (#12505) - `noNewArrows` (#12613, #12793) - `setPublicClassFields` and `privateFieldsAsProperties` (#12497) - `constantReexports` and `enumerableModuleMeta` (#12618) - `constantSuper`, `superIsCallableConstructor` and `noClassCalls` (#12726) Co-authored-by: Justin Ridgewell <justin@ridgewell.name> Co-authored-by: Huáng Jùnliàng <JLHwung@users.noreply.github.com>
This commit is contained in:
parent
7965c15557
commit
6ef7b51a11
@ -332,8 +332,26 @@ type EnvPath = $ReadOnly<{
|
||||
export type NestingPath = RootPath | OverridesPath | EnvPath;
|
||||
|
||||
export const assumptionsNames = new Set<string>([
|
||||
"arrayLikeIsIterable",
|
||||
"constantReexports",
|
||||
"constantSuper",
|
||||
"enumerableModuleMeta",
|
||||
"ignoreFunctionLength",
|
||||
"ignoreToPrimitiveHint",
|
||||
"iterableIsArray",
|
||||
"mutableTemplateObject",
|
||||
"noClassCalls",
|
||||
"noDocumentAll",
|
||||
"noNewArrows",
|
||||
"objectRestNoSymbols",
|
||||
"privateFieldsAsProperties",
|
||||
"pureGetters",
|
||||
"setClassMethods",
|
||||
"setComputedProperties",
|
||||
"setPublicClassFields",
|
||||
"setSpreadProperties",
|
||||
"skipForOfIteratorClosing",
|
||||
"superIsCallableConstructor",
|
||||
]);
|
||||
|
||||
function getSource(loc: NestingPath): OptionsSource {
|
||||
|
||||
@ -35,11 +35,16 @@ export function buildPrivateNamesMap(props) {
|
||||
return privateNamesMap;
|
||||
}
|
||||
|
||||
export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
|
||||
export function buildPrivateNamesNodes(
|
||||
privateNamesMap,
|
||||
privateFieldsAsProperties,
|
||||
state,
|
||||
) {
|
||||
const initNodes = [];
|
||||
|
||||
for (const [name, value] of privateNamesMap) {
|
||||
// In loose mode, both static and instance fields are transpiled using a
|
||||
// When the privateFieldsAsProperties assumption is enabled,
|
||||
// both static and instance fields are transpiled using a
|
||||
// secret non-enumerable property. Hence, we also need to generate that
|
||||
// key (using the classPrivateFieldLooseKey helper).
|
||||
// In spec mode, only instance fields need a "private name" initializer
|
||||
@ -48,7 +53,7 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
|
||||
const { static: isStatic, method: isMethod, getId, setId } = value;
|
||||
const isAccessor = getId || setId;
|
||||
const id = t.cloneNode(value.id);
|
||||
if (loose) {
|
||||
if (privateFieldsAsProperties) {
|
||||
initNodes.push(
|
||||
template.statement.ast`
|
||||
var ${id} = ${state.addHelper("classPrivateFieldLooseKey")}("${name}")
|
||||
@ -149,13 +154,13 @@ const privateInVisitor = privateNameVisitorFactory({
|
||||
if (operator !== "in") return;
|
||||
if (!path.get("left").isPrivateName()) return;
|
||||
|
||||
const { loose, privateNamesMap, redeclared } = this;
|
||||
const { privateFieldsAsProperties, privateNamesMap, redeclared } = this;
|
||||
const { name } = left.id;
|
||||
|
||||
if (!privateNamesMap.has(name)) return;
|
||||
if (redeclared && redeclared.includes(name)) return;
|
||||
|
||||
if (loose) {
|
||||
if (privateFieldsAsProperties) {
|
||||
const { id } = privateNamesMap.get(name);
|
||||
path.replaceWith(template.expression.ast`
|
||||
Object.prototype.hasOwnProperty.call(${right}, ${t.cloneNode(id)})
|
||||
@ -373,13 +378,15 @@ export function transformPrivateNamesUsage(
|
||||
ref,
|
||||
path,
|
||||
privateNamesMap,
|
||||
loose,
|
||||
{ privateFieldsAsProperties },
|
||||
state,
|
||||
) {
|
||||
if (!privateNamesMap.size) return;
|
||||
|
||||
const body = path.get("body");
|
||||
const handler = loose ? privateNameHandlerLoose : privateNameHandlerSpec;
|
||||
const handler = privateFieldsAsProperties
|
||||
? privateNameHandlerLoose
|
||||
: privateNameHandlerSpec;
|
||||
|
||||
memberExpressionToFunctions(body, privateNameVisitor, {
|
||||
privateNamesMap,
|
||||
@ -391,7 +398,7 @@ export function transformPrivateNamesUsage(
|
||||
privateNamesMap,
|
||||
classRef: ref,
|
||||
file: state,
|
||||
loose,
|
||||
privateFieldsAsProperties,
|
||||
});
|
||||
}
|
||||
|
||||
@ -573,7 +580,11 @@ function buildPrivateStaticMethodInitLoose(ref, prop, state, privateNamesMap) {
|
||||
`;
|
||||
}
|
||||
|
||||
function buildPrivateMethodDeclaration(prop, privateNamesMap, loose = false) {
|
||||
function buildPrivateMethodDeclaration(
|
||||
prop,
|
||||
privateNamesMap,
|
||||
privateFieldsAsProperties = false,
|
||||
) {
|
||||
const privateName = privateNamesMap.get(prop.node.key.id.name);
|
||||
const {
|
||||
id,
|
||||
@ -613,7 +624,7 @@ function buildPrivateMethodDeclaration(prop, privateNamesMap, loose = false) {
|
||||
t.variableDeclarator(setId, methodValue),
|
||||
]);
|
||||
}
|
||||
if (isStatic && !loose) {
|
||||
if (isStatic && !privateFieldsAsProperties) {
|
||||
return t.variableDeclaration("var", [
|
||||
t.variableDeclarator(
|
||||
t.cloneNode(id),
|
||||
@ -637,12 +648,12 @@ const thisContextVisitor = traverse.visitors.merge([
|
||||
environmentVisitor,
|
||||
]);
|
||||
|
||||
function replaceThisContext(path, ref, superRef, file, loose) {
|
||||
function replaceThisContext(path, ref, superRef, file, constantSuper) {
|
||||
const state = { classRef: ref, needsClassRef: false };
|
||||
|
||||
const replacer = new ReplaceSupers({
|
||||
methodPath: path,
|
||||
isLoose: loose,
|
||||
constantSuper,
|
||||
superRef,
|
||||
file,
|
||||
refToPreserve: ref,
|
||||
@ -666,7 +677,9 @@ export function buildFieldsInitNodes(
|
||||
props,
|
||||
privateNamesMap,
|
||||
state,
|
||||
loose,
|
||||
setPublicClassFields,
|
||||
privateFieldsAsProperties,
|
||||
constantSuper,
|
||||
) {
|
||||
const staticNodes = [];
|
||||
const instanceNodes = [];
|
||||
@ -683,39 +696,45 @@ export function buildFieldsInitNodes(
|
||||
const isMethod = !isField;
|
||||
|
||||
if (isStatic || (isMethod && isPrivate)) {
|
||||
const replaced = replaceThisContext(prop, ref, superRef, state, loose);
|
||||
const replaced = replaceThisContext(
|
||||
prop,
|
||||
ref,
|
||||
superRef,
|
||||
state,
|
||||
constantSuper,
|
||||
);
|
||||
needsClassRef = needsClassRef || replaced;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case isStatic && isPrivate && isField && loose:
|
||||
case isStatic && isPrivate && isField && privateFieldsAsProperties:
|
||||
needsClassRef = true;
|
||||
staticNodes.push(
|
||||
buildPrivateFieldInitLoose(t.cloneNode(ref), prop, privateNamesMap),
|
||||
);
|
||||
break;
|
||||
case isStatic && isPrivate && isField && !loose:
|
||||
case isStatic && isPrivate && isField && !privateFieldsAsProperties:
|
||||
needsClassRef = true;
|
||||
staticNodes.push(
|
||||
buildPrivateStaticFieldInitSpec(prop, privateNamesMap),
|
||||
);
|
||||
break;
|
||||
case isStatic && isPublic && isField && loose:
|
||||
case isStatic && isPublic && isField && setPublicClassFields:
|
||||
needsClassRef = true;
|
||||
staticNodes.push(buildPublicFieldInitLoose(t.cloneNode(ref), prop));
|
||||
break;
|
||||
case isStatic && isPublic && isField && !loose:
|
||||
case isStatic && isPublic && isField && !setPublicClassFields:
|
||||
needsClassRef = true;
|
||||
staticNodes.push(
|
||||
buildPublicFieldInitSpec(t.cloneNode(ref), prop, state),
|
||||
);
|
||||
break;
|
||||
case isInstance && isPrivate && isField && loose:
|
||||
case isInstance && isPrivate && isField && privateFieldsAsProperties:
|
||||
instanceNodes.push(
|
||||
buildPrivateFieldInitLoose(t.thisExpression(), prop, privateNamesMap),
|
||||
);
|
||||
break;
|
||||
case isInstance && isPrivate && isField && !loose:
|
||||
case isInstance && isPrivate && isField && !privateFieldsAsProperties:
|
||||
instanceNodes.push(
|
||||
buildPrivateInstanceFieldInitSpec(
|
||||
t.thisExpression(),
|
||||
@ -724,7 +743,7 @@ export function buildFieldsInitNodes(
|
||||
),
|
||||
);
|
||||
break;
|
||||
case isInstance && isPrivate && isMethod && loose:
|
||||
case isInstance && isPrivate && isMethod && privateFieldsAsProperties:
|
||||
instanceNodes.unshift(
|
||||
buildPrivateMethodInitLoose(
|
||||
t.thisExpression(),
|
||||
@ -733,10 +752,14 @@ export function buildFieldsInitNodes(
|
||||
),
|
||||
);
|
||||
staticNodes.push(
|
||||
buildPrivateMethodDeclaration(prop, privateNamesMap, loose),
|
||||
buildPrivateMethodDeclaration(
|
||||
prop,
|
||||
privateNamesMap,
|
||||
privateFieldsAsProperties,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case isInstance && isPrivate && isMethod && !loose:
|
||||
case isInstance && isPrivate && isMethod && !privateFieldsAsProperties:
|
||||
instanceNodes.unshift(
|
||||
buildPrivateInstanceMethodInitSpec(
|
||||
t.thisExpression(),
|
||||
@ -745,19 +768,27 @@ export function buildFieldsInitNodes(
|
||||
),
|
||||
);
|
||||
staticNodes.push(
|
||||
buildPrivateMethodDeclaration(prop, privateNamesMap, loose),
|
||||
buildPrivateMethodDeclaration(
|
||||
prop,
|
||||
privateNamesMap,
|
||||
privateFieldsAsProperties,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case isStatic && isPrivate && isMethod && !loose:
|
||||
case isStatic && isPrivate && isMethod && !privateFieldsAsProperties:
|
||||
needsClassRef = true;
|
||||
staticNodes.push(
|
||||
buildPrivateStaticFieldInitSpec(prop, privateNamesMap),
|
||||
);
|
||||
staticNodes.unshift(
|
||||
buildPrivateMethodDeclaration(prop, privateNamesMap, loose),
|
||||
buildPrivateMethodDeclaration(
|
||||
prop,
|
||||
privateNamesMap,
|
||||
privateFieldsAsProperties,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case isStatic && isPrivate && isMethod && loose:
|
||||
case isStatic && isPrivate && isMethod && privateFieldsAsProperties:
|
||||
needsClassRef = true;
|
||||
staticNodes.push(
|
||||
buildPrivateStaticMethodInitLoose(
|
||||
@ -768,13 +799,17 @@ export function buildFieldsInitNodes(
|
||||
),
|
||||
);
|
||||
staticNodes.unshift(
|
||||
buildPrivateMethodDeclaration(prop, privateNamesMap, loose),
|
||||
buildPrivateMethodDeclaration(
|
||||
prop,
|
||||
privateNamesMap,
|
||||
privateFieldsAsProperties,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case isInstance && isPublic && isField && loose:
|
||||
case isInstance && isPublic && isField && setPublicClassFields:
|
||||
instanceNodes.push(buildPublicFieldInitLoose(t.thisExpression(), prop));
|
||||
break;
|
||||
case isInstance && isPublic && isField && !loose:
|
||||
case isInstance && isPublic && isField && !setPublicClassFields:
|
||||
instanceNodes.push(
|
||||
buildPublicFieldInitSpec(t.thisExpression(), prop, state),
|
||||
);
|
||||
|
||||
@ -36,7 +36,38 @@ export function createClassFeaturePlugin({
|
||||
feature,
|
||||
loose,
|
||||
manipulateOptions,
|
||||
// TODO(Babel 8): Remove the default falue
|
||||
api = { assumption: () => {} },
|
||||
}) {
|
||||
const setPublicClassFields = api.assumption("setPublicClassFields");
|
||||
const privateFieldsAsProperties = api.assumption("privateFieldsAsProperties");
|
||||
const constantSuper = api.assumption("constantSuper");
|
||||
|
||||
if (loose) {
|
||||
const explicit = [];
|
||||
|
||||
if (setPublicClassFields !== undefined) {
|
||||
explicit.push(`"setPublicClassFields"`);
|
||||
}
|
||||
if (privateFieldsAsProperties !== undefined) {
|
||||
explicit.push(`"privateFieldsAsProperties"`);
|
||||
}
|
||||
if (explicit.length !== 0) {
|
||||
console.warn(
|
||||
`[${name}]: You are using the "loose: true" option and you are` +
|
||||
` explicitly setting a value for the ${explicit.join(" and ")}` +
|
||||
` assumption${explicit.length > 1 ? "s" : ""}. The "loose" option` +
|
||||
` can cause incompatibilities with the other class features` +
|
||||
` plugins, so it's recommended that you replace it with the` +
|
||||
` following top-level option:\n` +
|
||||
`\t"assumptions": {\n` +
|
||||
`\t\t"setPublicClassFields": true,\n` +
|
||||
`\t\t"privateFieldsAsProperties": true\n` +
|
||||
`\t}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
manipulateOptions,
|
||||
@ -151,11 +182,17 @@ export function createClassFeaturePlugin({
|
||||
const privateNamesMap = buildPrivateNamesMap(props);
|
||||
const privateNamesNodes = buildPrivateNamesNodes(
|
||||
privateNamesMap,
|
||||
loose,
|
||||
privateFieldsAsProperties ?? loose,
|
||||
state,
|
||||
);
|
||||
|
||||
transformPrivateNamesUsage(ref, path, privateNamesMap, loose, state);
|
||||
transformPrivateNamesUsage(
|
||||
ref,
|
||||
path,
|
||||
privateNamesMap,
|
||||
{ privateFieldsAsProperties: privateFieldsAsProperties ?? loose },
|
||||
state,
|
||||
);
|
||||
|
||||
let keysNodes, staticNodes, instanceNodes, wrapClass;
|
||||
|
||||
@ -175,7 +212,9 @@ export function createClassFeaturePlugin({
|
||||
props,
|
||||
privateNamesMap,
|
||||
state,
|
||||
loose,
|
||||
setPublicClassFields ?? loose,
|
||||
privateFieldsAsProperties ?? loose,
|
||||
constantSuper ?? loose,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
class A {
|
||||
foo;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
{
|
||||
"validateLogs": true,
|
||||
"plugins": [
|
||||
["proposal-class-properties", { "loose": true }]
|
||||
],
|
||||
"assumptions": {
|
||||
"setPublicClassFields": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
class A {
|
||||
constructor() {
|
||||
this.foo = void 0;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
[proposal-class-properties]: You are using the "loose: true" option and you are explicitly setting a value for the "setPublicClassFields" assumption. The "loose" option can cause incompatibilities with the other class features plugins, so it's recommended that you replace it with the following top-level option:
|
||||
"assumptions": {
|
||||
"setPublicClassFields": true,
|
||||
"privateFieldsAsProperties": true
|
||||
}
|
||||
@ -27,14 +27,19 @@ export { hasExports, isSideEffectImport, isModule, rewriteThis };
|
||||
export function rewriteModuleStatementsAndPrepareHeader(
|
||||
path: NodePath,
|
||||
{
|
||||
// TODO(Babel 8): Remove this
|
||||
loose,
|
||||
|
||||
exportName,
|
||||
strict,
|
||||
allowTopLevelThis,
|
||||
strictMode,
|
||||
loose,
|
||||
noInterop,
|
||||
lazy,
|
||||
esNamespaceOnly,
|
||||
|
||||
constantReexports = loose,
|
||||
enumerableModuleMeta = loose,
|
||||
},
|
||||
) {
|
||||
assert(isModule(path), "Cannot process module statements in a script");
|
||||
@ -42,7 +47,7 @@ export function rewriteModuleStatementsAndPrepareHeader(
|
||||
|
||||
const meta = normalizeAndLoadModuleMetadata(path, exportName, {
|
||||
noInterop,
|
||||
loose,
|
||||
initializeReexports: constantReexports,
|
||||
lazy,
|
||||
esNamespaceOnly,
|
||||
});
|
||||
@ -67,7 +72,7 @@ export function rewriteModuleStatementsAndPrepareHeader(
|
||||
|
||||
const headers = [];
|
||||
if (hasExports(meta) && !strict) {
|
||||
headers.push(buildESModuleHeader(meta, loose /* enumerable */));
|
||||
headers.push(buildESModuleHeader(meta, enumerableModuleMeta));
|
||||
}
|
||||
|
||||
const nameList = buildExportNameListDeclaration(path, meta);
|
||||
@ -78,7 +83,9 @@ export function rewriteModuleStatementsAndPrepareHeader(
|
||||
}
|
||||
|
||||
// Create all of the statically known named exports.
|
||||
headers.push(...buildExportInitializationStatements(path, meta, loose));
|
||||
headers.push(
|
||||
...buildExportInitializationStatements(path, meta, constantReexports),
|
||||
);
|
||||
|
||||
return { meta, headers };
|
||||
}
|
||||
@ -128,7 +135,7 @@ export function wrapInterop(
|
||||
export function buildNamespaceInitStatements(
|
||||
metadata: ModuleMetadata,
|
||||
sourceMetadata: SourceModuleMetadata,
|
||||
loose: boolean = false,
|
||||
constantReexports: boolean = false,
|
||||
) {
|
||||
const statements = [];
|
||||
|
||||
@ -146,8 +153,8 @@ export function buildNamespaceInitStatements(
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (loose) {
|
||||
statements.push(...buildReexportsFromMeta(metadata, sourceMetadata, loose));
|
||||
if (constantReexports) {
|
||||
statements.push(...buildReexportsFromMeta(metadata, sourceMetadata, true));
|
||||
}
|
||||
for (const exportName of sourceMetadata.reexportNamespace) {
|
||||
// Assign export to namespace object.
|
||||
@ -172,7 +179,7 @@ export function buildNamespaceInitStatements(
|
||||
const statement = buildNamespaceReexport(
|
||||
metadata,
|
||||
t.cloneNode(srcNamespace),
|
||||
loose,
|
||||
constantReexports,
|
||||
);
|
||||
statement.loc = sourceMetadata.reexportAll.loc;
|
||||
|
||||
@ -183,8 +190,8 @@ export function buildNamespaceInitStatements(
|
||||
}
|
||||
|
||||
const ReexportTemplate = {
|
||||
loose: template.statement`EXPORTS.EXPORT_NAME = NAMESPACE_IMPORT;`,
|
||||
looseComputed: template.statement`EXPORTS["EXPORT_NAME"] = NAMESPACE_IMPORT;`,
|
||||
constant: template.statement`EXPORTS.EXPORT_NAME = NAMESPACE_IMPORT;`,
|
||||
constantComputed: template.statement`EXPORTS["EXPORT_NAME"] = NAMESPACE_IMPORT;`,
|
||||
spec: template`
|
||||
Object.defineProperty(EXPORTS, "EXPORT_NAME", {
|
||||
enumerable: true,
|
||||
@ -198,7 +205,7 @@ const ReexportTemplate = {
|
||||
const buildReexportsFromMeta = (
|
||||
meta: ModuleMetadata,
|
||||
metadata: SourceModuleMetadata,
|
||||
loose,
|
||||
constantReexports: boolean,
|
||||
) => {
|
||||
const namespace = metadata.lazy
|
||||
? t.callExpression(t.identifier(metadata.name), [])
|
||||
@ -224,11 +231,11 @@ const buildReexportsFromMeta = (
|
||||
EXPORT_NAME: exportName,
|
||||
NAMESPACE_IMPORT,
|
||||
};
|
||||
if (loose) {
|
||||
if (constantReexports) {
|
||||
if (stringSpecifiers.has(exportName)) {
|
||||
return ReexportTemplate.looseComputed(astNodes);
|
||||
return ReexportTemplate.constantComputed(astNodes);
|
||||
} else {
|
||||
return ReexportTemplate.loose(astNodes);
|
||||
return ReexportTemplate.constant(astNodes);
|
||||
}
|
||||
} else {
|
||||
return ReexportTemplate.spec(astNodes);
|
||||
@ -241,9 +248,9 @@ const buildReexportsFromMeta = (
|
||||
*/
|
||||
function buildESModuleHeader(
|
||||
metadata: ModuleMetadata,
|
||||
enumerable: boolean = false,
|
||||
enumerableModuleMeta: boolean = false,
|
||||
) {
|
||||
return (enumerable
|
||||
return (enumerableModuleMeta
|
||||
? template.statement`
|
||||
EXPORTS.__esModule = true;
|
||||
`
|
||||
@ -257,8 +264,8 @@ function buildESModuleHeader(
|
||||
/**
|
||||
* Create a re-export initialization loop for a specific imported namespace.
|
||||
*/
|
||||
function buildNamespaceReexport(metadata, namespace, loose) {
|
||||
return (loose
|
||||
function buildNamespaceReexport(metadata, namespace, constantReexports) {
|
||||
return (constantReexports
|
||||
? template.statement`
|
||||
Object.keys(NAMESPACE).forEach(function(key) {
|
||||
if (key === "default" || key === "__esModule") return;
|
||||
@ -347,7 +354,7 @@ function buildExportNameListDeclaration(
|
||||
function buildExportInitializationStatements(
|
||||
programPath: NodePath,
|
||||
metadata: ModuleMetadata,
|
||||
loose: boolean = false,
|
||||
constantReexports: boolean = false,
|
||||
) {
|
||||
const initStatements = [];
|
||||
|
||||
@ -365,8 +372,8 @@ function buildExportInitializationStatements(
|
||||
}
|
||||
|
||||
for (const data of metadata.source.values()) {
|
||||
if (!loose) {
|
||||
initStatements.push(...buildReexportsFromMeta(metadata, data, loose));
|
||||
if (!constantReexports) {
|
||||
initStatements.push(...buildReexportsFromMeta(metadata, data, false));
|
||||
}
|
||||
for (const exportName of data.reexportNamespace) {
|
||||
exportNames.push(exportName);
|
||||
|
||||
@ -86,7 +86,7 @@ export default function normalizeModuleAndLoadMetadata(
|
||||
exportName?: string,
|
||||
{
|
||||
noInterop = false,
|
||||
loose = false,
|
||||
initializeReexports = false,
|
||||
lazy = false,
|
||||
esNamespaceOnly = false,
|
||||
} = {},
|
||||
@ -100,10 +100,7 @@ export default function normalizeModuleAndLoadMetadata(
|
||||
|
||||
const { local, source, hasExports } = getModuleMetadata(
|
||||
programPath,
|
||||
{
|
||||
loose,
|
||||
lazy,
|
||||
},
|
||||
{ initializeReexports, lazy },
|
||||
stringSpecifiers,
|
||||
);
|
||||
|
||||
@ -170,12 +167,15 @@ function getExportSpecifierName(
|
||||
*/
|
||||
function getModuleMetadata(
|
||||
programPath: NodePath,
|
||||
{ loose, lazy }: { loose: boolean, lazy: boolean },
|
||||
{
|
||||
lazy,
|
||||
initializeReexports,
|
||||
}: { lazy: boolean, initializeReexports: boolean },
|
||||
stringSpecifiers: Set<string>,
|
||||
) {
|
||||
const localData = getLocalExportMetadata(
|
||||
programPath,
|
||||
loose,
|
||||
initializeReexports,
|
||||
stringSpecifiers,
|
||||
);
|
||||
|
||||
@ -361,7 +361,7 @@ function getModuleMetadata(
|
||||
*/
|
||||
function getLocalExportMetadata(
|
||||
programPath: NodePath,
|
||||
loose: boolean,
|
||||
initializeReexports: boolean,
|
||||
stringSpecifiers: Set<string>,
|
||||
): Map<string, LocalExportMetadata> {
|
||||
const bindingKindLookup = new Map();
|
||||
@ -376,7 +376,7 @@ function getLocalExportMetadata(
|
||||
if (child.node.declaration) {
|
||||
child = child.get("declaration");
|
||||
} else if (
|
||||
loose &&
|
||||
initializeReexports &&
|
||||
child.node.source &&
|
||||
child.get("source").isStringLiteral()
|
||||
) {
|
||||
@ -429,7 +429,10 @@ function getLocalExportMetadata(
|
||||
};
|
||||
|
||||
programPath.get("body").forEach(child => {
|
||||
if (child.isExportNamedDeclaration() && (loose || !child.node.source)) {
|
||||
if (
|
||||
child.isExportNamedDeclaration() &&
|
||||
(initializeReexports || !child.node.source)
|
||||
) {
|
||||
if (child.node.declaration) {
|
||||
const declaration = child.get("declaration");
|
||||
const ids = declaration.getOuterBindingIdentifierPaths();
|
||||
|
||||
@ -31,6 +31,7 @@ const awaitVisitor = {
|
||||
export default function (
|
||||
path: NodePath,
|
||||
helpers: { wrapAsync: Object, wrapAwait: Object },
|
||||
noNewArrows?: boolean,
|
||||
) {
|
||||
path.traverse(awaitVisitor, {
|
||||
wrapAwait: helpers.wrapAwait,
|
||||
@ -41,7 +42,7 @@ export default function (
|
||||
path.node.async = false;
|
||||
path.node.generator = true;
|
||||
|
||||
wrapFunction(path, t.cloneNode(helpers.wrapAsync));
|
||||
wrapFunction(path, t.cloneNode(helpers.wrapAsync), noNewArrows);
|
||||
|
||||
const isProperty =
|
||||
path.isObjectMethod() ||
|
||||
|
||||
@ -255,7 +255,7 @@ const looseHandlers = {
|
||||
type ReplaceSupersOptionsBase = {|
|
||||
methodPath: NodePath,
|
||||
superRef: Object,
|
||||
isLoose: boolean,
|
||||
constantSuper: boolean,
|
||||
file: any,
|
||||
// objectRef might have been shadowed in child scopes,
|
||||
// in that case, we need to rename related variables.
|
||||
@ -284,13 +284,16 @@ export default class ReplaceSupers {
|
||||
|
||||
this.file = opts.file;
|
||||
this.superRef = opts.superRef;
|
||||
this.isLoose = opts.isLoose;
|
||||
this.constantSuper = process.env.BABEL_8_BREAKING
|
||||
? opts.constantSuper
|
||||
: // Fallback to isLoose for backward compatibility
|
||||
opts.constantSuper ?? (opts: any).isLoose;
|
||||
this.opts = opts;
|
||||
}
|
||||
|
||||
declare file: HubInterface;
|
||||
declare isDerivedConstructor: boolean;
|
||||
declare isLoose: boolean;
|
||||
declare constantSuper: boolean;
|
||||
declare isPrivateMethod: boolean;
|
||||
declare isStatic: boolean;
|
||||
declare methodPath: NodePath;
|
||||
@ -309,7 +312,7 @@ export default class ReplaceSupers {
|
||||
});
|
||||
}
|
||||
|
||||
const handler = this.isLoose ? looseHandlers : specHandlers;
|
||||
const handler = this.constantSuper ? looseHandlers : specHandlers;
|
||||
|
||||
memberExpressionToFunctions(this.methodPath, visitor, {
|
||||
file: this.file,
|
||||
|
||||
@ -57,7 +57,7 @@ function classOrObjectMethod(path: NodePath, callId: Object) {
|
||||
.unwrapFunctionEnvironment();
|
||||
}
|
||||
|
||||
function plainFunction(path: NodePath, callId: Object) {
|
||||
function plainFunction(path: NodePath, callId: Object, noNewArrows: boolean) {
|
||||
const node = path.node;
|
||||
const isDeclaration = path.isFunctionDeclaration();
|
||||
const functionId = node.id;
|
||||
@ -68,7 +68,7 @@ function plainFunction(path: NodePath, callId: Object) {
|
||||
: buildAnonymousExpressionWrapper;
|
||||
|
||||
if (path.isArrowFunctionExpression()) {
|
||||
path.arrowFunctionToExpression();
|
||||
path.arrowFunctionToExpression({ noNewArrows });
|
||||
}
|
||||
|
||||
node.id = null;
|
||||
@ -123,10 +123,15 @@ function plainFunction(path: NodePath, callId: Object) {
|
||||
}
|
||||
}
|
||||
|
||||
export default function wrapFunction(path: NodePath, callId: Object) {
|
||||
export default function wrapFunction(
|
||||
path: NodePath,
|
||||
callId: Object,
|
||||
// TODO(Babel 8): Consider defaulting to false for spec compliancy
|
||||
noNewArrows: boolean = true,
|
||||
) {
|
||||
if (path.isMethod()) {
|
||||
classOrObjectMethod(path, callId);
|
||||
} else {
|
||||
plainFunction(path, callId);
|
||||
plainFunction(path, callId, noNewArrows);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,6 +70,8 @@ export default declare(api => {
|
||||
|
||||
path.traverse(yieldStarVisitor, state);
|
||||
|
||||
// We don't need to pass the noNewArrows assumption, since
|
||||
// async generators are never arrow functions.
|
||||
remapAsyncToGenerator(path, {
|
||||
wrapAsync: state.addHelper("wrapAsyncGenerator"),
|
||||
wrapAwait: state.addHelper("awaitAsyncGenerator"),
|
||||
|
||||
@ -12,6 +12,7 @@ export default declare((api, options) => {
|
||||
return createClassFeaturePlugin({
|
||||
name: "proposal-class-properties",
|
||||
|
||||
api,
|
||||
feature: FEATURES.fields,
|
||||
loose: options.loose,
|
||||
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
const actualOrder = [];
|
||||
|
||||
const track = i => {
|
||||
actualOrder.push(i);
|
||||
return i;
|
||||
};
|
||||
|
||||
class MyClass {
|
||||
static [track(1)] = track(10);
|
||||
[track(2)] = track(13);
|
||||
get [track(3)]() {
|
||||
return "foo";
|
||||
}
|
||||
set [track(4)](value) {
|
||||
this.bar = value;
|
||||
}
|
||||
[track(5)] = track(14);
|
||||
static [track(6)] = track(11);
|
||||
static [track(7)] = track(12);
|
||||
[track(8)]() {}
|
||||
[track(9)] = track(15);
|
||||
}
|
||||
|
||||
const inst = new MyClass();
|
||||
|
||||
const expectedOrder = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
expect(actualOrder).toEqual(expectedOrder);
|
||||
|
||||
expect(MyClass[1]).toBe(10);
|
||||
expect(inst[2]).toBe(13);
|
||||
expect(inst[3]).toBe("foo");
|
||||
inst[4] = "baz";
|
||||
expect(inst.bar).toBe("baz");
|
||||
expect(inst[5]).toBe(14);
|
||||
expect(MyClass[6]).toBe(11);
|
||||
expect(MyClass[7]).toBe(12);
|
||||
expect(typeof inst[8]).toBe("function");
|
||||
expect(inst[9]).toBe(15);
|
||||
@ -0,0 +1,25 @@
|
||||
const foo = "foo";
|
||||
const bar = () => {};
|
||||
const four = 4;
|
||||
|
||||
class MyClass {
|
||||
static [one()] = "test";
|
||||
static [2 * 4 + 7] = "247";
|
||||
static [2 * four + 7] = "247";
|
||||
static [2 * four + seven] = "247";
|
||||
[null] = "null";
|
||||
[undefined] = "undefined";
|
||||
[void 0] = "void 0";
|
||||
get ["whatever"]() {}
|
||||
set ["whatever"](value) {}
|
||||
get [computed()]() {}
|
||||
set [computed()](value) {}
|
||||
["test" + one]() {}
|
||||
static [10]() {}
|
||||
[/regex/] = "regex";
|
||||
[foo] = "foo";
|
||||
[bar] = "bar";
|
||||
[baz] = "baz";
|
||||
[`template`] = "template";
|
||||
[`template${expression}`] = "template-with-expression";
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
let _one, _ref, _undefined, _computed, _computed2, _ref2, _ref3, _baz, _ref4;
|
||||
|
||||
const foo = "foo";
|
||||
|
||||
const bar = () => {};
|
||||
|
||||
const four = 4;
|
||||
_one = one();
|
||||
_ref = 2 * four + seven;
|
||||
_undefined = undefined;
|
||||
_computed = computed();
|
||||
_computed2 = computed();
|
||||
_ref2 = "test" + one;
|
||||
_ref3 = /regex/;
|
||||
_baz = baz;
|
||||
_ref4 = `template${expression}`;
|
||||
|
||||
class MyClass {
|
||||
constructor() {
|
||||
this[null] = "null";
|
||||
this[_undefined] = "undefined";
|
||||
this[void 0] = "void 0";
|
||||
this[_ref3] = "regex";
|
||||
this[foo] = "foo";
|
||||
this[bar] = "bar";
|
||||
this[_baz] = "baz";
|
||||
this[`template`] = "template";
|
||||
this[_ref4] = "template-with-expression";
|
||||
}
|
||||
|
||||
get ["whatever"]() {}
|
||||
|
||||
set ["whatever"](value) {}
|
||||
|
||||
get [_computed]() {}
|
||||
|
||||
set [_computed2](value) {}
|
||||
|
||||
[_ref2]() {}
|
||||
|
||||
static [10]() {}
|
||||
|
||||
}
|
||||
|
||||
MyClass[_one] = "test";
|
||||
MyClass[2 * 4 + 7] = "247";
|
||||
MyClass[2 * four + 7] = "247";
|
||||
MyClass[_ref] = "247";
|
||||
@ -0,0 +1,11 @@
|
||||
var foo = "bar";
|
||||
|
||||
class Foo {
|
||||
bar = foo;
|
||||
static bar = baz;
|
||||
|
||||
constructor() {
|
||||
var foo = "foo";
|
||||
var baz = "baz";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
var foo = "bar";
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
this.bar = foo;
|
||||
var _foo = "foo";
|
||||
var baz = "baz";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Foo.bar = baz;
|
||||
@ -0,0 +1,3 @@
|
||||
class Foo extends Bar {
|
||||
bar = "foo";
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
class Foo extends Bar {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this.bar = "foo";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
class Child extends Parent {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
scopedFunctionWithThis = () => {
|
||||
this.name = {};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
{
|
||||
"plugins": [
|
||||
["external-helpers", { "helperVersion": "7.100.0" }],
|
||||
"proposal-class-properties"
|
||||
],
|
||||
"presets": ["env"],
|
||||
"assumptions": {
|
||||
"setPublicClassFields": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
var Child = /*#__PURE__*/function (_Parent) {
|
||||
"use strict";
|
||||
|
||||
babelHelpers.inherits(Child, _Parent);
|
||||
|
||||
var _super = babelHelpers.createSuper(Child);
|
||||
|
||||
function Child() {
|
||||
var _this;
|
||||
|
||||
babelHelpers.classCallCheck(this, Child);
|
||||
_this = _super.call(this);
|
||||
|
||||
_this.scopedFunctionWithThis = function () {
|
||||
_this.name = {};
|
||||
};
|
||||
|
||||
return _this;
|
||||
}
|
||||
|
||||
return Child;
|
||||
}(Parent);
|
||||
@ -0,0 +1,13 @@
|
||||
function test(x) {
|
||||
class F {
|
||||
[x] = 1;
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
x = 'deadbeef';
|
||||
expect(new F().foo).toBe(1);
|
||||
x = 'wrong';
|
||||
expect(new F().foo).toBe(1);
|
||||
}
|
||||
|
||||
test('foo');
|
||||
@ -0,0 +1,13 @@
|
||||
function test(x) {
|
||||
class F {
|
||||
[x] = 1;
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
x = 'deadbeef';
|
||||
expect(new F().foo).toBe(1);
|
||||
x = 'wrong';
|
||||
expect(new F().foo).toBe(1);
|
||||
}
|
||||
|
||||
test('foo');
|
||||
@ -0,0 +1,19 @@
|
||||
function test(x) {
|
||||
let _x;
|
||||
|
||||
_x = x;
|
||||
|
||||
class F {
|
||||
constructor() {
|
||||
this[_x] = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
x = 'deadbeef';
|
||||
expect(new F().foo).toBe(1);
|
||||
x = 'wrong';
|
||||
expect(new F().foo).toBe(1);
|
||||
}
|
||||
|
||||
test('foo');
|
||||
@ -0,0 +1,3 @@
|
||||
class Foo {
|
||||
bar;
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
constructor() {
|
||||
this.bar = void 0;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
class Foo {
|
||||
bar = "foo";
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
constructor() {
|
||||
this.bar = "foo";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
export default param =>
|
||||
class App {
|
||||
static props = {
|
||||
prop1: 'prop1',
|
||||
prop2: 'prop2'
|
||||
}
|
||||
|
||||
getParam() {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
export default (param => {
|
||||
var _class, _temp;
|
||||
|
||||
return _temp = _class = class App {
|
||||
getParam() {
|
||||
return param;
|
||||
}
|
||||
|
||||
}, _class.props = {
|
||||
prop1: 'prop1',
|
||||
prop2: 'prop2'
|
||||
}, _temp;
|
||||
});
|
||||
@ -0,0 +1,10 @@
|
||||
{
|
||||
"plugins": [
|
||||
["external-helpers", { "helperVersion": "7.100.0" }],
|
||||
"proposal-class-properties",
|
||||
"syntax-class-properties"
|
||||
],
|
||||
"assumptions": {
|
||||
"setPublicClassFields": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
call(class {
|
||||
static test = true
|
||||
});
|
||||
|
||||
export default class {
|
||||
static test = true
|
||||
};
|
||||
@ -0,0 +1,6 @@
|
||||
var _class, _temp;
|
||||
|
||||
call((_temp = _class = class {}, _class.test = true, _temp));
|
||||
export default class _class2 {}
|
||||
_class2.test = true;
|
||||
;
|
||||
@ -0,0 +1,14 @@
|
||||
function withContext(ComposedComponent) {
|
||||
return class WithContext extends Component {
|
||||
|
||||
static propTypes = {
|
||||
context: PropTypes.shape(
|
||||
{
|
||||
addCss: PropTypes.func,
|
||||
setTitle: PropTypes.func,
|
||||
setMeta: PropTypes.func,
|
||||
}
|
||||
),
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
function withContext(ComposedComponent) {
|
||||
var _class, _temp;
|
||||
|
||||
return _temp = _class = class WithContext extends Component {}, _class.propTypes = {
|
||||
context: PropTypes.shape({
|
||||
addCss: PropTypes.func,
|
||||
setTitle: PropTypes.func,
|
||||
setMeta: PropTypes.func
|
||||
})
|
||||
}, _temp;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
class MyClass {
|
||||
myAsyncMethod = async () => {
|
||||
console.log(this);
|
||||
}
|
||||
}
|
||||
|
||||
(class MyClass2 {
|
||||
myAsyncMethod = async () => {
|
||||
console.log(this);
|
||||
}
|
||||
})
|
||||
|
||||
export default class MyClass3 {
|
||||
myAsyncMethod = async () => {
|
||||
console.log(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
{
|
||||
"plugins": [
|
||||
"external-helpers",
|
||||
"transform-async-to-generator",
|
||||
"proposal-class-properties"
|
||||
],
|
||||
"assumptions": {
|
||||
"setPublicClassFields": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
class MyClass {
|
||||
constructor() {
|
||||
var _this = this;
|
||||
|
||||
this.myAsyncMethod = /*#__PURE__*/babelHelpers.asyncToGenerator(function* () {
|
||||
console.log(_this);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(class MyClass2 {
|
||||
constructor() {
|
||||
var _this2 = this;
|
||||
|
||||
this.myAsyncMethod = /*#__PURE__*/babelHelpers.asyncToGenerator(function* () {
|
||||
console.log(_this2);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
export default class MyClass3 {
|
||||
constructor() {
|
||||
var _this3 = this;
|
||||
|
||||
this.myAsyncMethod = /*#__PURE__*/babelHelpers.asyncToGenerator(function* () {
|
||||
console.log(_this3);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
export class MyClass {
|
||||
static property = value;
|
||||
}
|
||||
|
||||
export default class MyClass2 {
|
||||
static property = value;
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
export class MyClass {}
|
||||
MyClass.property = value;
|
||||
export default class MyClass2 {}
|
||||
MyClass2.property = value;
|
||||
@ -0,0 +1,7 @@
|
||||
var Foo = class {
|
||||
static num = 0;
|
||||
}
|
||||
|
||||
expect(Foo.num).toBe(0);
|
||||
expect(Foo.num = 1).toBe(1);
|
||||
expect(Foo.name).toBe("Foo");
|
||||
@ -0,0 +1,3 @@
|
||||
var Foo = class {
|
||||
static num = 0;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
var _class, _temp;
|
||||
|
||||
var Foo = (_temp = _class = class Foo {}, _class.num = 0, _temp);
|
||||
@ -0,0 +1,9 @@
|
||||
class A {
|
||||
static prop = 1;
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
static prop = 2;
|
||||
static propA = super.prop;
|
||||
static getPropA = () => super.prop;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
{
|
||||
"validateLogs": true,
|
||||
"plugins": [
|
||||
["external-helpers", { "helperVersion": "7.100.0" }],
|
||||
["proposal-class-properties", { "loose": true }],
|
||||
"syntax-class-properties"
|
||||
],
|
||||
"assumptions": {
|
||||
"setPublicClassFields": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
class A {}
|
||||
|
||||
A.prop = 1;
|
||||
|
||||
class B extends A {}
|
||||
|
||||
B.prop = 2;
|
||||
B.propA = A.prop;
|
||||
|
||||
B.getPropA = () => A.prop;
|
||||
@ -0,0 +1,5 @@
|
||||
[proposal-class-properties]: You are using the "loose: true" option and you are explicitly setting a value for the "setPublicClassFields" assumption. The "loose" option can cause incompatibilities with the other class features plugins, so it's recommended that you replace it with the following top-level option:
|
||||
"assumptions": {
|
||||
"setPublicClassFields": true,
|
||||
"privateFieldsAsProperties": true
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
class A {
|
||||
static prop = 1;
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
static prop = 2;
|
||||
static propA = super.prop;
|
||||
static getPropA = () => super.prop;
|
||||
}
|
||||
|
||||
const { prop, propA, getPropA } = B;
|
||||
|
||||
expect(prop).toBe(2);
|
||||
expect(propA).toBe(1);
|
||||
expect(getPropA()).toBe(1);
|
||||
@ -0,0 +1,9 @@
|
||||
class A {
|
||||
static prop = 1;
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
static prop = 2;
|
||||
static propA = super.prop;
|
||||
static getPropA = () => super.prop;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
class A {}
|
||||
|
||||
A.prop = 1;
|
||||
|
||||
class B extends A {}
|
||||
|
||||
B.prop = 2;
|
||||
B.propA = babelHelpers.get(babelHelpers.getPrototypeOf(B), "prop", B);
|
||||
|
||||
B.getPropA = () => babelHelpers.get(babelHelpers.getPrototypeOf(B), "prop", B);
|
||||
@ -0,0 +1,9 @@
|
||||
class A {
|
||||
static self = this;
|
||||
static getA = () => this;
|
||||
}
|
||||
|
||||
const { self, getA } = A;
|
||||
|
||||
expect(self).toBe(A);
|
||||
expect(getA()).toBe(A);
|
||||
@ -0,0 +1,4 @@
|
||||
class A {
|
||||
static self = this;
|
||||
static getA = () => this;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
class A {}
|
||||
|
||||
A.self = A;
|
||||
|
||||
A.getA = () => A;
|
||||
@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
static num;
|
||||
}
|
||||
|
||||
expect("num" in Foo).toBe(true);
|
||||
expect(Foo.num).toBeUndefined();
|
||||
@ -0,0 +1,3 @@
|
||||
class Foo {
|
||||
static bar;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
class Foo {}
|
||||
|
||||
Foo.bar = void 0;
|
||||
@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
static num = 0;
|
||||
static str = "foo";
|
||||
}
|
||||
|
||||
expect(Foo.num).toBe(0);
|
||||
expect(Foo.num = 1).toBe(1);
|
||||
expect(Foo.str).toBe("foo");
|
||||
expect(Foo.str = "bar").toBe("bar");
|
||||
@ -0,0 +1,3 @@
|
||||
class Foo {
|
||||
static bar = "foo";
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
class Foo {}
|
||||
|
||||
Foo.bar = "foo";
|
||||
@ -0,0 +1,9 @@
|
||||
class A {
|
||||
foo() {
|
||||
return "bar";
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
foo = super.foo();
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
class A {
|
||||
foo() {
|
||||
return "bar";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this.foo = super.foo();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
class Foo extends Bar {
|
||||
bar = "foo";
|
||||
|
||||
constructor() {
|
||||
foo(super());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
class Foo extends Bar {
|
||||
constructor() {
|
||||
var _temp;
|
||||
|
||||
foo((_temp = super(), this.bar = "foo", _temp));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
class Foo extends Bar {
|
||||
bar = "foo";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
class Foo extends Bar {
|
||||
constructor() {
|
||||
super();
|
||||
this.bar = "foo";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
class A {
|
||||
force = force;
|
||||
foo = super.method();
|
||||
|
||||
constructor(force) {}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
class A {
|
||||
constructor(_force) {
|
||||
this.force = force;
|
||||
this.foo = super.method();
|
||||
}
|
||||
|
||||
}
|
||||
@ -50,6 +50,7 @@ export default declare((api, options) => {
|
||||
return createClassFeaturePlugin({
|
||||
name: "proposal-decorators",
|
||||
|
||||
api,
|
||||
feature: FEATURES.decorators,
|
||||
// loose: options.loose, Not supported
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import { types as t, template } from "@babel/core";
|
||||
|
||||
export default declare((api, { loose = false }) => {
|
||||
api.assertVersion(7);
|
||||
const noDocumentAll = api.assumption("noDocumentAll") ?? loose;
|
||||
|
||||
return {
|
||||
name: "proposal-nullish-coalescing-operator",
|
||||
@ -38,7 +39,7 @@ export default declare((api, { loose = false }) => {
|
||||
t.conditionalExpression(
|
||||
// We cannot use `!= null` in spec mode because
|
||||
// `document.all == null` and `document.all` is not "nullish".
|
||||
loose
|
||||
noDocumentAll
|
||||
? t.binaryExpression("!=", assignment, t.nullLiteral())
|
||||
: t.logicalExpression(
|
||||
"&&",
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": ["proposal-nullish-coalescing-operator"],
|
||||
"assumptions": {
|
||||
"noDocumentAll": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
expect(null ?? undefined).toBeUndefined(undefined);
|
||||
expect(undefined ?? null).toBeNull();
|
||||
expect(false ?? true).toBe(false);
|
||||
expect(0 ?? 1).toBe(0);
|
||||
expect("" ?? "foo").toBe("");
|
||||
|
||||
var obj = { exists: true };
|
||||
expect(obj.exists ?? false).toBe(true);
|
||||
expect(obj.doesNotExist ?? "foo").toBe("foo");
|
||||
|
||||
var counter = 0;
|
||||
function sideEffect() { return counter++; }
|
||||
expect(sideEffect() ?? -1).toBe(0);
|
||||
|
||||
var counter2 = 0;
|
||||
var obj2 = {
|
||||
get foo() { return counter2++; }
|
||||
};
|
||||
expect(obj2.foo ?? -1).toBe(0);
|
||||
@ -0,0 +1 @@
|
||||
var { qux = foo.bar ?? "qux" } = {};
|
||||
@ -0,0 +1,5 @@
|
||||
var _foo$bar;
|
||||
|
||||
var {
|
||||
qux = (_foo$bar = foo.bar) != null ? _foo$bar : "qux"
|
||||
} = {};
|
||||
@ -0,0 +1,3 @@
|
||||
function foo(foo, qux = foo.bar ?? "qux") {}
|
||||
|
||||
function bar(bar, qux = bar ?? "qux") {}
|
||||
@ -0,0 +1,7 @@
|
||||
function foo(foo, qux = (() => {
|
||||
var _foo$bar;
|
||||
|
||||
return (_foo$bar = foo.bar) != null ? _foo$bar : "qux";
|
||||
})()) {}
|
||||
|
||||
function bar(bar, qux = bar != null ? bar : "qux") {}
|
||||
@ -0,0 +1,3 @@
|
||||
function foo(opts) {
|
||||
var foo = opts.foo ?? "default";
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
function foo(opts) {
|
||||
var _opts$foo;
|
||||
|
||||
var foo = (_opts$foo = opts.foo) != null ? _opts$foo : "default";
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
function foo(foo, bar = foo ?? "bar") {}
|
||||
@ -0,0 +1 @@
|
||||
function foo(foo, bar = foo != null ? foo : "bar") {}
|
||||
@ -0,0 +1,3 @@
|
||||
function foo() {
|
||||
var foo = this ?? {};
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
function foo() {
|
||||
var foo = this != null ? this : {};
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
function foo(opts) {
|
||||
var foo = opts.foo ?? "default";
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
function foo(opts) {
|
||||
var _opts$foo;
|
||||
|
||||
var foo = (_opts$foo = opts.foo) != null ? _opts$foo : "default";
|
||||
}
|
||||
@ -23,6 +23,11 @@ export default declare((api, opts) => {
|
||||
throw new Error(".loose must be a boolean, or undefined");
|
||||
}
|
||||
|
||||
const ignoreFunctionLength = api.assumption("ignoreFunctionLength") ?? loose;
|
||||
const objectRestNoSymbols = api.assumption("objectRestNoSymbols") ?? loose;
|
||||
const pureGetters = api.assumption("pureGetters") ?? loose;
|
||||
const setSpreadProperties = api.assumption("setSpreadProperties") ?? loose;
|
||||
|
||||
function getExtendsHelper(file) {
|
||||
return useBuiltIns
|
||||
? t.memberExpression(t.identifier("Object"), t.identifier("assign"))
|
||||
@ -133,7 +138,7 @@ export default declare((api, opts) => {
|
||||
}
|
||||
|
||||
//expects path to an object pattern
|
||||
function createObjectSpread(path, file, objRef) {
|
||||
function createObjectRest(path, file, objRef) {
|
||||
const props = path.get("properties");
|
||||
const last = props[props.length - 1];
|
||||
t.assertRestElement(last.node);
|
||||
@ -172,7 +177,9 @@ export default declare((api, opts) => {
|
||||
impureComputedPropertyDeclarators,
|
||||
restElement.argument,
|
||||
t.callExpression(
|
||||
file.addHelper(`objectWithoutProperties${loose ? "Loose" : ""}`),
|
||||
file.addHelper(
|
||||
`objectWithoutProperties${objectRestNoSymbols ? "Loose" : ""}`,
|
||||
),
|
||||
[t.cloneNode(objRef), keyExpression],
|
||||
),
|
||||
];
|
||||
@ -275,7 +282,7 @@ export default declare((api, opts) => {
|
||||
idx >= i - 1 || paramsWithRestElement.has(idx);
|
||||
convertFunctionParams(
|
||||
path,
|
||||
loose,
|
||||
ignoreFunctionLength,
|
||||
shouldTransformParam,
|
||||
replaceRestElement,
|
||||
);
|
||||
@ -361,9 +368,9 @@ export default declare((api, opts) => {
|
||||
impureComputedPropertyDeclarators,
|
||||
argument,
|
||||
callExpression,
|
||||
] = createObjectSpread(objectPatternPath, file, ref);
|
||||
] = createObjectRest(objectPatternPath, file, ref);
|
||||
|
||||
if (loose) {
|
||||
if (pureGetters) {
|
||||
removeUnusedExcludedKeys(objectPatternPath);
|
||||
}
|
||||
|
||||
@ -444,7 +451,7 @@ export default declare((api, opts) => {
|
||||
impureComputedPropertyDeclarators,
|
||||
argument,
|
||||
callExpression,
|
||||
] = createObjectSpread(leftPath, file, t.identifier(refName));
|
||||
] = createObjectRest(leftPath, file, t.identifier(refName));
|
||||
|
||||
if (impureComputedPropertyDeclarators.length > 0) {
|
||||
nodes.push(
|
||||
@ -553,7 +560,7 @@ export default declare((api, opts) => {
|
||||
if (!hasSpread(path.node)) return;
|
||||
|
||||
let helper;
|
||||
if (loose) {
|
||||
if (setSpreadProperties) {
|
||||
helper = getExtendsHelper(file);
|
||||
} else {
|
||||
try {
|
||||
@ -583,10 +590,9 @@ export default declare((api, opts) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// In loose mode, we don't want to make multiple calls. We're assuming
|
||||
// that the spread objects either don't use getters, or that the
|
||||
// getters are pure and don't depend on the order of evaluation.
|
||||
if (loose) {
|
||||
// When we can assume that getters are pure and don't depend on
|
||||
// the order of evaluation, we can avoid making multiple calls.
|
||||
if (pureGetters) {
|
||||
if (hadProps) {
|
||||
exp.arguments.push(obj);
|
||||
}
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
{
|
||||
"plugins": [
|
||||
"proposal-object-rest-spread"
|
||||
],
|
||||
"assumptions": {
|
||||
"ignoreFunctionLength": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
({...R}, a = R) => {}
|
||||
({...R}, e, c = 2, a = R, f = q) => { let q; }
|
||||
({...R}, a = f(R)) => {}
|
||||
@ -0,0 +1,33 @@
|
||||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
|
||||
(_ref, a) => {
|
||||
let R = _extends({}, _ref);
|
||||
|
||||
if (a === void 0) {
|
||||
a = R;
|
||||
}
|
||||
};
|
||||
|
||||
(_ref2, e, c = 2, a, f) => {
|
||||
let R = _extends({}, _ref2);
|
||||
|
||||
if (a === void 0) {
|
||||
a = R;
|
||||
}
|
||||
|
||||
if (f === void 0) {
|
||||
f = q;
|
||||
}
|
||||
|
||||
return function () {
|
||||
let q;
|
||||
}();
|
||||
};
|
||||
|
||||
(_ref3, a) => {
|
||||
let R = _extends({}, _ref3);
|
||||
|
||||
if (a === void 0) {
|
||||
a = f(R);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,9 @@
|
||||
{
|
||||
"plugins": [
|
||||
["external-helpers", { "helperVersion": "7.100.0"}],
|
||||
"proposal-object-rest-spread"
|
||||
],
|
||||
"assumptions": {
|
||||
"objectRestNoSymbols": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
({ a, b, ...c } = obj);
|
||||
@ -0,0 +1,7 @@
|
||||
var _obj = obj;
|
||||
({
|
||||
a,
|
||||
b
|
||||
} = _obj);
|
||||
c = babelHelpers.objectWithoutPropertiesLoose(_obj, ["a", "b"]);
|
||||
_obj;
|
||||
@ -0,0 +1 @@
|
||||
let { [a]: b, ...c } = obj;
|
||||
@ -0,0 +1,5 @@
|
||||
let _a = a,
|
||||
{
|
||||
[_a]: b
|
||||
} = obj,
|
||||
c = babelHelpers.objectWithoutPropertiesLoose(obj, [_a].map(babelHelpers.toPropertyKey));
|
||||
@ -0,0 +1,7 @@
|
||||
let sym = Symbol();
|
||||
|
||||
let { a, ...r } = { a: 1, b: 2, [sym]: 3 };
|
||||
|
||||
expect(a).toBe(1);
|
||||
expect(r.b).toBe(2);
|
||||
expect(sym in r).toBe(false);
|
||||
@ -0,0 +1 @@
|
||||
let { a, nested: { b, c, ...d }, e } = obj;
|
||||
@ -0,0 +1,9 @@
|
||||
let {
|
||||
a,
|
||||
nested: {
|
||||
b,
|
||||
c
|
||||
},
|
||||
e
|
||||
} = obj,
|
||||
d = babelHelpers.objectWithoutPropertiesLoose(obj.nested, ["b", "c"]);
|
||||
@ -0,0 +1 @@
|
||||
var { a, b, ...c } = obj;
|
||||
@ -0,0 +1,5 @@
|
||||
var {
|
||||
a,
|
||||
b
|
||||
} = obj,
|
||||
c = babelHelpers.objectWithoutPropertiesLoose(obj, ["a", "b"]);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user