55467 lines
1.9 MiB
Plaintext
55467 lines
1.9 MiB
Plaintext
/**
|
|
* @license React
|
|
* eslint-plugin-react-hooks.development.js
|
|
*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
if (process.env.NODE_ENV !== "production") {
|
|
(function() {
|
|
'use strict';
|
|
|
|
var core$1 = require('@babel/core');
|
|
var BabelParser = require('@babel/parser');
|
|
var v4 = require('zod/v4');
|
|
var v4$1 = require('zod-validation-error/v4');
|
|
var crypto = require('crypto');
|
|
var HermesParser = require('hermes-parser');
|
|
var util = require('util');
|
|
|
|
const SETTINGS_KEY = 'react-hooks';
|
|
const SETTINGS_ADDITIONAL_EFFECT_HOOKS_KEY = 'additionalEffectHooks';
|
|
function getAdditionalEffectHooksFromSettings(settings) {
|
|
var _a;
|
|
const additionalHooks = (_a = settings[SETTINGS_KEY]) === null || _a === void 0 ? void 0 : _a[SETTINGS_ADDITIONAL_EFFECT_HOOKS_KEY];
|
|
if (additionalHooks != null && typeof additionalHooks === 'string') {
|
|
return new RegExp(additionalHooks);
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
const rule$1 = {
|
|
meta: {
|
|
type: 'suggestion',
|
|
docs: {
|
|
description: 'verifies the list of dependencies for Hooks like useEffect and similar',
|
|
recommended: true,
|
|
url: 'https://github.com/facebook/react/issues/14920',
|
|
},
|
|
fixable: 'code',
|
|
hasSuggestions: true,
|
|
schema: [
|
|
{
|
|
type: 'object',
|
|
additionalProperties: false,
|
|
enableDangerousAutofixThisMayCauseInfiniteLoops: false,
|
|
properties: {
|
|
additionalHooks: {
|
|
type: 'string',
|
|
},
|
|
enableDangerousAutofixThisMayCauseInfiniteLoops: {
|
|
type: 'boolean',
|
|
},
|
|
experimental_autoDependenciesHooks: {
|
|
type: 'array',
|
|
items: {
|
|
type: 'string',
|
|
},
|
|
},
|
|
requireExplicitEffectDeps: {
|
|
type: 'boolean',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
create(context) {
|
|
const rawOptions = context.options && context.options[0];
|
|
const settings = context.settings || {};
|
|
const additionalHooks = rawOptions && rawOptions.additionalHooks
|
|
? new RegExp(rawOptions.additionalHooks)
|
|
: getAdditionalEffectHooksFromSettings(settings);
|
|
const enableDangerousAutofixThisMayCauseInfiniteLoops = (rawOptions &&
|
|
rawOptions.enableDangerousAutofixThisMayCauseInfiniteLoops) ||
|
|
false;
|
|
const experimental_autoDependenciesHooks = rawOptions && Array.isArray(rawOptions.experimental_autoDependenciesHooks)
|
|
? rawOptions.experimental_autoDependenciesHooks
|
|
: [];
|
|
const requireExplicitEffectDeps = (rawOptions && rawOptions.requireExplicitEffectDeps) || false;
|
|
const options = {
|
|
additionalHooks,
|
|
experimental_autoDependenciesHooks,
|
|
enableDangerousAutofixThisMayCauseInfiniteLoops,
|
|
requireExplicitEffectDeps,
|
|
};
|
|
function reportProblem(problem) {
|
|
if (enableDangerousAutofixThisMayCauseInfiniteLoops) {
|
|
if (Array.isArray(problem.suggest) &&
|
|
problem.suggest.length > 0 &&
|
|
problem.suggest[0]) {
|
|
problem.fix = problem.suggest[0].fix;
|
|
}
|
|
}
|
|
context.report(problem);
|
|
}
|
|
const getSourceCode = typeof context.getSourceCode === 'function'
|
|
? () => {
|
|
return context.getSourceCode();
|
|
}
|
|
: () => {
|
|
return context.sourceCode;
|
|
};
|
|
const getScope = typeof context.getScope === 'function'
|
|
? () => {
|
|
return context.getScope();
|
|
}
|
|
: (node) => {
|
|
return context.sourceCode.getScope(node);
|
|
};
|
|
const scopeManager = getSourceCode().scopeManager;
|
|
const setStateCallSites = new WeakMap();
|
|
const stateVariables = new WeakSet();
|
|
const stableKnownValueCache = new WeakMap();
|
|
const functionWithoutCapturedValueCache = new WeakMap();
|
|
const useEffectEventVariables = new WeakSet();
|
|
function memoizeWithWeakMap(fn, map) {
|
|
return function (arg) {
|
|
if (map.has(arg)) {
|
|
return map.get(arg);
|
|
}
|
|
const result = fn(arg);
|
|
map.set(arg, result);
|
|
return result;
|
|
};
|
|
}
|
|
function visitFunctionWithDependencies(node, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect, isAutoDepsHook) {
|
|
if (isEffect && node.async) {
|
|
reportProblem({
|
|
node: node,
|
|
message: `Effect callbacks are synchronous to prevent race conditions. ` +
|
|
`Put the async function inside:\n\n` +
|
|
'useEffect(() => {\n' +
|
|
' async function fetchData() {\n' +
|
|
' // You can await here\n' +
|
|
' const response = await MyAPI.getData(someId);\n' +
|
|
' // ...\n' +
|
|
' }\n' +
|
|
' fetchData();\n' +
|
|
`}, [someId]); // Or [] if effect doesn't need props or state\n\n` +
|
|
'Learn more about data fetching with Hooks: https://react.dev/link/hooks-data-fetching',
|
|
});
|
|
}
|
|
const scope = scopeManager.acquire(node);
|
|
if (!scope) {
|
|
throw new Error('Unable to acquire scope for the current node. This is a bug in eslint-plugin-react-hooks, please file an issue.');
|
|
}
|
|
const pureScopes = new Set();
|
|
let componentScope = null;
|
|
{
|
|
let currentScope = scope.upper;
|
|
while (currentScope) {
|
|
pureScopes.add(currentScope);
|
|
if (currentScope.type === 'function' ||
|
|
currentScope.type === 'hook' ||
|
|
currentScope.type === 'component') {
|
|
break;
|
|
}
|
|
currentScope = currentScope.upper;
|
|
}
|
|
if (!currentScope) {
|
|
return;
|
|
}
|
|
componentScope = currentScope;
|
|
}
|
|
const isArray = Array.isArray;
|
|
function isStableKnownHookValue(resolved) {
|
|
if (!isArray(resolved.defs)) {
|
|
return false;
|
|
}
|
|
const def = resolved.defs[0];
|
|
if (def == null) {
|
|
return false;
|
|
}
|
|
const defNode = def.node;
|
|
if (defNode.type !== 'VariableDeclarator') {
|
|
return false;
|
|
}
|
|
let init = defNode.init;
|
|
if (init == null) {
|
|
return false;
|
|
}
|
|
while (init.type === 'TSAsExpression' || init.type === 'AsExpression') {
|
|
init = init.expression;
|
|
}
|
|
let declaration = defNode.parent;
|
|
if (declaration == null && componentScope != null) {
|
|
fastFindReferenceWithParent(componentScope.block, def.node.id);
|
|
declaration = def.node.parent;
|
|
if (declaration == null) {
|
|
return false;
|
|
}
|
|
}
|
|
if (declaration != null &&
|
|
'kind' in declaration &&
|
|
declaration.kind === 'const' &&
|
|
init.type === 'Literal' &&
|
|
(typeof init.value === 'string' ||
|
|
typeof init.value === 'number' ||
|
|
init.value === null)) {
|
|
return true;
|
|
}
|
|
if (init.type !== 'CallExpression') {
|
|
return false;
|
|
}
|
|
let callee = init.callee;
|
|
if (callee.type === 'MemberExpression' &&
|
|
'name' in callee.object &&
|
|
callee.object.name === 'React' &&
|
|
callee.property != null &&
|
|
!callee.computed) {
|
|
callee = callee.property;
|
|
}
|
|
if (callee.type !== 'Identifier') {
|
|
return false;
|
|
}
|
|
const definitionNode = def.node;
|
|
const id = definitionNode.id;
|
|
const { name } = callee;
|
|
if (name === 'useRef' && id.type === 'Identifier') {
|
|
return true;
|
|
}
|
|
else if (isUseEffectEventIdentifier$1(callee) &&
|
|
id.type === 'Identifier') {
|
|
for (const ref of resolved.references) {
|
|
if (ref !== id) {
|
|
useEffectEventVariables.add(ref.identifier);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if (name === 'useState' ||
|
|
name === 'useReducer' ||
|
|
name === 'useActionState') {
|
|
if (id.type === 'ArrayPattern' &&
|
|
id.elements.length === 2 &&
|
|
isArray(resolved.identifiers)) {
|
|
if (id.elements[1] === resolved.identifiers[0]) {
|
|
if (name === 'useState') {
|
|
const references = resolved.references;
|
|
let writeCount = 0;
|
|
for (const reference of references) {
|
|
if (reference.isWrite()) {
|
|
writeCount++;
|
|
}
|
|
if (writeCount > 1) {
|
|
return false;
|
|
}
|
|
setStateCallSites.set(reference.identifier, id.elements[0]);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if (id.elements[0] === resolved.identifiers[0]) {
|
|
if (name === 'useState') {
|
|
const references = resolved.references;
|
|
for (const reference of references) {
|
|
stateVariables.add(reference.identifier);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else if (name === 'useTransition') {
|
|
if (id.type === 'ArrayPattern' &&
|
|
id.elements.length === 2 &&
|
|
Array.isArray(resolved.identifiers)) {
|
|
if (id.elements[1] === resolved.identifiers[0]) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function isFunctionWithoutCapturedValues(resolved) {
|
|
if (!isArray(resolved.defs)) {
|
|
return false;
|
|
}
|
|
const def = resolved.defs[0];
|
|
if (def == null) {
|
|
return false;
|
|
}
|
|
if (def.node == null || def.node.id == null) {
|
|
return false;
|
|
}
|
|
const fnNode = def.node;
|
|
const childScopes = (componentScope === null || componentScope === void 0 ? void 0 : componentScope.childScopes) || [];
|
|
let fnScope = null;
|
|
for (const childScope of childScopes) {
|
|
const childScopeBlock = childScope.block;
|
|
if ((fnNode.type === 'FunctionDeclaration' &&
|
|
childScopeBlock === fnNode) ||
|
|
(fnNode.type === 'VariableDeclarator' &&
|
|
childScopeBlock.parent === fnNode)) {
|
|
fnScope = childScope;
|
|
break;
|
|
}
|
|
}
|
|
if (fnScope == null) {
|
|
return false;
|
|
}
|
|
for (const ref of fnScope.through) {
|
|
if (ref.resolved == null) {
|
|
continue;
|
|
}
|
|
if (pureScopes.has(ref.resolved.scope) &&
|
|
!memoizedIsStableKnownHookValue(ref.resolved)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
const memoizedIsStableKnownHookValue = memoizeWithWeakMap(isStableKnownHookValue, stableKnownValueCache);
|
|
const memoizedIsFunctionWithoutCapturedValues = memoizeWithWeakMap(isFunctionWithoutCapturedValues, functionWithoutCapturedValueCache);
|
|
const currentRefsInEffectCleanup = new Map();
|
|
function isInsideEffectCleanup(reference) {
|
|
let curScope = reference.from;
|
|
let isInReturnedFunction = false;
|
|
while (curScope != null && curScope.block !== node) {
|
|
if (curScope.type === 'function') {
|
|
isInReturnedFunction =
|
|
curScope.block.parent != null &&
|
|
curScope.block.parent.type === 'ReturnStatement';
|
|
}
|
|
curScope = curScope.upper;
|
|
}
|
|
return isInReturnedFunction;
|
|
}
|
|
const dependencies = new Map();
|
|
const optionalChains = new Map();
|
|
gatherDependenciesRecursively(scope);
|
|
function gatherDependenciesRecursively(currentScope) {
|
|
var _a, _b, _c, _d, _e, _f;
|
|
for (const reference of currentScope.references) {
|
|
if (!reference.resolved) {
|
|
continue;
|
|
}
|
|
if (!pureScopes.has(reference.resolved.scope)) {
|
|
continue;
|
|
}
|
|
const referenceNode = fastFindReferenceWithParent(node, reference.identifier);
|
|
if (referenceNode == null) {
|
|
continue;
|
|
}
|
|
const dependencyNode = getDependency(referenceNode);
|
|
const dependency = analyzePropertyChain(dependencyNode, optionalChains);
|
|
if (isEffect &&
|
|
dependencyNode.type === 'Identifier' &&
|
|
(((_a = dependencyNode.parent) === null || _a === void 0 ? void 0 : _a.type) === 'MemberExpression' ||
|
|
((_b = dependencyNode.parent) === null || _b === void 0 ? void 0 : _b.type) === 'OptionalMemberExpression') &&
|
|
!dependencyNode.parent.computed &&
|
|
dependencyNode.parent.property.type === 'Identifier' &&
|
|
dependencyNode.parent.property.name === 'current' &&
|
|
isInsideEffectCleanup(reference)) {
|
|
currentRefsInEffectCleanup.set(dependency, {
|
|
reference,
|
|
dependencyNode,
|
|
});
|
|
}
|
|
if (((_c = dependencyNode.parent) === null || _c === void 0 ? void 0 : _c.type) === 'TSTypeQuery' ||
|
|
((_d = dependencyNode.parent) === null || _d === void 0 ? void 0 : _d.type) === 'TSTypeReference') {
|
|
continue;
|
|
}
|
|
const def = reference.resolved.defs[0];
|
|
if (def == null) {
|
|
continue;
|
|
}
|
|
if (def.node != null && def.node.init === node.parent) {
|
|
continue;
|
|
}
|
|
if (def.type === 'TypeParameter' ||
|
|
((_e = dependencyNode.parent) === null || _e === void 0 ? void 0 : _e.type) === 'GenericTypeAnnotation') {
|
|
continue;
|
|
}
|
|
if (!dependencies.has(dependency)) {
|
|
const resolved = reference.resolved;
|
|
const isStable = memoizedIsStableKnownHookValue(resolved) ||
|
|
memoizedIsFunctionWithoutCapturedValues(resolved);
|
|
dependencies.set(dependency, {
|
|
isStable,
|
|
references: [reference],
|
|
});
|
|
}
|
|
else {
|
|
(_f = dependencies.get(dependency)) === null || _f === void 0 ? void 0 : _f.references.push(reference);
|
|
}
|
|
}
|
|
for (const childScope of currentScope.childScopes) {
|
|
gatherDependenciesRecursively(childScope);
|
|
}
|
|
}
|
|
currentRefsInEffectCleanup.forEach(({ reference, dependencyNode }, dependency) => {
|
|
var _a, _b;
|
|
const references = ((_a = reference.resolved) === null || _a === void 0 ? void 0 : _a.references) || [];
|
|
let foundCurrentAssignment = false;
|
|
for (const ref of references) {
|
|
const { identifier } = ref;
|
|
const { parent } = identifier;
|
|
if (parent != null &&
|
|
parent.type === 'MemberExpression' &&
|
|
!parent.computed &&
|
|
parent.property.type === 'Identifier' &&
|
|
parent.property.name === 'current' &&
|
|
((_b = parent.parent) === null || _b === void 0 ? void 0 : _b.type) === 'AssignmentExpression' &&
|
|
parent.parent.left === parent) {
|
|
foundCurrentAssignment = true;
|
|
break;
|
|
}
|
|
}
|
|
if (foundCurrentAssignment) {
|
|
return;
|
|
}
|
|
reportProblem({
|
|
node: dependencyNode.parent.property,
|
|
message: `The ref value '${dependency}.current' will likely have ` +
|
|
`changed by the time this effect cleanup function runs. If ` +
|
|
`this ref points to a node rendered by React, copy ` +
|
|
`'${dependency}.current' to a variable inside the effect, and ` +
|
|
`use that variable in the cleanup function.`,
|
|
});
|
|
});
|
|
const staleAssignments = new Set();
|
|
function reportStaleAssignment(writeExpr, key) {
|
|
if (staleAssignments.has(key)) {
|
|
return;
|
|
}
|
|
staleAssignments.add(key);
|
|
reportProblem({
|
|
node: writeExpr,
|
|
message: `Assignments to the '${key}' variable from inside React Hook ` +
|
|
`${getSourceCode().getText(reactiveHook)} will be lost after each ` +
|
|
`render. To preserve the value over time, store it in a useRef ` +
|
|
`Hook and keep the mutable value in the '.current' property. ` +
|
|
`Otherwise, you can move this variable directly inside ` +
|
|
`${getSourceCode().getText(reactiveHook)}.`,
|
|
});
|
|
}
|
|
const stableDependencies = new Set();
|
|
dependencies.forEach(({ isStable, references }, key) => {
|
|
if (isStable) {
|
|
stableDependencies.add(key);
|
|
}
|
|
references.forEach(reference => {
|
|
if (reference.writeExpr) {
|
|
reportStaleAssignment(reference.writeExpr, key);
|
|
}
|
|
});
|
|
});
|
|
if (staleAssignments.size > 0) {
|
|
return;
|
|
}
|
|
if (!declaredDependenciesNode) {
|
|
if (isAutoDepsHook) {
|
|
return;
|
|
}
|
|
let setStateInsideEffectWithoutDeps = null;
|
|
dependencies.forEach(({ references }, key) => {
|
|
if (setStateInsideEffectWithoutDeps) {
|
|
return;
|
|
}
|
|
references.forEach(reference => {
|
|
if (setStateInsideEffectWithoutDeps) {
|
|
return;
|
|
}
|
|
const id = reference.identifier;
|
|
const isSetState = setStateCallSites.has(id);
|
|
if (!isSetState) {
|
|
return;
|
|
}
|
|
let fnScope = reference.from;
|
|
while (fnScope != null && fnScope.type !== 'function') {
|
|
fnScope = fnScope.upper;
|
|
}
|
|
const isDirectlyInsideEffect = (fnScope === null || fnScope === void 0 ? void 0 : fnScope.block) === node;
|
|
if (isDirectlyInsideEffect) {
|
|
setStateInsideEffectWithoutDeps = key;
|
|
}
|
|
});
|
|
});
|
|
if (setStateInsideEffectWithoutDeps) {
|
|
const { suggestedDependencies } = collectRecommendations({
|
|
dependencies,
|
|
declaredDependencies: [],
|
|
stableDependencies,
|
|
externalDependencies: new Set(),
|
|
isEffect: true,
|
|
});
|
|
reportProblem({
|
|
node: reactiveHook,
|
|
message: `React Hook ${reactiveHookName} contains a call to '${setStateInsideEffectWithoutDeps}'. ` +
|
|
`Without a list of dependencies, this can lead to an infinite chain of updates. ` +
|
|
`To fix this, pass [` +
|
|
suggestedDependencies.join(', ') +
|
|
`] as a second argument to the ${reactiveHookName} Hook.`,
|
|
suggest: [
|
|
{
|
|
desc: `Add dependencies array: [${suggestedDependencies.join(', ')}]`,
|
|
fix(fixer) {
|
|
return fixer.insertTextAfter(node, `, [${suggestedDependencies.join(', ')}]`);
|
|
},
|
|
},
|
|
],
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
if (isAutoDepsHook &&
|
|
declaredDependenciesNode.type === 'Literal' &&
|
|
declaredDependenciesNode.value === null) {
|
|
return;
|
|
}
|
|
const declaredDependencies = [];
|
|
const externalDependencies = new Set();
|
|
const isArrayExpression = declaredDependenciesNode.type === 'ArrayExpression';
|
|
const isTSAsArrayExpression = declaredDependenciesNode.type === 'TSAsExpression' &&
|
|
declaredDependenciesNode.expression.type === 'ArrayExpression';
|
|
if (!isArrayExpression && !isTSAsArrayExpression) {
|
|
reportProblem({
|
|
node: declaredDependenciesNode,
|
|
message: `React Hook ${getSourceCode().getText(reactiveHook)} was passed a ` +
|
|
'dependency list that is not an array literal. This means we ' +
|
|
"can't statically verify whether you've passed the correct " +
|
|
'dependencies.',
|
|
});
|
|
}
|
|
else {
|
|
const arrayExpression = isTSAsArrayExpression
|
|
? declaredDependenciesNode.expression
|
|
: declaredDependenciesNode;
|
|
arrayExpression.elements.forEach(declaredDependencyNode => {
|
|
if (declaredDependencyNode === null) {
|
|
return;
|
|
}
|
|
if (declaredDependencyNode.type === 'SpreadElement') {
|
|
reportProblem({
|
|
node: declaredDependencyNode,
|
|
message: `React Hook ${getSourceCode().getText(reactiveHook)} has a spread ` +
|
|
"element in its dependency array. This means we can't " +
|
|
"statically verify whether you've passed the " +
|
|
'correct dependencies.',
|
|
});
|
|
return;
|
|
}
|
|
if (useEffectEventVariables.has(declaredDependencyNode)) {
|
|
reportProblem({
|
|
node: declaredDependencyNode,
|
|
message: 'Functions returned from `useEffectEvent` must not be included in the dependency array. ' +
|
|
`Remove \`${getSourceCode().getText(declaredDependencyNode)}\` from the list.`,
|
|
suggest: [
|
|
{
|
|
desc: `Remove the dependency \`${getSourceCode().getText(declaredDependencyNode)}\``,
|
|
fix(fixer) {
|
|
return fixer.removeRange(declaredDependencyNode.range);
|
|
},
|
|
},
|
|
],
|
|
});
|
|
}
|
|
let declaredDependency;
|
|
try {
|
|
declaredDependency = analyzePropertyChain(declaredDependencyNode, null);
|
|
}
|
|
catch (error) {
|
|
if (error instanceof Error &&
|
|
/Unsupported node type/.test(error.message)) {
|
|
if (declaredDependencyNode.type === 'Literal') {
|
|
if (declaredDependencyNode.value &&
|
|
dependencies.has(declaredDependencyNode.value)) {
|
|
reportProblem({
|
|
node: declaredDependencyNode,
|
|
message: `The ${declaredDependencyNode.raw} literal is not a valid dependency ` +
|
|
`because it never changes. ` +
|
|
`Did you mean to include ${declaredDependencyNode.value} in the array instead?`,
|
|
});
|
|
}
|
|
else {
|
|
reportProblem({
|
|
node: declaredDependencyNode,
|
|
message: `The ${declaredDependencyNode.raw} literal is not a valid dependency ` +
|
|
'because it never changes. You can safely remove it.',
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
reportProblem({
|
|
node: declaredDependencyNode,
|
|
message: `React Hook ${getSourceCode().getText(reactiveHook)} has a ` +
|
|
`complex expression in the dependency array. ` +
|
|
'Extract it to a separate variable so it can be statically checked.',
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
else {
|
|
throw error;
|
|
}
|
|
}
|
|
let maybeID = declaredDependencyNode;
|
|
while (maybeID.type === 'MemberExpression' ||
|
|
maybeID.type === 'OptionalMemberExpression' ||
|
|
maybeID.type === 'ChainExpression') {
|
|
maybeID = maybeID.object || maybeID.expression.object;
|
|
}
|
|
const isDeclaredInComponent = !componentScope.through.some(ref => ref.identifier === maybeID);
|
|
declaredDependencies.push({
|
|
key: declaredDependency,
|
|
node: declaredDependencyNode,
|
|
});
|
|
if (!isDeclaredInComponent) {
|
|
externalDependencies.add(declaredDependency);
|
|
}
|
|
});
|
|
}
|
|
const { suggestedDependencies, unnecessaryDependencies, missingDependencies, duplicateDependencies, } = collectRecommendations({
|
|
dependencies,
|
|
declaredDependencies,
|
|
stableDependencies,
|
|
externalDependencies,
|
|
isEffect,
|
|
});
|
|
let suggestedDeps = suggestedDependencies;
|
|
const problemCount = duplicateDependencies.size +
|
|
missingDependencies.size +
|
|
unnecessaryDependencies.size;
|
|
if (problemCount === 0) {
|
|
const constructions = scanForConstructions({
|
|
declaredDependencies,
|
|
declaredDependenciesNode,
|
|
componentScope,
|
|
scope,
|
|
});
|
|
constructions.forEach(({ construction, isUsedOutsideOfHook, depType }) => {
|
|
var _a;
|
|
const wrapperHook = depType === 'function' ? 'useCallback' : 'useMemo';
|
|
const constructionType = depType === 'function' ? 'definition' : 'initialization';
|
|
const defaultAdvice = `wrap the ${constructionType} of '${construction.name.name}' in its own ${wrapperHook}() Hook.`;
|
|
const advice = isUsedOutsideOfHook
|
|
? `To fix this, ${defaultAdvice}`
|
|
: `Move it inside the ${reactiveHookName} callback. Alternatively, ${defaultAdvice}`;
|
|
const causation = depType === 'conditional' || depType === 'logical expression'
|
|
? 'could make'
|
|
: 'makes';
|
|
const message = `The '${construction.name.name}' ${depType} ${causation} the dependencies of ` +
|
|
`${reactiveHookName} Hook (at line ${(_a = declaredDependenciesNode.loc) === null || _a === void 0 ? void 0 : _a.start.line}) ` +
|
|
`change on every render. ${advice}`;
|
|
let suggest;
|
|
if (isUsedOutsideOfHook &&
|
|
construction.type === 'Variable' &&
|
|
depType === 'function') {
|
|
suggest = [
|
|
{
|
|
desc: `Wrap the ${constructionType} of '${construction.name.name}' in its own ${wrapperHook}() Hook.`,
|
|
fix(fixer) {
|
|
const [before, after] = wrapperHook === 'useMemo'
|
|
? [`useMemo(() => { return `, '; })']
|
|
: ['useCallback(', ')'];
|
|
return [
|
|
fixer.insertTextBefore(construction.node.init, before),
|
|
fixer.insertTextAfter(construction.node.init, after),
|
|
];
|
|
},
|
|
},
|
|
];
|
|
}
|
|
reportProblem({
|
|
node: construction.node,
|
|
message,
|
|
suggest,
|
|
});
|
|
});
|
|
return;
|
|
}
|
|
if (!isEffect && missingDependencies.size > 0) {
|
|
suggestedDeps = collectRecommendations({
|
|
dependencies,
|
|
declaredDependencies: [],
|
|
stableDependencies,
|
|
externalDependencies,
|
|
isEffect,
|
|
}).suggestedDependencies;
|
|
}
|
|
function areDeclaredDepsAlphabetized() {
|
|
if (declaredDependencies.length === 0) {
|
|
return true;
|
|
}
|
|
const declaredDepKeys = declaredDependencies.map(dep => dep.key);
|
|
const sortedDeclaredDepKeys = declaredDepKeys.slice().sort();
|
|
return declaredDepKeys.join(',') === sortedDeclaredDepKeys.join(',');
|
|
}
|
|
if (areDeclaredDepsAlphabetized()) {
|
|
suggestedDeps.sort();
|
|
}
|
|
function formatDependency(path) {
|
|
const members = path.split('.');
|
|
let finalPath = '';
|
|
for (let i = 0; i < members.length; i++) {
|
|
if (i !== 0) {
|
|
const pathSoFar = members.slice(0, i + 1).join('.');
|
|
const isOptional = optionalChains.get(pathSoFar) === true;
|
|
finalPath += isOptional ? '?.' : '.';
|
|
}
|
|
finalPath += members[i];
|
|
}
|
|
return finalPath;
|
|
}
|
|
function getWarningMessage(deps, singlePrefix, label, fixVerb) {
|
|
if (deps.size === 0) {
|
|
return null;
|
|
}
|
|
return ((deps.size > 1 ? '' : singlePrefix + ' ') +
|
|
label +
|
|
' ' +
|
|
(deps.size > 1 ? 'dependencies' : 'dependency') +
|
|
': ' +
|
|
joinEnglish(Array.from(deps)
|
|
.sort()
|
|
.map(name => "'" + formatDependency(name) + "'")) +
|
|
`. Either ${fixVerb} ${deps.size > 1 ? 'them' : 'it'} or remove the dependency array.`);
|
|
}
|
|
let extraWarning = '';
|
|
if (unnecessaryDependencies.size > 0) {
|
|
let badRef = null;
|
|
Array.from(unnecessaryDependencies.keys()).forEach(key => {
|
|
if (badRef !== null) {
|
|
return;
|
|
}
|
|
if (key.endsWith('.current')) {
|
|
badRef = key;
|
|
}
|
|
});
|
|
if (badRef !== null) {
|
|
extraWarning =
|
|
` Mutable values like '${badRef}' aren't valid dependencies ` +
|
|
"because mutating them doesn't re-render the component.";
|
|
}
|
|
else if (externalDependencies.size > 0) {
|
|
const dep = Array.from(externalDependencies)[0];
|
|
if (!scope.set.has(dep)) {
|
|
extraWarning =
|
|
` Outer scope values like '${dep}' aren't valid dependencies ` +
|
|
`because mutating them doesn't re-render the component.`;
|
|
}
|
|
}
|
|
}
|
|
if (!extraWarning && missingDependencies.has('props')) {
|
|
const propDep = dependencies.get('props');
|
|
if (propDep == null) {
|
|
return;
|
|
}
|
|
const refs = propDep.references;
|
|
if (!Array.isArray(refs)) {
|
|
return;
|
|
}
|
|
let isPropsOnlyUsedInMembers = true;
|
|
for (const ref of refs) {
|
|
const id = fastFindReferenceWithParent(componentScope.block, ref.identifier);
|
|
if (!id) {
|
|
isPropsOnlyUsedInMembers = false;
|
|
break;
|
|
}
|
|
const parent = id.parent;
|
|
if (parent == null) {
|
|
isPropsOnlyUsedInMembers = false;
|
|
break;
|
|
}
|
|
if (parent.type !== 'MemberExpression' &&
|
|
parent.type !== 'OptionalMemberExpression') {
|
|
isPropsOnlyUsedInMembers = false;
|
|
break;
|
|
}
|
|
}
|
|
if (isPropsOnlyUsedInMembers) {
|
|
extraWarning =
|
|
` However, 'props' will change when *any* prop changes, so the ` +
|
|
`preferred fix is to destructure the 'props' object outside of ` +
|
|
`the ${reactiveHookName} call and refer to those specific props ` +
|
|
`inside ${getSourceCode().getText(reactiveHook)}.`;
|
|
}
|
|
}
|
|
if (!extraWarning && missingDependencies.size > 0) {
|
|
let missingCallbackDep = null;
|
|
missingDependencies.forEach(missingDep => {
|
|
var _a;
|
|
if (missingCallbackDep) {
|
|
return;
|
|
}
|
|
const topScopeRef = componentScope.set.get(missingDep);
|
|
const usedDep = dependencies.get(missingDep);
|
|
if (!(usedDep === null || usedDep === void 0 ? void 0 : usedDep.references) ||
|
|
((_a = usedDep === null || usedDep === void 0 ? void 0 : usedDep.references[0]) === null || _a === void 0 ? void 0 : _a.resolved) !== topScopeRef) {
|
|
return;
|
|
}
|
|
const def = topScopeRef === null || topScopeRef === void 0 ? void 0 : topScopeRef.defs[0];
|
|
if (def == null || def.name == null || def.type !== 'Parameter') {
|
|
return;
|
|
}
|
|
let isFunctionCall = false;
|
|
let id;
|
|
for (const reference of usedDep.references) {
|
|
id = reference.identifier;
|
|
if (id != null &&
|
|
id.parent != null &&
|
|
(id.parent.type === 'CallExpression' ||
|
|
id.parent.type === 'OptionalCallExpression') &&
|
|
id.parent.callee === id) {
|
|
isFunctionCall = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!isFunctionCall) {
|
|
return;
|
|
}
|
|
missingCallbackDep = missingDep;
|
|
});
|
|
if (missingCallbackDep !== null) {
|
|
extraWarning =
|
|
` If '${missingCallbackDep}' changes too often, ` +
|
|
`find the parent component that defines it ` +
|
|
`and wrap that definition in useCallback.`;
|
|
}
|
|
}
|
|
if (!extraWarning && missingDependencies.size > 0) {
|
|
let setStateRecommendation = null;
|
|
for (const missingDep of missingDependencies) {
|
|
if (setStateRecommendation !== null) {
|
|
break;
|
|
}
|
|
const usedDep = dependencies.get(missingDep);
|
|
const references = usedDep.references;
|
|
let id;
|
|
let maybeCall;
|
|
for (const reference of references) {
|
|
id = reference.identifier;
|
|
maybeCall = id.parent;
|
|
while (maybeCall != null && maybeCall !== componentScope.block) {
|
|
if (maybeCall.type === 'CallExpression') {
|
|
const correspondingStateVariable = setStateCallSites.get(maybeCall.callee);
|
|
if (correspondingStateVariable != null) {
|
|
if ('name' in correspondingStateVariable &&
|
|
correspondingStateVariable.name === missingDep) {
|
|
setStateRecommendation = {
|
|
missingDep,
|
|
setter: 'name' in maybeCall.callee ? maybeCall.callee.name : '',
|
|
form: 'updater',
|
|
};
|
|
}
|
|
else if (stateVariables.has(id)) {
|
|
setStateRecommendation = {
|
|
missingDep,
|
|
setter: 'name' in maybeCall.callee ? maybeCall.callee.name : '',
|
|
form: 'reducer',
|
|
};
|
|
}
|
|
else {
|
|
const resolved = reference.resolved;
|
|
if (resolved != null) {
|
|
const def = resolved.defs[0];
|
|
if (def != null && def.type === 'Parameter') {
|
|
setStateRecommendation = {
|
|
missingDep,
|
|
setter: 'name' in maybeCall.callee
|
|
? maybeCall.callee.name
|
|
: '',
|
|
form: 'inlineReducer',
|
|
};
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
maybeCall = maybeCall.parent;
|
|
}
|
|
if (setStateRecommendation !== null) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (setStateRecommendation !== null) {
|
|
switch (setStateRecommendation.form) {
|
|
case 'reducer':
|
|
extraWarning =
|
|
` You can also replace multiple useState variables with useReducer ` +
|
|
`if '${setStateRecommendation.setter}' needs the ` +
|
|
`current value of '${setStateRecommendation.missingDep}'.`;
|
|
break;
|
|
case 'inlineReducer':
|
|
extraWarning =
|
|
` If '${setStateRecommendation.setter}' needs the ` +
|
|
`current value of '${setStateRecommendation.missingDep}', ` +
|
|
`you can also switch to useReducer instead of useState and ` +
|
|
`read '${setStateRecommendation.missingDep}' in the reducer.`;
|
|
break;
|
|
case 'updater':
|
|
extraWarning =
|
|
` You can also do a functional update '${setStateRecommendation.setter}(${setStateRecommendation.missingDep.slice(0, 1)} => ...)' if you only need '${setStateRecommendation.missingDep}'` + ` in the '${setStateRecommendation.setter}' call.`;
|
|
break;
|
|
default:
|
|
throw new Error('Unknown case.');
|
|
}
|
|
}
|
|
}
|
|
reportProblem({
|
|
node: declaredDependenciesNode,
|
|
message: `React Hook ${getSourceCode().getText(reactiveHook)} has ` +
|
|
(getWarningMessage(missingDependencies, 'a', 'missing', 'include') ||
|
|
getWarningMessage(unnecessaryDependencies, 'an', 'unnecessary', 'exclude') ||
|
|
getWarningMessage(duplicateDependencies, 'a', 'duplicate', 'omit')) +
|
|
extraWarning,
|
|
suggest: [
|
|
{
|
|
desc: `Update the dependencies array to be: [${suggestedDeps
|
|
.map(formatDependency)
|
|
.join(', ')}]`,
|
|
fix(fixer) {
|
|
return fixer.replaceText(declaredDependenciesNode, `[${suggestedDeps.map(formatDependency).join(', ')}]`);
|
|
},
|
|
},
|
|
],
|
|
});
|
|
}
|
|
function visitCallExpression(node) {
|
|
const callbackIndex = getReactiveHookCallbackIndex(node.callee, options);
|
|
if (callbackIndex === -1) {
|
|
return;
|
|
}
|
|
let callback = node.arguments[callbackIndex];
|
|
const reactiveHook = node.callee;
|
|
const nodeWithoutNamespace = getNodeWithoutReactNamespace$1(reactiveHook);
|
|
const reactiveHookName = 'name' in nodeWithoutNamespace ? nodeWithoutNamespace.name : '';
|
|
const maybeNode = node.arguments[callbackIndex + 1];
|
|
const declaredDependenciesNode = maybeNode &&
|
|
!(maybeNode.type === 'Identifier' && maybeNode.name === 'undefined')
|
|
? maybeNode
|
|
: undefined;
|
|
const isEffect = /Effect($|[^a-z])/g.test(reactiveHookName);
|
|
if (!callback) {
|
|
reportProblem({
|
|
node: reactiveHook,
|
|
message: `React Hook ${reactiveHookName} requires an effect callback. ` +
|
|
`Did you forget to pass a callback to the hook?`,
|
|
});
|
|
return;
|
|
}
|
|
if (!maybeNode && isEffect && options.requireExplicitEffectDeps) {
|
|
reportProblem({
|
|
node: reactiveHook,
|
|
message: `React Hook ${reactiveHookName} always requires dependencies. ` +
|
|
`Please add a dependency array or an explicit \`undefined\``,
|
|
});
|
|
}
|
|
const isAutoDepsHook = options.experimental_autoDependenciesHooks.includes(reactiveHookName);
|
|
if ((!declaredDependenciesNode ||
|
|
(isAutoDepsHook &&
|
|
declaredDependenciesNode.type === 'Literal' &&
|
|
declaredDependenciesNode.value === null)) &&
|
|
!isEffect) {
|
|
if (reactiveHookName === 'useMemo' ||
|
|
reactiveHookName === 'useCallback') {
|
|
reportProblem({
|
|
node: reactiveHook,
|
|
message: `React Hook ${reactiveHookName} does nothing when called with ` +
|
|
`only one argument. Did you forget to pass an array of ` +
|
|
`dependencies?`,
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
while (callback.type === 'TSAsExpression' ||
|
|
callback.type === 'AsExpression') {
|
|
callback = callback.expression;
|
|
}
|
|
switch (callback.type) {
|
|
case 'FunctionExpression':
|
|
case 'ArrowFunctionExpression':
|
|
visitFunctionWithDependencies(callback, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect, isAutoDepsHook);
|
|
return;
|
|
case 'Identifier':
|
|
if (!declaredDependenciesNode ||
|
|
(isAutoDepsHook &&
|
|
declaredDependenciesNode.type === 'Literal' &&
|
|
declaredDependenciesNode.value === null)) {
|
|
return;
|
|
}
|
|
if ('elements' in declaredDependenciesNode &&
|
|
declaredDependenciesNode.elements &&
|
|
declaredDependenciesNode.elements.some(el => el && el.type === 'Identifier' && el.name === callback.name)) {
|
|
return;
|
|
}
|
|
const variable = getScope(callback).set.get(callback.name);
|
|
if (variable == null || variable.defs == null) {
|
|
return;
|
|
}
|
|
const def = variable.defs[0];
|
|
if (!def || !def.node) {
|
|
break;
|
|
}
|
|
if (def.type === 'Parameter') {
|
|
reportProblem({
|
|
node: reactiveHook,
|
|
message: getUnknownDependenciesMessage(reactiveHookName),
|
|
});
|
|
return;
|
|
}
|
|
if (def.type !== 'Variable' && def.type !== 'FunctionName') {
|
|
break;
|
|
}
|
|
switch (def.node.type) {
|
|
case 'FunctionDeclaration':
|
|
visitFunctionWithDependencies(def.node, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect, isAutoDepsHook);
|
|
return;
|
|
case 'VariableDeclarator':
|
|
const init = def.node.init;
|
|
if (!init) {
|
|
break;
|
|
}
|
|
switch (init.type) {
|
|
case 'ArrowFunctionExpression':
|
|
case 'FunctionExpression':
|
|
visitFunctionWithDependencies(init, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect, isAutoDepsHook);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
reportProblem({
|
|
node: reactiveHook,
|
|
message: getUnknownDependenciesMessage(reactiveHookName),
|
|
});
|
|
return;
|
|
}
|
|
reportProblem({
|
|
node: reactiveHook,
|
|
message: `React Hook ${reactiveHookName} has a missing dependency: '${callback.name}'. ` +
|
|
`Either include it or remove the dependency array.`,
|
|
suggest: [
|
|
{
|
|
desc: `Update the dependencies array to be: [${callback.name}]`,
|
|
fix(fixer) {
|
|
return fixer.replaceText(declaredDependenciesNode, `[${callback.name}]`);
|
|
},
|
|
},
|
|
],
|
|
});
|
|
}
|
|
return {
|
|
CallExpression: visitCallExpression,
|
|
};
|
|
},
|
|
};
|
|
function collectRecommendations({ dependencies, declaredDependencies, stableDependencies, externalDependencies, isEffect, }) {
|
|
const depTree = createDepTree();
|
|
function createDepTree() {
|
|
return {
|
|
isUsed: false,
|
|
isSatisfiedRecursively: false,
|
|
isSubtreeUsed: false,
|
|
children: new Map(),
|
|
};
|
|
}
|
|
dependencies.forEach((_, key) => {
|
|
const node = getOrCreateNodeByPath(depTree, key);
|
|
node.isUsed = true;
|
|
markAllParentsByPath(depTree, key, parent => {
|
|
parent.isSubtreeUsed = true;
|
|
});
|
|
});
|
|
declaredDependencies.forEach(({ key }) => {
|
|
const node = getOrCreateNodeByPath(depTree, key);
|
|
node.isSatisfiedRecursively = true;
|
|
});
|
|
stableDependencies.forEach(key => {
|
|
const node = getOrCreateNodeByPath(depTree, key);
|
|
node.isSatisfiedRecursively = true;
|
|
});
|
|
function getOrCreateNodeByPath(rootNode, path) {
|
|
const keys = path.split('.');
|
|
let node = rootNode;
|
|
for (const key of keys) {
|
|
let child = node.children.get(key);
|
|
if (!child) {
|
|
child = createDepTree();
|
|
node.children.set(key, child);
|
|
}
|
|
node = child;
|
|
}
|
|
return node;
|
|
}
|
|
function markAllParentsByPath(rootNode, path, fn) {
|
|
const keys = path.split('.');
|
|
let node = rootNode;
|
|
for (const key of keys) {
|
|
const child = node.children.get(key);
|
|
if (!child) {
|
|
return;
|
|
}
|
|
fn(child);
|
|
node = child;
|
|
}
|
|
}
|
|
const missingDependencies = new Set();
|
|
const satisfyingDependencies = new Set();
|
|
scanTreeRecursively(depTree, missingDependencies, satisfyingDependencies, key => key);
|
|
function scanTreeRecursively(node, missingPaths, satisfyingPaths, keyToPath) {
|
|
node.children.forEach((child, key) => {
|
|
const path = keyToPath(key);
|
|
if (child.isSatisfiedRecursively) {
|
|
if (child.isSubtreeUsed) {
|
|
satisfyingPaths.add(path);
|
|
}
|
|
return;
|
|
}
|
|
if (child.isUsed) {
|
|
missingPaths.add(path);
|
|
return;
|
|
}
|
|
scanTreeRecursively(child, missingPaths, satisfyingPaths, childKey => path + '.' + childKey);
|
|
});
|
|
}
|
|
const suggestedDependencies = [];
|
|
const unnecessaryDependencies = new Set();
|
|
const duplicateDependencies = new Set();
|
|
declaredDependencies.forEach(({ key }) => {
|
|
if (satisfyingDependencies.has(key)) {
|
|
if (suggestedDependencies.indexOf(key) === -1) {
|
|
suggestedDependencies.push(key);
|
|
}
|
|
else {
|
|
duplicateDependencies.add(key);
|
|
}
|
|
}
|
|
else {
|
|
if (isEffect &&
|
|
!key.endsWith('.current') &&
|
|
!externalDependencies.has(key)) {
|
|
if (suggestedDependencies.indexOf(key) === -1) {
|
|
suggestedDependencies.push(key);
|
|
}
|
|
}
|
|
else {
|
|
unnecessaryDependencies.add(key);
|
|
}
|
|
}
|
|
});
|
|
missingDependencies.forEach(key => {
|
|
suggestedDependencies.push(key);
|
|
});
|
|
return {
|
|
suggestedDependencies,
|
|
unnecessaryDependencies,
|
|
duplicateDependencies,
|
|
missingDependencies,
|
|
};
|
|
}
|
|
function getConstructionExpressionType(node) {
|
|
switch (node.type) {
|
|
case 'ObjectExpression':
|
|
return 'object';
|
|
case 'ArrayExpression':
|
|
return 'array';
|
|
case 'ArrowFunctionExpression':
|
|
case 'FunctionExpression':
|
|
return 'function';
|
|
case 'ClassExpression':
|
|
return 'class';
|
|
case 'ConditionalExpression':
|
|
if (getConstructionExpressionType(node.consequent) != null ||
|
|
getConstructionExpressionType(node.alternate) != null) {
|
|
return 'conditional';
|
|
}
|
|
return null;
|
|
case 'LogicalExpression':
|
|
if (getConstructionExpressionType(node.left) != null ||
|
|
getConstructionExpressionType(node.right) != null) {
|
|
return 'logical expression';
|
|
}
|
|
return null;
|
|
case 'JSXFragment':
|
|
return 'JSX fragment';
|
|
case 'JSXElement':
|
|
return 'JSX element';
|
|
case 'AssignmentExpression':
|
|
if (getConstructionExpressionType(node.right) != null) {
|
|
return 'assignment expression';
|
|
}
|
|
return null;
|
|
case 'NewExpression':
|
|
return 'object construction';
|
|
case 'Literal':
|
|
if (node.value instanceof RegExp) {
|
|
return 'regular expression';
|
|
}
|
|
return null;
|
|
case 'TypeCastExpression':
|
|
case 'AsExpression':
|
|
case 'TSAsExpression':
|
|
return getConstructionExpressionType(node.expression);
|
|
}
|
|
return null;
|
|
}
|
|
function scanForConstructions({ declaredDependencies, declaredDependenciesNode, componentScope, scope, }) {
|
|
const constructions = declaredDependencies
|
|
.map(({ key }) => {
|
|
const ref = componentScope.variables.find(v => v.name === key);
|
|
if (ref == null) {
|
|
return null;
|
|
}
|
|
const node = ref.defs[0];
|
|
if (node == null) {
|
|
return null;
|
|
}
|
|
if (node.type === 'Variable' &&
|
|
node.node.type === 'VariableDeclarator' &&
|
|
node.node.id.type === 'Identifier' &&
|
|
node.node.init != null) {
|
|
const constantExpressionType = getConstructionExpressionType(node.node.init);
|
|
if (constantExpressionType) {
|
|
return [ref, constantExpressionType];
|
|
}
|
|
}
|
|
if (node.type === 'FunctionName' &&
|
|
node.node.type === 'FunctionDeclaration') {
|
|
return [ref, 'function'];
|
|
}
|
|
if (node.type === 'ClassName' && node.node.type === 'ClassDeclaration') {
|
|
return [ref, 'class'];
|
|
}
|
|
return null;
|
|
})
|
|
.filter(Boolean);
|
|
function isUsedOutsideOfHook(ref) {
|
|
let foundWriteExpr = false;
|
|
for (const reference of ref.references) {
|
|
if (reference.writeExpr) {
|
|
if (foundWriteExpr) {
|
|
return true;
|
|
}
|
|
else {
|
|
foundWriteExpr = true;
|
|
continue;
|
|
}
|
|
}
|
|
let currentScope = reference.from;
|
|
while (currentScope !== scope && currentScope != null) {
|
|
currentScope = currentScope.upper;
|
|
}
|
|
if (currentScope !== scope) {
|
|
if (!isAncestorNodeOf(declaredDependenciesNode, reference.identifier)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
return constructions.map(([ref, depType]) => ({
|
|
construction: ref.defs[0],
|
|
depType,
|
|
isUsedOutsideOfHook: isUsedOutsideOfHook(ref),
|
|
}));
|
|
}
|
|
function getDependency(node) {
|
|
if (node.parent &&
|
|
(node.parent.type === 'MemberExpression' ||
|
|
node.parent.type === 'OptionalMemberExpression') &&
|
|
node.parent.object === node &&
|
|
'name' in node.parent.property &&
|
|
node.parent.property.name !== 'current' &&
|
|
!node.parent.computed &&
|
|
!(node.parent.parent != null &&
|
|
(node.parent.parent.type === 'CallExpression' ||
|
|
node.parent.parent.type === 'OptionalCallExpression') &&
|
|
node.parent.parent.callee === node.parent)) {
|
|
return getDependency(node.parent);
|
|
}
|
|
else if (node.type === 'MemberExpression' &&
|
|
node.parent &&
|
|
node.parent.type === 'AssignmentExpression' &&
|
|
node.parent.left === node) {
|
|
return node.object;
|
|
}
|
|
else {
|
|
return node;
|
|
}
|
|
}
|
|
function markNode(node, optionalChains, result) {
|
|
if (optionalChains) {
|
|
if ('optional' in node && node.optional) {
|
|
if (!optionalChains.has(result)) {
|
|
optionalChains.set(result, true);
|
|
}
|
|
}
|
|
else {
|
|
optionalChains.set(result, false);
|
|
}
|
|
}
|
|
}
|
|
function analyzePropertyChain(node, optionalChains) {
|
|
if (node.type === 'Identifier' || node.type === 'JSXIdentifier') {
|
|
const result = node.name;
|
|
if (optionalChains) {
|
|
optionalChains.set(result, false);
|
|
}
|
|
return result;
|
|
}
|
|
else if (node.type === 'MemberExpression' && !node.computed) {
|
|
const object = analyzePropertyChain(node.object, optionalChains);
|
|
const property = analyzePropertyChain(node.property, null);
|
|
const result = `${object}.${property}`;
|
|
markNode(node, optionalChains, result);
|
|
return result;
|
|
}
|
|
else if (node.type === 'OptionalMemberExpression' && !node.computed) {
|
|
const object = analyzePropertyChain(node.object, optionalChains);
|
|
const property = analyzePropertyChain(node.property, null);
|
|
const result = `${object}.${property}`;
|
|
markNode(node, optionalChains, result);
|
|
return result;
|
|
}
|
|
else if (node.type === 'ChainExpression' &&
|
|
(!('computed' in node) || !node.computed)) {
|
|
const expression = node.expression;
|
|
if (expression.type === 'CallExpression') {
|
|
throw new Error(`Unsupported node type: ${expression.type}`);
|
|
}
|
|
const object = analyzePropertyChain(expression.object, optionalChains);
|
|
const property = analyzePropertyChain(expression.property, null);
|
|
const result = `${object}.${property}`;
|
|
markNode(expression, optionalChains, result);
|
|
return result;
|
|
}
|
|
else {
|
|
throw new Error(`Unsupported node type: ${node.type}`);
|
|
}
|
|
}
|
|
function getNodeWithoutReactNamespace$1(node) {
|
|
if (node.type === 'MemberExpression' &&
|
|
node.object.type === 'Identifier' &&
|
|
node.object.name === 'React' &&
|
|
node.property.type === 'Identifier' &&
|
|
!node.computed) {
|
|
return node.property;
|
|
}
|
|
return node;
|
|
}
|
|
function getReactiveHookCallbackIndex(calleeNode, options) {
|
|
const node = getNodeWithoutReactNamespace$1(calleeNode);
|
|
if (node.type !== 'Identifier') {
|
|
return -1;
|
|
}
|
|
switch (node.name) {
|
|
case 'useEffect':
|
|
case 'useLayoutEffect':
|
|
case 'useCallback':
|
|
case 'useMemo':
|
|
return 0;
|
|
case 'useImperativeHandle':
|
|
return 1;
|
|
default:
|
|
if (node === calleeNode && options && options.additionalHooks) {
|
|
let name;
|
|
try {
|
|
name = analyzePropertyChain(node, null);
|
|
}
|
|
catch (error) {
|
|
if (error instanceof Error &&
|
|
/Unsupported node type/.test(error.message)) {
|
|
return 0;
|
|
}
|
|
else {
|
|
throw error;
|
|
}
|
|
}
|
|
return options.additionalHooks.test(name) ? 0 : -1;
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
function fastFindReferenceWithParent(start, target) {
|
|
const queue = [start];
|
|
let item;
|
|
while (queue.length) {
|
|
item = queue.shift();
|
|
if (isSameIdentifier(item, target)) {
|
|
return item;
|
|
}
|
|
if (!isAncestorNodeOf(item, target)) {
|
|
continue;
|
|
}
|
|
for (const [key, value] of Object.entries(item)) {
|
|
if (key === 'parent') {
|
|
continue;
|
|
}
|
|
if (isNodeLike(value)) {
|
|
value.parent = item;
|
|
queue.push(value);
|
|
}
|
|
else if (Array.isArray(value)) {
|
|
value.forEach(val => {
|
|
if (isNodeLike(val)) {
|
|
val.parent = item;
|
|
queue.push(val);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
function joinEnglish(arr) {
|
|
let s = '';
|
|
for (let i = 0; i < arr.length; i++) {
|
|
s += arr[i];
|
|
if (i === 0 && arr.length === 2) {
|
|
s += ' and ';
|
|
}
|
|
else if (i === arr.length - 2 && arr.length > 2) {
|
|
s += ', and ';
|
|
}
|
|
else if (i < arr.length - 1) {
|
|
s += ', ';
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
function isNodeLike(val) {
|
|
return (typeof val === 'object' &&
|
|
val !== null &&
|
|
!Array.isArray(val) &&
|
|
'type' in val &&
|
|
typeof val.type === 'string');
|
|
}
|
|
function isSameIdentifier(a, b) {
|
|
return ((a.type === 'Identifier' || a.type === 'JSXIdentifier') &&
|
|
a.type === b.type &&
|
|
a.name === b.name &&
|
|
!!a.range &&
|
|
!!b.range &&
|
|
a.range[0] === b.range[0] &&
|
|
a.range[1] === b.range[1]);
|
|
}
|
|
function isAncestorNodeOf(a, b) {
|
|
return (!!a.range &&
|
|
!!b.range &&
|
|
a.range[0] <= b.range[0] &&
|
|
a.range[1] >= b.range[1]);
|
|
}
|
|
function isUseEffectEventIdentifier$1(node) {
|
|
return node.type === 'Identifier' && node.name === 'useEffectEvent';
|
|
}
|
|
function getUnknownDependenciesMessage(reactiveHookName) {
|
|
return (`React Hook ${reactiveHookName} received a function whose dependencies ` +
|
|
`are unknown. Pass an inline function instead.`);
|
|
}
|
|
|
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
|
|
function getDefaultExportFromCjs (x) {
|
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
}
|
|
|
|
var invariant_1;
|
|
var hasRequiredInvariant;
|
|
|
|
function requireInvariant () {
|
|
if (hasRequiredInvariant) return invariant_1;
|
|
hasRequiredInvariant = 1;
|
|
|
|
var invariant = function(condition, format, a, b, c, d, e, f) {
|
|
{
|
|
if (format === undefined) {
|
|
throw new Error('invariant requires an error message argument');
|
|
}
|
|
}
|
|
|
|
if (!condition) {
|
|
var error;
|
|
if (format === undefined) {
|
|
error = new Error(
|
|
'Minified exception occurred; use the non-minified dev environment ' +
|
|
'for the full error message and additional helpful warnings.'
|
|
);
|
|
} else {
|
|
var args = [a, b, c, d, e, f];
|
|
var argIndex = 0;
|
|
error = new Error(
|
|
format.replace(/%s/g, function() { return args[argIndex++]; })
|
|
);
|
|
error.name = 'Invariant Violation';
|
|
}
|
|
|
|
error.framesToPop = 1; // we don't care about invariant's own frame
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
invariant_1 = invariant;
|
|
return invariant_1;
|
|
}
|
|
|
|
var invariantExports = requireInvariant();
|
|
var invariant = /*@__PURE__*/getDefaultExportFromCjs(invariantExports);
|
|
|
|
var lib$3 = {};
|
|
|
|
var isReactComponent = {};
|
|
|
|
var buildMatchMemberExpression = {};
|
|
|
|
var matchesPattern = {};
|
|
|
|
var generated$3 = {};
|
|
|
|
var shallowEqual = {};
|
|
|
|
var hasRequiredShallowEqual;
|
|
|
|
function requireShallowEqual () {
|
|
if (hasRequiredShallowEqual) return shallowEqual;
|
|
hasRequiredShallowEqual = 1;
|
|
|
|
Object.defineProperty(shallowEqual, "__esModule", {
|
|
value: true
|
|
});
|
|
shallowEqual.default = shallowEqual$1;
|
|
function shallowEqual$1(actual, expected) {
|
|
const keys = Object.keys(expected);
|
|
for (const key of keys) {
|
|
if (actual[key] !== expected[key]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
return shallowEqual;
|
|
}
|
|
|
|
var deprecationWarning = {};
|
|
|
|
var hasRequiredDeprecationWarning;
|
|
|
|
function requireDeprecationWarning () {
|
|
if (hasRequiredDeprecationWarning) return deprecationWarning;
|
|
hasRequiredDeprecationWarning = 1;
|
|
|
|
Object.defineProperty(deprecationWarning, "__esModule", {
|
|
value: true
|
|
});
|
|
deprecationWarning.default = deprecationWarning$1;
|
|
const warnings = new Set();
|
|
function deprecationWarning$1(oldName, newName, prefix = "") {
|
|
if (warnings.has(oldName)) return;
|
|
warnings.add(oldName);
|
|
const {
|
|
internal,
|
|
trace
|
|
} = captureShortStackTrace(1, 2);
|
|
if (internal) {
|
|
return;
|
|
}
|
|
console.warn(`${prefix}\`${oldName}\` has been deprecated, please migrate to \`${newName}\`\n${trace}`);
|
|
}
|
|
function captureShortStackTrace(skip, length) {
|
|
const {
|
|
stackTraceLimit,
|
|
prepareStackTrace
|
|
} = Error;
|
|
let stackTrace;
|
|
Error.stackTraceLimit = 1 + skip + length;
|
|
Error.prepareStackTrace = function (err, stack) {
|
|
stackTrace = stack;
|
|
};
|
|
Error.stackTraceLimit = stackTraceLimit;
|
|
Error.prepareStackTrace = prepareStackTrace;
|
|
if (!stackTrace) return {
|
|
internal: false,
|
|
trace: ""
|
|
};
|
|
const shortStackTrace = stackTrace.slice(1 + skip, 1 + skip + length);
|
|
return {
|
|
internal: /[\\/]@babel[\\/]/.test(shortStackTrace[1].getFileName()),
|
|
trace: shortStackTrace.map(frame => ` at ${frame}`).join("\n")
|
|
};
|
|
}
|
|
|
|
|
|
return deprecationWarning;
|
|
}
|
|
|
|
var hasRequiredGenerated$3;
|
|
|
|
function requireGenerated$3 () {
|
|
if (hasRequiredGenerated$3) return generated$3;
|
|
hasRequiredGenerated$3 = 1;
|
|
|
|
Object.defineProperty(generated$3, "__esModule", {
|
|
value: true
|
|
});
|
|
generated$3.isAccessor = isAccessor;
|
|
generated$3.isAnyTypeAnnotation = isAnyTypeAnnotation;
|
|
generated$3.isArgumentPlaceholder = isArgumentPlaceholder;
|
|
generated$3.isArrayExpression = isArrayExpression;
|
|
generated$3.isArrayPattern = isArrayPattern;
|
|
generated$3.isArrayTypeAnnotation = isArrayTypeAnnotation;
|
|
generated$3.isArrowFunctionExpression = isArrowFunctionExpression;
|
|
generated$3.isAssignmentExpression = isAssignmentExpression;
|
|
generated$3.isAssignmentPattern = isAssignmentPattern;
|
|
generated$3.isAwaitExpression = isAwaitExpression;
|
|
generated$3.isBigIntLiteral = isBigIntLiteral;
|
|
generated$3.isBinary = isBinary;
|
|
generated$3.isBinaryExpression = isBinaryExpression;
|
|
generated$3.isBindExpression = isBindExpression;
|
|
generated$3.isBlock = isBlock;
|
|
generated$3.isBlockParent = isBlockParent;
|
|
generated$3.isBlockStatement = isBlockStatement;
|
|
generated$3.isBooleanLiteral = isBooleanLiteral;
|
|
generated$3.isBooleanLiteralTypeAnnotation = isBooleanLiteralTypeAnnotation;
|
|
generated$3.isBooleanTypeAnnotation = isBooleanTypeAnnotation;
|
|
generated$3.isBreakStatement = isBreakStatement;
|
|
generated$3.isCallExpression = isCallExpression;
|
|
generated$3.isCatchClause = isCatchClause;
|
|
generated$3.isClass = isClass;
|
|
generated$3.isClassAccessorProperty = isClassAccessorProperty;
|
|
generated$3.isClassBody = isClassBody;
|
|
generated$3.isClassDeclaration = isClassDeclaration;
|
|
generated$3.isClassExpression = isClassExpression;
|
|
generated$3.isClassImplements = isClassImplements;
|
|
generated$3.isClassMethod = isClassMethod;
|
|
generated$3.isClassPrivateMethod = isClassPrivateMethod;
|
|
generated$3.isClassPrivateProperty = isClassPrivateProperty;
|
|
generated$3.isClassProperty = isClassProperty;
|
|
generated$3.isCompletionStatement = isCompletionStatement;
|
|
generated$3.isConditional = isConditional;
|
|
generated$3.isConditionalExpression = isConditionalExpression;
|
|
generated$3.isContinueStatement = isContinueStatement;
|
|
generated$3.isDebuggerStatement = isDebuggerStatement;
|
|
generated$3.isDecimalLiteral = isDecimalLiteral;
|
|
generated$3.isDeclaration = isDeclaration;
|
|
generated$3.isDeclareClass = isDeclareClass;
|
|
generated$3.isDeclareExportAllDeclaration = isDeclareExportAllDeclaration;
|
|
generated$3.isDeclareExportDeclaration = isDeclareExportDeclaration;
|
|
generated$3.isDeclareFunction = isDeclareFunction;
|
|
generated$3.isDeclareInterface = isDeclareInterface;
|
|
generated$3.isDeclareModule = isDeclareModule;
|
|
generated$3.isDeclareModuleExports = isDeclareModuleExports;
|
|
generated$3.isDeclareOpaqueType = isDeclareOpaqueType;
|
|
generated$3.isDeclareTypeAlias = isDeclareTypeAlias;
|
|
generated$3.isDeclareVariable = isDeclareVariable;
|
|
generated$3.isDeclaredPredicate = isDeclaredPredicate;
|
|
generated$3.isDecorator = isDecorator;
|
|
generated$3.isDirective = isDirective;
|
|
generated$3.isDirectiveLiteral = isDirectiveLiteral;
|
|
generated$3.isDoExpression = isDoExpression;
|
|
generated$3.isDoWhileStatement = isDoWhileStatement;
|
|
generated$3.isEmptyStatement = isEmptyStatement;
|
|
generated$3.isEmptyTypeAnnotation = isEmptyTypeAnnotation;
|
|
generated$3.isEnumBody = isEnumBody;
|
|
generated$3.isEnumBooleanBody = isEnumBooleanBody;
|
|
generated$3.isEnumBooleanMember = isEnumBooleanMember;
|
|
generated$3.isEnumDeclaration = isEnumDeclaration;
|
|
generated$3.isEnumDefaultedMember = isEnumDefaultedMember;
|
|
generated$3.isEnumMember = isEnumMember;
|
|
generated$3.isEnumNumberBody = isEnumNumberBody;
|
|
generated$3.isEnumNumberMember = isEnumNumberMember;
|
|
generated$3.isEnumStringBody = isEnumStringBody;
|
|
generated$3.isEnumStringMember = isEnumStringMember;
|
|
generated$3.isEnumSymbolBody = isEnumSymbolBody;
|
|
generated$3.isExistsTypeAnnotation = isExistsTypeAnnotation;
|
|
generated$3.isExportAllDeclaration = isExportAllDeclaration;
|
|
generated$3.isExportDeclaration = isExportDeclaration;
|
|
generated$3.isExportDefaultDeclaration = isExportDefaultDeclaration;
|
|
generated$3.isExportDefaultSpecifier = isExportDefaultSpecifier;
|
|
generated$3.isExportNamedDeclaration = isExportNamedDeclaration;
|
|
generated$3.isExportNamespaceSpecifier = isExportNamespaceSpecifier;
|
|
generated$3.isExportSpecifier = isExportSpecifier;
|
|
generated$3.isExpression = isExpression;
|
|
generated$3.isExpressionStatement = isExpressionStatement;
|
|
generated$3.isExpressionWrapper = isExpressionWrapper;
|
|
generated$3.isFile = isFile;
|
|
generated$3.isFlow = isFlow;
|
|
generated$3.isFlowBaseAnnotation = isFlowBaseAnnotation;
|
|
generated$3.isFlowDeclaration = isFlowDeclaration;
|
|
generated$3.isFlowPredicate = isFlowPredicate;
|
|
generated$3.isFlowType = isFlowType;
|
|
generated$3.isFor = isFor;
|
|
generated$3.isForInStatement = isForInStatement;
|
|
generated$3.isForOfStatement = isForOfStatement;
|
|
generated$3.isForStatement = isForStatement;
|
|
generated$3.isForXStatement = isForXStatement;
|
|
generated$3.isFunction = isFunction;
|
|
generated$3.isFunctionDeclaration = isFunctionDeclaration;
|
|
generated$3.isFunctionExpression = isFunctionExpression;
|
|
generated$3.isFunctionParent = isFunctionParent;
|
|
generated$3.isFunctionTypeAnnotation = isFunctionTypeAnnotation;
|
|
generated$3.isFunctionTypeParam = isFunctionTypeParam;
|
|
generated$3.isGenericTypeAnnotation = isGenericTypeAnnotation;
|
|
generated$3.isIdentifier = isIdentifier;
|
|
generated$3.isIfStatement = isIfStatement;
|
|
generated$3.isImmutable = isImmutable;
|
|
generated$3.isImport = isImport;
|
|
generated$3.isImportAttribute = isImportAttribute;
|
|
generated$3.isImportDeclaration = isImportDeclaration;
|
|
generated$3.isImportDefaultSpecifier = isImportDefaultSpecifier;
|
|
generated$3.isImportExpression = isImportExpression;
|
|
generated$3.isImportNamespaceSpecifier = isImportNamespaceSpecifier;
|
|
generated$3.isImportOrExportDeclaration = isImportOrExportDeclaration;
|
|
generated$3.isImportSpecifier = isImportSpecifier;
|
|
generated$3.isIndexedAccessType = isIndexedAccessType;
|
|
generated$3.isInferredPredicate = isInferredPredicate;
|
|
generated$3.isInterfaceDeclaration = isInterfaceDeclaration;
|
|
generated$3.isInterfaceExtends = isInterfaceExtends;
|
|
generated$3.isInterfaceTypeAnnotation = isInterfaceTypeAnnotation;
|
|
generated$3.isInterpreterDirective = isInterpreterDirective;
|
|
generated$3.isIntersectionTypeAnnotation = isIntersectionTypeAnnotation;
|
|
generated$3.isJSX = isJSX;
|
|
generated$3.isJSXAttribute = isJSXAttribute;
|
|
generated$3.isJSXClosingElement = isJSXClosingElement;
|
|
generated$3.isJSXClosingFragment = isJSXClosingFragment;
|
|
generated$3.isJSXElement = isJSXElement;
|
|
generated$3.isJSXEmptyExpression = isJSXEmptyExpression;
|
|
generated$3.isJSXExpressionContainer = isJSXExpressionContainer;
|
|
generated$3.isJSXFragment = isJSXFragment;
|
|
generated$3.isJSXIdentifier = isJSXIdentifier;
|
|
generated$3.isJSXMemberExpression = isJSXMemberExpression;
|
|
generated$3.isJSXNamespacedName = isJSXNamespacedName;
|
|
generated$3.isJSXOpeningElement = isJSXOpeningElement;
|
|
generated$3.isJSXOpeningFragment = isJSXOpeningFragment;
|
|
generated$3.isJSXSpreadAttribute = isJSXSpreadAttribute;
|
|
generated$3.isJSXSpreadChild = isJSXSpreadChild;
|
|
generated$3.isJSXText = isJSXText;
|
|
generated$3.isLVal = isLVal;
|
|
generated$3.isLabeledStatement = isLabeledStatement;
|
|
generated$3.isLiteral = isLiteral;
|
|
generated$3.isLogicalExpression = isLogicalExpression;
|
|
generated$3.isLoop = isLoop;
|
|
generated$3.isMemberExpression = isMemberExpression;
|
|
generated$3.isMetaProperty = isMetaProperty;
|
|
generated$3.isMethod = isMethod;
|
|
generated$3.isMiscellaneous = isMiscellaneous;
|
|
generated$3.isMixedTypeAnnotation = isMixedTypeAnnotation;
|
|
generated$3.isModuleDeclaration = isModuleDeclaration;
|
|
generated$3.isModuleExpression = isModuleExpression;
|
|
generated$3.isModuleSpecifier = isModuleSpecifier;
|
|
generated$3.isNewExpression = isNewExpression;
|
|
generated$3.isNoop = isNoop;
|
|
generated$3.isNullLiteral = isNullLiteral;
|
|
generated$3.isNullLiteralTypeAnnotation = isNullLiteralTypeAnnotation;
|
|
generated$3.isNullableTypeAnnotation = isNullableTypeAnnotation;
|
|
generated$3.isNumberLiteral = isNumberLiteral;
|
|
generated$3.isNumberLiteralTypeAnnotation = isNumberLiteralTypeAnnotation;
|
|
generated$3.isNumberTypeAnnotation = isNumberTypeAnnotation;
|
|
generated$3.isNumericLiteral = isNumericLiteral;
|
|
generated$3.isObjectExpression = isObjectExpression;
|
|
generated$3.isObjectMember = isObjectMember;
|
|
generated$3.isObjectMethod = isObjectMethod;
|
|
generated$3.isObjectPattern = isObjectPattern;
|
|
generated$3.isObjectProperty = isObjectProperty;
|
|
generated$3.isObjectTypeAnnotation = isObjectTypeAnnotation;
|
|
generated$3.isObjectTypeCallProperty = isObjectTypeCallProperty;
|
|
generated$3.isObjectTypeIndexer = isObjectTypeIndexer;
|
|
generated$3.isObjectTypeInternalSlot = isObjectTypeInternalSlot;
|
|
generated$3.isObjectTypeProperty = isObjectTypeProperty;
|
|
generated$3.isObjectTypeSpreadProperty = isObjectTypeSpreadProperty;
|
|
generated$3.isOpaqueType = isOpaqueType;
|
|
generated$3.isOptionalCallExpression = isOptionalCallExpression;
|
|
generated$3.isOptionalIndexedAccessType = isOptionalIndexedAccessType;
|
|
generated$3.isOptionalMemberExpression = isOptionalMemberExpression;
|
|
generated$3.isParenthesizedExpression = isParenthesizedExpression;
|
|
generated$3.isPattern = isPattern;
|
|
generated$3.isPatternLike = isPatternLike;
|
|
generated$3.isPipelineBareFunction = isPipelineBareFunction;
|
|
generated$3.isPipelinePrimaryTopicReference = isPipelinePrimaryTopicReference;
|
|
generated$3.isPipelineTopicExpression = isPipelineTopicExpression;
|
|
generated$3.isPlaceholder = isPlaceholder;
|
|
generated$3.isPrivate = isPrivate;
|
|
generated$3.isPrivateName = isPrivateName;
|
|
generated$3.isProgram = isProgram;
|
|
generated$3.isProperty = isProperty;
|
|
generated$3.isPureish = isPureish;
|
|
generated$3.isQualifiedTypeIdentifier = isQualifiedTypeIdentifier;
|
|
generated$3.isRecordExpression = isRecordExpression;
|
|
generated$3.isRegExpLiteral = isRegExpLiteral;
|
|
generated$3.isRegexLiteral = isRegexLiteral;
|
|
generated$3.isRestElement = isRestElement;
|
|
generated$3.isRestProperty = isRestProperty;
|
|
generated$3.isReturnStatement = isReturnStatement;
|
|
generated$3.isScopable = isScopable;
|
|
generated$3.isSequenceExpression = isSequenceExpression;
|
|
generated$3.isSpreadElement = isSpreadElement;
|
|
generated$3.isSpreadProperty = isSpreadProperty;
|
|
generated$3.isStandardized = isStandardized;
|
|
generated$3.isStatement = isStatement;
|
|
generated$3.isStaticBlock = isStaticBlock;
|
|
generated$3.isStringLiteral = isStringLiteral;
|
|
generated$3.isStringLiteralTypeAnnotation = isStringLiteralTypeAnnotation;
|
|
generated$3.isStringTypeAnnotation = isStringTypeAnnotation;
|
|
generated$3.isSuper = isSuper;
|
|
generated$3.isSwitchCase = isSwitchCase;
|
|
generated$3.isSwitchStatement = isSwitchStatement;
|
|
generated$3.isSymbolTypeAnnotation = isSymbolTypeAnnotation;
|
|
generated$3.isTSAnyKeyword = isTSAnyKeyword;
|
|
generated$3.isTSArrayType = isTSArrayType;
|
|
generated$3.isTSAsExpression = isTSAsExpression;
|
|
generated$3.isTSBaseType = isTSBaseType;
|
|
generated$3.isTSBigIntKeyword = isTSBigIntKeyword;
|
|
generated$3.isTSBooleanKeyword = isTSBooleanKeyword;
|
|
generated$3.isTSCallSignatureDeclaration = isTSCallSignatureDeclaration;
|
|
generated$3.isTSConditionalType = isTSConditionalType;
|
|
generated$3.isTSConstructSignatureDeclaration = isTSConstructSignatureDeclaration;
|
|
generated$3.isTSConstructorType = isTSConstructorType;
|
|
generated$3.isTSDeclareFunction = isTSDeclareFunction;
|
|
generated$3.isTSDeclareMethod = isTSDeclareMethod;
|
|
generated$3.isTSEntityName = isTSEntityName;
|
|
generated$3.isTSEnumDeclaration = isTSEnumDeclaration;
|
|
generated$3.isTSEnumMember = isTSEnumMember;
|
|
generated$3.isTSExportAssignment = isTSExportAssignment;
|
|
generated$3.isTSExpressionWithTypeArguments = isTSExpressionWithTypeArguments;
|
|
generated$3.isTSExternalModuleReference = isTSExternalModuleReference;
|
|
generated$3.isTSFunctionType = isTSFunctionType;
|
|
generated$3.isTSImportEqualsDeclaration = isTSImportEqualsDeclaration;
|
|
generated$3.isTSImportType = isTSImportType;
|
|
generated$3.isTSIndexSignature = isTSIndexSignature;
|
|
generated$3.isTSIndexedAccessType = isTSIndexedAccessType;
|
|
generated$3.isTSInferType = isTSInferType;
|
|
generated$3.isTSInstantiationExpression = isTSInstantiationExpression;
|
|
generated$3.isTSInterfaceBody = isTSInterfaceBody;
|
|
generated$3.isTSInterfaceDeclaration = isTSInterfaceDeclaration;
|
|
generated$3.isTSIntersectionType = isTSIntersectionType;
|
|
generated$3.isTSIntrinsicKeyword = isTSIntrinsicKeyword;
|
|
generated$3.isTSLiteralType = isTSLiteralType;
|
|
generated$3.isTSMappedType = isTSMappedType;
|
|
generated$3.isTSMethodSignature = isTSMethodSignature;
|
|
generated$3.isTSModuleBlock = isTSModuleBlock;
|
|
generated$3.isTSModuleDeclaration = isTSModuleDeclaration;
|
|
generated$3.isTSNamedTupleMember = isTSNamedTupleMember;
|
|
generated$3.isTSNamespaceExportDeclaration = isTSNamespaceExportDeclaration;
|
|
generated$3.isTSNeverKeyword = isTSNeverKeyword;
|
|
generated$3.isTSNonNullExpression = isTSNonNullExpression;
|
|
generated$3.isTSNullKeyword = isTSNullKeyword;
|
|
generated$3.isTSNumberKeyword = isTSNumberKeyword;
|
|
generated$3.isTSObjectKeyword = isTSObjectKeyword;
|
|
generated$3.isTSOptionalType = isTSOptionalType;
|
|
generated$3.isTSParameterProperty = isTSParameterProperty;
|
|
generated$3.isTSParenthesizedType = isTSParenthesizedType;
|
|
generated$3.isTSPropertySignature = isTSPropertySignature;
|
|
generated$3.isTSQualifiedName = isTSQualifiedName;
|
|
generated$3.isTSRestType = isTSRestType;
|
|
generated$3.isTSSatisfiesExpression = isTSSatisfiesExpression;
|
|
generated$3.isTSStringKeyword = isTSStringKeyword;
|
|
generated$3.isTSSymbolKeyword = isTSSymbolKeyword;
|
|
generated$3.isTSThisType = isTSThisType;
|
|
generated$3.isTSTupleType = isTSTupleType;
|
|
generated$3.isTSType = isTSType;
|
|
generated$3.isTSTypeAliasDeclaration = isTSTypeAliasDeclaration;
|
|
generated$3.isTSTypeAnnotation = isTSTypeAnnotation;
|
|
generated$3.isTSTypeAssertion = isTSTypeAssertion;
|
|
generated$3.isTSTypeElement = isTSTypeElement;
|
|
generated$3.isTSTypeLiteral = isTSTypeLiteral;
|
|
generated$3.isTSTypeOperator = isTSTypeOperator;
|
|
generated$3.isTSTypeParameter = isTSTypeParameter;
|
|
generated$3.isTSTypeParameterDeclaration = isTSTypeParameterDeclaration;
|
|
generated$3.isTSTypeParameterInstantiation = isTSTypeParameterInstantiation;
|
|
generated$3.isTSTypePredicate = isTSTypePredicate;
|
|
generated$3.isTSTypeQuery = isTSTypeQuery;
|
|
generated$3.isTSTypeReference = isTSTypeReference;
|
|
generated$3.isTSUndefinedKeyword = isTSUndefinedKeyword;
|
|
generated$3.isTSUnionType = isTSUnionType;
|
|
generated$3.isTSUnknownKeyword = isTSUnknownKeyword;
|
|
generated$3.isTSVoidKeyword = isTSVoidKeyword;
|
|
generated$3.isTaggedTemplateExpression = isTaggedTemplateExpression;
|
|
generated$3.isTemplateElement = isTemplateElement;
|
|
generated$3.isTemplateLiteral = isTemplateLiteral;
|
|
generated$3.isTerminatorless = isTerminatorless;
|
|
generated$3.isThisExpression = isThisExpression;
|
|
generated$3.isThisTypeAnnotation = isThisTypeAnnotation;
|
|
generated$3.isThrowStatement = isThrowStatement;
|
|
generated$3.isTopicReference = isTopicReference;
|
|
generated$3.isTryStatement = isTryStatement;
|
|
generated$3.isTupleExpression = isTupleExpression;
|
|
generated$3.isTupleTypeAnnotation = isTupleTypeAnnotation;
|
|
generated$3.isTypeAlias = isTypeAlias;
|
|
generated$3.isTypeAnnotation = isTypeAnnotation;
|
|
generated$3.isTypeCastExpression = isTypeCastExpression;
|
|
generated$3.isTypeParameter = isTypeParameter;
|
|
generated$3.isTypeParameterDeclaration = isTypeParameterDeclaration;
|
|
generated$3.isTypeParameterInstantiation = isTypeParameterInstantiation;
|
|
generated$3.isTypeScript = isTypeScript;
|
|
generated$3.isTypeofTypeAnnotation = isTypeofTypeAnnotation;
|
|
generated$3.isUnaryExpression = isUnaryExpression;
|
|
generated$3.isUnaryLike = isUnaryLike;
|
|
generated$3.isUnionTypeAnnotation = isUnionTypeAnnotation;
|
|
generated$3.isUpdateExpression = isUpdateExpression;
|
|
generated$3.isUserWhitespacable = isUserWhitespacable;
|
|
generated$3.isV8IntrinsicIdentifier = isV8IntrinsicIdentifier;
|
|
generated$3.isVariableDeclaration = isVariableDeclaration;
|
|
generated$3.isVariableDeclarator = isVariableDeclarator;
|
|
generated$3.isVariance = isVariance;
|
|
generated$3.isVoidTypeAnnotation = isVoidTypeAnnotation;
|
|
generated$3.isWhile = isWhile;
|
|
generated$3.isWhileStatement = isWhileStatement;
|
|
generated$3.isWithStatement = isWithStatement;
|
|
generated$3.isYieldExpression = isYieldExpression;
|
|
var _shallowEqual = requireShallowEqual();
|
|
var _deprecationWarning = requireDeprecationWarning();
|
|
function isArrayExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ArrayExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isAssignmentExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "AssignmentExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBinaryExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "BinaryExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isInterpreterDirective(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "InterpreterDirective") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDirective(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "Directive") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDirectiveLiteral(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DirectiveLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBlockStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "BlockStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBreakStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "BreakStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isCallExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "CallExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isCatchClause(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "CatchClause") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isConditionalExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ConditionalExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isContinueStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ContinueStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDebuggerStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DebuggerStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDoWhileStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DoWhileStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEmptyStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EmptyStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExpressionStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ExpressionStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFile(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "File") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isForInStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ForInStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isForStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ForStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFunctionDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "FunctionDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFunctionExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "FunctionExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isIdentifier(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "Identifier") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isIfStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "IfStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isLabeledStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "LabeledStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isStringLiteral(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "StringLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isNumericLiteral(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "NumericLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isNullLiteral(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "NullLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBooleanLiteral(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "BooleanLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isRegExpLiteral(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "RegExpLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isLogicalExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "LogicalExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isMemberExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "MemberExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isNewExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "NewExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isProgram(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "Program") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ObjectExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectMethod(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ObjectMethod") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectProperty(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ObjectProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isRestElement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "RestElement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isReturnStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ReturnStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isSequenceExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "SequenceExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isParenthesizedExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ParenthesizedExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isSwitchCase(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "SwitchCase") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isSwitchStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "SwitchStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isThisExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ThisExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isThrowStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ThrowStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTryStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TryStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isUnaryExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "UnaryExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isUpdateExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "UpdateExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isVariableDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "VariableDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isVariableDeclarator(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "VariableDeclarator") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isWhileStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "WhileStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isWithStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "WithStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isAssignmentPattern(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "AssignmentPattern") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isArrayPattern(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ArrayPattern") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isArrowFunctionExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ArrowFunctionExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isClassBody(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ClassBody") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isClassExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ClassExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isClassDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ClassDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExportAllDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ExportAllDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExportDefaultDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ExportDefaultDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExportNamedDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ExportNamedDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExportSpecifier(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ExportSpecifier") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isForOfStatement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ForOfStatement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isImportDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ImportDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isImportDefaultSpecifier(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ImportDefaultSpecifier") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isImportNamespaceSpecifier(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ImportNamespaceSpecifier") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isImportSpecifier(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ImportSpecifier") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isImportExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ImportExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isMetaProperty(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "MetaProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isClassMethod(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ClassMethod") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectPattern(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ObjectPattern") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isSpreadElement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "SpreadElement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isSuper(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "Super") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTaggedTemplateExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TaggedTemplateExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTemplateElement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TemplateElement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTemplateLiteral(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TemplateLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isYieldExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "YieldExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isAwaitExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "AwaitExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isImport(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "Import") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBigIntLiteral(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "BigIntLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExportNamespaceSpecifier(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ExportNamespaceSpecifier") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isOptionalMemberExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "OptionalMemberExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isOptionalCallExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "OptionalCallExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isClassProperty(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ClassProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isClassAccessorProperty(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ClassAccessorProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isClassPrivateProperty(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ClassPrivateProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isClassPrivateMethod(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ClassPrivateMethod") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isPrivateName(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "PrivateName") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isStaticBlock(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "StaticBlock") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isAnyTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "AnyTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isArrayTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ArrayTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBooleanTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "BooleanTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBooleanLiteralTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "BooleanLiteralTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isNullLiteralTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "NullLiteralTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isClassImplements(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ClassImplements") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclareClass(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclareClass") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclareFunction(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclareFunction") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclareInterface(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclareInterface") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclareModule(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclareModule") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclareModuleExports(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclareModuleExports") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclareTypeAlias(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclareTypeAlias") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclareOpaqueType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclareOpaqueType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclareVariable(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclareVariable") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclareExportDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclareExportDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclareExportAllDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclareExportAllDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclaredPredicate(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DeclaredPredicate") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExistsTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ExistsTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFunctionTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "FunctionTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFunctionTypeParam(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "FunctionTypeParam") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isGenericTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "GenericTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isInferredPredicate(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "InferredPredicate") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isInterfaceExtends(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "InterfaceExtends") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isInterfaceDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "InterfaceDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isInterfaceTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "InterfaceTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isIntersectionTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "IntersectionTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isMixedTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "MixedTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEmptyTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EmptyTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isNullableTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "NullableTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isNumberLiteralTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "NumberLiteralTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isNumberTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "NumberTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ObjectTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectTypeInternalSlot(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ObjectTypeInternalSlot") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectTypeCallProperty(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ObjectTypeCallProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectTypeIndexer(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ObjectTypeIndexer") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectTypeProperty(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ObjectTypeProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectTypeSpreadProperty(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ObjectTypeSpreadProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isOpaqueType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "OpaqueType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isQualifiedTypeIdentifier(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "QualifiedTypeIdentifier") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isStringLiteralTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "StringLiteralTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isStringTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "StringTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isSymbolTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "SymbolTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isThisTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ThisTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTupleTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TupleTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTypeofTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TypeofTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTypeAlias(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TypeAlias") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTypeCastExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TypeCastExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTypeParameter(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TypeParameter") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTypeParameterDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TypeParameterDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTypeParameterInstantiation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TypeParameterInstantiation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isUnionTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "UnionTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isVariance(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "Variance") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isVoidTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "VoidTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EnumDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumBooleanBody(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EnumBooleanBody") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumNumberBody(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EnumNumberBody") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumStringBody(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EnumStringBody") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumSymbolBody(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EnumSymbolBody") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumBooleanMember(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EnumBooleanMember") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumNumberMember(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EnumNumberMember") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumStringMember(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EnumStringMember") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumDefaultedMember(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "EnumDefaultedMember") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isIndexedAccessType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "IndexedAccessType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isOptionalIndexedAccessType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "OptionalIndexedAccessType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXAttribute(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXAttribute") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXClosingElement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXClosingElement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXElement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXElement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXEmptyExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXEmptyExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXExpressionContainer(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXExpressionContainer") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXSpreadChild(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXSpreadChild") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXIdentifier(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXIdentifier") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXMemberExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXMemberExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXNamespacedName(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXNamespacedName") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXOpeningElement(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXOpeningElement") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXSpreadAttribute(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXSpreadAttribute") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXText(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXText") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXFragment(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXFragment") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXOpeningFragment(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXOpeningFragment") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSXClosingFragment(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "JSXClosingFragment") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isNoop(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "Noop") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isPlaceholder(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "Placeholder") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isV8IntrinsicIdentifier(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "V8IntrinsicIdentifier") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isArgumentPlaceholder(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ArgumentPlaceholder") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBindExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "BindExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isImportAttribute(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ImportAttribute") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDecorator(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "Decorator") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDoExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DoExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExportDefaultSpecifier(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ExportDefaultSpecifier") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isRecordExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "RecordExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTupleExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TupleExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDecimalLiteral(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "DecimalLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isModuleExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "ModuleExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTopicReference(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TopicReference") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isPipelineTopicExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "PipelineTopicExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isPipelineBareFunction(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "PipelineBareFunction") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isPipelinePrimaryTopicReference(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "PipelinePrimaryTopicReference") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSParameterProperty(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSParameterProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSDeclareFunction(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSDeclareFunction") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSDeclareMethod(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSDeclareMethod") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSQualifiedName(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSQualifiedName") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSCallSignatureDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSCallSignatureDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSConstructSignatureDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSConstructSignatureDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSPropertySignature(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSPropertySignature") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSMethodSignature(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSMethodSignature") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSIndexSignature(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSIndexSignature") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSAnyKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSAnyKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSBooleanKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSBooleanKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSBigIntKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSBigIntKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSIntrinsicKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSIntrinsicKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSNeverKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSNeverKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSNullKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSNullKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSNumberKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSNumberKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSObjectKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSObjectKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSStringKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSStringKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSSymbolKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSSymbolKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSUndefinedKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSUndefinedKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSUnknownKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSUnknownKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSVoidKeyword(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSVoidKeyword") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSThisType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSThisType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSFunctionType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSFunctionType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSConstructorType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSConstructorType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeReference(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypeReference") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypePredicate(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypePredicate") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeQuery(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypeQuery") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeLiteral(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypeLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSArrayType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSArrayType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTupleType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTupleType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSOptionalType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSOptionalType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSRestType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSRestType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSNamedTupleMember(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSNamedTupleMember") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSUnionType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSUnionType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSIntersectionType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSIntersectionType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSConditionalType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSConditionalType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSInferType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSInferType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSParenthesizedType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSParenthesizedType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeOperator(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypeOperator") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSIndexedAccessType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSIndexedAccessType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSMappedType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSMappedType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSLiteralType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSLiteralType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSExpressionWithTypeArguments(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSExpressionWithTypeArguments") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSInterfaceDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSInterfaceDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSInterfaceBody(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSInterfaceBody") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeAliasDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypeAliasDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSInstantiationExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSInstantiationExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSAsExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSAsExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSSatisfiesExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSSatisfiesExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeAssertion(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypeAssertion") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSEnumDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSEnumDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSEnumMember(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSEnumMember") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSModuleDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSModuleDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSModuleBlock(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSModuleBlock") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSImportType(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSImportType") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSImportEqualsDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSImportEqualsDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSExternalModuleReference(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSExternalModuleReference") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSNonNullExpression(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSNonNullExpression") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSExportAssignment(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSExportAssignment") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSNamespaceExportDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSNamespaceExportDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypeAnnotation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeParameterInstantiation(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypeParameterInstantiation") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeParameterDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypeParameterDeclaration") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeParameter(node, opts) {
|
|
if (!node) return false;
|
|
if (node.type !== "TSTypeParameter") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isStandardized(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ArrayExpression":
|
|
case "AssignmentExpression":
|
|
case "BinaryExpression":
|
|
case "InterpreterDirective":
|
|
case "Directive":
|
|
case "DirectiveLiteral":
|
|
case "BlockStatement":
|
|
case "BreakStatement":
|
|
case "CallExpression":
|
|
case "CatchClause":
|
|
case "ConditionalExpression":
|
|
case "ContinueStatement":
|
|
case "DebuggerStatement":
|
|
case "DoWhileStatement":
|
|
case "EmptyStatement":
|
|
case "ExpressionStatement":
|
|
case "File":
|
|
case "ForInStatement":
|
|
case "ForStatement":
|
|
case "FunctionDeclaration":
|
|
case "FunctionExpression":
|
|
case "Identifier":
|
|
case "IfStatement":
|
|
case "LabeledStatement":
|
|
case "StringLiteral":
|
|
case "NumericLiteral":
|
|
case "NullLiteral":
|
|
case "BooleanLiteral":
|
|
case "RegExpLiteral":
|
|
case "LogicalExpression":
|
|
case "MemberExpression":
|
|
case "NewExpression":
|
|
case "Program":
|
|
case "ObjectExpression":
|
|
case "ObjectMethod":
|
|
case "ObjectProperty":
|
|
case "RestElement":
|
|
case "ReturnStatement":
|
|
case "SequenceExpression":
|
|
case "ParenthesizedExpression":
|
|
case "SwitchCase":
|
|
case "SwitchStatement":
|
|
case "ThisExpression":
|
|
case "ThrowStatement":
|
|
case "TryStatement":
|
|
case "UnaryExpression":
|
|
case "UpdateExpression":
|
|
case "VariableDeclaration":
|
|
case "VariableDeclarator":
|
|
case "WhileStatement":
|
|
case "WithStatement":
|
|
case "AssignmentPattern":
|
|
case "ArrayPattern":
|
|
case "ArrowFunctionExpression":
|
|
case "ClassBody":
|
|
case "ClassExpression":
|
|
case "ClassDeclaration":
|
|
case "ExportAllDeclaration":
|
|
case "ExportDefaultDeclaration":
|
|
case "ExportNamedDeclaration":
|
|
case "ExportSpecifier":
|
|
case "ForOfStatement":
|
|
case "ImportDeclaration":
|
|
case "ImportDefaultSpecifier":
|
|
case "ImportNamespaceSpecifier":
|
|
case "ImportSpecifier":
|
|
case "ImportExpression":
|
|
case "MetaProperty":
|
|
case "ClassMethod":
|
|
case "ObjectPattern":
|
|
case "SpreadElement":
|
|
case "Super":
|
|
case "TaggedTemplateExpression":
|
|
case "TemplateElement":
|
|
case "TemplateLiteral":
|
|
case "YieldExpression":
|
|
case "AwaitExpression":
|
|
case "Import":
|
|
case "BigIntLiteral":
|
|
case "ExportNamespaceSpecifier":
|
|
case "OptionalMemberExpression":
|
|
case "OptionalCallExpression":
|
|
case "ClassProperty":
|
|
case "ClassAccessorProperty":
|
|
case "ClassPrivateProperty":
|
|
case "ClassPrivateMethod":
|
|
case "PrivateName":
|
|
case "StaticBlock":
|
|
break;
|
|
case "Placeholder":
|
|
switch (node.expectedNode) {
|
|
case "Identifier":
|
|
case "StringLiteral":
|
|
case "BlockStatement":
|
|
case "ClassBody":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExpression(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ArrayExpression":
|
|
case "AssignmentExpression":
|
|
case "BinaryExpression":
|
|
case "CallExpression":
|
|
case "ConditionalExpression":
|
|
case "FunctionExpression":
|
|
case "Identifier":
|
|
case "StringLiteral":
|
|
case "NumericLiteral":
|
|
case "NullLiteral":
|
|
case "BooleanLiteral":
|
|
case "RegExpLiteral":
|
|
case "LogicalExpression":
|
|
case "MemberExpression":
|
|
case "NewExpression":
|
|
case "ObjectExpression":
|
|
case "SequenceExpression":
|
|
case "ParenthesizedExpression":
|
|
case "ThisExpression":
|
|
case "UnaryExpression":
|
|
case "UpdateExpression":
|
|
case "ArrowFunctionExpression":
|
|
case "ClassExpression":
|
|
case "ImportExpression":
|
|
case "MetaProperty":
|
|
case "Super":
|
|
case "TaggedTemplateExpression":
|
|
case "TemplateLiteral":
|
|
case "YieldExpression":
|
|
case "AwaitExpression":
|
|
case "Import":
|
|
case "BigIntLiteral":
|
|
case "OptionalMemberExpression":
|
|
case "OptionalCallExpression":
|
|
case "TypeCastExpression":
|
|
case "JSXElement":
|
|
case "JSXFragment":
|
|
case "BindExpression":
|
|
case "DoExpression":
|
|
case "RecordExpression":
|
|
case "TupleExpression":
|
|
case "DecimalLiteral":
|
|
case "ModuleExpression":
|
|
case "TopicReference":
|
|
case "PipelineTopicExpression":
|
|
case "PipelineBareFunction":
|
|
case "PipelinePrimaryTopicReference":
|
|
case "TSInstantiationExpression":
|
|
case "TSAsExpression":
|
|
case "TSSatisfiesExpression":
|
|
case "TSTypeAssertion":
|
|
case "TSNonNullExpression":
|
|
break;
|
|
case "Placeholder":
|
|
switch (node.expectedNode) {
|
|
case "Expression":
|
|
case "Identifier":
|
|
case "StringLiteral":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBinary(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "BinaryExpression":
|
|
case "LogicalExpression":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isScopable(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "BlockStatement":
|
|
case "CatchClause":
|
|
case "DoWhileStatement":
|
|
case "ForInStatement":
|
|
case "ForStatement":
|
|
case "FunctionDeclaration":
|
|
case "FunctionExpression":
|
|
case "Program":
|
|
case "ObjectMethod":
|
|
case "SwitchStatement":
|
|
case "WhileStatement":
|
|
case "ArrowFunctionExpression":
|
|
case "ClassExpression":
|
|
case "ClassDeclaration":
|
|
case "ForOfStatement":
|
|
case "ClassMethod":
|
|
case "ClassPrivateMethod":
|
|
case "StaticBlock":
|
|
case "TSModuleBlock":
|
|
break;
|
|
case "Placeholder":
|
|
if (node.expectedNode === "BlockStatement") break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBlockParent(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "BlockStatement":
|
|
case "CatchClause":
|
|
case "DoWhileStatement":
|
|
case "ForInStatement":
|
|
case "ForStatement":
|
|
case "FunctionDeclaration":
|
|
case "FunctionExpression":
|
|
case "Program":
|
|
case "ObjectMethod":
|
|
case "SwitchStatement":
|
|
case "WhileStatement":
|
|
case "ArrowFunctionExpression":
|
|
case "ForOfStatement":
|
|
case "ClassMethod":
|
|
case "ClassPrivateMethod":
|
|
case "StaticBlock":
|
|
case "TSModuleBlock":
|
|
break;
|
|
case "Placeholder":
|
|
if (node.expectedNode === "BlockStatement") break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isBlock(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "BlockStatement":
|
|
case "Program":
|
|
case "TSModuleBlock":
|
|
break;
|
|
case "Placeholder":
|
|
if (node.expectedNode === "BlockStatement") break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isStatement(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "BlockStatement":
|
|
case "BreakStatement":
|
|
case "ContinueStatement":
|
|
case "DebuggerStatement":
|
|
case "DoWhileStatement":
|
|
case "EmptyStatement":
|
|
case "ExpressionStatement":
|
|
case "ForInStatement":
|
|
case "ForStatement":
|
|
case "FunctionDeclaration":
|
|
case "IfStatement":
|
|
case "LabeledStatement":
|
|
case "ReturnStatement":
|
|
case "SwitchStatement":
|
|
case "ThrowStatement":
|
|
case "TryStatement":
|
|
case "VariableDeclaration":
|
|
case "WhileStatement":
|
|
case "WithStatement":
|
|
case "ClassDeclaration":
|
|
case "ExportAllDeclaration":
|
|
case "ExportDefaultDeclaration":
|
|
case "ExportNamedDeclaration":
|
|
case "ForOfStatement":
|
|
case "ImportDeclaration":
|
|
case "DeclareClass":
|
|
case "DeclareFunction":
|
|
case "DeclareInterface":
|
|
case "DeclareModule":
|
|
case "DeclareModuleExports":
|
|
case "DeclareTypeAlias":
|
|
case "DeclareOpaqueType":
|
|
case "DeclareVariable":
|
|
case "DeclareExportDeclaration":
|
|
case "DeclareExportAllDeclaration":
|
|
case "InterfaceDeclaration":
|
|
case "OpaqueType":
|
|
case "TypeAlias":
|
|
case "EnumDeclaration":
|
|
case "TSDeclareFunction":
|
|
case "TSInterfaceDeclaration":
|
|
case "TSTypeAliasDeclaration":
|
|
case "TSEnumDeclaration":
|
|
case "TSModuleDeclaration":
|
|
case "TSImportEqualsDeclaration":
|
|
case "TSExportAssignment":
|
|
case "TSNamespaceExportDeclaration":
|
|
break;
|
|
case "Placeholder":
|
|
switch (node.expectedNode) {
|
|
case "Statement":
|
|
case "Declaration":
|
|
case "BlockStatement":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTerminatorless(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "BreakStatement":
|
|
case "ContinueStatement":
|
|
case "ReturnStatement":
|
|
case "ThrowStatement":
|
|
case "YieldExpression":
|
|
case "AwaitExpression":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isCompletionStatement(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "BreakStatement":
|
|
case "ContinueStatement":
|
|
case "ReturnStatement":
|
|
case "ThrowStatement":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isConditional(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ConditionalExpression":
|
|
case "IfStatement":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isLoop(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "DoWhileStatement":
|
|
case "ForInStatement":
|
|
case "ForStatement":
|
|
case "WhileStatement":
|
|
case "ForOfStatement":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isWhile(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "DoWhileStatement":
|
|
case "WhileStatement":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExpressionWrapper(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ExpressionStatement":
|
|
case "ParenthesizedExpression":
|
|
case "TypeCastExpression":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFor(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ForInStatement":
|
|
case "ForStatement":
|
|
case "ForOfStatement":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isForXStatement(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ForInStatement":
|
|
case "ForOfStatement":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFunction(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "FunctionDeclaration":
|
|
case "FunctionExpression":
|
|
case "ObjectMethod":
|
|
case "ArrowFunctionExpression":
|
|
case "ClassMethod":
|
|
case "ClassPrivateMethod":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFunctionParent(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "FunctionDeclaration":
|
|
case "FunctionExpression":
|
|
case "ObjectMethod":
|
|
case "ArrowFunctionExpression":
|
|
case "ClassMethod":
|
|
case "ClassPrivateMethod":
|
|
case "StaticBlock":
|
|
case "TSModuleBlock":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isPureish(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "FunctionDeclaration":
|
|
case "FunctionExpression":
|
|
case "StringLiteral":
|
|
case "NumericLiteral":
|
|
case "NullLiteral":
|
|
case "BooleanLiteral":
|
|
case "RegExpLiteral":
|
|
case "ArrowFunctionExpression":
|
|
case "BigIntLiteral":
|
|
case "DecimalLiteral":
|
|
break;
|
|
case "Placeholder":
|
|
if (node.expectedNode === "StringLiteral") break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "FunctionDeclaration":
|
|
case "VariableDeclaration":
|
|
case "ClassDeclaration":
|
|
case "ExportAllDeclaration":
|
|
case "ExportDefaultDeclaration":
|
|
case "ExportNamedDeclaration":
|
|
case "ImportDeclaration":
|
|
case "DeclareClass":
|
|
case "DeclareFunction":
|
|
case "DeclareInterface":
|
|
case "DeclareModule":
|
|
case "DeclareModuleExports":
|
|
case "DeclareTypeAlias":
|
|
case "DeclareOpaqueType":
|
|
case "DeclareVariable":
|
|
case "DeclareExportDeclaration":
|
|
case "DeclareExportAllDeclaration":
|
|
case "InterfaceDeclaration":
|
|
case "OpaqueType":
|
|
case "TypeAlias":
|
|
case "EnumDeclaration":
|
|
case "TSDeclareFunction":
|
|
case "TSInterfaceDeclaration":
|
|
case "TSTypeAliasDeclaration":
|
|
case "TSEnumDeclaration":
|
|
case "TSModuleDeclaration":
|
|
break;
|
|
case "Placeholder":
|
|
if (node.expectedNode === "Declaration") break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isPatternLike(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "Identifier":
|
|
case "RestElement":
|
|
case "AssignmentPattern":
|
|
case "ArrayPattern":
|
|
case "ObjectPattern":
|
|
case "TSAsExpression":
|
|
case "TSSatisfiesExpression":
|
|
case "TSTypeAssertion":
|
|
case "TSNonNullExpression":
|
|
break;
|
|
case "Placeholder":
|
|
switch (node.expectedNode) {
|
|
case "Pattern":
|
|
case "Identifier":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isLVal(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "Identifier":
|
|
case "MemberExpression":
|
|
case "RestElement":
|
|
case "AssignmentPattern":
|
|
case "ArrayPattern":
|
|
case "ObjectPattern":
|
|
case "TSParameterProperty":
|
|
case "TSAsExpression":
|
|
case "TSSatisfiesExpression":
|
|
case "TSTypeAssertion":
|
|
case "TSNonNullExpression":
|
|
break;
|
|
case "Placeholder":
|
|
switch (node.expectedNode) {
|
|
case "Pattern":
|
|
case "Identifier":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSEntityName(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "Identifier":
|
|
case "TSQualifiedName":
|
|
break;
|
|
case "Placeholder":
|
|
if (node.expectedNode === "Identifier") break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isLiteral(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "StringLiteral":
|
|
case "NumericLiteral":
|
|
case "NullLiteral":
|
|
case "BooleanLiteral":
|
|
case "RegExpLiteral":
|
|
case "TemplateLiteral":
|
|
case "BigIntLiteral":
|
|
case "DecimalLiteral":
|
|
break;
|
|
case "Placeholder":
|
|
if (node.expectedNode === "StringLiteral") break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isImmutable(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "StringLiteral":
|
|
case "NumericLiteral":
|
|
case "NullLiteral":
|
|
case "BooleanLiteral":
|
|
case "BigIntLiteral":
|
|
case "JSXAttribute":
|
|
case "JSXClosingElement":
|
|
case "JSXElement":
|
|
case "JSXExpressionContainer":
|
|
case "JSXSpreadChild":
|
|
case "JSXOpeningElement":
|
|
case "JSXText":
|
|
case "JSXFragment":
|
|
case "JSXOpeningFragment":
|
|
case "JSXClosingFragment":
|
|
case "DecimalLiteral":
|
|
break;
|
|
case "Placeholder":
|
|
if (node.expectedNode === "StringLiteral") break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isUserWhitespacable(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ObjectMethod":
|
|
case "ObjectProperty":
|
|
case "ObjectTypeInternalSlot":
|
|
case "ObjectTypeCallProperty":
|
|
case "ObjectTypeIndexer":
|
|
case "ObjectTypeProperty":
|
|
case "ObjectTypeSpreadProperty":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isMethod(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ObjectMethod":
|
|
case "ClassMethod":
|
|
case "ClassPrivateMethod":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isObjectMember(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ObjectMethod":
|
|
case "ObjectProperty":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isProperty(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ObjectProperty":
|
|
case "ClassProperty":
|
|
case "ClassAccessorProperty":
|
|
case "ClassPrivateProperty":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isUnaryLike(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "UnaryExpression":
|
|
case "SpreadElement":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isPattern(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "AssignmentPattern":
|
|
case "ArrayPattern":
|
|
case "ObjectPattern":
|
|
break;
|
|
case "Placeholder":
|
|
if (node.expectedNode === "Pattern") break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isClass(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ClassExpression":
|
|
case "ClassDeclaration":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isImportOrExportDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ExportAllDeclaration":
|
|
case "ExportDefaultDeclaration":
|
|
case "ExportNamedDeclaration":
|
|
case "ImportDeclaration":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isExportDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ExportAllDeclaration":
|
|
case "ExportDefaultDeclaration":
|
|
case "ExportNamedDeclaration":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isModuleSpecifier(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ExportSpecifier":
|
|
case "ImportDefaultSpecifier":
|
|
case "ImportNamespaceSpecifier":
|
|
case "ImportSpecifier":
|
|
case "ExportNamespaceSpecifier":
|
|
case "ExportDefaultSpecifier":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isAccessor(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ClassAccessorProperty":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isPrivate(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "ClassPrivateProperty":
|
|
case "ClassPrivateMethod":
|
|
case "PrivateName":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFlow(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "AnyTypeAnnotation":
|
|
case "ArrayTypeAnnotation":
|
|
case "BooleanTypeAnnotation":
|
|
case "BooleanLiteralTypeAnnotation":
|
|
case "NullLiteralTypeAnnotation":
|
|
case "ClassImplements":
|
|
case "DeclareClass":
|
|
case "DeclareFunction":
|
|
case "DeclareInterface":
|
|
case "DeclareModule":
|
|
case "DeclareModuleExports":
|
|
case "DeclareTypeAlias":
|
|
case "DeclareOpaqueType":
|
|
case "DeclareVariable":
|
|
case "DeclareExportDeclaration":
|
|
case "DeclareExportAllDeclaration":
|
|
case "DeclaredPredicate":
|
|
case "ExistsTypeAnnotation":
|
|
case "FunctionTypeAnnotation":
|
|
case "FunctionTypeParam":
|
|
case "GenericTypeAnnotation":
|
|
case "InferredPredicate":
|
|
case "InterfaceExtends":
|
|
case "InterfaceDeclaration":
|
|
case "InterfaceTypeAnnotation":
|
|
case "IntersectionTypeAnnotation":
|
|
case "MixedTypeAnnotation":
|
|
case "EmptyTypeAnnotation":
|
|
case "NullableTypeAnnotation":
|
|
case "NumberLiteralTypeAnnotation":
|
|
case "NumberTypeAnnotation":
|
|
case "ObjectTypeAnnotation":
|
|
case "ObjectTypeInternalSlot":
|
|
case "ObjectTypeCallProperty":
|
|
case "ObjectTypeIndexer":
|
|
case "ObjectTypeProperty":
|
|
case "ObjectTypeSpreadProperty":
|
|
case "OpaqueType":
|
|
case "QualifiedTypeIdentifier":
|
|
case "StringLiteralTypeAnnotation":
|
|
case "StringTypeAnnotation":
|
|
case "SymbolTypeAnnotation":
|
|
case "ThisTypeAnnotation":
|
|
case "TupleTypeAnnotation":
|
|
case "TypeofTypeAnnotation":
|
|
case "TypeAlias":
|
|
case "TypeAnnotation":
|
|
case "TypeCastExpression":
|
|
case "TypeParameter":
|
|
case "TypeParameterDeclaration":
|
|
case "TypeParameterInstantiation":
|
|
case "UnionTypeAnnotation":
|
|
case "Variance":
|
|
case "VoidTypeAnnotation":
|
|
case "EnumDeclaration":
|
|
case "EnumBooleanBody":
|
|
case "EnumNumberBody":
|
|
case "EnumStringBody":
|
|
case "EnumSymbolBody":
|
|
case "EnumBooleanMember":
|
|
case "EnumNumberMember":
|
|
case "EnumStringMember":
|
|
case "EnumDefaultedMember":
|
|
case "IndexedAccessType":
|
|
case "OptionalIndexedAccessType":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFlowType(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "AnyTypeAnnotation":
|
|
case "ArrayTypeAnnotation":
|
|
case "BooleanTypeAnnotation":
|
|
case "BooleanLiteralTypeAnnotation":
|
|
case "NullLiteralTypeAnnotation":
|
|
case "ExistsTypeAnnotation":
|
|
case "FunctionTypeAnnotation":
|
|
case "GenericTypeAnnotation":
|
|
case "InterfaceTypeAnnotation":
|
|
case "IntersectionTypeAnnotation":
|
|
case "MixedTypeAnnotation":
|
|
case "EmptyTypeAnnotation":
|
|
case "NullableTypeAnnotation":
|
|
case "NumberLiteralTypeAnnotation":
|
|
case "NumberTypeAnnotation":
|
|
case "ObjectTypeAnnotation":
|
|
case "StringLiteralTypeAnnotation":
|
|
case "StringTypeAnnotation":
|
|
case "SymbolTypeAnnotation":
|
|
case "ThisTypeAnnotation":
|
|
case "TupleTypeAnnotation":
|
|
case "TypeofTypeAnnotation":
|
|
case "UnionTypeAnnotation":
|
|
case "VoidTypeAnnotation":
|
|
case "IndexedAccessType":
|
|
case "OptionalIndexedAccessType":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFlowBaseAnnotation(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "AnyTypeAnnotation":
|
|
case "BooleanTypeAnnotation":
|
|
case "NullLiteralTypeAnnotation":
|
|
case "MixedTypeAnnotation":
|
|
case "EmptyTypeAnnotation":
|
|
case "NumberTypeAnnotation":
|
|
case "StringTypeAnnotation":
|
|
case "SymbolTypeAnnotation":
|
|
case "ThisTypeAnnotation":
|
|
case "VoidTypeAnnotation":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFlowDeclaration(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "DeclareClass":
|
|
case "DeclareFunction":
|
|
case "DeclareInterface":
|
|
case "DeclareModule":
|
|
case "DeclareModuleExports":
|
|
case "DeclareTypeAlias":
|
|
case "DeclareOpaqueType":
|
|
case "DeclareVariable":
|
|
case "DeclareExportDeclaration":
|
|
case "DeclareExportAllDeclaration":
|
|
case "InterfaceDeclaration":
|
|
case "OpaqueType":
|
|
case "TypeAlias":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isFlowPredicate(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "DeclaredPredicate":
|
|
case "InferredPredicate":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumBody(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "EnumBooleanBody":
|
|
case "EnumNumberBody":
|
|
case "EnumStringBody":
|
|
case "EnumSymbolBody":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isEnumMember(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "EnumBooleanMember":
|
|
case "EnumNumberMember":
|
|
case "EnumStringMember":
|
|
case "EnumDefaultedMember":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isJSX(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "JSXAttribute":
|
|
case "JSXClosingElement":
|
|
case "JSXElement":
|
|
case "JSXEmptyExpression":
|
|
case "JSXExpressionContainer":
|
|
case "JSXSpreadChild":
|
|
case "JSXIdentifier":
|
|
case "JSXMemberExpression":
|
|
case "JSXNamespacedName":
|
|
case "JSXOpeningElement":
|
|
case "JSXSpreadAttribute":
|
|
case "JSXText":
|
|
case "JSXFragment":
|
|
case "JSXOpeningFragment":
|
|
case "JSXClosingFragment":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isMiscellaneous(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "Noop":
|
|
case "Placeholder":
|
|
case "V8IntrinsicIdentifier":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTypeScript(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "TSParameterProperty":
|
|
case "TSDeclareFunction":
|
|
case "TSDeclareMethod":
|
|
case "TSQualifiedName":
|
|
case "TSCallSignatureDeclaration":
|
|
case "TSConstructSignatureDeclaration":
|
|
case "TSPropertySignature":
|
|
case "TSMethodSignature":
|
|
case "TSIndexSignature":
|
|
case "TSAnyKeyword":
|
|
case "TSBooleanKeyword":
|
|
case "TSBigIntKeyword":
|
|
case "TSIntrinsicKeyword":
|
|
case "TSNeverKeyword":
|
|
case "TSNullKeyword":
|
|
case "TSNumberKeyword":
|
|
case "TSObjectKeyword":
|
|
case "TSStringKeyword":
|
|
case "TSSymbolKeyword":
|
|
case "TSUndefinedKeyword":
|
|
case "TSUnknownKeyword":
|
|
case "TSVoidKeyword":
|
|
case "TSThisType":
|
|
case "TSFunctionType":
|
|
case "TSConstructorType":
|
|
case "TSTypeReference":
|
|
case "TSTypePredicate":
|
|
case "TSTypeQuery":
|
|
case "TSTypeLiteral":
|
|
case "TSArrayType":
|
|
case "TSTupleType":
|
|
case "TSOptionalType":
|
|
case "TSRestType":
|
|
case "TSNamedTupleMember":
|
|
case "TSUnionType":
|
|
case "TSIntersectionType":
|
|
case "TSConditionalType":
|
|
case "TSInferType":
|
|
case "TSParenthesizedType":
|
|
case "TSTypeOperator":
|
|
case "TSIndexedAccessType":
|
|
case "TSMappedType":
|
|
case "TSLiteralType":
|
|
case "TSExpressionWithTypeArguments":
|
|
case "TSInterfaceDeclaration":
|
|
case "TSInterfaceBody":
|
|
case "TSTypeAliasDeclaration":
|
|
case "TSInstantiationExpression":
|
|
case "TSAsExpression":
|
|
case "TSSatisfiesExpression":
|
|
case "TSTypeAssertion":
|
|
case "TSEnumDeclaration":
|
|
case "TSEnumMember":
|
|
case "TSModuleDeclaration":
|
|
case "TSModuleBlock":
|
|
case "TSImportType":
|
|
case "TSImportEqualsDeclaration":
|
|
case "TSExternalModuleReference":
|
|
case "TSNonNullExpression":
|
|
case "TSExportAssignment":
|
|
case "TSNamespaceExportDeclaration":
|
|
case "TSTypeAnnotation":
|
|
case "TSTypeParameterInstantiation":
|
|
case "TSTypeParameterDeclaration":
|
|
case "TSTypeParameter":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSTypeElement(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "TSCallSignatureDeclaration":
|
|
case "TSConstructSignatureDeclaration":
|
|
case "TSPropertySignature":
|
|
case "TSMethodSignature":
|
|
case "TSIndexSignature":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSType(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "TSAnyKeyword":
|
|
case "TSBooleanKeyword":
|
|
case "TSBigIntKeyword":
|
|
case "TSIntrinsicKeyword":
|
|
case "TSNeverKeyword":
|
|
case "TSNullKeyword":
|
|
case "TSNumberKeyword":
|
|
case "TSObjectKeyword":
|
|
case "TSStringKeyword":
|
|
case "TSSymbolKeyword":
|
|
case "TSUndefinedKeyword":
|
|
case "TSUnknownKeyword":
|
|
case "TSVoidKeyword":
|
|
case "TSThisType":
|
|
case "TSFunctionType":
|
|
case "TSConstructorType":
|
|
case "TSTypeReference":
|
|
case "TSTypePredicate":
|
|
case "TSTypeQuery":
|
|
case "TSTypeLiteral":
|
|
case "TSArrayType":
|
|
case "TSTupleType":
|
|
case "TSOptionalType":
|
|
case "TSRestType":
|
|
case "TSUnionType":
|
|
case "TSIntersectionType":
|
|
case "TSConditionalType":
|
|
case "TSInferType":
|
|
case "TSParenthesizedType":
|
|
case "TSTypeOperator":
|
|
case "TSIndexedAccessType":
|
|
case "TSMappedType":
|
|
case "TSLiteralType":
|
|
case "TSExpressionWithTypeArguments":
|
|
case "TSImportType":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isTSBaseType(node, opts) {
|
|
if (!node) return false;
|
|
switch (node.type) {
|
|
case "TSAnyKeyword":
|
|
case "TSBooleanKeyword":
|
|
case "TSBigIntKeyword":
|
|
case "TSIntrinsicKeyword":
|
|
case "TSNeverKeyword":
|
|
case "TSNullKeyword":
|
|
case "TSNumberKeyword":
|
|
case "TSObjectKeyword":
|
|
case "TSStringKeyword":
|
|
case "TSSymbolKeyword":
|
|
case "TSUndefinedKeyword":
|
|
case "TSUnknownKeyword":
|
|
case "TSVoidKeyword":
|
|
case "TSThisType":
|
|
case "TSLiteralType":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isNumberLiteral(node, opts) {
|
|
(0, _deprecationWarning.default)("isNumberLiteral", "isNumericLiteral");
|
|
if (!node) return false;
|
|
if (node.type !== "NumberLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isRegexLiteral(node, opts) {
|
|
(0, _deprecationWarning.default)("isRegexLiteral", "isRegExpLiteral");
|
|
if (!node) return false;
|
|
if (node.type !== "RegexLiteral") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isRestProperty(node, opts) {
|
|
(0, _deprecationWarning.default)("isRestProperty", "isRestElement");
|
|
if (!node) return false;
|
|
if (node.type !== "RestProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isSpreadProperty(node, opts) {
|
|
(0, _deprecationWarning.default)("isSpreadProperty", "isSpreadElement");
|
|
if (!node) return false;
|
|
if (node.type !== "SpreadProperty") return false;
|
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
function isModuleDeclaration(node, opts) {
|
|
(0, _deprecationWarning.default)("isModuleDeclaration", "isImportOrExportDeclaration");
|
|
return isImportOrExportDeclaration(node, opts);
|
|
}
|
|
|
|
|
|
return generated$3;
|
|
}
|
|
|
|
var hasRequiredMatchesPattern;
|
|
|
|
function requireMatchesPattern () {
|
|
if (hasRequiredMatchesPattern) return matchesPattern;
|
|
hasRequiredMatchesPattern = 1;
|
|
|
|
Object.defineProperty(matchesPattern, "__esModule", {
|
|
value: true
|
|
});
|
|
matchesPattern.default = matchesPattern$1;
|
|
var _index = requireGenerated$3();
|
|
function matchesPattern$1(member, match, allowPartial) {
|
|
if (!(0, _index.isMemberExpression)(member)) return false;
|
|
const parts = Array.isArray(match) ? match : match.split(".");
|
|
const nodes = [];
|
|
let node;
|
|
for (node = member; (0, _index.isMemberExpression)(node); node = node.object) {
|
|
nodes.push(node.property);
|
|
}
|
|
nodes.push(node);
|
|
if (nodes.length < parts.length) return false;
|
|
if (!allowPartial && nodes.length > parts.length) return false;
|
|
for (let i = 0, j = nodes.length - 1; i < parts.length; i++, j--) {
|
|
const node = nodes[j];
|
|
let value;
|
|
if ((0, _index.isIdentifier)(node)) {
|
|
value = node.name;
|
|
} else if ((0, _index.isStringLiteral)(node)) {
|
|
value = node.value;
|
|
} else if ((0, _index.isThisExpression)(node)) {
|
|
value = "this";
|
|
} else {
|
|
return false;
|
|
}
|
|
if (parts[i] !== value) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
return matchesPattern;
|
|
}
|
|
|
|
var hasRequiredBuildMatchMemberExpression;
|
|
|
|
function requireBuildMatchMemberExpression () {
|
|
if (hasRequiredBuildMatchMemberExpression) return buildMatchMemberExpression;
|
|
hasRequiredBuildMatchMemberExpression = 1;
|
|
|
|
Object.defineProperty(buildMatchMemberExpression, "__esModule", {
|
|
value: true
|
|
});
|
|
buildMatchMemberExpression.default = buildMatchMemberExpression$1;
|
|
var _matchesPattern = requireMatchesPattern();
|
|
function buildMatchMemberExpression$1(match, allowPartial) {
|
|
const parts = match.split(".");
|
|
return member => (0, _matchesPattern.default)(member, parts, allowPartial);
|
|
}
|
|
|
|
|
|
return buildMatchMemberExpression;
|
|
}
|
|
|
|
var hasRequiredIsReactComponent;
|
|
|
|
function requireIsReactComponent () {
|
|
if (hasRequiredIsReactComponent) return isReactComponent;
|
|
hasRequiredIsReactComponent = 1;
|
|
|
|
Object.defineProperty(isReactComponent, "__esModule", {
|
|
value: true
|
|
});
|
|
isReactComponent.default = void 0;
|
|
var _buildMatchMemberExpression = requireBuildMatchMemberExpression();
|
|
const isReactComponent$1 = (0, _buildMatchMemberExpression.default)("React.Component");
|
|
isReactComponent.default = isReactComponent$1;
|
|
|
|
|
|
return isReactComponent;
|
|
}
|
|
|
|
var isCompatTag = {};
|
|
|
|
var hasRequiredIsCompatTag;
|
|
|
|
function requireIsCompatTag () {
|
|
if (hasRequiredIsCompatTag) return isCompatTag;
|
|
hasRequiredIsCompatTag = 1;
|
|
|
|
Object.defineProperty(isCompatTag, "__esModule", {
|
|
value: true
|
|
});
|
|
isCompatTag.default = isCompatTag$1;
|
|
function isCompatTag$1(tagName) {
|
|
return !!tagName && /^[a-z]/.test(tagName);
|
|
}
|
|
|
|
|
|
return isCompatTag;
|
|
}
|
|
|
|
var buildChildren = {};
|
|
|
|
var cleanJSXElementLiteralChild = {};
|
|
|
|
var generated$2 = {};
|
|
|
|
var validate$1 = {};
|
|
|
|
var definitions = {};
|
|
|
|
var core = {};
|
|
|
|
var is = {};
|
|
|
|
var isType = {};
|
|
|
|
var hasRequiredIsType;
|
|
|
|
function requireIsType () {
|
|
if (hasRequiredIsType) return isType;
|
|
hasRequiredIsType = 1;
|
|
|
|
Object.defineProperty(isType, "__esModule", {
|
|
value: true
|
|
});
|
|
isType.default = isType$1;
|
|
var _index = requireDefinitions();
|
|
function isType$1(nodeType, targetType) {
|
|
if (nodeType === targetType) return true;
|
|
if (nodeType == null) return false;
|
|
if (_index.ALIAS_KEYS[targetType]) return false;
|
|
const aliases = _index.FLIPPED_ALIAS_KEYS[targetType];
|
|
if (aliases) {
|
|
if (aliases[0] === nodeType) return true;
|
|
for (const alias of aliases) {
|
|
if (nodeType === alias) return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
return isType;
|
|
}
|
|
|
|
var isPlaceholderType = {};
|
|
|
|
var hasRequiredIsPlaceholderType;
|
|
|
|
function requireIsPlaceholderType () {
|
|
if (hasRequiredIsPlaceholderType) return isPlaceholderType;
|
|
hasRequiredIsPlaceholderType = 1;
|
|
|
|
Object.defineProperty(isPlaceholderType, "__esModule", {
|
|
value: true
|
|
});
|
|
isPlaceholderType.default = isPlaceholderType$1;
|
|
var _index = requireDefinitions();
|
|
function isPlaceholderType$1(placeholderType, targetType) {
|
|
if (placeholderType === targetType) return true;
|
|
const aliases = _index.PLACEHOLDERS_ALIAS[placeholderType];
|
|
if (aliases) {
|
|
for (const alias of aliases) {
|
|
if (targetType === alias) return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
return isPlaceholderType;
|
|
}
|
|
|
|
var hasRequiredIs;
|
|
|
|
function requireIs () {
|
|
if (hasRequiredIs) return is;
|
|
hasRequiredIs = 1;
|
|
|
|
Object.defineProperty(is, "__esModule", {
|
|
value: true
|
|
});
|
|
is.default = is$1;
|
|
var _shallowEqual = requireShallowEqual();
|
|
var _isType = requireIsType();
|
|
var _isPlaceholderType = requireIsPlaceholderType();
|
|
var _index = requireDefinitions();
|
|
function is$1(type, node, opts) {
|
|
if (!node) return false;
|
|
const matches = (0, _isType.default)(node.type, type);
|
|
if (!matches) {
|
|
if (!opts && node.type === "Placeholder" && type in _index.FLIPPED_ALIAS_KEYS) {
|
|
return (0, _isPlaceholderType.default)(node.expectedNode, type);
|
|
}
|
|
return false;
|
|
}
|
|
if (opts === undefined) {
|
|
return true;
|
|
} else {
|
|
return (0, _shallowEqual.default)(node, opts);
|
|
}
|
|
}
|
|
|
|
|
|
return is;
|
|
}
|
|
|
|
var isValidIdentifier = {};
|
|
|
|
var lib$2 = {};
|
|
|
|
var identifier = {};
|
|
|
|
var hasRequiredIdentifier;
|
|
|
|
function requireIdentifier () {
|
|
if (hasRequiredIdentifier) return identifier;
|
|
hasRequiredIdentifier = 1;
|
|
|
|
Object.defineProperty(identifier, "__esModule", {
|
|
value: true
|
|
});
|
|
identifier.isIdentifierChar = isIdentifierChar;
|
|
identifier.isIdentifierName = isIdentifierName;
|
|
identifier.isIdentifierStart = isIdentifierStart;
|
|
let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u0870-\u0887\u0889-\u088e\u08a0-\u08c9\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u1711\u171f-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c8a\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7cd\ua7d0\ua7d1\ua7d3\ua7d5-\ua7dc\ua7f2-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
|
|
let nonASCIIidentifierChars = "\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0897-\u089f\u08ca-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3c\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0cf3\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ece\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1ace\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\u30fb\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f\uff65";
|
|
const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
|
|
const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
|
|
nonASCIIidentifierStartChars = nonASCIIidentifierChars = null;
|
|
const astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 71, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 28, 43, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 56, 50, 14, 50, 14, 35, 39, 27, 10, 22, 251, 41, 7, 1, 17, 2, 60, 28, 11, 0, 9, 21, 43, 17, 47, 20, 28, 22, 13, 52, 58, 1, 3, 0, 14, 44, 33, 24, 27, 35, 30, 0, 3, 0, 9, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36, 17, 2, 24, 20, 1, 64, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 19, 0, 13, 4, 31, 9, 2, 0, 3, 0, 2, 37, 2, 0, 26, 0, 2, 0, 45, 52, 19, 3, 21, 2, 31, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 14, 0, 72, 26, 38, 6, 186, 43, 117, 63, 32, 7, 3, 0, 3, 7, 2, 1, 2, 23, 16, 0, 2, 0, 95, 7, 3, 38, 17, 0, 2, 0, 29, 0, 11, 39, 8, 0, 22, 0, 12, 45, 20, 0, 19, 72, 200, 32, 32, 8, 2, 36, 18, 0, 50, 29, 113, 6, 2, 1, 2, 37, 22, 0, 26, 5, 2, 1, 2, 31, 15, 0, 328, 18, 16, 0, 2, 12, 2, 33, 125, 0, 80, 921, 103, 110, 18, 195, 2637, 96, 16, 1071, 18, 5, 26, 3994, 6, 582, 6842, 29, 1763, 568, 8, 30, 18, 78, 18, 29, 19, 47, 17, 3, 32, 20, 6, 18, 433, 44, 212, 63, 129, 74, 6, 0, 67, 12, 65, 1, 2, 0, 29, 6135, 9, 1237, 42, 9, 8936, 3, 2, 6, 2, 1, 2, 290, 16, 0, 30, 2, 3, 0, 15, 3, 9, 395, 2309, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 1845, 30, 7, 5, 262, 61, 147, 44, 11, 6, 17, 0, 322, 29, 19, 43, 485, 27, 229, 29, 3, 0, 496, 6, 2, 3, 2, 1, 2, 14, 2, 196, 60, 67, 8, 0, 1205, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42719, 33, 4153, 7, 221, 3, 5761, 15, 7472, 16, 621, 2467, 541, 1507, 4938, 6, 4191];
|
|
const astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 574, 3, 9, 9, 7, 9, 32, 4, 318, 1, 80, 3, 71, 10, 50, 3, 123, 2, 54, 14, 32, 10, 3, 1, 11, 3, 46, 10, 8, 0, 46, 9, 7, 2, 37, 13, 2, 9, 6, 1, 45, 0, 13, 2, 49, 13, 9, 3, 2, 11, 83, 11, 7, 0, 3, 0, 158, 11, 6, 9, 7, 3, 56, 1, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 68, 8, 2, 0, 3, 0, 2, 3, 2, 4, 2, 0, 15, 1, 83, 17, 10, 9, 5, 0, 82, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 7, 19, 58, 14, 5, 9, 243, 14, 166, 9, 71, 5, 2, 1, 3, 3, 2, 0, 2, 1, 13, 9, 120, 6, 3, 6, 4, 0, 29, 9, 41, 6, 2, 3, 9, 0, 10, 10, 47, 15, 343, 9, 54, 7, 2, 7, 17, 9, 57, 21, 2, 13, 123, 5, 4, 0, 2, 1, 2, 6, 2, 0, 9, 9, 49, 4, 2, 1, 2, 4, 9, 9, 330, 3, 10, 1, 2, 0, 49, 6, 4, 4, 14, 10, 5350, 0, 7, 14, 11465, 27, 2343, 9, 87, 9, 39, 4, 60, 6, 26, 9, 535, 9, 470, 0, 2, 54, 8, 3, 82, 0, 12, 1, 19628, 1, 4178, 9, 519, 45, 3, 22, 543, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3, 6, 2, 1, 2, 4, 101, 0, 161, 6, 10, 9, 357, 0, 62, 13, 499, 13, 245, 1, 2, 9, 726, 6, 110, 6, 6, 9, 4759, 9, 787719, 239];
|
|
function isInAstralSet(code, set) {
|
|
let pos = 0x10000;
|
|
for (let i = 0, length = set.length; i < length; i += 2) {
|
|
pos += set[i];
|
|
if (pos > code) return false;
|
|
pos += set[i + 1];
|
|
if (pos >= code) return true;
|
|
}
|
|
return false;
|
|
}
|
|
function isIdentifierStart(code) {
|
|
if (code < 65) return code === 36;
|
|
if (code <= 90) return true;
|
|
if (code < 97) return code === 95;
|
|
if (code <= 122) return true;
|
|
if (code <= 0xffff) {
|
|
return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code));
|
|
}
|
|
return isInAstralSet(code, astralIdentifierStartCodes);
|
|
}
|
|
function isIdentifierChar(code) {
|
|
if (code < 48) return code === 36;
|
|
if (code < 58) return true;
|
|
if (code < 65) return false;
|
|
if (code <= 90) return true;
|
|
if (code < 97) return code === 95;
|
|
if (code <= 122) return true;
|
|
if (code <= 0xffff) {
|
|
return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code));
|
|
}
|
|
return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
|
|
}
|
|
function isIdentifierName(name) {
|
|
let isFirst = true;
|
|
for (let i = 0; i < name.length; i++) {
|
|
let cp = name.charCodeAt(i);
|
|
if ((cp & 0xfc00) === 0xd800 && i + 1 < name.length) {
|
|
const trail = name.charCodeAt(++i);
|
|
if ((trail & 0xfc00) === 0xdc00) {
|
|
cp = 0x10000 + ((cp & 0x3ff) << 10) + (trail & 0x3ff);
|
|
}
|
|
}
|
|
if (isFirst) {
|
|
isFirst = false;
|
|
if (!isIdentifierStart(cp)) {
|
|
return false;
|
|
}
|
|
} else if (!isIdentifierChar(cp)) {
|
|
return false;
|
|
}
|
|
}
|
|
return !isFirst;
|
|
}
|
|
|
|
|
|
return identifier;
|
|
}
|
|
|
|
var keyword = {};
|
|
|
|
var hasRequiredKeyword;
|
|
|
|
function requireKeyword () {
|
|
if (hasRequiredKeyword) return keyword;
|
|
hasRequiredKeyword = 1;
|
|
|
|
Object.defineProperty(keyword, "__esModule", {
|
|
value: true
|
|
});
|
|
keyword.isKeyword = isKeyword;
|
|
keyword.isReservedWord = isReservedWord;
|
|
keyword.isStrictBindOnlyReservedWord = isStrictBindOnlyReservedWord;
|
|
keyword.isStrictBindReservedWord = isStrictBindReservedWord;
|
|
keyword.isStrictReservedWord = isStrictReservedWord;
|
|
const reservedWords = {
|
|
keyword: ["break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "const", "while", "with", "new", "this", "super", "class", "extends", "export", "import", "null", "true", "false", "in", "instanceof", "typeof", "void", "delete"],
|
|
strict: ["implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"],
|
|
strictBind: ["eval", "arguments"]
|
|
};
|
|
const keywords = new Set(reservedWords.keyword);
|
|
const reservedWordsStrictSet = new Set(reservedWords.strict);
|
|
const reservedWordsStrictBindSet = new Set(reservedWords.strictBind);
|
|
function isReservedWord(word, inModule) {
|
|
return inModule && word === "await" || word === "enum";
|
|
}
|
|
function isStrictReservedWord(word, inModule) {
|
|
return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);
|
|
}
|
|
function isStrictBindOnlyReservedWord(word) {
|
|
return reservedWordsStrictBindSet.has(word);
|
|
}
|
|
function isStrictBindReservedWord(word, inModule) {
|
|
return isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word);
|
|
}
|
|
function isKeyword(word) {
|
|
return keywords.has(word);
|
|
}
|
|
|
|
|
|
return keyword;
|
|
}
|
|
|
|
var hasRequiredLib$3;
|
|
|
|
function requireLib$3 () {
|
|
if (hasRequiredLib$3) return lib$2;
|
|
hasRequiredLib$3 = 1;
|
|
(function (exports) {
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
Object.defineProperty(exports, "isIdentifierChar", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _identifier.isIdentifierChar;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isIdentifierName", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _identifier.isIdentifierName;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isIdentifierStart", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _identifier.isIdentifierStart;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _keyword.isKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isReservedWord", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _keyword.isReservedWord;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isStrictBindOnlyReservedWord", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _keyword.isStrictBindOnlyReservedWord;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isStrictBindReservedWord", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _keyword.isStrictBindReservedWord;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isStrictReservedWord", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _keyword.isStrictReservedWord;
|
|
}
|
|
});
|
|
var _identifier = requireIdentifier();
|
|
var _keyword = requireKeyword();
|
|
|
|
|
|
} (lib$2));
|
|
return lib$2;
|
|
}
|
|
|
|
var hasRequiredIsValidIdentifier;
|
|
|
|
function requireIsValidIdentifier () {
|
|
if (hasRequiredIsValidIdentifier) return isValidIdentifier;
|
|
hasRequiredIsValidIdentifier = 1;
|
|
|
|
Object.defineProperty(isValidIdentifier, "__esModule", {
|
|
value: true
|
|
});
|
|
isValidIdentifier.default = isValidIdentifier$1;
|
|
var _helperValidatorIdentifier = requireLib$3();
|
|
function isValidIdentifier$1(name, reserved = true) {
|
|
if (typeof name !== "string") return false;
|
|
if (reserved) {
|
|
if ((0, _helperValidatorIdentifier.isKeyword)(name) || (0, _helperValidatorIdentifier.isStrictReservedWord)(name, true)) {
|
|
return false;
|
|
}
|
|
}
|
|
return (0, _helperValidatorIdentifier.isIdentifierName)(name);
|
|
}
|
|
|
|
|
|
return isValidIdentifier;
|
|
}
|
|
|
|
var lib$1 = {};
|
|
|
|
var hasRequiredLib$2;
|
|
|
|
function requireLib$2 () {
|
|
if (hasRequiredLib$2) return lib$1;
|
|
hasRequiredLib$2 = 1;
|
|
|
|
Object.defineProperty(lib$1, "__esModule", {
|
|
value: true
|
|
});
|
|
lib$1.readCodePoint = readCodePoint;
|
|
lib$1.readInt = readInt;
|
|
lib$1.readStringContents = readStringContents;
|
|
var _isDigit = function isDigit(code) {
|
|
return code >= 48 && code <= 57;
|
|
};
|
|
const forbiddenNumericSeparatorSiblings = {
|
|
decBinOct: new Set([46, 66, 69, 79, 95, 98, 101, 111]),
|
|
hex: new Set([46, 88, 95, 120])
|
|
};
|
|
const isAllowedNumericSeparatorSibling = {
|
|
bin: ch => ch === 48 || ch === 49,
|
|
oct: ch => ch >= 48 && ch <= 55,
|
|
dec: ch => ch >= 48 && ch <= 57,
|
|
hex: ch => ch >= 48 && ch <= 57 || ch >= 65 && ch <= 70 || ch >= 97 && ch <= 102
|
|
};
|
|
function readStringContents(type, input, pos, lineStart, curLine, errors) {
|
|
const initialPos = pos;
|
|
const initialLineStart = lineStart;
|
|
const initialCurLine = curLine;
|
|
let out = "";
|
|
let firstInvalidLoc = null;
|
|
let chunkStart = pos;
|
|
const {
|
|
length
|
|
} = input;
|
|
for (;;) {
|
|
if (pos >= length) {
|
|
errors.unterminated(initialPos, initialLineStart, initialCurLine);
|
|
out += input.slice(chunkStart, pos);
|
|
break;
|
|
}
|
|
const ch = input.charCodeAt(pos);
|
|
if (isStringEnd(type, ch, input, pos)) {
|
|
out += input.slice(chunkStart, pos);
|
|
break;
|
|
}
|
|
if (ch === 92) {
|
|
out += input.slice(chunkStart, pos);
|
|
const res = readEscapedChar(input, pos, lineStart, curLine, type === "template", errors);
|
|
if (res.ch === null && !firstInvalidLoc) {
|
|
firstInvalidLoc = {
|
|
pos,
|
|
lineStart,
|
|
curLine
|
|
};
|
|
} else {
|
|
out += res.ch;
|
|
}
|
|
({
|
|
pos,
|
|
lineStart,
|
|
curLine
|
|
} = res);
|
|
chunkStart = pos;
|
|
} else if (ch === 8232 || ch === 8233) {
|
|
++pos;
|
|
++curLine;
|
|
lineStart = pos;
|
|
} else if (ch === 10 || ch === 13) {
|
|
if (type === "template") {
|
|
out += input.slice(chunkStart, pos) + "\n";
|
|
++pos;
|
|
if (ch === 13 && input.charCodeAt(pos) === 10) {
|
|
++pos;
|
|
}
|
|
++curLine;
|
|
chunkStart = lineStart = pos;
|
|
} else {
|
|
errors.unterminated(initialPos, initialLineStart, initialCurLine);
|
|
}
|
|
} else {
|
|
++pos;
|
|
}
|
|
}
|
|
return {
|
|
pos,
|
|
str: out,
|
|
firstInvalidLoc,
|
|
lineStart,
|
|
curLine,
|
|
containsInvalid: !!firstInvalidLoc
|
|
};
|
|
}
|
|
function isStringEnd(type, ch, input, pos) {
|
|
if (type === "template") {
|
|
return ch === 96 || ch === 36 && input.charCodeAt(pos + 1) === 123;
|
|
}
|
|
return ch === (type === "double" ? 34 : 39);
|
|
}
|
|
function readEscapedChar(input, pos, lineStart, curLine, inTemplate, errors) {
|
|
const throwOnInvalid = !inTemplate;
|
|
pos++;
|
|
const res = ch => ({
|
|
pos,
|
|
ch,
|
|
lineStart,
|
|
curLine
|
|
});
|
|
const ch = input.charCodeAt(pos++);
|
|
switch (ch) {
|
|
case 110:
|
|
return res("\n");
|
|
case 114:
|
|
return res("\r");
|
|
case 120:
|
|
{
|
|
let code;
|
|
({
|
|
code,
|
|
pos
|
|
} = readHexChar(input, pos, lineStart, curLine, 2, false, throwOnInvalid, errors));
|
|
return res(code === null ? null : String.fromCharCode(code));
|
|
}
|
|
case 117:
|
|
{
|
|
let code;
|
|
({
|
|
code,
|
|
pos
|
|
} = readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors));
|
|
return res(code === null ? null : String.fromCodePoint(code));
|
|
}
|
|
case 116:
|
|
return res("\t");
|
|
case 98:
|
|
return res("\b");
|
|
case 118:
|
|
return res("\u000b");
|
|
case 102:
|
|
return res("\f");
|
|
case 13:
|
|
if (input.charCodeAt(pos) === 10) {
|
|
++pos;
|
|
}
|
|
case 10:
|
|
lineStart = pos;
|
|
++curLine;
|
|
case 8232:
|
|
case 8233:
|
|
return res("");
|
|
case 56:
|
|
case 57:
|
|
if (inTemplate) {
|
|
return res(null);
|
|
} else {
|
|
errors.strictNumericEscape(pos - 1, lineStart, curLine);
|
|
}
|
|
default:
|
|
if (ch >= 48 && ch <= 55) {
|
|
const startPos = pos - 1;
|
|
const match = /^[0-7]+/.exec(input.slice(startPos, pos + 2));
|
|
let octalStr = match[0];
|
|
let octal = parseInt(octalStr, 8);
|
|
if (octal > 255) {
|
|
octalStr = octalStr.slice(0, -1);
|
|
octal = parseInt(octalStr, 8);
|
|
}
|
|
pos += octalStr.length - 1;
|
|
const next = input.charCodeAt(pos);
|
|
if (octalStr !== "0" || next === 56 || next === 57) {
|
|
if (inTemplate) {
|
|
return res(null);
|
|
} else {
|
|
errors.strictNumericEscape(startPos, lineStart, curLine);
|
|
}
|
|
}
|
|
return res(String.fromCharCode(octal));
|
|
}
|
|
return res(String.fromCharCode(ch));
|
|
}
|
|
}
|
|
function readHexChar(input, pos, lineStart, curLine, len, forceLen, throwOnInvalid, errors) {
|
|
const initialPos = pos;
|
|
let n;
|
|
({
|
|
n,
|
|
pos
|
|
} = readInt(input, pos, lineStart, curLine, 16, len, forceLen, false, errors, !throwOnInvalid));
|
|
if (n === null) {
|
|
if (throwOnInvalid) {
|
|
errors.invalidEscapeSequence(initialPos, lineStart, curLine);
|
|
} else {
|
|
pos = initialPos - 1;
|
|
}
|
|
}
|
|
return {
|
|
code: n,
|
|
pos
|
|
};
|
|
}
|
|
function readInt(input, pos, lineStart, curLine, radix, len, forceLen, allowNumSeparator, errors, bailOnError) {
|
|
const start = pos;
|
|
const forbiddenSiblings = radix === 16 ? forbiddenNumericSeparatorSiblings.hex : forbiddenNumericSeparatorSiblings.decBinOct;
|
|
const isAllowedSibling = radix === 16 ? isAllowedNumericSeparatorSibling.hex : radix === 10 ? isAllowedNumericSeparatorSibling.dec : radix === 8 ? isAllowedNumericSeparatorSibling.oct : isAllowedNumericSeparatorSibling.bin;
|
|
let invalid = false;
|
|
let total = 0;
|
|
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
|
|
const code = input.charCodeAt(pos);
|
|
let val;
|
|
if (code === 95 && allowNumSeparator !== "bail") {
|
|
const prev = input.charCodeAt(pos - 1);
|
|
const next = input.charCodeAt(pos + 1);
|
|
if (!allowNumSeparator) {
|
|
if (bailOnError) return {
|
|
n: null,
|
|
pos
|
|
};
|
|
errors.numericSeparatorInEscapeSequence(pos, lineStart, curLine);
|
|
} else if (Number.isNaN(next) || !isAllowedSibling(next) || forbiddenSiblings.has(prev) || forbiddenSiblings.has(next)) {
|
|
if (bailOnError) return {
|
|
n: null,
|
|
pos
|
|
};
|
|
errors.unexpectedNumericSeparator(pos, lineStart, curLine);
|
|
}
|
|
++pos;
|
|
continue;
|
|
}
|
|
if (code >= 97) {
|
|
val = code - 97 + 10;
|
|
} else if (code >= 65) {
|
|
val = code - 65 + 10;
|
|
} else if (_isDigit(code)) {
|
|
val = code - 48;
|
|
} else {
|
|
val = Infinity;
|
|
}
|
|
if (val >= radix) {
|
|
if (val <= 9 && bailOnError) {
|
|
return {
|
|
n: null,
|
|
pos
|
|
};
|
|
} else if (val <= 9 && errors.invalidDigit(pos, lineStart, curLine, radix)) {
|
|
val = 0;
|
|
} else if (forceLen) {
|
|
val = 0;
|
|
invalid = true;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
++pos;
|
|
total = total * radix + val;
|
|
}
|
|
if (pos === start || len != null && pos - start !== len || invalid) {
|
|
return {
|
|
n: null,
|
|
pos
|
|
};
|
|
}
|
|
return {
|
|
n: total,
|
|
pos
|
|
};
|
|
}
|
|
function readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors) {
|
|
const ch = input.charCodeAt(pos);
|
|
let code;
|
|
if (ch === 123) {
|
|
++pos;
|
|
({
|
|
code,
|
|
pos
|
|
} = readHexChar(input, pos, lineStart, curLine, input.indexOf("}", pos) - pos, true, throwOnInvalid, errors));
|
|
++pos;
|
|
if (code !== null && code > 0x10ffff) {
|
|
if (throwOnInvalid) {
|
|
errors.invalidCodePoint(pos, lineStart, curLine);
|
|
} else {
|
|
return {
|
|
code: null,
|
|
pos
|
|
};
|
|
}
|
|
}
|
|
} else {
|
|
({
|
|
code,
|
|
pos
|
|
} = readHexChar(input, pos, lineStart, curLine, 4, false, throwOnInvalid, errors));
|
|
}
|
|
return {
|
|
code,
|
|
pos
|
|
};
|
|
}
|
|
|
|
|
|
return lib$1;
|
|
}
|
|
|
|
var constants = {};
|
|
|
|
var hasRequiredConstants;
|
|
|
|
function requireConstants () {
|
|
if (hasRequiredConstants) return constants;
|
|
hasRequiredConstants = 1;
|
|
|
|
Object.defineProperty(constants, "__esModule", {
|
|
value: true
|
|
});
|
|
constants.UPDATE_OPERATORS = constants.UNARY_OPERATORS = constants.STRING_UNARY_OPERATORS = constants.STATEMENT_OR_BLOCK_KEYS = constants.NUMBER_UNARY_OPERATORS = constants.NUMBER_BINARY_OPERATORS = constants.NOT_LOCAL_BINDING = constants.LOGICAL_OPERATORS = constants.INHERIT_KEYS = constants.FOR_INIT_KEYS = constants.FLATTENABLE_KEYS = constants.EQUALITY_BINARY_OPERATORS = constants.COMPARISON_BINARY_OPERATORS = constants.COMMENT_KEYS = constants.BOOLEAN_UNARY_OPERATORS = constants.BOOLEAN_NUMBER_BINARY_OPERATORS = constants.BOOLEAN_BINARY_OPERATORS = constants.BLOCK_SCOPED_SYMBOL = constants.BINARY_OPERATORS = constants.ASSIGNMENT_OPERATORS = void 0;
|
|
constants.STATEMENT_OR_BLOCK_KEYS = ["consequent", "body", "alternate"];
|
|
constants.FLATTENABLE_KEYS = ["body", "expressions"];
|
|
constants.FOR_INIT_KEYS = ["left", "init"];
|
|
constants.COMMENT_KEYS = ["leadingComments", "trailingComments", "innerComments"];
|
|
const LOGICAL_OPERATORS = constants.LOGICAL_OPERATORS = ["||", "&&", "??"];
|
|
constants.UPDATE_OPERATORS = ["++", "--"];
|
|
const BOOLEAN_NUMBER_BINARY_OPERATORS = constants.BOOLEAN_NUMBER_BINARY_OPERATORS = [">", "<", ">=", "<="];
|
|
const EQUALITY_BINARY_OPERATORS = constants.EQUALITY_BINARY_OPERATORS = ["==", "===", "!=", "!=="];
|
|
const COMPARISON_BINARY_OPERATORS = constants.COMPARISON_BINARY_OPERATORS = [...EQUALITY_BINARY_OPERATORS, "in", "instanceof"];
|
|
const BOOLEAN_BINARY_OPERATORS = constants.BOOLEAN_BINARY_OPERATORS = [...COMPARISON_BINARY_OPERATORS, ...BOOLEAN_NUMBER_BINARY_OPERATORS];
|
|
const NUMBER_BINARY_OPERATORS = constants.NUMBER_BINARY_OPERATORS = ["-", "/", "%", "*", "**", "&", "|", ">>", ">>>", "<<", "^"];
|
|
constants.BINARY_OPERATORS = ["+", ...NUMBER_BINARY_OPERATORS, ...BOOLEAN_BINARY_OPERATORS, "|>"];
|
|
constants.ASSIGNMENT_OPERATORS = ["=", "+=", ...NUMBER_BINARY_OPERATORS.map(op => op + "="), ...LOGICAL_OPERATORS.map(op => op + "=")];
|
|
const BOOLEAN_UNARY_OPERATORS = constants.BOOLEAN_UNARY_OPERATORS = ["delete", "!"];
|
|
const NUMBER_UNARY_OPERATORS = constants.NUMBER_UNARY_OPERATORS = ["+", "-", "~"];
|
|
const STRING_UNARY_OPERATORS = constants.STRING_UNARY_OPERATORS = ["typeof"];
|
|
constants.UNARY_OPERATORS = ["void", "throw", ...BOOLEAN_UNARY_OPERATORS, ...NUMBER_UNARY_OPERATORS, ...STRING_UNARY_OPERATORS];
|
|
constants.INHERIT_KEYS = {
|
|
optional: ["typeAnnotation", "typeParameters", "returnType"],
|
|
force: ["start", "loc", "end"]
|
|
};
|
|
constants.BLOCK_SCOPED_SYMBOL = Symbol.for("var used to be block scoped");
|
|
constants.NOT_LOCAL_BINDING = Symbol.for("should not be considered a local binding");
|
|
|
|
|
|
return constants;
|
|
}
|
|
|
|
var utils = {};
|
|
|
|
var hasRequiredUtils;
|
|
|
|
function requireUtils () {
|
|
if (hasRequiredUtils) return utils;
|
|
hasRequiredUtils = 1;
|
|
|
|
Object.defineProperty(utils, "__esModule", {
|
|
value: true
|
|
});
|
|
utils.VISITOR_KEYS = utils.NODE_PARENT_VALIDATIONS = utils.NODE_FIELDS = utils.FLIPPED_ALIAS_KEYS = utils.DEPRECATED_KEYS = utils.BUILDER_KEYS = utils.ALIAS_KEYS = void 0;
|
|
utils.arrayOf = arrayOf;
|
|
utils.arrayOfType = arrayOfType;
|
|
utils.assertEach = assertEach;
|
|
utils.assertNodeOrValueType = assertNodeOrValueType;
|
|
utils.assertNodeType = assertNodeType;
|
|
utils.assertOneOf = assertOneOf;
|
|
utils.assertOptionalChainStart = assertOptionalChainStart;
|
|
utils.assertShape = assertShape;
|
|
utils.assertValueType = assertValueType;
|
|
utils.chain = chain;
|
|
utils.default = defineType;
|
|
utils.defineAliasedType = defineAliasedType;
|
|
utils.validate = validate;
|
|
utils.validateArrayOfType = validateArrayOfType;
|
|
utils.validateOptional = validateOptional;
|
|
utils.validateOptionalType = validateOptionalType;
|
|
utils.validateType = validateType;
|
|
var _is = requireIs();
|
|
var _validate = requireValidate();
|
|
const VISITOR_KEYS = utils.VISITOR_KEYS = {};
|
|
const ALIAS_KEYS = utils.ALIAS_KEYS = {};
|
|
const FLIPPED_ALIAS_KEYS = utils.FLIPPED_ALIAS_KEYS = {};
|
|
const NODE_FIELDS = utils.NODE_FIELDS = {};
|
|
const BUILDER_KEYS = utils.BUILDER_KEYS = {};
|
|
const DEPRECATED_KEYS = utils.DEPRECATED_KEYS = {};
|
|
const NODE_PARENT_VALIDATIONS = utils.NODE_PARENT_VALIDATIONS = {};
|
|
function getType(val) {
|
|
if (Array.isArray(val)) {
|
|
return "array";
|
|
} else if (val === null) {
|
|
return "null";
|
|
} else {
|
|
return typeof val;
|
|
}
|
|
}
|
|
function validate(validate) {
|
|
return {
|
|
validate
|
|
};
|
|
}
|
|
function validateType(...typeNames) {
|
|
return validate(assertNodeType(...typeNames));
|
|
}
|
|
function validateOptional(validate) {
|
|
return {
|
|
validate,
|
|
optional: true
|
|
};
|
|
}
|
|
function validateOptionalType(...typeNames) {
|
|
return {
|
|
validate: assertNodeType(...typeNames),
|
|
optional: true
|
|
};
|
|
}
|
|
function arrayOf(elementType) {
|
|
return chain(assertValueType("array"), assertEach(elementType));
|
|
}
|
|
function arrayOfType(...typeNames) {
|
|
return arrayOf(assertNodeType(...typeNames));
|
|
}
|
|
function validateArrayOfType(...typeNames) {
|
|
return validate(arrayOfType(...typeNames));
|
|
}
|
|
function assertEach(callback) {
|
|
const childValidator = process.env.BABEL_TYPES_8_BREAKING ? _validate.validateChild : () => {};
|
|
function validator(node, key, val) {
|
|
if (!Array.isArray(val)) return;
|
|
for (let i = 0; i < val.length; i++) {
|
|
const subkey = `${key}[${i}]`;
|
|
const v = val[i];
|
|
callback(node, subkey, v);
|
|
childValidator(node, subkey, v);
|
|
}
|
|
}
|
|
validator.each = callback;
|
|
return validator;
|
|
}
|
|
function assertOneOf(...values) {
|
|
function validate(node, key, val) {
|
|
if (!values.includes(val)) {
|
|
throw new TypeError(`Property ${key} expected value to be one of ${JSON.stringify(values)} but got ${JSON.stringify(val)}`);
|
|
}
|
|
}
|
|
validate.oneOf = values;
|
|
return validate;
|
|
}
|
|
function assertNodeType(...types) {
|
|
function validate(node, key, val) {
|
|
for (const type of types) {
|
|
if ((0, _is.default)(type, val)) {
|
|
(0, _validate.validateChild)(node, key, val);
|
|
return;
|
|
}
|
|
}
|
|
throw new TypeError(`Property ${key} of ${node.type} expected node to be of a type ${JSON.stringify(types)} but instead got ${JSON.stringify(val == null ? void 0 : val.type)}`);
|
|
}
|
|
validate.oneOfNodeTypes = types;
|
|
return validate;
|
|
}
|
|
function assertNodeOrValueType(...types) {
|
|
function validate(node, key, val) {
|
|
for (const type of types) {
|
|
if (getType(val) === type || (0, _is.default)(type, val)) {
|
|
(0, _validate.validateChild)(node, key, val);
|
|
return;
|
|
}
|
|
}
|
|
throw new TypeError(`Property ${key} of ${node.type} expected node to be of a type ${JSON.stringify(types)} but instead got ${JSON.stringify(val == null ? void 0 : val.type)}`);
|
|
}
|
|
validate.oneOfNodeOrValueTypes = types;
|
|
return validate;
|
|
}
|
|
function assertValueType(type) {
|
|
function validate(node, key, val) {
|
|
const valid = getType(val) === type;
|
|
if (!valid) {
|
|
throw new TypeError(`Property ${key} expected type of ${type} but got ${getType(val)}`);
|
|
}
|
|
}
|
|
validate.type = type;
|
|
return validate;
|
|
}
|
|
function assertShape(shape) {
|
|
function validate(node, key, val) {
|
|
const errors = [];
|
|
for (const property of Object.keys(shape)) {
|
|
try {
|
|
(0, _validate.validateField)(node, property, val[property], shape[property]);
|
|
} catch (error) {
|
|
if (error instanceof TypeError) {
|
|
errors.push(error.message);
|
|
continue;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
if (errors.length) {
|
|
throw new TypeError(`Property ${key} of ${node.type} expected to have the following:\n${errors.join("\n")}`);
|
|
}
|
|
}
|
|
validate.shapeOf = shape;
|
|
return validate;
|
|
}
|
|
function assertOptionalChainStart() {
|
|
function validate(node) {
|
|
var _current;
|
|
let current = node;
|
|
while (node) {
|
|
const {
|
|
type
|
|
} = current;
|
|
if (type === "OptionalCallExpression") {
|
|
if (current.optional) return;
|
|
current = current.callee;
|
|
continue;
|
|
}
|
|
if (type === "OptionalMemberExpression") {
|
|
if (current.optional) return;
|
|
current = current.object;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
throw new TypeError(`Non-optional ${node.type} must chain from an optional OptionalMemberExpression or OptionalCallExpression. Found chain from ${(_current = current) == null ? void 0 : _current.type}`);
|
|
}
|
|
return validate;
|
|
}
|
|
function chain(...fns) {
|
|
function validate(...args) {
|
|
for (const fn of fns) {
|
|
fn(...args);
|
|
}
|
|
}
|
|
validate.chainOf = fns;
|
|
if (fns.length >= 2 && "type" in fns[0] && fns[0].type === "array" && !("each" in fns[1])) {
|
|
throw new Error(`An assertValueType("array") validator can only be followed by an assertEach(...) validator.`);
|
|
}
|
|
return validate;
|
|
}
|
|
const validTypeOpts = new Set(["aliases", "builder", "deprecatedAlias", "fields", "inherits", "visitor", "validate"]);
|
|
const validFieldKeys = new Set(["default", "optional", "deprecated", "validate"]);
|
|
const store = {};
|
|
function defineAliasedType(...aliases) {
|
|
return (type, opts = {}) => {
|
|
let defined = opts.aliases;
|
|
if (!defined) {
|
|
var _store$opts$inherits$, _defined;
|
|
if (opts.inherits) defined = (_store$opts$inherits$ = store[opts.inherits].aliases) == null ? void 0 : _store$opts$inherits$.slice();
|
|
(_defined = defined) != null ? _defined : defined = [];
|
|
opts.aliases = defined;
|
|
}
|
|
const additional = aliases.filter(a => !defined.includes(a));
|
|
defined.unshift(...additional);
|
|
defineType(type, opts);
|
|
};
|
|
}
|
|
function defineType(type, opts = {}) {
|
|
const inherits = opts.inherits && store[opts.inherits] || {};
|
|
let fields = opts.fields;
|
|
if (!fields) {
|
|
fields = {};
|
|
if (inherits.fields) {
|
|
const keys = Object.getOwnPropertyNames(inherits.fields);
|
|
for (const key of keys) {
|
|
const field = inherits.fields[key];
|
|
const def = field.default;
|
|
if (Array.isArray(def) ? def.length > 0 : def && typeof def === "object") {
|
|
throw new Error("field defaults can only be primitives or empty arrays currently");
|
|
}
|
|
fields[key] = {
|
|
default: Array.isArray(def) ? [] : def,
|
|
optional: field.optional,
|
|
deprecated: field.deprecated,
|
|
validate: field.validate
|
|
};
|
|
}
|
|
}
|
|
}
|
|
const visitor = opts.visitor || inherits.visitor || [];
|
|
const aliases = opts.aliases || inherits.aliases || [];
|
|
const builder = opts.builder || inherits.builder || opts.visitor || [];
|
|
for (const k of Object.keys(opts)) {
|
|
if (!validTypeOpts.has(k)) {
|
|
throw new Error(`Unknown type option "${k}" on ${type}`);
|
|
}
|
|
}
|
|
if (opts.deprecatedAlias) {
|
|
DEPRECATED_KEYS[opts.deprecatedAlias] = type;
|
|
}
|
|
for (const key of visitor.concat(builder)) {
|
|
fields[key] = fields[key] || {};
|
|
}
|
|
for (const key of Object.keys(fields)) {
|
|
const field = fields[key];
|
|
if (field.default !== undefined && !builder.includes(key)) {
|
|
field.optional = true;
|
|
}
|
|
if (field.default === undefined) {
|
|
field.default = null;
|
|
} else if (!field.validate && field.default != null) {
|
|
field.validate = assertValueType(getType(field.default));
|
|
}
|
|
for (const k of Object.keys(field)) {
|
|
if (!validFieldKeys.has(k)) {
|
|
throw new Error(`Unknown field key "${k}" on ${type}.${key}`);
|
|
}
|
|
}
|
|
}
|
|
VISITOR_KEYS[type] = opts.visitor = visitor;
|
|
BUILDER_KEYS[type] = opts.builder = builder;
|
|
NODE_FIELDS[type] = opts.fields = fields;
|
|
ALIAS_KEYS[type] = opts.aliases = aliases;
|
|
aliases.forEach(alias => {
|
|
FLIPPED_ALIAS_KEYS[alias] = FLIPPED_ALIAS_KEYS[alias] || [];
|
|
FLIPPED_ALIAS_KEYS[alias].push(type);
|
|
});
|
|
if (opts.validate) {
|
|
NODE_PARENT_VALIDATIONS[type] = opts.validate;
|
|
}
|
|
store[type] = opts;
|
|
}
|
|
|
|
|
|
return utils;
|
|
}
|
|
|
|
var hasRequiredCore;
|
|
|
|
function requireCore () {
|
|
if (hasRequiredCore) return core;
|
|
hasRequiredCore = 1;
|
|
|
|
Object.defineProperty(core, "__esModule", {
|
|
value: true
|
|
});
|
|
core.patternLikeCommon = core.importAttributes = core.functionTypeAnnotationCommon = core.functionDeclarationCommon = core.functionCommon = core.classMethodOrPropertyCommon = core.classMethodOrDeclareMethodCommon = void 0;
|
|
var _is = requireIs();
|
|
var _isValidIdentifier = requireIsValidIdentifier();
|
|
var _helperValidatorIdentifier = requireLib$3();
|
|
var _helperStringParser = requireLib$2();
|
|
var _index = requireConstants();
|
|
var _utils = requireUtils();
|
|
const defineType = (0, _utils.defineAliasedType)("Standardized");
|
|
defineType("ArrayExpression", {
|
|
fields: {
|
|
elements: {
|
|
validate: (0, _utils.arrayOf)((0, _utils.assertNodeOrValueType)("null", "Expression", "SpreadElement")),
|
|
default: !process.env.BABEL_TYPES_8_BREAKING ? [] : undefined
|
|
}
|
|
},
|
|
visitor: ["elements"],
|
|
aliases: ["Expression"]
|
|
});
|
|
defineType("AssignmentExpression", {
|
|
fields: {
|
|
operator: {
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.assertValueType)("string") : Object.assign(function () {
|
|
const identifier = (0, _utils.assertOneOf)(..._index.ASSIGNMENT_OPERATORS);
|
|
const pattern = (0, _utils.assertOneOf)("=");
|
|
return function (node, key, val) {
|
|
const validator = (0, _is.default)("Pattern", node.left) ? pattern : identifier;
|
|
validator(node, key, val);
|
|
};
|
|
}(), {
|
|
type: "string"
|
|
})
|
|
},
|
|
left: {
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.assertNodeType)("LVal", "OptionalMemberExpression") : (0, _utils.assertNodeType)("Identifier", "MemberExpression", "OptionalMemberExpression", "ArrayPattern", "ObjectPattern", "TSAsExpression", "TSSatisfiesExpression", "TSTypeAssertion", "TSNonNullExpression")
|
|
},
|
|
right: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
},
|
|
builder: ["operator", "left", "right"],
|
|
visitor: ["left", "right"],
|
|
aliases: ["Expression"]
|
|
});
|
|
defineType("BinaryExpression", {
|
|
builder: ["operator", "left", "right"],
|
|
fields: {
|
|
operator: {
|
|
validate: (0, _utils.assertOneOf)(..._index.BINARY_OPERATORS)
|
|
},
|
|
left: {
|
|
validate: function () {
|
|
const expression = (0, _utils.assertNodeType)("Expression");
|
|
const inOp = (0, _utils.assertNodeType)("Expression", "PrivateName");
|
|
const validator = Object.assign(function (node, key, val) {
|
|
const validator = node.operator === "in" ? inOp : expression;
|
|
validator(node, key, val);
|
|
}, {
|
|
oneOfNodeTypes: ["Expression", "PrivateName"]
|
|
});
|
|
return validator;
|
|
}()
|
|
},
|
|
right: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
},
|
|
visitor: ["left", "right"],
|
|
aliases: ["Binary", "Expression"]
|
|
});
|
|
defineType("InterpreterDirective", {
|
|
builder: ["value"],
|
|
fields: {
|
|
value: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
}
|
|
}
|
|
});
|
|
defineType("Directive", {
|
|
visitor: ["value"],
|
|
fields: {
|
|
value: {
|
|
validate: (0, _utils.assertNodeType)("DirectiveLiteral")
|
|
}
|
|
}
|
|
});
|
|
defineType("DirectiveLiteral", {
|
|
builder: ["value"],
|
|
fields: {
|
|
value: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
}
|
|
}
|
|
});
|
|
defineType("BlockStatement", {
|
|
builder: ["body", "directives"],
|
|
visitor: ["directives", "body"],
|
|
fields: {
|
|
directives: {
|
|
validate: (0, _utils.arrayOfType)("Directive"),
|
|
default: []
|
|
},
|
|
body: (0, _utils.validateArrayOfType)("Statement")
|
|
},
|
|
aliases: ["Scopable", "BlockParent", "Block", "Statement"]
|
|
});
|
|
defineType("BreakStatement", {
|
|
visitor: ["label"],
|
|
fields: {
|
|
label: {
|
|
validate: (0, _utils.assertNodeType)("Identifier"),
|
|
optional: true
|
|
}
|
|
},
|
|
aliases: ["Statement", "Terminatorless", "CompletionStatement"]
|
|
});
|
|
defineType("CallExpression", {
|
|
visitor: ["callee", "arguments", "typeParameters", "typeArguments"],
|
|
builder: ["callee", "arguments"],
|
|
aliases: ["Expression"],
|
|
fields: Object.assign({
|
|
callee: {
|
|
validate: (0, _utils.assertNodeType)("Expression", "Super", "V8IntrinsicIdentifier")
|
|
},
|
|
arguments: (0, _utils.validateArrayOfType)("Expression", "SpreadElement", "ArgumentPlaceholder")
|
|
}, !process.env.BABEL_TYPES_8_BREAKING ? {
|
|
optional: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
}
|
|
} : {}, {
|
|
typeArguments: {
|
|
validate: (0, _utils.assertNodeType)("TypeParameterInstantiation"),
|
|
optional: true
|
|
},
|
|
typeParameters: {
|
|
validate: (0, _utils.assertNodeType)("TSTypeParameterInstantiation"),
|
|
optional: true
|
|
}
|
|
})
|
|
});
|
|
defineType("CatchClause", {
|
|
visitor: ["param", "body"],
|
|
fields: {
|
|
param: {
|
|
validate: (0, _utils.assertNodeType)("Identifier", "ArrayPattern", "ObjectPattern"),
|
|
optional: true
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("BlockStatement")
|
|
}
|
|
},
|
|
aliases: ["Scopable", "BlockParent"]
|
|
});
|
|
defineType("ConditionalExpression", {
|
|
visitor: ["test", "consequent", "alternate"],
|
|
fields: {
|
|
test: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
consequent: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
alternate: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
},
|
|
aliases: ["Expression", "Conditional"]
|
|
});
|
|
defineType("ContinueStatement", {
|
|
visitor: ["label"],
|
|
fields: {
|
|
label: {
|
|
validate: (0, _utils.assertNodeType)("Identifier"),
|
|
optional: true
|
|
}
|
|
},
|
|
aliases: ["Statement", "Terminatorless", "CompletionStatement"]
|
|
});
|
|
defineType("DebuggerStatement", {
|
|
aliases: ["Statement"]
|
|
});
|
|
defineType("DoWhileStatement", {
|
|
builder: ["test", "body"],
|
|
visitor: ["body", "test"],
|
|
fields: {
|
|
test: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("Statement")
|
|
}
|
|
},
|
|
aliases: ["Statement", "BlockParent", "Loop", "While", "Scopable"]
|
|
});
|
|
defineType("EmptyStatement", {
|
|
aliases: ["Statement"]
|
|
});
|
|
defineType("ExpressionStatement", {
|
|
visitor: ["expression"],
|
|
fields: {
|
|
expression: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
},
|
|
aliases: ["Statement", "ExpressionWrapper"]
|
|
});
|
|
defineType("File", {
|
|
builder: ["program", "comments", "tokens"],
|
|
visitor: ["program"],
|
|
fields: {
|
|
program: {
|
|
validate: (0, _utils.assertNodeType)("Program")
|
|
},
|
|
comments: {
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? Object.assign(() => {}, {
|
|
each: {
|
|
oneOfNodeTypes: ["CommentBlock", "CommentLine"]
|
|
}
|
|
}) : (0, _utils.assertEach)((0, _utils.assertNodeType)("CommentBlock", "CommentLine")),
|
|
optional: true
|
|
},
|
|
tokens: {
|
|
validate: (0, _utils.assertEach)(Object.assign(() => {}, {
|
|
type: "any"
|
|
})),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("ForInStatement", {
|
|
visitor: ["left", "right", "body"],
|
|
aliases: ["Scopable", "Statement", "For", "BlockParent", "Loop", "ForXStatement"],
|
|
fields: {
|
|
left: {
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.assertNodeType)("VariableDeclaration", "LVal") : (0, _utils.assertNodeType)("VariableDeclaration", "Identifier", "MemberExpression", "ArrayPattern", "ObjectPattern", "TSAsExpression", "TSSatisfiesExpression", "TSTypeAssertion", "TSNonNullExpression")
|
|
},
|
|
right: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("Statement")
|
|
}
|
|
}
|
|
});
|
|
defineType("ForStatement", {
|
|
visitor: ["init", "test", "update", "body"],
|
|
aliases: ["Scopable", "Statement", "For", "BlockParent", "Loop"],
|
|
fields: {
|
|
init: {
|
|
validate: (0, _utils.assertNodeType)("VariableDeclaration", "Expression"),
|
|
optional: true
|
|
},
|
|
test: {
|
|
validate: (0, _utils.assertNodeType)("Expression"),
|
|
optional: true
|
|
},
|
|
update: {
|
|
validate: (0, _utils.assertNodeType)("Expression"),
|
|
optional: true
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("Statement")
|
|
}
|
|
}
|
|
});
|
|
const functionCommon = () => ({
|
|
params: (0, _utils.validateArrayOfType)("Identifier", "Pattern", "RestElement"),
|
|
generator: {
|
|
default: false
|
|
},
|
|
async: {
|
|
default: false
|
|
}
|
|
});
|
|
core.functionCommon = functionCommon;
|
|
const functionTypeAnnotationCommon = () => ({
|
|
returnType: {
|
|
validate: (0, _utils.assertNodeType)("TypeAnnotation", "TSTypeAnnotation", "Noop"),
|
|
optional: true
|
|
},
|
|
typeParameters: {
|
|
validate: (0, _utils.assertNodeType)("TypeParameterDeclaration", "TSTypeParameterDeclaration", "Noop"),
|
|
optional: true
|
|
}
|
|
});
|
|
core.functionTypeAnnotationCommon = functionTypeAnnotationCommon;
|
|
const functionDeclarationCommon = () => Object.assign({}, functionCommon(), {
|
|
declare: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
id: {
|
|
validate: (0, _utils.assertNodeType)("Identifier"),
|
|
optional: true
|
|
}
|
|
});
|
|
core.functionDeclarationCommon = functionDeclarationCommon;
|
|
defineType("FunctionDeclaration", {
|
|
builder: ["id", "params", "body", "generator", "async"],
|
|
visitor: ["id", "typeParameters", "params", "returnType", "body"],
|
|
fields: Object.assign({}, functionDeclarationCommon(), functionTypeAnnotationCommon(), {
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("BlockStatement")
|
|
},
|
|
predicate: {
|
|
validate: (0, _utils.assertNodeType)("DeclaredPredicate", "InferredPredicate"),
|
|
optional: true
|
|
}
|
|
}),
|
|
aliases: ["Scopable", "Function", "BlockParent", "FunctionParent", "Statement", "Pureish", "Declaration"],
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? undefined : function () {
|
|
const identifier = (0, _utils.assertNodeType)("Identifier");
|
|
return function (parent, key, node) {
|
|
if (!(0, _is.default)("ExportDefaultDeclaration", parent)) {
|
|
identifier(node, "id", node.id);
|
|
}
|
|
};
|
|
}()
|
|
});
|
|
defineType("FunctionExpression", {
|
|
inherits: "FunctionDeclaration",
|
|
aliases: ["Scopable", "Function", "BlockParent", "FunctionParent", "Expression", "Pureish"],
|
|
fields: Object.assign({}, functionCommon(), functionTypeAnnotationCommon(), {
|
|
id: {
|
|
validate: (0, _utils.assertNodeType)("Identifier"),
|
|
optional: true
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("BlockStatement")
|
|
},
|
|
predicate: {
|
|
validate: (0, _utils.assertNodeType)("DeclaredPredicate", "InferredPredicate"),
|
|
optional: true
|
|
}
|
|
})
|
|
});
|
|
const patternLikeCommon = () => ({
|
|
typeAnnotation: {
|
|
validate: (0, _utils.assertNodeType)("TypeAnnotation", "TSTypeAnnotation", "Noop"),
|
|
optional: true
|
|
},
|
|
optional: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
}
|
|
});
|
|
core.patternLikeCommon = patternLikeCommon;
|
|
defineType("Identifier", {
|
|
builder: ["name"],
|
|
visitor: ["typeAnnotation", "decorators"],
|
|
aliases: ["Expression", "PatternLike", "LVal", "TSEntityName"],
|
|
fields: Object.assign({}, patternLikeCommon(), {
|
|
name: {
|
|
validate: process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.chain)((0, _utils.assertValueType)("string"), Object.assign(function (node, key, val) {
|
|
if (!(0, _isValidIdentifier.default)(val, false)) {
|
|
throw new TypeError(`"${val}" is not a valid identifier name`);
|
|
}
|
|
}, {
|
|
type: "string"
|
|
})) : (0, _utils.assertValueType)("string")
|
|
}
|
|
}),
|
|
validate: process.env.BABEL_TYPES_8_BREAKING ? function (parent, key, node) {
|
|
const match = /\.(\w+)$/.exec(key);
|
|
if (!match) return;
|
|
const [, parentKey] = match;
|
|
const nonComp = {
|
|
computed: false
|
|
};
|
|
if (parentKey === "property") {
|
|
if ((0, _is.default)("MemberExpression", parent, nonComp)) return;
|
|
if ((0, _is.default)("OptionalMemberExpression", parent, nonComp)) return;
|
|
} else if (parentKey === "key") {
|
|
if ((0, _is.default)("Property", parent, nonComp)) return;
|
|
if ((0, _is.default)("Method", parent, nonComp)) return;
|
|
} else if (parentKey === "exported") {
|
|
if ((0, _is.default)("ExportSpecifier", parent)) return;
|
|
} else if (parentKey === "imported") {
|
|
if ((0, _is.default)("ImportSpecifier", parent, {
|
|
imported: node
|
|
})) return;
|
|
} else if (parentKey === "meta") {
|
|
if ((0, _is.default)("MetaProperty", parent, {
|
|
meta: node
|
|
})) return;
|
|
}
|
|
if (((0, _helperValidatorIdentifier.isKeyword)(node.name) || (0, _helperValidatorIdentifier.isReservedWord)(node.name, false)) && node.name !== "this") {
|
|
throw new TypeError(`"${node.name}" is not a valid identifier`);
|
|
}
|
|
} : undefined
|
|
});
|
|
defineType("IfStatement", {
|
|
visitor: ["test", "consequent", "alternate"],
|
|
aliases: ["Statement", "Conditional"],
|
|
fields: {
|
|
test: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
consequent: {
|
|
validate: (0, _utils.assertNodeType)("Statement")
|
|
},
|
|
alternate: {
|
|
optional: true,
|
|
validate: (0, _utils.assertNodeType)("Statement")
|
|
}
|
|
}
|
|
});
|
|
defineType("LabeledStatement", {
|
|
visitor: ["label", "body"],
|
|
aliases: ["Statement"],
|
|
fields: {
|
|
label: {
|
|
validate: (0, _utils.assertNodeType)("Identifier")
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("Statement")
|
|
}
|
|
}
|
|
});
|
|
defineType("StringLiteral", {
|
|
builder: ["value"],
|
|
fields: {
|
|
value: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
}
|
|
},
|
|
aliases: ["Expression", "Pureish", "Literal", "Immutable"]
|
|
});
|
|
defineType("NumericLiteral", {
|
|
builder: ["value"],
|
|
deprecatedAlias: "NumberLiteral",
|
|
fields: {
|
|
value: {
|
|
validate: (0, _utils.chain)((0, _utils.assertValueType)("number"), Object.assign(function (node, key, val) {
|
|
}, {
|
|
type: "number"
|
|
}))
|
|
}
|
|
},
|
|
aliases: ["Expression", "Pureish", "Literal", "Immutable"]
|
|
});
|
|
defineType("NullLiteral", {
|
|
aliases: ["Expression", "Pureish", "Literal", "Immutable"]
|
|
});
|
|
defineType("BooleanLiteral", {
|
|
builder: ["value"],
|
|
fields: {
|
|
value: {
|
|
validate: (0, _utils.assertValueType)("boolean")
|
|
}
|
|
},
|
|
aliases: ["Expression", "Pureish", "Literal", "Immutable"]
|
|
});
|
|
defineType("RegExpLiteral", {
|
|
builder: ["pattern", "flags"],
|
|
deprecatedAlias: "RegexLiteral",
|
|
aliases: ["Expression", "Pureish", "Literal"],
|
|
fields: {
|
|
pattern: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
},
|
|
flags: {
|
|
validate: process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.chain)((0, _utils.assertValueType)("string"), Object.assign(function (node, key, val) {
|
|
const invalid = /[^gimsuy]/.exec(val);
|
|
if (invalid) {
|
|
throw new TypeError(`"${invalid[0]}" is not a valid RegExp flag`);
|
|
}
|
|
}, {
|
|
type: "string"
|
|
})) : (0, _utils.assertValueType)("string"),
|
|
default: ""
|
|
}
|
|
}
|
|
});
|
|
defineType("LogicalExpression", {
|
|
builder: ["operator", "left", "right"],
|
|
visitor: ["left", "right"],
|
|
aliases: ["Binary", "Expression"],
|
|
fields: {
|
|
operator: {
|
|
validate: (0, _utils.assertOneOf)(..._index.LOGICAL_OPERATORS)
|
|
},
|
|
left: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
right: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
defineType("MemberExpression", {
|
|
builder: ["object", "property", "computed", ...(!process.env.BABEL_TYPES_8_BREAKING ? ["optional"] : [])],
|
|
visitor: ["object", "property"],
|
|
aliases: ["Expression", "LVal"],
|
|
fields: Object.assign({
|
|
object: {
|
|
validate: (0, _utils.assertNodeType)("Expression", "Super")
|
|
},
|
|
property: {
|
|
validate: function () {
|
|
const normal = (0, _utils.assertNodeType)("Identifier", "PrivateName");
|
|
const computed = (0, _utils.assertNodeType)("Expression");
|
|
const validator = function (node, key, val) {
|
|
const validator = node.computed ? computed : normal;
|
|
validator(node, key, val);
|
|
};
|
|
validator.oneOfNodeTypes = ["Expression", "Identifier", "PrivateName"];
|
|
return validator;
|
|
}()
|
|
},
|
|
computed: {
|
|
default: false
|
|
}
|
|
}, !process.env.BABEL_TYPES_8_BREAKING ? {
|
|
optional: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
}
|
|
} : {})
|
|
});
|
|
defineType("NewExpression", {
|
|
inherits: "CallExpression"
|
|
});
|
|
defineType("Program", {
|
|
visitor: ["directives", "body"],
|
|
builder: ["body", "directives", "sourceType", "interpreter"],
|
|
fields: {
|
|
sourceType: {
|
|
validate: (0, _utils.assertOneOf)("script", "module"),
|
|
default: "script"
|
|
},
|
|
interpreter: {
|
|
validate: (0, _utils.assertNodeType)("InterpreterDirective"),
|
|
default: null,
|
|
optional: true
|
|
},
|
|
directives: {
|
|
validate: (0, _utils.arrayOfType)("Directive"),
|
|
default: []
|
|
},
|
|
body: (0, _utils.validateArrayOfType)("Statement")
|
|
},
|
|
aliases: ["Scopable", "BlockParent", "Block"]
|
|
});
|
|
defineType("ObjectExpression", {
|
|
visitor: ["properties"],
|
|
aliases: ["Expression"],
|
|
fields: {
|
|
properties: (0, _utils.validateArrayOfType)("ObjectMethod", "ObjectProperty", "SpreadElement")
|
|
}
|
|
});
|
|
defineType("ObjectMethod", {
|
|
builder: ["kind", "key", "params", "body", "computed", "generator", "async"],
|
|
visitor: ["decorators", "key", "typeParameters", "params", "returnType", "body"],
|
|
fields: Object.assign({}, functionCommon(), functionTypeAnnotationCommon(), {
|
|
kind: Object.assign({
|
|
validate: (0, _utils.assertOneOf)("method", "get", "set")
|
|
}, !process.env.BABEL_TYPES_8_BREAKING ? {
|
|
default: "method"
|
|
} : {}),
|
|
computed: {
|
|
default: false
|
|
},
|
|
key: {
|
|
validate: function () {
|
|
const normal = (0, _utils.assertNodeType)("Identifier", "StringLiteral", "NumericLiteral", "BigIntLiteral");
|
|
const computed = (0, _utils.assertNodeType)("Expression");
|
|
const validator = function (node, key, val) {
|
|
const validator = node.computed ? computed : normal;
|
|
validator(node, key, val);
|
|
};
|
|
validator.oneOfNodeTypes = ["Expression", "Identifier", "StringLiteral", "NumericLiteral", "BigIntLiteral"];
|
|
return validator;
|
|
}()
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("BlockStatement")
|
|
}
|
|
}),
|
|
aliases: ["UserWhitespacable", "Function", "Scopable", "BlockParent", "FunctionParent", "Method", "ObjectMember"]
|
|
});
|
|
defineType("ObjectProperty", {
|
|
builder: ["key", "value", "computed", "shorthand", ...(!process.env.BABEL_TYPES_8_BREAKING ? ["decorators"] : [])],
|
|
fields: {
|
|
computed: {
|
|
default: false
|
|
},
|
|
key: {
|
|
validate: function () {
|
|
const normal = (0, _utils.assertNodeType)("Identifier", "StringLiteral", "NumericLiteral", "BigIntLiteral", "DecimalLiteral", "PrivateName");
|
|
const computed = (0, _utils.assertNodeType)("Expression");
|
|
const validator = Object.assign(function (node, key, val) {
|
|
const validator = node.computed ? computed : normal;
|
|
validator(node, key, val);
|
|
}, {
|
|
oneOfNodeTypes: ["Expression", "Identifier", "StringLiteral", "NumericLiteral", "BigIntLiteral", "DecimalLiteral", "PrivateName"]
|
|
});
|
|
return validator;
|
|
}()
|
|
},
|
|
value: {
|
|
validate: (0, _utils.assertNodeType)("Expression", "PatternLike")
|
|
},
|
|
shorthand: {
|
|
validate: process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.chain)((0, _utils.assertValueType)("boolean"), Object.assign(function (node, key, shorthand) {
|
|
if (!shorthand) return;
|
|
if (node.computed) {
|
|
throw new TypeError("Property shorthand of ObjectProperty cannot be true if computed is true");
|
|
}
|
|
if (!(0, _is.default)("Identifier", node.key)) {
|
|
throw new TypeError("Property shorthand of ObjectProperty cannot be true if key is not an Identifier");
|
|
}
|
|
}, {
|
|
type: "boolean"
|
|
})) : (0, _utils.assertValueType)("boolean"),
|
|
default: false
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
}
|
|
},
|
|
visitor: ["key", "value", "decorators"],
|
|
aliases: ["UserWhitespacable", "Property", "ObjectMember"],
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? undefined : function () {
|
|
const pattern = (0, _utils.assertNodeType)("Identifier", "Pattern", "TSAsExpression", "TSSatisfiesExpression", "TSNonNullExpression", "TSTypeAssertion");
|
|
const expression = (0, _utils.assertNodeType)("Expression");
|
|
return function (parent, key, node) {
|
|
const validator = (0, _is.default)("ObjectPattern", parent) ? pattern : expression;
|
|
validator(node, "value", node.value);
|
|
};
|
|
}()
|
|
});
|
|
defineType("RestElement", {
|
|
visitor: ["argument", "typeAnnotation"],
|
|
builder: ["argument"],
|
|
aliases: ["LVal", "PatternLike"],
|
|
deprecatedAlias: "RestProperty",
|
|
fields: Object.assign({}, patternLikeCommon(), {
|
|
argument: {
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.assertNodeType)("LVal") : (0, _utils.assertNodeType)("Identifier", "ArrayPattern", "ObjectPattern", "MemberExpression", "TSAsExpression", "TSSatisfiesExpression", "TSTypeAssertion", "TSNonNullExpression")
|
|
}
|
|
}),
|
|
validate: process.env.BABEL_TYPES_8_BREAKING ? function (parent, key) {
|
|
const match = /(\w+)\[(\d+)\]/.exec(key);
|
|
if (!match) throw new Error("Internal Babel error: malformed key.");
|
|
const [, listKey, index] = match;
|
|
if (parent[listKey].length > +index + 1) {
|
|
throw new TypeError(`RestElement must be last element of ${listKey}`);
|
|
}
|
|
} : undefined
|
|
});
|
|
defineType("ReturnStatement", {
|
|
visitor: ["argument"],
|
|
aliases: ["Statement", "Terminatorless", "CompletionStatement"],
|
|
fields: {
|
|
argument: {
|
|
validate: (0, _utils.assertNodeType)("Expression"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("SequenceExpression", {
|
|
visitor: ["expressions"],
|
|
fields: {
|
|
expressions: (0, _utils.validateArrayOfType)("Expression")
|
|
},
|
|
aliases: ["Expression"]
|
|
});
|
|
defineType("ParenthesizedExpression", {
|
|
visitor: ["expression"],
|
|
aliases: ["Expression", "ExpressionWrapper"],
|
|
fields: {
|
|
expression: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
defineType("SwitchCase", {
|
|
visitor: ["test", "consequent"],
|
|
fields: {
|
|
test: {
|
|
validate: (0, _utils.assertNodeType)("Expression"),
|
|
optional: true
|
|
},
|
|
consequent: (0, _utils.validateArrayOfType)("Statement")
|
|
}
|
|
});
|
|
defineType("SwitchStatement", {
|
|
visitor: ["discriminant", "cases"],
|
|
aliases: ["Statement", "BlockParent", "Scopable"],
|
|
fields: {
|
|
discriminant: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
cases: (0, _utils.validateArrayOfType)("SwitchCase")
|
|
}
|
|
});
|
|
defineType("ThisExpression", {
|
|
aliases: ["Expression"]
|
|
});
|
|
defineType("ThrowStatement", {
|
|
visitor: ["argument"],
|
|
aliases: ["Statement", "Terminatorless", "CompletionStatement"],
|
|
fields: {
|
|
argument: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
defineType("TryStatement", {
|
|
visitor: ["block", "handler", "finalizer"],
|
|
aliases: ["Statement"],
|
|
fields: {
|
|
block: {
|
|
validate: process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.chain)((0, _utils.assertNodeType)("BlockStatement"), Object.assign(function (node) {
|
|
if (!node.handler && !node.finalizer) {
|
|
throw new TypeError("TryStatement expects either a handler or finalizer, or both");
|
|
}
|
|
}, {
|
|
oneOfNodeTypes: ["BlockStatement"]
|
|
})) : (0, _utils.assertNodeType)("BlockStatement")
|
|
},
|
|
handler: {
|
|
optional: true,
|
|
validate: (0, _utils.assertNodeType)("CatchClause")
|
|
},
|
|
finalizer: {
|
|
optional: true,
|
|
validate: (0, _utils.assertNodeType)("BlockStatement")
|
|
}
|
|
}
|
|
});
|
|
defineType("UnaryExpression", {
|
|
builder: ["operator", "argument", "prefix"],
|
|
fields: {
|
|
prefix: {
|
|
default: true
|
|
},
|
|
argument: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
operator: {
|
|
validate: (0, _utils.assertOneOf)(..._index.UNARY_OPERATORS)
|
|
}
|
|
},
|
|
visitor: ["argument"],
|
|
aliases: ["UnaryLike", "Expression"]
|
|
});
|
|
defineType("UpdateExpression", {
|
|
builder: ["operator", "argument", "prefix"],
|
|
fields: {
|
|
prefix: {
|
|
default: false
|
|
},
|
|
argument: {
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.assertNodeType)("Expression") : (0, _utils.assertNodeType)("Identifier", "MemberExpression")
|
|
},
|
|
operator: {
|
|
validate: (0, _utils.assertOneOf)(..._index.UPDATE_OPERATORS)
|
|
}
|
|
},
|
|
visitor: ["argument"],
|
|
aliases: ["Expression"]
|
|
});
|
|
defineType("VariableDeclaration", {
|
|
builder: ["kind", "declarations"],
|
|
visitor: ["declarations"],
|
|
aliases: ["Statement", "Declaration"],
|
|
fields: {
|
|
declare: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
kind: {
|
|
validate: (0, _utils.assertOneOf)("var", "let", "const", "using", "await using")
|
|
},
|
|
declarations: (0, _utils.validateArrayOfType)("VariableDeclarator")
|
|
},
|
|
validate: process.env.BABEL_TYPES_8_BREAKING ? (() => {
|
|
const withoutInit = (0, _utils.assertNodeType)("Identifier");
|
|
return function (parent, key, node) {
|
|
if ((0, _is.default)("ForXStatement", parent, {
|
|
left: node
|
|
})) {
|
|
if (node.declarations.length !== 1) {
|
|
throw new TypeError(`Exactly one VariableDeclarator is required in the VariableDeclaration of a ${parent.type}`);
|
|
}
|
|
} else {
|
|
node.declarations.forEach(decl => {
|
|
if (!decl.init) withoutInit(decl, "id", decl.id);
|
|
});
|
|
}
|
|
};
|
|
})() : undefined
|
|
});
|
|
defineType("VariableDeclarator", {
|
|
visitor: ["id", "init"],
|
|
fields: {
|
|
id: {
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.assertNodeType)("LVal") : (0, _utils.assertNodeType)("Identifier", "ArrayPattern", "ObjectPattern")
|
|
},
|
|
definite: {
|
|
optional: true,
|
|
validate: (0, _utils.assertValueType)("boolean")
|
|
},
|
|
init: {
|
|
optional: true,
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
defineType("WhileStatement", {
|
|
visitor: ["test", "body"],
|
|
aliases: ["Statement", "BlockParent", "Loop", "While", "Scopable"],
|
|
fields: {
|
|
test: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("Statement")
|
|
}
|
|
}
|
|
});
|
|
defineType("WithStatement", {
|
|
visitor: ["object", "body"],
|
|
aliases: ["Statement"],
|
|
fields: {
|
|
object: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("Statement")
|
|
}
|
|
}
|
|
});
|
|
defineType("AssignmentPattern", {
|
|
visitor: ["left", "right", "decorators"],
|
|
builder: ["left", "right"],
|
|
aliases: ["Pattern", "PatternLike", "LVal"],
|
|
fields: Object.assign({}, patternLikeCommon(), {
|
|
left: {
|
|
validate: (0, _utils.assertNodeType)("Identifier", "ObjectPattern", "ArrayPattern", "MemberExpression", "TSAsExpression", "TSSatisfiesExpression", "TSTypeAssertion", "TSNonNullExpression")
|
|
},
|
|
right: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
}
|
|
})
|
|
});
|
|
defineType("ArrayPattern", {
|
|
visitor: ["elements", "typeAnnotation"],
|
|
builder: ["elements"],
|
|
aliases: ["Pattern", "PatternLike", "LVal"],
|
|
fields: Object.assign({}, patternLikeCommon(), {
|
|
elements: {
|
|
validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeOrValueType)("null", "PatternLike", "LVal")))
|
|
}
|
|
})
|
|
});
|
|
defineType("ArrowFunctionExpression", {
|
|
builder: ["params", "body", "async"],
|
|
visitor: ["typeParameters", "params", "returnType", "body"],
|
|
aliases: ["Scopable", "Function", "BlockParent", "FunctionParent", "Expression", "Pureish"],
|
|
fields: Object.assign({}, functionCommon(), functionTypeAnnotationCommon(), {
|
|
expression: {
|
|
validate: (0, _utils.assertValueType)("boolean")
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("BlockStatement", "Expression")
|
|
},
|
|
predicate: {
|
|
validate: (0, _utils.assertNodeType)("DeclaredPredicate", "InferredPredicate"),
|
|
optional: true
|
|
}
|
|
})
|
|
});
|
|
defineType("ClassBody", {
|
|
visitor: ["body"],
|
|
fields: {
|
|
body: (0, _utils.validateArrayOfType)("ClassMethod", "ClassPrivateMethod", "ClassProperty", "ClassPrivateProperty", "ClassAccessorProperty", "TSDeclareMethod", "TSIndexSignature", "StaticBlock")
|
|
}
|
|
});
|
|
defineType("ClassExpression", {
|
|
builder: ["id", "superClass", "body", "decorators"],
|
|
visitor: ["decorators", "id", "typeParameters", "superClass", "superTypeParameters", "mixins", "implements", "body"],
|
|
aliases: ["Scopable", "Class", "Expression"],
|
|
fields: {
|
|
id: {
|
|
validate: (0, _utils.assertNodeType)("Identifier"),
|
|
optional: true
|
|
},
|
|
typeParameters: {
|
|
validate: (0, _utils.assertNodeType)("TypeParameterDeclaration", "TSTypeParameterDeclaration", "Noop"),
|
|
optional: true
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("ClassBody")
|
|
},
|
|
superClass: {
|
|
optional: true,
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
superTypeParameters: {
|
|
validate: (0, _utils.assertNodeType)("TypeParameterInstantiation", "TSTypeParameterInstantiation"),
|
|
optional: true
|
|
},
|
|
implements: {
|
|
validate: (0, _utils.arrayOfType)("TSExpressionWithTypeArguments", "ClassImplements"),
|
|
optional: true
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
},
|
|
mixins: {
|
|
validate: (0, _utils.assertNodeType)("InterfaceExtends"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("ClassDeclaration", {
|
|
inherits: "ClassExpression",
|
|
aliases: ["Scopable", "Class", "Statement", "Declaration"],
|
|
fields: {
|
|
id: {
|
|
validate: (0, _utils.assertNodeType)("Identifier"),
|
|
optional: true
|
|
},
|
|
typeParameters: {
|
|
validate: (0, _utils.assertNodeType)("TypeParameterDeclaration", "TSTypeParameterDeclaration", "Noop"),
|
|
optional: true
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("ClassBody")
|
|
},
|
|
superClass: {
|
|
optional: true,
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
superTypeParameters: {
|
|
validate: (0, _utils.assertNodeType)("TypeParameterInstantiation", "TSTypeParameterInstantiation"),
|
|
optional: true
|
|
},
|
|
implements: {
|
|
validate: (0, _utils.arrayOfType)("TSExpressionWithTypeArguments", "ClassImplements"),
|
|
optional: true
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
},
|
|
mixins: {
|
|
validate: (0, _utils.assertNodeType)("InterfaceExtends"),
|
|
optional: true
|
|
},
|
|
declare: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
abstract: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
}
|
|
},
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? undefined : function () {
|
|
const identifier = (0, _utils.assertNodeType)("Identifier");
|
|
return function (parent, key, node) {
|
|
if (!(0, _is.default)("ExportDefaultDeclaration", parent)) {
|
|
identifier(node, "id", node.id);
|
|
}
|
|
};
|
|
}()
|
|
});
|
|
const importAttributes = core.importAttributes = {
|
|
attributes: {
|
|
optional: true,
|
|
validate: (0, _utils.arrayOfType)("ImportAttribute")
|
|
},
|
|
assertions: {
|
|
deprecated: true,
|
|
optional: true,
|
|
validate: (0, _utils.arrayOfType)("ImportAttribute")
|
|
}
|
|
};
|
|
defineType("ExportAllDeclaration", {
|
|
builder: ["source"],
|
|
visitor: ["source", "attributes", "assertions"],
|
|
aliases: ["Statement", "Declaration", "ImportOrExportDeclaration", "ExportDeclaration"],
|
|
fields: Object.assign({
|
|
source: {
|
|
validate: (0, _utils.assertNodeType)("StringLiteral")
|
|
},
|
|
exportKind: (0, _utils.validateOptional)((0, _utils.assertOneOf)("type", "value"))
|
|
}, importAttributes)
|
|
});
|
|
defineType("ExportDefaultDeclaration", {
|
|
visitor: ["declaration"],
|
|
aliases: ["Statement", "Declaration", "ImportOrExportDeclaration", "ExportDeclaration"],
|
|
fields: {
|
|
declaration: (0, _utils.validateType)("TSDeclareFunction", "FunctionDeclaration", "ClassDeclaration", "Expression"),
|
|
exportKind: (0, _utils.validateOptional)((0, _utils.assertOneOf)("value"))
|
|
}
|
|
});
|
|
defineType("ExportNamedDeclaration", {
|
|
builder: ["declaration", "specifiers", "source"],
|
|
visitor: process.env ? ["declaration", "specifiers", "source", "attributes"] : ["declaration", "specifiers", "source", "attributes", "assertions"],
|
|
aliases: ["Statement", "Declaration", "ImportOrExportDeclaration", "ExportDeclaration"],
|
|
fields: Object.assign({
|
|
declaration: {
|
|
optional: true,
|
|
validate: process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.chain)((0, _utils.assertNodeType)("Declaration"), Object.assign(function (node, key, val) {
|
|
if (val && node.specifiers.length) {
|
|
throw new TypeError("Only declaration or specifiers is allowed on ExportNamedDeclaration");
|
|
}
|
|
if (val && node.source) {
|
|
throw new TypeError("Cannot export a declaration from a source");
|
|
}
|
|
}, {
|
|
oneOfNodeTypes: ["Declaration"]
|
|
})) : (0, _utils.assertNodeType)("Declaration")
|
|
}
|
|
}, importAttributes, {
|
|
specifiers: {
|
|
default: [],
|
|
validate: (0, _utils.arrayOf)(function () {
|
|
const sourced = (0, _utils.assertNodeType)("ExportSpecifier", "ExportDefaultSpecifier", "ExportNamespaceSpecifier");
|
|
const sourceless = (0, _utils.assertNodeType)("ExportSpecifier");
|
|
if (!process.env.BABEL_TYPES_8_BREAKING) return sourced;
|
|
return Object.assign(function (node, key, val) {
|
|
const validator = node.source ? sourced : sourceless;
|
|
validator(node, key, val);
|
|
}, {
|
|
oneOfNodeTypes: ["ExportSpecifier", "ExportDefaultSpecifier", "ExportNamespaceSpecifier"]
|
|
});
|
|
}())
|
|
},
|
|
source: {
|
|
validate: (0, _utils.assertNodeType)("StringLiteral"),
|
|
optional: true
|
|
},
|
|
exportKind: (0, _utils.validateOptional)((0, _utils.assertOneOf)("type", "value"))
|
|
})
|
|
});
|
|
defineType("ExportSpecifier", {
|
|
visitor: ["local", "exported"],
|
|
aliases: ["ModuleSpecifier"],
|
|
fields: {
|
|
local: {
|
|
validate: (0, _utils.assertNodeType)("Identifier")
|
|
},
|
|
exported: {
|
|
validate: (0, _utils.assertNodeType)("Identifier", "StringLiteral")
|
|
},
|
|
exportKind: {
|
|
validate: (0, _utils.assertOneOf)("type", "value"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("ForOfStatement", {
|
|
visitor: ["left", "right", "body"],
|
|
builder: ["left", "right", "body", "await"],
|
|
aliases: ["Scopable", "Statement", "For", "BlockParent", "Loop", "ForXStatement"],
|
|
fields: {
|
|
left: {
|
|
validate: function () {
|
|
if (!process.env.BABEL_TYPES_8_BREAKING) {
|
|
return (0, _utils.assertNodeType)("VariableDeclaration", "LVal");
|
|
}
|
|
const declaration = (0, _utils.assertNodeType)("VariableDeclaration");
|
|
const lval = (0, _utils.assertNodeType)("Identifier", "MemberExpression", "ArrayPattern", "ObjectPattern", "TSAsExpression", "TSSatisfiesExpression", "TSTypeAssertion", "TSNonNullExpression");
|
|
return Object.assign(function (node, key, val) {
|
|
if ((0, _is.default)("VariableDeclaration", val)) {
|
|
declaration(node, key, val);
|
|
} else {
|
|
lval(node, key, val);
|
|
}
|
|
}, {
|
|
oneOfNodeTypes: ["VariableDeclaration", "Identifier", "MemberExpression", "ArrayPattern", "ObjectPattern", "TSAsExpression", "TSSatisfiesExpression", "TSTypeAssertion", "TSNonNullExpression"]
|
|
});
|
|
}()
|
|
},
|
|
right: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("Statement")
|
|
},
|
|
await: {
|
|
default: false
|
|
}
|
|
}
|
|
});
|
|
defineType("ImportDeclaration", {
|
|
builder: ["specifiers", "source"],
|
|
visitor: ["specifiers", "source", "attributes", "assertions"],
|
|
aliases: ["Statement", "Declaration", "ImportOrExportDeclaration"],
|
|
fields: Object.assign({}, importAttributes, {
|
|
module: {
|
|
optional: true,
|
|
validate: (0, _utils.assertValueType)("boolean")
|
|
},
|
|
phase: {
|
|
default: null,
|
|
validate: (0, _utils.assertOneOf)("source", "defer")
|
|
},
|
|
specifiers: (0, _utils.validateArrayOfType)("ImportSpecifier", "ImportDefaultSpecifier", "ImportNamespaceSpecifier"),
|
|
source: {
|
|
validate: (0, _utils.assertNodeType)("StringLiteral")
|
|
},
|
|
importKind: {
|
|
validate: (0, _utils.assertOneOf)("type", "typeof", "value"),
|
|
optional: true
|
|
}
|
|
})
|
|
});
|
|
defineType("ImportDefaultSpecifier", {
|
|
visitor: ["local"],
|
|
aliases: ["ModuleSpecifier"],
|
|
fields: {
|
|
local: {
|
|
validate: (0, _utils.assertNodeType)("Identifier")
|
|
}
|
|
}
|
|
});
|
|
defineType("ImportNamespaceSpecifier", {
|
|
visitor: ["local"],
|
|
aliases: ["ModuleSpecifier"],
|
|
fields: {
|
|
local: {
|
|
validate: (0, _utils.assertNodeType)("Identifier")
|
|
}
|
|
}
|
|
});
|
|
defineType("ImportSpecifier", {
|
|
visitor: ["imported", "local"],
|
|
builder: ["local", "imported"],
|
|
aliases: ["ModuleSpecifier"],
|
|
fields: {
|
|
local: {
|
|
validate: (0, _utils.assertNodeType)("Identifier")
|
|
},
|
|
imported: {
|
|
validate: (0, _utils.assertNodeType)("Identifier", "StringLiteral")
|
|
},
|
|
importKind: {
|
|
validate: (0, _utils.assertOneOf)("type", "typeof", "value"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("ImportExpression", {
|
|
visitor: ["source", "options"],
|
|
aliases: ["Expression"],
|
|
fields: {
|
|
phase: {
|
|
default: null,
|
|
validate: (0, _utils.assertOneOf)("source", "defer")
|
|
},
|
|
source: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
options: {
|
|
validate: (0, _utils.assertNodeType)("Expression"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("MetaProperty", {
|
|
visitor: ["meta", "property"],
|
|
aliases: ["Expression"],
|
|
fields: {
|
|
meta: {
|
|
validate: process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.chain)((0, _utils.assertNodeType)("Identifier"), Object.assign(function (node, key, val) {
|
|
let property;
|
|
switch (val.name) {
|
|
case "function":
|
|
property = "sent";
|
|
break;
|
|
case "new":
|
|
property = "target";
|
|
break;
|
|
case "import":
|
|
property = "meta";
|
|
break;
|
|
}
|
|
if (!(0, _is.default)("Identifier", node.property, {
|
|
name: property
|
|
})) {
|
|
throw new TypeError("Unrecognised MetaProperty");
|
|
}
|
|
}, {
|
|
oneOfNodeTypes: ["Identifier"]
|
|
})) : (0, _utils.assertNodeType)("Identifier")
|
|
},
|
|
property: {
|
|
validate: (0, _utils.assertNodeType)("Identifier")
|
|
}
|
|
}
|
|
});
|
|
const classMethodOrPropertyCommon = () => ({
|
|
abstract: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
accessibility: {
|
|
validate: (0, _utils.assertOneOf)("public", "private", "protected"),
|
|
optional: true
|
|
},
|
|
static: {
|
|
default: false
|
|
},
|
|
override: {
|
|
default: false
|
|
},
|
|
computed: {
|
|
default: false
|
|
},
|
|
optional: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
key: {
|
|
validate: (0, _utils.chain)(function () {
|
|
const normal = (0, _utils.assertNodeType)("Identifier", "StringLiteral", "NumericLiteral", "BigIntLiteral");
|
|
const computed = (0, _utils.assertNodeType)("Expression");
|
|
return function (node, key, val) {
|
|
const validator = node.computed ? computed : normal;
|
|
validator(node, key, val);
|
|
};
|
|
}(), (0, _utils.assertNodeType)("Identifier", "StringLiteral", "NumericLiteral", "BigIntLiteral", "Expression"))
|
|
}
|
|
});
|
|
core.classMethodOrPropertyCommon = classMethodOrPropertyCommon;
|
|
const classMethodOrDeclareMethodCommon = () => Object.assign({}, functionCommon(), classMethodOrPropertyCommon(), {
|
|
params: (0, _utils.validateArrayOfType)("Identifier", "Pattern", "RestElement", "TSParameterProperty"),
|
|
kind: {
|
|
validate: (0, _utils.assertOneOf)("get", "set", "method", "constructor"),
|
|
default: "method"
|
|
},
|
|
access: {
|
|
validate: (0, _utils.chain)((0, _utils.assertValueType)("string"), (0, _utils.assertOneOf)("public", "private", "protected")),
|
|
optional: true
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
}
|
|
});
|
|
core.classMethodOrDeclareMethodCommon = classMethodOrDeclareMethodCommon;
|
|
defineType("ClassMethod", {
|
|
aliases: ["Function", "Scopable", "BlockParent", "FunctionParent", "Method"],
|
|
builder: ["kind", "key", "params", "body", "computed", "static", "generator", "async"],
|
|
visitor: ["decorators", "key", "typeParameters", "params", "returnType", "body"],
|
|
fields: Object.assign({}, classMethodOrDeclareMethodCommon(), functionTypeAnnotationCommon(), {
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("BlockStatement")
|
|
}
|
|
})
|
|
});
|
|
defineType("ObjectPattern", {
|
|
visitor: ["properties", "typeAnnotation", "decorators"],
|
|
builder: ["properties"],
|
|
aliases: ["Pattern", "PatternLike", "LVal"],
|
|
fields: Object.assign({}, patternLikeCommon(), {
|
|
properties: (0, _utils.validateArrayOfType)("RestElement", "ObjectProperty")
|
|
})
|
|
});
|
|
defineType("SpreadElement", {
|
|
visitor: ["argument"],
|
|
aliases: ["UnaryLike"],
|
|
deprecatedAlias: "SpreadProperty",
|
|
fields: {
|
|
argument: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
defineType("Super", {
|
|
aliases: ["Expression"]
|
|
});
|
|
defineType("TaggedTemplateExpression", {
|
|
visitor: ["tag", "typeParameters", "quasi"],
|
|
builder: ["tag", "quasi"],
|
|
aliases: ["Expression"],
|
|
fields: {
|
|
tag: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
quasi: {
|
|
validate: (0, _utils.assertNodeType)("TemplateLiteral")
|
|
},
|
|
typeParameters: {
|
|
validate: (0, _utils.assertNodeType)("TypeParameterInstantiation", "TSTypeParameterInstantiation"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("TemplateElement", {
|
|
builder: ["value", "tail"],
|
|
fields: {
|
|
value: {
|
|
validate: (0, _utils.chain)((0, _utils.assertShape)({
|
|
raw: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
},
|
|
cooked: {
|
|
validate: (0, _utils.assertValueType)("string"),
|
|
optional: true
|
|
}
|
|
}), function templateElementCookedValidator(node) {
|
|
const raw = node.value.raw;
|
|
let unterminatedCalled = false;
|
|
const error = () => {
|
|
throw new Error("Internal @babel/types error.");
|
|
};
|
|
const {
|
|
str,
|
|
firstInvalidLoc
|
|
} = (0, _helperStringParser.readStringContents)("template", raw, 0, 0, 0, {
|
|
unterminated() {
|
|
unterminatedCalled = true;
|
|
},
|
|
strictNumericEscape: error,
|
|
invalidEscapeSequence: error,
|
|
numericSeparatorInEscapeSequence: error,
|
|
unexpectedNumericSeparator: error,
|
|
invalidDigit: error,
|
|
invalidCodePoint: error
|
|
});
|
|
if (!unterminatedCalled) throw new Error("Invalid raw");
|
|
node.value.cooked = firstInvalidLoc ? null : str;
|
|
})
|
|
},
|
|
tail: {
|
|
default: false
|
|
}
|
|
}
|
|
});
|
|
defineType("TemplateLiteral", {
|
|
visitor: ["quasis", "expressions"],
|
|
aliases: ["Expression", "Literal"],
|
|
fields: {
|
|
quasis: (0, _utils.validateArrayOfType)("TemplateElement"),
|
|
expressions: {
|
|
validate: (0, _utils.chain)((0, _utils.assertValueType)("array"), (0, _utils.assertEach)((0, _utils.assertNodeType)("Expression", "TSType")), function (node, key, val) {
|
|
if (node.quasis.length !== val.length + 1) {
|
|
throw new TypeError(`Number of ${node.type} quasis should be exactly one more than the number of expressions.\nExpected ${val.length + 1} quasis but got ${node.quasis.length}`);
|
|
}
|
|
})
|
|
}
|
|
}
|
|
});
|
|
defineType("YieldExpression", {
|
|
builder: ["argument", "delegate"],
|
|
visitor: ["argument"],
|
|
aliases: ["Expression", "Terminatorless"],
|
|
fields: {
|
|
delegate: {
|
|
validate: process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.chain)((0, _utils.assertValueType)("boolean"), Object.assign(function (node, key, val) {
|
|
if (val && !node.argument) {
|
|
throw new TypeError("Property delegate of YieldExpression cannot be true if there is no argument");
|
|
}
|
|
}, {
|
|
type: "boolean"
|
|
})) : (0, _utils.assertValueType)("boolean"),
|
|
default: false
|
|
},
|
|
argument: {
|
|
optional: true,
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
defineType("AwaitExpression", {
|
|
builder: ["argument"],
|
|
visitor: ["argument"],
|
|
aliases: ["Expression", "Terminatorless"],
|
|
fields: {
|
|
argument: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
defineType("Import", {
|
|
aliases: ["Expression"]
|
|
});
|
|
defineType("BigIntLiteral", {
|
|
builder: ["value"],
|
|
fields: {
|
|
value: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
}
|
|
},
|
|
aliases: ["Expression", "Pureish", "Literal", "Immutable"]
|
|
});
|
|
defineType("ExportNamespaceSpecifier", {
|
|
visitor: ["exported"],
|
|
aliases: ["ModuleSpecifier"],
|
|
fields: {
|
|
exported: {
|
|
validate: (0, _utils.assertNodeType)("Identifier")
|
|
}
|
|
}
|
|
});
|
|
defineType("OptionalMemberExpression", {
|
|
builder: ["object", "property", "computed", "optional"],
|
|
visitor: ["object", "property"],
|
|
aliases: ["Expression"],
|
|
fields: {
|
|
object: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
property: {
|
|
validate: function () {
|
|
const normal = (0, _utils.assertNodeType)("Identifier");
|
|
const computed = (0, _utils.assertNodeType)("Expression");
|
|
const validator = Object.assign(function (node, key, val) {
|
|
const validator = node.computed ? computed : normal;
|
|
validator(node, key, val);
|
|
}, {
|
|
oneOfNodeTypes: ["Expression", "Identifier"]
|
|
});
|
|
return validator;
|
|
}()
|
|
},
|
|
computed: {
|
|
default: false
|
|
},
|
|
optional: {
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.assertValueType)("boolean") : (0, _utils.chain)((0, _utils.assertValueType)("boolean"), (0, _utils.assertOptionalChainStart)())
|
|
}
|
|
}
|
|
});
|
|
defineType("OptionalCallExpression", {
|
|
visitor: ["callee", "arguments", "typeParameters", "typeArguments"],
|
|
builder: ["callee", "arguments", "optional"],
|
|
aliases: ["Expression"],
|
|
fields: {
|
|
callee: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
arguments: (0, _utils.validateArrayOfType)("Expression", "SpreadElement", "ArgumentPlaceholder"),
|
|
optional: {
|
|
validate: !process.env.BABEL_TYPES_8_BREAKING ? (0, _utils.assertValueType)("boolean") : (0, _utils.chain)((0, _utils.assertValueType)("boolean"), (0, _utils.assertOptionalChainStart)())
|
|
},
|
|
typeArguments: {
|
|
validate: (0, _utils.assertNodeType)("TypeParameterInstantiation"),
|
|
optional: true
|
|
},
|
|
typeParameters: {
|
|
validate: (0, _utils.assertNodeType)("TSTypeParameterInstantiation"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("ClassProperty", {
|
|
visitor: ["decorators", "key", "typeAnnotation", "value"],
|
|
builder: ["key", "value", "typeAnnotation", "decorators", "computed", "static"],
|
|
aliases: ["Property"],
|
|
fields: Object.assign({}, classMethodOrPropertyCommon(), {
|
|
value: {
|
|
validate: (0, _utils.assertNodeType)("Expression"),
|
|
optional: true
|
|
},
|
|
definite: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
typeAnnotation: {
|
|
validate: (0, _utils.assertNodeType)("TypeAnnotation", "TSTypeAnnotation", "Noop"),
|
|
optional: true
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
},
|
|
readonly: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
declare: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
variance: {
|
|
validate: (0, _utils.assertNodeType)("Variance"),
|
|
optional: true
|
|
}
|
|
})
|
|
});
|
|
defineType("ClassAccessorProperty", {
|
|
visitor: ["decorators", "key", "typeAnnotation", "value"],
|
|
builder: ["key", "value", "typeAnnotation", "decorators", "computed", "static"],
|
|
aliases: ["Property", "Accessor"],
|
|
fields: Object.assign({}, classMethodOrPropertyCommon(), {
|
|
key: {
|
|
validate: (0, _utils.chain)(function () {
|
|
const normal = (0, _utils.assertNodeType)("Identifier", "StringLiteral", "NumericLiteral", "BigIntLiteral", "PrivateName");
|
|
const computed = (0, _utils.assertNodeType)("Expression");
|
|
return function (node, key, val) {
|
|
const validator = node.computed ? computed : normal;
|
|
validator(node, key, val);
|
|
};
|
|
}(), (0, _utils.assertNodeType)("Identifier", "StringLiteral", "NumericLiteral", "BigIntLiteral", "Expression", "PrivateName"))
|
|
},
|
|
value: {
|
|
validate: (0, _utils.assertNodeType)("Expression"),
|
|
optional: true
|
|
},
|
|
definite: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
typeAnnotation: {
|
|
validate: (0, _utils.assertNodeType)("TypeAnnotation", "TSTypeAnnotation", "Noop"),
|
|
optional: true
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
},
|
|
readonly: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
declare: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
variance: {
|
|
validate: (0, _utils.assertNodeType)("Variance"),
|
|
optional: true
|
|
}
|
|
})
|
|
});
|
|
defineType("ClassPrivateProperty", {
|
|
visitor: ["decorators", "key", "typeAnnotation", "value"],
|
|
builder: ["key", "value", "decorators", "static"],
|
|
aliases: ["Property", "Private"],
|
|
fields: {
|
|
key: {
|
|
validate: (0, _utils.assertNodeType)("PrivateName")
|
|
},
|
|
value: {
|
|
validate: (0, _utils.assertNodeType)("Expression"),
|
|
optional: true
|
|
},
|
|
typeAnnotation: {
|
|
validate: (0, _utils.assertNodeType)("TypeAnnotation", "TSTypeAnnotation", "Noop"),
|
|
optional: true
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
},
|
|
static: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
default: false
|
|
},
|
|
readonly: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
definite: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
variance: {
|
|
validate: (0, _utils.assertNodeType)("Variance"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("ClassPrivateMethod", {
|
|
builder: ["kind", "key", "params", "body", "static"],
|
|
visitor: ["decorators", "key", "typeParameters", "params", "returnType", "body"],
|
|
aliases: ["Function", "Scopable", "BlockParent", "FunctionParent", "Method", "Private"],
|
|
fields: Object.assign({}, classMethodOrDeclareMethodCommon(), functionTypeAnnotationCommon(), {
|
|
kind: {
|
|
validate: (0, _utils.assertOneOf)("get", "set", "method"),
|
|
default: "method"
|
|
},
|
|
key: {
|
|
validate: (0, _utils.assertNodeType)("PrivateName")
|
|
},
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("BlockStatement")
|
|
}
|
|
})
|
|
});
|
|
defineType("PrivateName", {
|
|
visitor: ["id"],
|
|
aliases: ["Private"],
|
|
fields: {
|
|
id: {
|
|
validate: (0, _utils.assertNodeType)("Identifier")
|
|
}
|
|
}
|
|
});
|
|
defineType("StaticBlock", {
|
|
visitor: ["body"],
|
|
fields: {
|
|
body: (0, _utils.validateArrayOfType)("Statement")
|
|
},
|
|
aliases: ["Scopable", "BlockParent", "FunctionParent"]
|
|
});
|
|
|
|
|
|
return core;
|
|
}
|
|
|
|
var flow = {};
|
|
|
|
var hasRequiredFlow;
|
|
|
|
function requireFlow () {
|
|
if (hasRequiredFlow) return flow;
|
|
hasRequiredFlow = 1;
|
|
|
|
var _core = requireCore();
|
|
var _utils = requireUtils();
|
|
const defineType = (0, _utils.defineAliasedType)("Flow");
|
|
const defineInterfaceishType = name => {
|
|
const isDeclareClass = name === "DeclareClass";
|
|
defineType(name, {
|
|
builder: ["id", "typeParameters", "extends", "body"],
|
|
visitor: ["id", "typeParameters", "extends", ...(isDeclareClass ? ["mixins", "implements"] : []), "body"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: Object.assign({
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TypeParameterDeclaration"),
|
|
extends: (0, _utils.validateOptional)((0, _utils.arrayOfType)("InterfaceExtends"))
|
|
}, isDeclareClass ? {
|
|
mixins: (0, _utils.validateOptional)((0, _utils.arrayOfType)("InterfaceExtends")),
|
|
implements: (0, _utils.validateOptional)((0, _utils.arrayOfType)("ClassImplements"))
|
|
} : {}, {
|
|
body: (0, _utils.validateType)("ObjectTypeAnnotation")
|
|
})
|
|
});
|
|
};
|
|
defineType("AnyTypeAnnotation", {
|
|
aliases: ["FlowType", "FlowBaseAnnotation"]
|
|
});
|
|
defineType("ArrayTypeAnnotation", {
|
|
visitor: ["elementType"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
elementType: (0, _utils.validateType)("FlowType")
|
|
}
|
|
});
|
|
defineType("BooleanTypeAnnotation", {
|
|
aliases: ["FlowType", "FlowBaseAnnotation"]
|
|
});
|
|
defineType("BooleanLiteralTypeAnnotation", {
|
|
builder: ["value"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
value: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
defineType("NullLiteralTypeAnnotation", {
|
|
aliases: ["FlowType", "FlowBaseAnnotation"]
|
|
});
|
|
defineType("ClassImplements", {
|
|
visitor: ["id", "typeParameters"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TypeParameterInstantiation")
|
|
}
|
|
});
|
|
defineInterfaceishType("DeclareClass");
|
|
defineType("DeclareFunction", {
|
|
visitor: ["id"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
predicate: (0, _utils.validateOptionalType)("DeclaredPredicate")
|
|
}
|
|
});
|
|
defineInterfaceishType("DeclareInterface");
|
|
defineType("DeclareModule", {
|
|
builder: ["id", "body", "kind"],
|
|
visitor: ["id", "body"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier", "StringLiteral"),
|
|
body: (0, _utils.validateType)("BlockStatement"),
|
|
kind: (0, _utils.validateOptional)((0, _utils.assertOneOf)("CommonJS", "ES"))
|
|
}
|
|
});
|
|
defineType("DeclareModuleExports", {
|
|
visitor: ["typeAnnotation"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: {
|
|
typeAnnotation: (0, _utils.validateType)("TypeAnnotation")
|
|
}
|
|
});
|
|
defineType("DeclareTypeAlias", {
|
|
visitor: ["id", "typeParameters", "right"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TypeParameterDeclaration"),
|
|
right: (0, _utils.validateType)("FlowType")
|
|
}
|
|
});
|
|
defineType("DeclareOpaqueType", {
|
|
visitor: ["id", "typeParameters", "supertype"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TypeParameterDeclaration"),
|
|
supertype: (0, _utils.validateOptionalType)("FlowType"),
|
|
impltype: (0, _utils.validateOptionalType)("FlowType")
|
|
}
|
|
});
|
|
defineType("DeclareVariable", {
|
|
visitor: ["id"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier")
|
|
}
|
|
});
|
|
defineType("DeclareExportDeclaration", {
|
|
visitor: ["declaration", "specifiers", "source", "attributes"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: Object.assign({
|
|
declaration: (0, _utils.validateOptionalType)("Flow"),
|
|
specifiers: (0, _utils.validateOptional)((0, _utils.arrayOfType)("ExportSpecifier", "ExportNamespaceSpecifier")),
|
|
source: (0, _utils.validateOptionalType)("StringLiteral"),
|
|
default: (0, _utils.validateOptional)((0, _utils.assertValueType)("boolean"))
|
|
}, _core.importAttributes)
|
|
});
|
|
defineType("DeclareExportAllDeclaration", {
|
|
visitor: ["source", "attributes"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: Object.assign({
|
|
source: (0, _utils.validateType)("StringLiteral"),
|
|
exportKind: (0, _utils.validateOptional)((0, _utils.assertOneOf)("type", "value"))
|
|
}, _core.importAttributes)
|
|
});
|
|
defineType("DeclaredPredicate", {
|
|
visitor: ["value"],
|
|
aliases: ["FlowPredicate"],
|
|
fields: {
|
|
value: (0, _utils.validateType)("Flow")
|
|
}
|
|
});
|
|
defineType("ExistsTypeAnnotation", {
|
|
aliases: ["FlowType"]
|
|
});
|
|
defineType("FunctionTypeAnnotation", {
|
|
visitor: ["typeParameters", "params", "rest", "returnType"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
typeParameters: (0, _utils.validateOptionalType)("TypeParameterDeclaration"),
|
|
params: (0, _utils.validateArrayOfType)("FunctionTypeParam"),
|
|
rest: (0, _utils.validateOptionalType)("FunctionTypeParam"),
|
|
this: (0, _utils.validateOptionalType)("FunctionTypeParam"),
|
|
returnType: (0, _utils.validateType)("FlowType")
|
|
}
|
|
});
|
|
defineType("FunctionTypeParam", {
|
|
visitor: ["name", "typeAnnotation"],
|
|
fields: {
|
|
name: (0, _utils.validateOptionalType)("Identifier"),
|
|
typeAnnotation: (0, _utils.validateType)("FlowType"),
|
|
optional: (0, _utils.validateOptional)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
defineType("GenericTypeAnnotation", {
|
|
visitor: ["id", "typeParameters"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier", "QualifiedTypeIdentifier"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TypeParameterInstantiation")
|
|
}
|
|
});
|
|
defineType("InferredPredicate", {
|
|
aliases: ["FlowPredicate"]
|
|
});
|
|
defineType("InterfaceExtends", {
|
|
visitor: ["id", "typeParameters"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier", "QualifiedTypeIdentifier"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TypeParameterInstantiation")
|
|
}
|
|
});
|
|
defineInterfaceishType("InterfaceDeclaration");
|
|
defineType("InterfaceTypeAnnotation", {
|
|
visitor: ["extends", "body"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
extends: (0, _utils.validateOptional)((0, _utils.arrayOfType)("InterfaceExtends")),
|
|
body: (0, _utils.validateType)("ObjectTypeAnnotation")
|
|
}
|
|
});
|
|
defineType("IntersectionTypeAnnotation", {
|
|
visitor: ["types"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
types: (0, _utils.validate)((0, _utils.arrayOfType)("FlowType"))
|
|
}
|
|
});
|
|
defineType("MixedTypeAnnotation", {
|
|
aliases: ["FlowType", "FlowBaseAnnotation"]
|
|
});
|
|
defineType("EmptyTypeAnnotation", {
|
|
aliases: ["FlowType", "FlowBaseAnnotation"]
|
|
});
|
|
defineType("NullableTypeAnnotation", {
|
|
visitor: ["typeAnnotation"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
typeAnnotation: (0, _utils.validateType)("FlowType")
|
|
}
|
|
});
|
|
defineType("NumberLiteralTypeAnnotation", {
|
|
builder: ["value"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
value: (0, _utils.validate)((0, _utils.assertValueType)("number"))
|
|
}
|
|
});
|
|
defineType("NumberTypeAnnotation", {
|
|
aliases: ["FlowType", "FlowBaseAnnotation"]
|
|
});
|
|
defineType("ObjectTypeAnnotation", {
|
|
visitor: ["properties", "indexers", "callProperties", "internalSlots"],
|
|
aliases: ["FlowType"],
|
|
builder: ["properties", "indexers", "callProperties", "internalSlots", "exact"],
|
|
fields: {
|
|
properties: (0, _utils.validate)((0, _utils.arrayOfType)("ObjectTypeProperty", "ObjectTypeSpreadProperty")),
|
|
indexers: {
|
|
validate: (0, _utils.arrayOfType)("ObjectTypeIndexer"),
|
|
optional: true,
|
|
default: []
|
|
},
|
|
callProperties: {
|
|
validate: (0, _utils.arrayOfType)("ObjectTypeCallProperty"),
|
|
optional: true,
|
|
default: []
|
|
},
|
|
internalSlots: {
|
|
validate: (0, _utils.arrayOfType)("ObjectTypeInternalSlot"),
|
|
optional: true,
|
|
default: []
|
|
},
|
|
exact: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
default: false
|
|
},
|
|
inexact: (0, _utils.validateOptional)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
defineType("ObjectTypeInternalSlot", {
|
|
visitor: ["id", "value"],
|
|
builder: ["id", "value", "optional", "static", "method"],
|
|
aliases: ["UserWhitespacable"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
value: (0, _utils.validateType)("FlowType"),
|
|
optional: (0, _utils.validate)((0, _utils.assertValueType)("boolean")),
|
|
static: (0, _utils.validate)((0, _utils.assertValueType)("boolean")),
|
|
method: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
defineType("ObjectTypeCallProperty", {
|
|
visitor: ["value"],
|
|
aliases: ["UserWhitespacable"],
|
|
fields: {
|
|
value: (0, _utils.validateType)("FlowType"),
|
|
static: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
defineType("ObjectTypeIndexer", {
|
|
visitor: ["variance", "id", "key", "value"],
|
|
builder: ["id", "key", "value", "variance"],
|
|
aliases: ["UserWhitespacable"],
|
|
fields: {
|
|
id: (0, _utils.validateOptionalType)("Identifier"),
|
|
key: (0, _utils.validateType)("FlowType"),
|
|
value: (0, _utils.validateType)("FlowType"),
|
|
static: (0, _utils.validate)((0, _utils.assertValueType)("boolean")),
|
|
variance: (0, _utils.validateOptionalType)("Variance")
|
|
}
|
|
});
|
|
defineType("ObjectTypeProperty", {
|
|
visitor: ["key", "value", "variance"],
|
|
aliases: ["UserWhitespacable"],
|
|
fields: {
|
|
key: (0, _utils.validateType)("Identifier", "StringLiteral"),
|
|
value: (0, _utils.validateType)("FlowType"),
|
|
kind: (0, _utils.validate)((0, _utils.assertOneOf)("init", "get", "set")),
|
|
static: (0, _utils.validate)((0, _utils.assertValueType)("boolean")),
|
|
proto: (0, _utils.validate)((0, _utils.assertValueType)("boolean")),
|
|
optional: (0, _utils.validate)((0, _utils.assertValueType)("boolean")),
|
|
variance: (0, _utils.validateOptionalType)("Variance"),
|
|
method: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
defineType("ObjectTypeSpreadProperty", {
|
|
visitor: ["argument"],
|
|
aliases: ["UserWhitespacable"],
|
|
fields: {
|
|
argument: (0, _utils.validateType)("FlowType")
|
|
}
|
|
});
|
|
defineType("OpaqueType", {
|
|
visitor: ["id", "typeParameters", "supertype", "impltype"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TypeParameterDeclaration"),
|
|
supertype: (0, _utils.validateOptionalType)("FlowType"),
|
|
impltype: (0, _utils.validateType)("FlowType")
|
|
}
|
|
});
|
|
defineType("QualifiedTypeIdentifier", {
|
|
visitor: ["qualification", "id"],
|
|
builder: ["id", "qualification"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
qualification: (0, _utils.validateType)("Identifier", "QualifiedTypeIdentifier")
|
|
}
|
|
});
|
|
defineType("StringLiteralTypeAnnotation", {
|
|
builder: ["value"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
value: (0, _utils.validate)((0, _utils.assertValueType)("string"))
|
|
}
|
|
});
|
|
defineType("StringTypeAnnotation", {
|
|
aliases: ["FlowType", "FlowBaseAnnotation"]
|
|
});
|
|
defineType("SymbolTypeAnnotation", {
|
|
aliases: ["FlowType", "FlowBaseAnnotation"]
|
|
});
|
|
defineType("ThisTypeAnnotation", {
|
|
aliases: ["FlowType", "FlowBaseAnnotation"]
|
|
});
|
|
defineType("TupleTypeAnnotation", {
|
|
visitor: ["types"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
types: (0, _utils.validate)((0, _utils.arrayOfType)("FlowType"))
|
|
}
|
|
});
|
|
defineType("TypeofTypeAnnotation", {
|
|
visitor: ["argument"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
argument: (0, _utils.validateType)("FlowType")
|
|
}
|
|
});
|
|
defineType("TypeAlias", {
|
|
visitor: ["id", "typeParameters", "right"],
|
|
aliases: ["FlowDeclaration", "Statement", "Declaration"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TypeParameterDeclaration"),
|
|
right: (0, _utils.validateType)("FlowType")
|
|
}
|
|
});
|
|
defineType("TypeAnnotation", {
|
|
visitor: ["typeAnnotation"],
|
|
fields: {
|
|
typeAnnotation: (0, _utils.validateType)("FlowType")
|
|
}
|
|
});
|
|
defineType("TypeCastExpression", {
|
|
visitor: ["expression", "typeAnnotation"],
|
|
aliases: ["ExpressionWrapper", "Expression"],
|
|
fields: {
|
|
expression: (0, _utils.validateType)("Expression"),
|
|
typeAnnotation: (0, _utils.validateType)("TypeAnnotation")
|
|
}
|
|
});
|
|
defineType("TypeParameter", {
|
|
visitor: ["bound", "default", "variance"],
|
|
fields: {
|
|
name: (0, _utils.validate)((0, _utils.assertValueType)("string")),
|
|
bound: (0, _utils.validateOptionalType)("TypeAnnotation"),
|
|
default: (0, _utils.validateOptionalType)("FlowType"),
|
|
variance: (0, _utils.validateOptionalType)("Variance")
|
|
}
|
|
});
|
|
defineType("TypeParameterDeclaration", {
|
|
visitor: ["params"],
|
|
fields: {
|
|
params: (0, _utils.validate)((0, _utils.arrayOfType)("TypeParameter"))
|
|
}
|
|
});
|
|
defineType("TypeParameterInstantiation", {
|
|
visitor: ["params"],
|
|
fields: {
|
|
params: (0, _utils.validate)((0, _utils.arrayOfType)("FlowType"))
|
|
}
|
|
});
|
|
defineType("UnionTypeAnnotation", {
|
|
visitor: ["types"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
types: (0, _utils.validate)((0, _utils.arrayOfType)("FlowType"))
|
|
}
|
|
});
|
|
defineType("Variance", {
|
|
builder: ["kind"],
|
|
fields: {
|
|
kind: (0, _utils.validate)((0, _utils.assertOneOf)("minus", "plus"))
|
|
}
|
|
});
|
|
defineType("VoidTypeAnnotation", {
|
|
aliases: ["FlowType", "FlowBaseAnnotation"]
|
|
});
|
|
defineType("EnumDeclaration", {
|
|
aliases: ["Statement", "Declaration"],
|
|
visitor: ["id", "body"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
body: (0, _utils.validateType)("EnumBooleanBody", "EnumNumberBody", "EnumStringBody", "EnumSymbolBody")
|
|
}
|
|
});
|
|
defineType("EnumBooleanBody", {
|
|
aliases: ["EnumBody"],
|
|
visitor: ["members"],
|
|
fields: {
|
|
explicitType: (0, _utils.validate)((0, _utils.assertValueType)("boolean")),
|
|
members: (0, _utils.validateArrayOfType)("EnumBooleanMember"),
|
|
hasUnknownMembers: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
defineType("EnumNumberBody", {
|
|
aliases: ["EnumBody"],
|
|
visitor: ["members"],
|
|
fields: {
|
|
explicitType: (0, _utils.validate)((0, _utils.assertValueType)("boolean")),
|
|
members: (0, _utils.validateArrayOfType)("EnumNumberMember"),
|
|
hasUnknownMembers: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
defineType("EnumStringBody", {
|
|
aliases: ["EnumBody"],
|
|
visitor: ["members"],
|
|
fields: {
|
|
explicitType: (0, _utils.validate)((0, _utils.assertValueType)("boolean")),
|
|
members: (0, _utils.validateArrayOfType)("EnumStringMember", "EnumDefaultedMember"),
|
|
hasUnknownMembers: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
defineType("EnumSymbolBody", {
|
|
aliases: ["EnumBody"],
|
|
visitor: ["members"],
|
|
fields: {
|
|
members: (0, _utils.validateArrayOfType)("EnumDefaultedMember"),
|
|
hasUnknownMembers: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
defineType("EnumBooleanMember", {
|
|
aliases: ["EnumMember"],
|
|
visitor: ["id"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
init: (0, _utils.validateType)("BooleanLiteral")
|
|
}
|
|
});
|
|
defineType("EnumNumberMember", {
|
|
aliases: ["EnumMember"],
|
|
visitor: ["id", "init"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
init: (0, _utils.validateType)("NumericLiteral")
|
|
}
|
|
});
|
|
defineType("EnumStringMember", {
|
|
aliases: ["EnumMember"],
|
|
visitor: ["id", "init"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
init: (0, _utils.validateType)("StringLiteral")
|
|
}
|
|
});
|
|
defineType("EnumDefaultedMember", {
|
|
aliases: ["EnumMember"],
|
|
visitor: ["id"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier")
|
|
}
|
|
});
|
|
defineType("IndexedAccessType", {
|
|
visitor: ["objectType", "indexType"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
objectType: (0, _utils.validateType)("FlowType"),
|
|
indexType: (0, _utils.validateType)("FlowType")
|
|
}
|
|
});
|
|
defineType("OptionalIndexedAccessType", {
|
|
visitor: ["objectType", "indexType"],
|
|
aliases: ["FlowType"],
|
|
fields: {
|
|
objectType: (0, _utils.validateType)("FlowType"),
|
|
indexType: (0, _utils.validateType)("FlowType"),
|
|
optional: (0, _utils.validate)((0, _utils.assertValueType)("boolean"))
|
|
}
|
|
});
|
|
|
|
|
|
return flow;
|
|
}
|
|
|
|
var jsx = {};
|
|
|
|
var hasRequiredJsx;
|
|
|
|
function requireJsx () {
|
|
if (hasRequiredJsx) return jsx;
|
|
hasRequiredJsx = 1;
|
|
|
|
var _utils = requireUtils();
|
|
const defineType = (0, _utils.defineAliasedType)("JSX");
|
|
defineType("JSXAttribute", {
|
|
visitor: ["name", "value"],
|
|
aliases: ["Immutable"],
|
|
fields: {
|
|
name: {
|
|
validate: (0, _utils.assertNodeType)("JSXIdentifier", "JSXNamespacedName")
|
|
},
|
|
value: {
|
|
optional: true,
|
|
validate: (0, _utils.assertNodeType)("JSXElement", "JSXFragment", "StringLiteral", "JSXExpressionContainer")
|
|
}
|
|
}
|
|
});
|
|
defineType("JSXClosingElement", {
|
|
visitor: ["name"],
|
|
aliases: ["Immutable"],
|
|
fields: {
|
|
name: {
|
|
validate: (0, _utils.assertNodeType)("JSXIdentifier", "JSXMemberExpression", "JSXNamespacedName")
|
|
}
|
|
}
|
|
});
|
|
defineType("JSXElement", {
|
|
builder: ["openingElement", "closingElement", "children", "selfClosing"],
|
|
visitor: ["openingElement", "children", "closingElement"],
|
|
aliases: ["Immutable", "Expression"],
|
|
fields: Object.assign({
|
|
openingElement: {
|
|
validate: (0, _utils.assertNodeType)("JSXOpeningElement")
|
|
},
|
|
closingElement: {
|
|
optional: true,
|
|
validate: (0, _utils.assertNodeType)("JSXClosingElement")
|
|
},
|
|
children: (0, _utils.validateArrayOfType)("JSXText", "JSXExpressionContainer", "JSXSpreadChild", "JSXElement", "JSXFragment")
|
|
}, {
|
|
selfClosing: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
}
|
|
})
|
|
});
|
|
defineType("JSXEmptyExpression", {});
|
|
defineType("JSXExpressionContainer", {
|
|
visitor: ["expression"],
|
|
aliases: ["Immutable"],
|
|
fields: {
|
|
expression: {
|
|
validate: (0, _utils.assertNodeType)("Expression", "JSXEmptyExpression")
|
|
}
|
|
}
|
|
});
|
|
defineType("JSXSpreadChild", {
|
|
visitor: ["expression"],
|
|
aliases: ["Immutable"],
|
|
fields: {
|
|
expression: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
defineType("JSXIdentifier", {
|
|
builder: ["name"],
|
|
fields: {
|
|
name: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
}
|
|
}
|
|
});
|
|
defineType("JSXMemberExpression", {
|
|
visitor: ["object", "property"],
|
|
fields: {
|
|
object: {
|
|
validate: (0, _utils.assertNodeType)("JSXMemberExpression", "JSXIdentifier")
|
|
},
|
|
property: {
|
|
validate: (0, _utils.assertNodeType)("JSXIdentifier")
|
|
}
|
|
}
|
|
});
|
|
defineType("JSXNamespacedName", {
|
|
visitor: ["namespace", "name"],
|
|
fields: {
|
|
namespace: {
|
|
validate: (0, _utils.assertNodeType)("JSXIdentifier")
|
|
},
|
|
name: {
|
|
validate: (0, _utils.assertNodeType)("JSXIdentifier")
|
|
}
|
|
}
|
|
});
|
|
defineType("JSXOpeningElement", {
|
|
builder: ["name", "attributes", "selfClosing"],
|
|
visitor: ["name", "attributes"],
|
|
aliases: ["Immutable"],
|
|
fields: {
|
|
name: {
|
|
validate: (0, _utils.assertNodeType)("JSXIdentifier", "JSXMemberExpression", "JSXNamespacedName")
|
|
},
|
|
selfClosing: {
|
|
default: false
|
|
},
|
|
attributes: (0, _utils.validateArrayOfType)("JSXAttribute", "JSXSpreadAttribute"),
|
|
typeParameters: {
|
|
validate: (0, _utils.assertNodeType)("TypeParameterInstantiation", "TSTypeParameterInstantiation"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("JSXSpreadAttribute", {
|
|
visitor: ["argument"],
|
|
fields: {
|
|
argument: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
defineType("JSXText", {
|
|
aliases: ["Immutable"],
|
|
builder: ["value"],
|
|
fields: {
|
|
value: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
}
|
|
}
|
|
});
|
|
defineType("JSXFragment", {
|
|
builder: ["openingFragment", "closingFragment", "children"],
|
|
visitor: ["openingFragment", "children", "closingFragment"],
|
|
aliases: ["Immutable", "Expression"],
|
|
fields: {
|
|
openingFragment: {
|
|
validate: (0, _utils.assertNodeType)("JSXOpeningFragment")
|
|
},
|
|
closingFragment: {
|
|
validate: (0, _utils.assertNodeType)("JSXClosingFragment")
|
|
},
|
|
children: (0, _utils.validateArrayOfType)("JSXText", "JSXExpressionContainer", "JSXSpreadChild", "JSXElement", "JSXFragment")
|
|
}
|
|
});
|
|
defineType("JSXOpeningFragment", {
|
|
aliases: ["Immutable"]
|
|
});
|
|
defineType("JSXClosingFragment", {
|
|
aliases: ["Immutable"]
|
|
});
|
|
|
|
|
|
return jsx;
|
|
}
|
|
|
|
var misc = {};
|
|
|
|
var placeholders = {};
|
|
|
|
var hasRequiredPlaceholders;
|
|
|
|
function requirePlaceholders () {
|
|
if (hasRequiredPlaceholders) return placeholders;
|
|
hasRequiredPlaceholders = 1;
|
|
|
|
Object.defineProperty(placeholders, "__esModule", {
|
|
value: true
|
|
});
|
|
placeholders.PLACEHOLDERS_FLIPPED_ALIAS = placeholders.PLACEHOLDERS_ALIAS = placeholders.PLACEHOLDERS = void 0;
|
|
var _utils = requireUtils();
|
|
const PLACEHOLDERS = placeholders.PLACEHOLDERS = ["Identifier", "StringLiteral", "Expression", "Statement", "Declaration", "BlockStatement", "ClassBody", "Pattern"];
|
|
const PLACEHOLDERS_ALIAS = placeholders.PLACEHOLDERS_ALIAS = {
|
|
Declaration: ["Statement"],
|
|
Pattern: ["PatternLike", "LVal"]
|
|
};
|
|
for (const type of PLACEHOLDERS) {
|
|
const alias = _utils.ALIAS_KEYS[type];
|
|
if (alias != null && alias.length) PLACEHOLDERS_ALIAS[type] = alias;
|
|
}
|
|
const PLACEHOLDERS_FLIPPED_ALIAS = placeholders.PLACEHOLDERS_FLIPPED_ALIAS = {};
|
|
Object.keys(PLACEHOLDERS_ALIAS).forEach(type => {
|
|
PLACEHOLDERS_ALIAS[type].forEach(alias => {
|
|
if (!hasOwnProperty.call(PLACEHOLDERS_FLIPPED_ALIAS, alias)) {
|
|
PLACEHOLDERS_FLIPPED_ALIAS[alias] = [];
|
|
}
|
|
PLACEHOLDERS_FLIPPED_ALIAS[alias].push(type);
|
|
});
|
|
});
|
|
|
|
|
|
return placeholders;
|
|
}
|
|
|
|
var hasRequiredMisc;
|
|
|
|
function requireMisc () {
|
|
if (hasRequiredMisc) return misc;
|
|
hasRequiredMisc = 1;
|
|
|
|
var _utils = requireUtils();
|
|
var _placeholders = requirePlaceholders();
|
|
var _core = requireCore();
|
|
const defineType = (0, _utils.defineAliasedType)("Miscellaneous");
|
|
{
|
|
defineType("Noop", {
|
|
visitor: []
|
|
});
|
|
}
|
|
defineType("Placeholder", {
|
|
visitor: [],
|
|
builder: ["expectedNode", "name"],
|
|
fields: Object.assign({
|
|
name: {
|
|
validate: (0, _utils.assertNodeType)("Identifier")
|
|
},
|
|
expectedNode: {
|
|
validate: (0, _utils.assertOneOf)(..._placeholders.PLACEHOLDERS)
|
|
}
|
|
}, (0, _core.patternLikeCommon)())
|
|
});
|
|
defineType("V8IntrinsicIdentifier", {
|
|
builder: ["name"],
|
|
fields: {
|
|
name: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
return misc;
|
|
}
|
|
|
|
var experimental = {};
|
|
|
|
var hasRequiredExperimental;
|
|
|
|
function requireExperimental () {
|
|
if (hasRequiredExperimental) return experimental;
|
|
hasRequiredExperimental = 1;
|
|
|
|
var _utils = requireUtils();
|
|
(0, _utils.default)("ArgumentPlaceholder", {});
|
|
(0, _utils.default)("BindExpression", {
|
|
visitor: ["object", "callee"],
|
|
aliases: ["Expression"],
|
|
fields: !process.env.BABEL_TYPES_8_BREAKING ? {
|
|
object: {
|
|
validate: Object.assign(() => {}, {
|
|
oneOfNodeTypes: ["Expression"]
|
|
})
|
|
},
|
|
callee: {
|
|
validate: Object.assign(() => {}, {
|
|
oneOfNodeTypes: ["Expression"]
|
|
})
|
|
}
|
|
} : {
|
|
object: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
},
|
|
callee: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
(0, _utils.default)("ImportAttribute", {
|
|
visitor: ["key", "value"],
|
|
fields: {
|
|
key: {
|
|
validate: (0, _utils.assertNodeType)("Identifier", "StringLiteral")
|
|
},
|
|
value: {
|
|
validate: (0, _utils.assertNodeType)("StringLiteral")
|
|
}
|
|
}
|
|
});
|
|
(0, _utils.default)("Decorator", {
|
|
visitor: ["expression"],
|
|
fields: {
|
|
expression: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
}
|
|
});
|
|
(0, _utils.default)("DoExpression", {
|
|
visitor: ["body"],
|
|
builder: ["body", "async"],
|
|
aliases: ["Expression"],
|
|
fields: {
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("BlockStatement")
|
|
},
|
|
async: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
default: false
|
|
}
|
|
}
|
|
});
|
|
(0, _utils.default)("ExportDefaultSpecifier", {
|
|
visitor: ["exported"],
|
|
aliases: ["ModuleSpecifier"],
|
|
fields: {
|
|
exported: {
|
|
validate: (0, _utils.assertNodeType)("Identifier")
|
|
}
|
|
}
|
|
});
|
|
(0, _utils.default)("RecordExpression", {
|
|
visitor: ["properties"],
|
|
aliases: ["Expression"],
|
|
fields: {
|
|
properties: (0, _utils.validateArrayOfType)("ObjectProperty", "SpreadElement")
|
|
}
|
|
});
|
|
(0, _utils.default)("TupleExpression", {
|
|
fields: {
|
|
elements: {
|
|
validate: (0, _utils.arrayOfType)("Expression", "SpreadElement"),
|
|
default: []
|
|
}
|
|
},
|
|
visitor: ["elements"],
|
|
aliases: ["Expression"]
|
|
});
|
|
{
|
|
(0, _utils.default)("DecimalLiteral", {
|
|
builder: ["value"],
|
|
fields: {
|
|
value: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
}
|
|
},
|
|
aliases: ["Expression", "Pureish", "Literal", "Immutable"]
|
|
});
|
|
}
|
|
(0, _utils.default)("ModuleExpression", {
|
|
visitor: ["body"],
|
|
fields: {
|
|
body: {
|
|
validate: (0, _utils.assertNodeType)("Program")
|
|
}
|
|
},
|
|
aliases: ["Expression"]
|
|
});
|
|
(0, _utils.default)("TopicReference", {
|
|
aliases: ["Expression"]
|
|
});
|
|
(0, _utils.default)("PipelineTopicExpression", {
|
|
builder: ["expression"],
|
|
visitor: ["expression"],
|
|
fields: {
|
|
expression: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
},
|
|
aliases: ["Expression"]
|
|
});
|
|
(0, _utils.default)("PipelineBareFunction", {
|
|
builder: ["callee"],
|
|
visitor: ["callee"],
|
|
fields: {
|
|
callee: {
|
|
validate: (0, _utils.assertNodeType)("Expression")
|
|
}
|
|
},
|
|
aliases: ["Expression"]
|
|
});
|
|
(0, _utils.default)("PipelinePrimaryTopicReference", {
|
|
aliases: ["Expression"]
|
|
});
|
|
|
|
|
|
return experimental;
|
|
}
|
|
|
|
var typescript = {};
|
|
|
|
var hasRequiredTypescript;
|
|
|
|
function requireTypescript () {
|
|
if (hasRequiredTypescript) return typescript;
|
|
hasRequiredTypescript = 1;
|
|
|
|
var _utils = requireUtils();
|
|
var _core = requireCore();
|
|
var _is = requireIs();
|
|
const defineType = (0, _utils.defineAliasedType)("TypeScript");
|
|
const bool = (0, _utils.assertValueType)("boolean");
|
|
const tSFunctionTypeAnnotationCommon = () => ({
|
|
returnType: {
|
|
validate: (0, _utils.assertNodeType)("TSTypeAnnotation", "Noop"),
|
|
optional: true
|
|
},
|
|
typeParameters: {
|
|
validate: (0, _utils.assertNodeType)("TSTypeParameterDeclaration", "Noop"),
|
|
optional: true
|
|
}
|
|
});
|
|
defineType("TSParameterProperty", {
|
|
aliases: ["LVal"],
|
|
visitor: ["parameter"],
|
|
fields: {
|
|
accessibility: {
|
|
validate: (0, _utils.assertOneOf)("public", "private", "protected"),
|
|
optional: true
|
|
},
|
|
readonly: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
parameter: {
|
|
validate: (0, _utils.assertNodeType)("Identifier", "AssignmentPattern")
|
|
},
|
|
override: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
decorators: {
|
|
validate: (0, _utils.arrayOfType)("Decorator"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("TSDeclareFunction", {
|
|
aliases: ["Statement", "Declaration"],
|
|
visitor: ["id", "typeParameters", "params", "returnType"],
|
|
fields: Object.assign({}, (0, _core.functionDeclarationCommon)(), tSFunctionTypeAnnotationCommon())
|
|
});
|
|
defineType("TSDeclareMethod", {
|
|
visitor: ["decorators", "key", "typeParameters", "params", "returnType"],
|
|
fields: Object.assign({}, (0, _core.classMethodOrDeclareMethodCommon)(), tSFunctionTypeAnnotationCommon())
|
|
});
|
|
defineType("TSQualifiedName", {
|
|
aliases: ["TSEntityName"],
|
|
visitor: ["left", "right"],
|
|
fields: {
|
|
left: (0, _utils.validateType)("TSEntityName"),
|
|
right: (0, _utils.validateType)("Identifier")
|
|
}
|
|
});
|
|
const signatureDeclarationCommon = () => ({
|
|
typeParameters: (0, _utils.validateOptionalType)("TSTypeParameterDeclaration"),
|
|
["parameters"]: (0, _utils.validateArrayOfType)("ArrayPattern", "Identifier", "ObjectPattern", "RestElement"),
|
|
["typeAnnotation"]: (0, _utils.validateOptionalType)("TSTypeAnnotation")
|
|
});
|
|
const callConstructSignatureDeclaration = {
|
|
aliases: ["TSTypeElement"],
|
|
visitor: ["typeParameters", "parameters", "typeAnnotation"],
|
|
fields: signatureDeclarationCommon()
|
|
};
|
|
defineType("TSCallSignatureDeclaration", callConstructSignatureDeclaration);
|
|
defineType("TSConstructSignatureDeclaration", callConstructSignatureDeclaration);
|
|
const namedTypeElementCommon = () => ({
|
|
key: (0, _utils.validateType)("Expression"),
|
|
computed: {
|
|
default: false
|
|
},
|
|
optional: (0, _utils.validateOptional)(bool)
|
|
});
|
|
defineType("TSPropertySignature", {
|
|
aliases: ["TSTypeElement"],
|
|
visitor: ["key", "typeAnnotation"],
|
|
fields: Object.assign({}, namedTypeElementCommon(), {
|
|
readonly: (0, _utils.validateOptional)(bool),
|
|
typeAnnotation: (0, _utils.validateOptionalType)("TSTypeAnnotation"),
|
|
kind: {
|
|
validate: (0, _utils.assertOneOf)("get", "set")
|
|
}
|
|
})
|
|
});
|
|
defineType("TSMethodSignature", {
|
|
aliases: ["TSTypeElement"],
|
|
visitor: ["key", "typeParameters", "parameters", "typeAnnotation"],
|
|
fields: Object.assign({}, signatureDeclarationCommon(), namedTypeElementCommon(), {
|
|
kind: {
|
|
validate: (0, _utils.assertOneOf)("method", "get", "set")
|
|
}
|
|
})
|
|
});
|
|
defineType("TSIndexSignature", {
|
|
aliases: ["TSTypeElement"],
|
|
visitor: ["parameters", "typeAnnotation"],
|
|
fields: {
|
|
readonly: (0, _utils.validateOptional)(bool),
|
|
static: (0, _utils.validateOptional)(bool),
|
|
parameters: (0, _utils.validateArrayOfType)("Identifier"),
|
|
typeAnnotation: (0, _utils.validateOptionalType)("TSTypeAnnotation")
|
|
}
|
|
});
|
|
const tsKeywordTypes = ["TSAnyKeyword", "TSBooleanKeyword", "TSBigIntKeyword", "TSIntrinsicKeyword", "TSNeverKeyword", "TSNullKeyword", "TSNumberKeyword", "TSObjectKeyword", "TSStringKeyword", "TSSymbolKeyword", "TSUndefinedKeyword", "TSUnknownKeyword", "TSVoidKeyword"];
|
|
for (const type of tsKeywordTypes) {
|
|
defineType(type, {
|
|
aliases: ["TSType", "TSBaseType"],
|
|
visitor: [],
|
|
fields: {}
|
|
});
|
|
}
|
|
defineType("TSThisType", {
|
|
aliases: ["TSType", "TSBaseType"],
|
|
visitor: [],
|
|
fields: {}
|
|
});
|
|
const fnOrCtrBase = {
|
|
aliases: ["TSType"],
|
|
visitor: ["typeParameters", "parameters", "typeAnnotation"]
|
|
};
|
|
defineType("TSFunctionType", Object.assign({}, fnOrCtrBase, {
|
|
fields: signatureDeclarationCommon()
|
|
}));
|
|
defineType("TSConstructorType", Object.assign({}, fnOrCtrBase, {
|
|
fields: Object.assign({}, signatureDeclarationCommon(), {
|
|
abstract: (0, _utils.validateOptional)(bool)
|
|
})
|
|
}));
|
|
defineType("TSTypeReference", {
|
|
aliases: ["TSType"],
|
|
visitor: ["typeName", "typeParameters"],
|
|
fields: {
|
|
typeName: (0, _utils.validateType)("TSEntityName"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TSTypeParameterInstantiation")
|
|
}
|
|
});
|
|
defineType("TSTypePredicate", {
|
|
aliases: ["TSType"],
|
|
visitor: ["parameterName", "typeAnnotation"],
|
|
builder: ["parameterName", "typeAnnotation", "asserts"],
|
|
fields: {
|
|
parameterName: (0, _utils.validateType)("Identifier", "TSThisType"),
|
|
typeAnnotation: (0, _utils.validateOptionalType)("TSTypeAnnotation"),
|
|
asserts: (0, _utils.validateOptional)(bool)
|
|
}
|
|
});
|
|
defineType("TSTypeQuery", {
|
|
aliases: ["TSType"],
|
|
visitor: ["exprName", "typeParameters"],
|
|
fields: {
|
|
exprName: (0, _utils.validateType)("TSEntityName", "TSImportType"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TSTypeParameterInstantiation")
|
|
}
|
|
});
|
|
defineType("TSTypeLiteral", {
|
|
aliases: ["TSType"],
|
|
visitor: ["members"],
|
|
fields: {
|
|
members: (0, _utils.validateArrayOfType)("TSTypeElement")
|
|
}
|
|
});
|
|
defineType("TSArrayType", {
|
|
aliases: ["TSType"],
|
|
visitor: ["elementType"],
|
|
fields: {
|
|
elementType: (0, _utils.validateType)("TSType")
|
|
}
|
|
});
|
|
defineType("TSTupleType", {
|
|
aliases: ["TSType"],
|
|
visitor: ["elementTypes"],
|
|
fields: {
|
|
elementTypes: (0, _utils.validateArrayOfType)("TSType", "TSNamedTupleMember")
|
|
}
|
|
});
|
|
defineType("TSOptionalType", {
|
|
aliases: ["TSType"],
|
|
visitor: ["typeAnnotation"],
|
|
fields: {
|
|
typeAnnotation: (0, _utils.validateType)("TSType")
|
|
}
|
|
});
|
|
defineType("TSRestType", {
|
|
aliases: ["TSType"],
|
|
visitor: ["typeAnnotation"],
|
|
fields: {
|
|
typeAnnotation: (0, _utils.validateType)("TSType")
|
|
}
|
|
});
|
|
defineType("TSNamedTupleMember", {
|
|
visitor: ["label", "elementType"],
|
|
builder: ["label", "elementType", "optional"],
|
|
fields: {
|
|
label: (0, _utils.validateType)("Identifier"),
|
|
optional: {
|
|
validate: bool,
|
|
default: false
|
|
},
|
|
elementType: (0, _utils.validateType)("TSType")
|
|
}
|
|
});
|
|
const unionOrIntersection = {
|
|
aliases: ["TSType"],
|
|
visitor: ["types"],
|
|
fields: {
|
|
types: (0, _utils.validateArrayOfType)("TSType")
|
|
}
|
|
};
|
|
defineType("TSUnionType", unionOrIntersection);
|
|
defineType("TSIntersectionType", unionOrIntersection);
|
|
defineType("TSConditionalType", {
|
|
aliases: ["TSType"],
|
|
visitor: ["checkType", "extendsType", "trueType", "falseType"],
|
|
fields: {
|
|
checkType: (0, _utils.validateType)("TSType"),
|
|
extendsType: (0, _utils.validateType)("TSType"),
|
|
trueType: (0, _utils.validateType)("TSType"),
|
|
falseType: (0, _utils.validateType)("TSType")
|
|
}
|
|
});
|
|
defineType("TSInferType", {
|
|
aliases: ["TSType"],
|
|
visitor: ["typeParameter"],
|
|
fields: {
|
|
typeParameter: (0, _utils.validateType)("TSTypeParameter")
|
|
}
|
|
});
|
|
defineType("TSParenthesizedType", {
|
|
aliases: ["TSType"],
|
|
visitor: ["typeAnnotation"],
|
|
fields: {
|
|
typeAnnotation: (0, _utils.validateType)("TSType")
|
|
}
|
|
});
|
|
defineType("TSTypeOperator", {
|
|
aliases: ["TSType"],
|
|
visitor: ["typeAnnotation"],
|
|
fields: {
|
|
operator: (0, _utils.validate)((0, _utils.assertValueType)("string")),
|
|
typeAnnotation: (0, _utils.validateType)("TSType")
|
|
}
|
|
});
|
|
defineType("TSIndexedAccessType", {
|
|
aliases: ["TSType"],
|
|
visitor: ["objectType", "indexType"],
|
|
fields: {
|
|
objectType: (0, _utils.validateType)("TSType"),
|
|
indexType: (0, _utils.validateType)("TSType")
|
|
}
|
|
});
|
|
defineType("TSMappedType", {
|
|
aliases: ["TSType"],
|
|
visitor: ["typeParameter", "nameType", "typeAnnotation"],
|
|
builder: ["typeParameter", "typeAnnotation", "nameType"],
|
|
fields: Object.assign({}, {
|
|
typeParameter: (0, _utils.validateType)("TSTypeParameter")
|
|
}, {
|
|
readonly: (0, _utils.validateOptional)((0, _utils.assertOneOf)(true, false, "+", "-")),
|
|
optional: (0, _utils.validateOptional)((0, _utils.assertOneOf)(true, false, "+", "-")),
|
|
typeAnnotation: (0, _utils.validateOptionalType)("TSType"),
|
|
nameType: (0, _utils.validateOptionalType)("TSType")
|
|
})
|
|
});
|
|
defineType("TSLiteralType", {
|
|
aliases: ["TSType", "TSBaseType"],
|
|
visitor: ["literal"],
|
|
fields: {
|
|
literal: {
|
|
validate: function () {
|
|
const unaryExpression = (0, _utils.assertNodeType)("NumericLiteral", "BigIntLiteral");
|
|
const unaryOperator = (0, _utils.assertOneOf)("-");
|
|
const literal = (0, _utils.assertNodeType)("NumericLiteral", "StringLiteral", "BooleanLiteral", "BigIntLiteral", "TemplateLiteral");
|
|
function validator(parent, key, node) {
|
|
if ((0, _is.default)("UnaryExpression", node)) {
|
|
unaryOperator(node, "operator", node.operator);
|
|
unaryExpression(node, "argument", node.argument);
|
|
} else {
|
|
literal(parent, key, node);
|
|
}
|
|
}
|
|
validator.oneOfNodeTypes = ["NumericLiteral", "StringLiteral", "BooleanLiteral", "BigIntLiteral", "TemplateLiteral", "UnaryExpression"];
|
|
return validator;
|
|
}()
|
|
}
|
|
}
|
|
});
|
|
const expressionWithTypeArguments = {
|
|
aliases: ["TSType"],
|
|
visitor: ["expression", "typeParameters"],
|
|
fields: {
|
|
expression: (0, _utils.validateType)("TSEntityName"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TSTypeParameterInstantiation")
|
|
}
|
|
};
|
|
{
|
|
defineType("TSExpressionWithTypeArguments", expressionWithTypeArguments);
|
|
}
|
|
defineType("TSInterfaceDeclaration", {
|
|
aliases: ["Statement", "Declaration"],
|
|
visitor: ["id", "typeParameters", "extends", "body"],
|
|
fields: {
|
|
declare: (0, _utils.validateOptional)(bool),
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TSTypeParameterDeclaration"),
|
|
extends: (0, _utils.validateOptional)((0, _utils.arrayOfType)("TSExpressionWithTypeArguments")),
|
|
body: (0, _utils.validateType)("TSInterfaceBody")
|
|
}
|
|
});
|
|
defineType("TSInterfaceBody", {
|
|
visitor: ["body"],
|
|
fields: {
|
|
body: (0, _utils.validateArrayOfType)("TSTypeElement")
|
|
}
|
|
});
|
|
defineType("TSTypeAliasDeclaration", {
|
|
aliases: ["Statement", "Declaration"],
|
|
visitor: ["id", "typeParameters", "typeAnnotation"],
|
|
fields: {
|
|
declare: (0, _utils.validateOptional)(bool),
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TSTypeParameterDeclaration"),
|
|
typeAnnotation: (0, _utils.validateType)("TSType")
|
|
}
|
|
});
|
|
defineType("TSInstantiationExpression", {
|
|
aliases: ["Expression"],
|
|
visitor: ["expression", "typeParameters"],
|
|
fields: {
|
|
expression: (0, _utils.validateType)("Expression"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TSTypeParameterInstantiation")
|
|
}
|
|
});
|
|
const TSTypeExpression = {
|
|
aliases: ["Expression", "LVal", "PatternLike"],
|
|
visitor: ["expression", "typeAnnotation"],
|
|
fields: {
|
|
expression: (0, _utils.validateType)("Expression"),
|
|
typeAnnotation: (0, _utils.validateType)("TSType")
|
|
}
|
|
};
|
|
defineType("TSAsExpression", TSTypeExpression);
|
|
defineType("TSSatisfiesExpression", TSTypeExpression);
|
|
defineType("TSTypeAssertion", {
|
|
aliases: ["Expression", "LVal", "PatternLike"],
|
|
visitor: ["typeAnnotation", "expression"],
|
|
fields: {
|
|
typeAnnotation: (0, _utils.validateType)("TSType"),
|
|
expression: (0, _utils.validateType)("Expression")
|
|
}
|
|
});
|
|
defineType("TSEnumDeclaration", {
|
|
aliases: ["Statement", "Declaration"],
|
|
visitor: ["id", "members"],
|
|
fields: {
|
|
declare: (0, _utils.validateOptional)(bool),
|
|
const: (0, _utils.validateOptional)(bool),
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
members: (0, _utils.validateArrayOfType)("TSEnumMember"),
|
|
initializer: (0, _utils.validateOptionalType)("Expression")
|
|
}
|
|
});
|
|
defineType("TSEnumMember", {
|
|
visitor: ["id", "initializer"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier", "StringLiteral"),
|
|
initializer: (0, _utils.validateOptionalType)("Expression")
|
|
}
|
|
});
|
|
defineType("TSModuleDeclaration", {
|
|
aliases: ["Statement", "Declaration"],
|
|
visitor: ["id", "body"],
|
|
fields: Object.assign({
|
|
kind: {
|
|
validate: (0, _utils.assertOneOf)("global", "module", "namespace")
|
|
},
|
|
declare: (0, _utils.validateOptional)(bool)
|
|
}, {
|
|
global: (0, _utils.validateOptional)(bool)
|
|
}, {
|
|
id: (0, _utils.validateType)("Identifier", "StringLiteral"),
|
|
body: (0, _utils.validateType)("TSModuleBlock", "TSModuleDeclaration")
|
|
})
|
|
});
|
|
defineType("TSModuleBlock", {
|
|
aliases: ["Scopable", "Block", "BlockParent", "FunctionParent"],
|
|
visitor: ["body"],
|
|
fields: {
|
|
body: (0, _utils.validateArrayOfType)("Statement")
|
|
}
|
|
});
|
|
defineType("TSImportType", {
|
|
aliases: ["TSType"],
|
|
visitor: ["argument", "qualifier", "typeParameters"],
|
|
fields: {
|
|
argument: (0, _utils.validateType)("StringLiteral"),
|
|
qualifier: (0, _utils.validateOptionalType)("TSEntityName"),
|
|
typeParameters: (0, _utils.validateOptionalType)("TSTypeParameterInstantiation"),
|
|
options: {
|
|
validate: (0, _utils.assertNodeType)("Expression"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("TSImportEqualsDeclaration", {
|
|
aliases: ["Statement"],
|
|
visitor: ["id", "moduleReference"],
|
|
fields: {
|
|
isExport: (0, _utils.validate)(bool),
|
|
id: (0, _utils.validateType)("Identifier"),
|
|
moduleReference: (0, _utils.validateType)("TSEntityName", "TSExternalModuleReference"),
|
|
importKind: {
|
|
validate: (0, _utils.assertOneOf)("type", "value"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
defineType("TSExternalModuleReference", {
|
|
visitor: ["expression"],
|
|
fields: {
|
|
expression: (0, _utils.validateType)("StringLiteral")
|
|
}
|
|
});
|
|
defineType("TSNonNullExpression", {
|
|
aliases: ["Expression", "LVal", "PatternLike"],
|
|
visitor: ["expression"],
|
|
fields: {
|
|
expression: (0, _utils.validateType)("Expression")
|
|
}
|
|
});
|
|
defineType("TSExportAssignment", {
|
|
aliases: ["Statement"],
|
|
visitor: ["expression"],
|
|
fields: {
|
|
expression: (0, _utils.validateType)("Expression")
|
|
}
|
|
});
|
|
defineType("TSNamespaceExportDeclaration", {
|
|
aliases: ["Statement"],
|
|
visitor: ["id"],
|
|
fields: {
|
|
id: (0, _utils.validateType)("Identifier")
|
|
}
|
|
});
|
|
defineType("TSTypeAnnotation", {
|
|
visitor: ["typeAnnotation"],
|
|
fields: {
|
|
typeAnnotation: {
|
|
validate: (0, _utils.assertNodeType)("TSType")
|
|
}
|
|
}
|
|
});
|
|
defineType("TSTypeParameterInstantiation", {
|
|
visitor: ["params"],
|
|
fields: {
|
|
params: (0, _utils.validateArrayOfType)("TSType")
|
|
}
|
|
});
|
|
defineType("TSTypeParameterDeclaration", {
|
|
visitor: ["params"],
|
|
fields: {
|
|
params: (0, _utils.validateArrayOfType)("TSTypeParameter")
|
|
}
|
|
});
|
|
defineType("TSTypeParameter", {
|
|
builder: ["constraint", "default", "name"],
|
|
visitor: ["constraint", "default"],
|
|
fields: {
|
|
name: {
|
|
validate: (0, _utils.assertValueType)("string")
|
|
},
|
|
in: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
out: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
const: {
|
|
validate: (0, _utils.assertValueType)("boolean"),
|
|
optional: true
|
|
},
|
|
constraint: {
|
|
validate: (0, _utils.assertNodeType)("TSType"),
|
|
optional: true
|
|
},
|
|
default: {
|
|
validate: (0, _utils.assertNodeType)("TSType"),
|
|
optional: true
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
return typescript;
|
|
}
|
|
|
|
var deprecatedAliases = {};
|
|
|
|
var hasRequiredDeprecatedAliases;
|
|
|
|
function requireDeprecatedAliases () {
|
|
if (hasRequiredDeprecatedAliases) return deprecatedAliases;
|
|
hasRequiredDeprecatedAliases = 1;
|
|
|
|
Object.defineProperty(deprecatedAliases, "__esModule", {
|
|
value: true
|
|
});
|
|
deprecatedAliases.DEPRECATED_ALIASES = void 0;
|
|
deprecatedAliases.DEPRECATED_ALIASES = {
|
|
ModuleDeclaration: "ImportOrExportDeclaration"
|
|
};
|
|
|
|
|
|
return deprecatedAliases;
|
|
}
|
|
|
|
var hasRequiredDefinitions;
|
|
|
|
function requireDefinitions () {
|
|
if (hasRequiredDefinitions) return definitions;
|
|
hasRequiredDefinitions = 1;
|
|
(function (exports) {
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
Object.defineProperty(exports, "ALIAS_KEYS", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _utils.ALIAS_KEYS;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "BUILDER_KEYS", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _utils.BUILDER_KEYS;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DEPRECATED_ALIASES", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _deprecatedAliases.DEPRECATED_ALIASES;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DEPRECATED_KEYS", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _utils.DEPRECATED_KEYS;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "FLIPPED_ALIAS_KEYS", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _utils.FLIPPED_ALIAS_KEYS;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "NODE_FIELDS", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _utils.NODE_FIELDS;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "NODE_PARENT_VALIDATIONS", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _utils.NODE_PARENT_VALIDATIONS;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "PLACEHOLDERS", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _placeholders.PLACEHOLDERS;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "PLACEHOLDERS_ALIAS", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _placeholders.PLACEHOLDERS_ALIAS;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "PLACEHOLDERS_FLIPPED_ALIAS", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _placeholders.PLACEHOLDERS_FLIPPED_ALIAS;
|
|
}
|
|
});
|
|
exports.TYPES = void 0;
|
|
Object.defineProperty(exports, "VISITOR_KEYS", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _utils.VISITOR_KEYS;
|
|
}
|
|
});
|
|
requireCore();
|
|
requireFlow();
|
|
requireJsx();
|
|
requireMisc();
|
|
requireExperimental();
|
|
requireTypescript();
|
|
var _utils = requireUtils();
|
|
var _placeholders = requirePlaceholders();
|
|
var _deprecatedAliases = requireDeprecatedAliases();
|
|
Object.keys(_deprecatedAliases.DEPRECATED_ALIASES).forEach(deprecatedAlias => {
|
|
_utils.FLIPPED_ALIAS_KEYS[deprecatedAlias] = _utils.FLIPPED_ALIAS_KEYS[_deprecatedAliases.DEPRECATED_ALIASES[deprecatedAlias]];
|
|
});
|
|
exports.TYPES = [].concat(Object.keys(_utils.VISITOR_KEYS), Object.keys(_utils.FLIPPED_ALIAS_KEYS), Object.keys(_utils.DEPRECATED_KEYS));
|
|
|
|
|
|
} (definitions));
|
|
return definitions;
|
|
}
|
|
|
|
var hasRequiredValidate;
|
|
|
|
function requireValidate () {
|
|
if (hasRequiredValidate) return validate$1;
|
|
hasRequiredValidate = 1;
|
|
|
|
Object.defineProperty(validate$1, "__esModule", {
|
|
value: true
|
|
});
|
|
validate$1.default = validate;
|
|
validate$1.validateChild = validateChild;
|
|
validate$1.validateField = validateField;
|
|
validate$1.validateInternal = validateInternal;
|
|
var _index = requireDefinitions();
|
|
function validate(node, key, val) {
|
|
if (!node) return;
|
|
const fields = _index.NODE_FIELDS[node.type];
|
|
if (!fields) return;
|
|
const field = fields[key];
|
|
validateField(node, key, val, field);
|
|
validateChild(node, key, val);
|
|
}
|
|
function validateInternal(field, node, key, val, maybeNode) {
|
|
if (!(field != null && field.validate)) return;
|
|
if (field.optional && val == null) return;
|
|
field.validate(node, key, val);
|
|
if (maybeNode) {
|
|
var _NODE_PARENT_VALIDATI;
|
|
const type = val.type;
|
|
if (type == null) return;
|
|
(_NODE_PARENT_VALIDATI = _index.NODE_PARENT_VALIDATIONS[type]) == null || _NODE_PARENT_VALIDATI.call(_index.NODE_PARENT_VALIDATIONS, node, key, val);
|
|
}
|
|
}
|
|
function validateField(node, key, val, field) {
|
|
if (!(field != null && field.validate)) return;
|
|
if (field.optional && val == null) return;
|
|
field.validate(node, key, val);
|
|
}
|
|
function validateChild(node, key, val) {
|
|
var _NODE_PARENT_VALIDATI2;
|
|
const type = val == null ? void 0 : val.type;
|
|
if (type == null) return;
|
|
(_NODE_PARENT_VALIDATI2 = _index.NODE_PARENT_VALIDATIONS[type]) == null || _NODE_PARENT_VALIDATI2.call(_index.NODE_PARENT_VALIDATIONS, node, key, val);
|
|
}
|
|
|
|
|
|
return validate$1;
|
|
}
|
|
|
|
var hasRequiredGenerated$2;
|
|
|
|
function requireGenerated$2 () {
|
|
if (hasRequiredGenerated$2) return generated$2;
|
|
hasRequiredGenerated$2 = 1;
|
|
|
|
Object.defineProperty(generated$2, "__esModule", {
|
|
value: true
|
|
});
|
|
generated$2.anyTypeAnnotation = anyTypeAnnotation;
|
|
generated$2.argumentPlaceholder = argumentPlaceholder;
|
|
generated$2.arrayExpression = arrayExpression;
|
|
generated$2.arrayPattern = arrayPattern;
|
|
generated$2.arrayTypeAnnotation = arrayTypeAnnotation;
|
|
generated$2.arrowFunctionExpression = arrowFunctionExpression;
|
|
generated$2.assignmentExpression = assignmentExpression;
|
|
generated$2.assignmentPattern = assignmentPattern;
|
|
generated$2.awaitExpression = awaitExpression;
|
|
generated$2.bigIntLiteral = bigIntLiteral;
|
|
generated$2.binaryExpression = binaryExpression;
|
|
generated$2.bindExpression = bindExpression;
|
|
generated$2.blockStatement = blockStatement;
|
|
generated$2.booleanLiteral = booleanLiteral;
|
|
generated$2.booleanLiteralTypeAnnotation = booleanLiteralTypeAnnotation;
|
|
generated$2.booleanTypeAnnotation = booleanTypeAnnotation;
|
|
generated$2.breakStatement = breakStatement;
|
|
generated$2.callExpression = callExpression;
|
|
generated$2.catchClause = catchClause;
|
|
generated$2.classAccessorProperty = classAccessorProperty;
|
|
generated$2.classBody = classBody;
|
|
generated$2.classDeclaration = classDeclaration;
|
|
generated$2.classExpression = classExpression;
|
|
generated$2.classImplements = classImplements;
|
|
generated$2.classMethod = classMethod;
|
|
generated$2.classPrivateMethod = classPrivateMethod;
|
|
generated$2.classPrivateProperty = classPrivateProperty;
|
|
generated$2.classProperty = classProperty;
|
|
generated$2.conditionalExpression = conditionalExpression;
|
|
generated$2.continueStatement = continueStatement;
|
|
generated$2.debuggerStatement = debuggerStatement;
|
|
generated$2.decimalLiteral = decimalLiteral;
|
|
generated$2.declareClass = declareClass;
|
|
generated$2.declareExportAllDeclaration = declareExportAllDeclaration;
|
|
generated$2.declareExportDeclaration = declareExportDeclaration;
|
|
generated$2.declareFunction = declareFunction;
|
|
generated$2.declareInterface = declareInterface;
|
|
generated$2.declareModule = declareModule;
|
|
generated$2.declareModuleExports = declareModuleExports;
|
|
generated$2.declareOpaqueType = declareOpaqueType;
|
|
generated$2.declareTypeAlias = declareTypeAlias;
|
|
generated$2.declareVariable = declareVariable;
|
|
generated$2.declaredPredicate = declaredPredicate;
|
|
generated$2.decorator = decorator;
|
|
generated$2.directive = directive;
|
|
generated$2.directiveLiteral = directiveLiteral;
|
|
generated$2.doExpression = doExpression;
|
|
generated$2.doWhileStatement = doWhileStatement;
|
|
generated$2.emptyStatement = emptyStatement;
|
|
generated$2.emptyTypeAnnotation = emptyTypeAnnotation;
|
|
generated$2.enumBooleanBody = enumBooleanBody;
|
|
generated$2.enumBooleanMember = enumBooleanMember;
|
|
generated$2.enumDeclaration = enumDeclaration;
|
|
generated$2.enumDefaultedMember = enumDefaultedMember;
|
|
generated$2.enumNumberBody = enumNumberBody;
|
|
generated$2.enumNumberMember = enumNumberMember;
|
|
generated$2.enumStringBody = enumStringBody;
|
|
generated$2.enumStringMember = enumStringMember;
|
|
generated$2.enumSymbolBody = enumSymbolBody;
|
|
generated$2.existsTypeAnnotation = existsTypeAnnotation;
|
|
generated$2.exportAllDeclaration = exportAllDeclaration;
|
|
generated$2.exportDefaultDeclaration = exportDefaultDeclaration;
|
|
generated$2.exportDefaultSpecifier = exportDefaultSpecifier;
|
|
generated$2.exportNamedDeclaration = exportNamedDeclaration;
|
|
generated$2.exportNamespaceSpecifier = exportNamespaceSpecifier;
|
|
generated$2.exportSpecifier = exportSpecifier;
|
|
generated$2.expressionStatement = expressionStatement;
|
|
generated$2.file = file;
|
|
generated$2.forInStatement = forInStatement;
|
|
generated$2.forOfStatement = forOfStatement;
|
|
generated$2.forStatement = forStatement;
|
|
generated$2.functionDeclaration = functionDeclaration;
|
|
generated$2.functionExpression = functionExpression;
|
|
generated$2.functionTypeAnnotation = functionTypeAnnotation;
|
|
generated$2.functionTypeParam = functionTypeParam;
|
|
generated$2.genericTypeAnnotation = genericTypeAnnotation;
|
|
generated$2.identifier = identifier;
|
|
generated$2.ifStatement = ifStatement;
|
|
generated$2.import = _import;
|
|
generated$2.importAttribute = importAttribute;
|
|
generated$2.importDeclaration = importDeclaration;
|
|
generated$2.importDefaultSpecifier = importDefaultSpecifier;
|
|
generated$2.importExpression = importExpression;
|
|
generated$2.importNamespaceSpecifier = importNamespaceSpecifier;
|
|
generated$2.importSpecifier = importSpecifier;
|
|
generated$2.indexedAccessType = indexedAccessType;
|
|
generated$2.inferredPredicate = inferredPredicate;
|
|
generated$2.interfaceDeclaration = interfaceDeclaration;
|
|
generated$2.interfaceExtends = interfaceExtends;
|
|
generated$2.interfaceTypeAnnotation = interfaceTypeAnnotation;
|
|
generated$2.interpreterDirective = interpreterDirective;
|
|
generated$2.intersectionTypeAnnotation = intersectionTypeAnnotation;
|
|
generated$2.jSXAttribute = generated$2.jsxAttribute = jsxAttribute;
|
|
generated$2.jSXClosingElement = generated$2.jsxClosingElement = jsxClosingElement;
|
|
generated$2.jSXClosingFragment = generated$2.jsxClosingFragment = jsxClosingFragment;
|
|
generated$2.jSXElement = generated$2.jsxElement = jsxElement;
|
|
generated$2.jSXEmptyExpression = generated$2.jsxEmptyExpression = jsxEmptyExpression;
|
|
generated$2.jSXExpressionContainer = generated$2.jsxExpressionContainer = jsxExpressionContainer;
|
|
generated$2.jSXFragment = generated$2.jsxFragment = jsxFragment;
|
|
generated$2.jSXIdentifier = generated$2.jsxIdentifier = jsxIdentifier;
|
|
generated$2.jSXMemberExpression = generated$2.jsxMemberExpression = jsxMemberExpression;
|
|
generated$2.jSXNamespacedName = generated$2.jsxNamespacedName = jsxNamespacedName;
|
|
generated$2.jSXOpeningElement = generated$2.jsxOpeningElement = jsxOpeningElement;
|
|
generated$2.jSXOpeningFragment = generated$2.jsxOpeningFragment = jsxOpeningFragment;
|
|
generated$2.jSXSpreadAttribute = generated$2.jsxSpreadAttribute = jsxSpreadAttribute;
|
|
generated$2.jSXSpreadChild = generated$2.jsxSpreadChild = jsxSpreadChild;
|
|
generated$2.jSXText = generated$2.jsxText = jsxText;
|
|
generated$2.labeledStatement = labeledStatement;
|
|
generated$2.logicalExpression = logicalExpression;
|
|
generated$2.memberExpression = memberExpression;
|
|
generated$2.metaProperty = metaProperty;
|
|
generated$2.mixedTypeAnnotation = mixedTypeAnnotation;
|
|
generated$2.moduleExpression = moduleExpression;
|
|
generated$2.newExpression = newExpression;
|
|
generated$2.noop = noop;
|
|
generated$2.nullLiteral = nullLiteral;
|
|
generated$2.nullLiteralTypeAnnotation = nullLiteralTypeAnnotation;
|
|
generated$2.nullableTypeAnnotation = nullableTypeAnnotation;
|
|
generated$2.numberLiteral = NumberLiteral;
|
|
generated$2.numberLiteralTypeAnnotation = numberLiteralTypeAnnotation;
|
|
generated$2.numberTypeAnnotation = numberTypeAnnotation;
|
|
generated$2.numericLiteral = numericLiteral;
|
|
generated$2.objectExpression = objectExpression;
|
|
generated$2.objectMethod = objectMethod;
|
|
generated$2.objectPattern = objectPattern;
|
|
generated$2.objectProperty = objectProperty;
|
|
generated$2.objectTypeAnnotation = objectTypeAnnotation;
|
|
generated$2.objectTypeCallProperty = objectTypeCallProperty;
|
|
generated$2.objectTypeIndexer = objectTypeIndexer;
|
|
generated$2.objectTypeInternalSlot = objectTypeInternalSlot;
|
|
generated$2.objectTypeProperty = objectTypeProperty;
|
|
generated$2.objectTypeSpreadProperty = objectTypeSpreadProperty;
|
|
generated$2.opaqueType = opaqueType;
|
|
generated$2.optionalCallExpression = optionalCallExpression;
|
|
generated$2.optionalIndexedAccessType = optionalIndexedAccessType;
|
|
generated$2.optionalMemberExpression = optionalMemberExpression;
|
|
generated$2.parenthesizedExpression = parenthesizedExpression;
|
|
generated$2.pipelineBareFunction = pipelineBareFunction;
|
|
generated$2.pipelinePrimaryTopicReference = pipelinePrimaryTopicReference;
|
|
generated$2.pipelineTopicExpression = pipelineTopicExpression;
|
|
generated$2.placeholder = placeholder;
|
|
generated$2.privateName = privateName;
|
|
generated$2.program = program;
|
|
generated$2.qualifiedTypeIdentifier = qualifiedTypeIdentifier;
|
|
generated$2.recordExpression = recordExpression;
|
|
generated$2.regExpLiteral = regExpLiteral;
|
|
generated$2.regexLiteral = RegexLiteral;
|
|
generated$2.restElement = restElement;
|
|
generated$2.restProperty = RestProperty;
|
|
generated$2.returnStatement = returnStatement;
|
|
generated$2.sequenceExpression = sequenceExpression;
|
|
generated$2.spreadElement = spreadElement;
|
|
generated$2.spreadProperty = SpreadProperty;
|
|
generated$2.staticBlock = staticBlock;
|
|
generated$2.stringLiteral = stringLiteral;
|
|
generated$2.stringLiteralTypeAnnotation = stringLiteralTypeAnnotation;
|
|
generated$2.stringTypeAnnotation = stringTypeAnnotation;
|
|
generated$2.super = _super;
|
|
generated$2.switchCase = switchCase;
|
|
generated$2.switchStatement = switchStatement;
|
|
generated$2.symbolTypeAnnotation = symbolTypeAnnotation;
|
|
generated$2.taggedTemplateExpression = taggedTemplateExpression;
|
|
generated$2.templateElement = templateElement;
|
|
generated$2.templateLiteral = templateLiteral;
|
|
generated$2.thisExpression = thisExpression;
|
|
generated$2.thisTypeAnnotation = thisTypeAnnotation;
|
|
generated$2.throwStatement = throwStatement;
|
|
generated$2.topicReference = topicReference;
|
|
generated$2.tryStatement = tryStatement;
|
|
generated$2.tSAnyKeyword = generated$2.tsAnyKeyword = tsAnyKeyword;
|
|
generated$2.tSArrayType = generated$2.tsArrayType = tsArrayType;
|
|
generated$2.tSAsExpression = generated$2.tsAsExpression = tsAsExpression;
|
|
generated$2.tSBigIntKeyword = generated$2.tsBigIntKeyword = tsBigIntKeyword;
|
|
generated$2.tSBooleanKeyword = generated$2.tsBooleanKeyword = tsBooleanKeyword;
|
|
generated$2.tSCallSignatureDeclaration = generated$2.tsCallSignatureDeclaration = tsCallSignatureDeclaration;
|
|
generated$2.tSConditionalType = generated$2.tsConditionalType = tsConditionalType;
|
|
generated$2.tSConstructSignatureDeclaration = generated$2.tsConstructSignatureDeclaration = tsConstructSignatureDeclaration;
|
|
generated$2.tSConstructorType = generated$2.tsConstructorType = tsConstructorType;
|
|
generated$2.tSDeclareFunction = generated$2.tsDeclareFunction = tsDeclareFunction;
|
|
generated$2.tSDeclareMethod = generated$2.tsDeclareMethod = tsDeclareMethod;
|
|
generated$2.tSEnumDeclaration = generated$2.tsEnumDeclaration = tsEnumDeclaration;
|
|
generated$2.tSEnumMember = generated$2.tsEnumMember = tsEnumMember;
|
|
generated$2.tSExportAssignment = generated$2.tsExportAssignment = tsExportAssignment;
|
|
generated$2.tSExpressionWithTypeArguments = generated$2.tsExpressionWithTypeArguments = tsExpressionWithTypeArguments;
|
|
generated$2.tSExternalModuleReference = generated$2.tsExternalModuleReference = tsExternalModuleReference;
|
|
generated$2.tSFunctionType = generated$2.tsFunctionType = tsFunctionType;
|
|
generated$2.tSImportEqualsDeclaration = generated$2.tsImportEqualsDeclaration = tsImportEqualsDeclaration;
|
|
generated$2.tSImportType = generated$2.tsImportType = tsImportType;
|
|
generated$2.tSIndexSignature = generated$2.tsIndexSignature = tsIndexSignature;
|
|
generated$2.tSIndexedAccessType = generated$2.tsIndexedAccessType = tsIndexedAccessType;
|
|
generated$2.tSInferType = generated$2.tsInferType = tsInferType;
|
|
generated$2.tSInstantiationExpression = generated$2.tsInstantiationExpression = tsInstantiationExpression;
|
|
generated$2.tSInterfaceBody = generated$2.tsInterfaceBody = tsInterfaceBody;
|
|
generated$2.tSInterfaceDeclaration = generated$2.tsInterfaceDeclaration = tsInterfaceDeclaration;
|
|
generated$2.tSIntersectionType = generated$2.tsIntersectionType = tsIntersectionType;
|
|
generated$2.tSIntrinsicKeyword = generated$2.tsIntrinsicKeyword = tsIntrinsicKeyword;
|
|
generated$2.tSLiteralType = generated$2.tsLiteralType = tsLiteralType;
|
|
generated$2.tSMappedType = generated$2.tsMappedType = tsMappedType;
|
|
generated$2.tSMethodSignature = generated$2.tsMethodSignature = tsMethodSignature;
|
|
generated$2.tSModuleBlock = generated$2.tsModuleBlock = tsModuleBlock;
|
|
generated$2.tSModuleDeclaration = generated$2.tsModuleDeclaration = tsModuleDeclaration;
|
|
generated$2.tSNamedTupleMember = generated$2.tsNamedTupleMember = tsNamedTupleMember;
|
|
generated$2.tSNamespaceExportDeclaration = generated$2.tsNamespaceExportDeclaration = tsNamespaceExportDeclaration;
|
|
generated$2.tSNeverKeyword = generated$2.tsNeverKeyword = tsNeverKeyword;
|
|
generated$2.tSNonNullExpression = generated$2.tsNonNullExpression = tsNonNullExpression;
|
|
generated$2.tSNullKeyword = generated$2.tsNullKeyword = tsNullKeyword;
|
|
generated$2.tSNumberKeyword = generated$2.tsNumberKeyword = tsNumberKeyword;
|
|
generated$2.tSObjectKeyword = generated$2.tsObjectKeyword = tsObjectKeyword;
|
|
generated$2.tSOptionalType = generated$2.tsOptionalType = tsOptionalType;
|
|
generated$2.tSParameterProperty = generated$2.tsParameterProperty = tsParameterProperty;
|
|
generated$2.tSParenthesizedType = generated$2.tsParenthesizedType = tsParenthesizedType;
|
|
generated$2.tSPropertySignature = generated$2.tsPropertySignature = tsPropertySignature;
|
|
generated$2.tSQualifiedName = generated$2.tsQualifiedName = tsQualifiedName;
|
|
generated$2.tSRestType = generated$2.tsRestType = tsRestType;
|
|
generated$2.tSSatisfiesExpression = generated$2.tsSatisfiesExpression = tsSatisfiesExpression;
|
|
generated$2.tSStringKeyword = generated$2.tsStringKeyword = tsStringKeyword;
|
|
generated$2.tSSymbolKeyword = generated$2.tsSymbolKeyword = tsSymbolKeyword;
|
|
generated$2.tSThisType = generated$2.tsThisType = tsThisType;
|
|
generated$2.tSTupleType = generated$2.tsTupleType = tsTupleType;
|
|
generated$2.tSTypeAliasDeclaration = generated$2.tsTypeAliasDeclaration = tsTypeAliasDeclaration;
|
|
generated$2.tSTypeAnnotation = generated$2.tsTypeAnnotation = tsTypeAnnotation;
|
|
generated$2.tSTypeAssertion = generated$2.tsTypeAssertion = tsTypeAssertion;
|
|
generated$2.tSTypeLiteral = generated$2.tsTypeLiteral = tsTypeLiteral;
|
|
generated$2.tSTypeOperator = generated$2.tsTypeOperator = tsTypeOperator;
|
|
generated$2.tSTypeParameter = generated$2.tsTypeParameter = tsTypeParameter;
|
|
generated$2.tSTypeParameterDeclaration = generated$2.tsTypeParameterDeclaration = tsTypeParameterDeclaration;
|
|
generated$2.tSTypeParameterInstantiation = generated$2.tsTypeParameterInstantiation = tsTypeParameterInstantiation;
|
|
generated$2.tSTypePredicate = generated$2.tsTypePredicate = tsTypePredicate;
|
|
generated$2.tSTypeQuery = generated$2.tsTypeQuery = tsTypeQuery;
|
|
generated$2.tSTypeReference = generated$2.tsTypeReference = tsTypeReference;
|
|
generated$2.tSUndefinedKeyword = generated$2.tsUndefinedKeyword = tsUndefinedKeyword;
|
|
generated$2.tSUnionType = generated$2.tsUnionType = tsUnionType;
|
|
generated$2.tSUnknownKeyword = generated$2.tsUnknownKeyword = tsUnknownKeyword;
|
|
generated$2.tSVoidKeyword = generated$2.tsVoidKeyword = tsVoidKeyword;
|
|
generated$2.tupleExpression = tupleExpression;
|
|
generated$2.tupleTypeAnnotation = tupleTypeAnnotation;
|
|
generated$2.typeAlias = typeAlias;
|
|
generated$2.typeAnnotation = typeAnnotation;
|
|
generated$2.typeCastExpression = typeCastExpression;
|
|
generated$2.typeParameter = typeParameter;
|
|
generated$2.typeParameterDeclaration = typeParameterDeclaration;
|
|
generated$2.typeParameterInstantiation = typeParameterInstantiation;
|
|
generated$2.typeofTypeAnnotation = typeofTypeAnnotation;
|
|
generated$2.unaryExpression = unaryExpression;
|
|
generated$2.unionTypeAnnotation = unionTypeAnnotation;
|
|
generated$2.updateExpression = updateExpression;
|
|
generated$2.v8IntrinsicIdentifier = v8IntrinsicIdentifier;
|
|
generated$2.variableDeclaration = variableDeclaration;
|
|
generated$2.variableDeclarator = variableDeclarator;
|
|
generated$2.variance = variance;
|
|
generated$2.voidTypeAnnotation = voidTypeAnnotation;
|
|
generated$2.whileStatement = whileStatement;
|
|
generated$2.withStatement = withStatement;
|
|
generated$2.yieldExpression = yieldExpression;
|
|
var _validate = requireValidate();
|
|
var _deprecationWarning = requireDeprecationWarning();
|
|
var utils = requireUtils();
|
|
const {
|
|
validateInternal: validate
|
|
} = _validate;
|
|
const {
|
|
NODE_FIELDS
|
|
} = utils;
|
|
function arrayExpression(elements = []) {
|
|
const node = {
|
|
type: "ArrayExpression",
|
|
elements
|
|
};
|
|
const defs = NODE_FIELDS.ArrayExpression;
|
|
validate(defs.elements, node, "elements", elements, 1);
|
|
return node;
|
|
}
|
|
function assignmentExpression(operator, left, right) {
|
|
const node = {
|
|
type: "AssignmentExpression",
|
|
operator,
|
|
left,
|
|
right
|
|
};
|
|
const defs = NODE_FIELDS.AssignmentExpression;
|
|
validate(defs.operator, node, "operator", operator);
|
|
validate(defs.left, node, "left", left, 1);
|
|
validate(defs.right, node, "right", right, 1);
|
|
return node;
|
|
}
|
|
function binaryExpression(operator, left, right) {
|
|
const node = {
|
|
type: "BinaryExpression",
|
|
operator,
|
|
left,
|
|
right
|
|
};
|
|
const defs = NODE_FIELDS.BinaryExpression;
|
|
validate(defs.operator, node, "operator", operator);
|
|
validate(defs.left, node, "left", left, 1);
|
|
validate(defs.right, node, "right", right, 1);
|
|
return node;
|
|
}
|
|
function interpreterDirective(value) {
|
|
const node = {
|
|
type: "InterpreterDirective",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.InterpreterDirective;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function directive(value) {
|
|
const node = {
|
|
type: "Directive",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.Directive;
|
|
validate(defs.value, node, "value", value, 1);
|
|
return node;
|
|
}
|
|
function directiveLiteral(value) {
|
|
const node = {
|
|
type: "DirectiveLiteral",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.DirectiveLiteral;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function blockStatement(body, directives = []) {
|
|
const node = {
|
|
type: "BlockStatement",
|
|
body,
|
|
directives
|
|
};
|
|
const defs = NODE_FIELDS.BlockStatement;
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.directives, node, "directives", directives, 1);
|
|
return node;
|
|
}
|
|
function breakStatement(label = null) {
|
|
const node = {
|
|
type: "BreakStatement",
|
|
label
|
|
};
|
|
const defs = NODE_FIELDS.BreakStatement;
|
|
validate(defs.label, node, "label", label, 1);
|
|
return node;
|
|
}
|
|
function callExpression(callee, _arguments) {
|
|
const node = {
|
|
type: "CallExpression",
|
|
callee,
|
|
arguments: _arguments
|
|
};
|
|
const defs = NODE_FIELDS.CallExpression;
|
|
validate(defs.callee, node, "callee", callee, 1);
|
|
validate(defs.arguments, node, "arguments", _arguments, 1);
|
|
return node;
|
|
}
|
|
function catchClause(param = null, body) {
|
|
const node = {
|
|
type: "CatchClause",
|
|
param,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.CatchClause;
|
|
validate(defs.param, node, "param", param, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function conditionalExpression(test, consequent, alternate) {
|
|
const node = {
|
|
type: "ConditionalExpression",
|
|
test,
|
|
consequent,
|
|
alternate
|
|
};
|
|
const defs = NODE_FIELDS.ConditionalExpression;
|
|
validate(defs.test, node, "test", test, 1);
|
|
validate(defs.consequent, node, "consequent", consequent, 1);
|
|
validate(defs.alternate, node, "alternate", alternate, 1);
|
|
return node;
|
|
}
|
|
function continueStatement(label = null) {
|
|
const node = {
|
|
type: "ContinueStatement",
|
|
label
|
|
};
|
|
const defs = NODE_FIELDS.ContinueStatement;
|
|
validate(defs.label, node, "label", label, 1);
|
|
return node;
|
|
}
|
|
function debuggerStatement() {
|
|
return {
|
|
type: "DebuggerStatement"
|
|
};
|
|
}
|
|
function doWhileStatement(test, body) {
|
|
const node = {
|
|
type: "DoWhileStatement",
|
|
test,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.DoWhileStatement;
|
|
validate(defs.test, node, "test", test, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function emptyStatement() {
|
|
return {
|
|
type: "EmptyStatement"
|
|
};
|
|
}
|
|
function expressionStatement(expression) {
|
|
const node = {
|
|
type: "ExpressionStatement",
|
|
expression
|
|
};
|
|
const defs = NODE_FIELDS.ExpressionStatement;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
return node;
|
|
}
|
|
function file(program, comments = null, tokens = null) {
|
|
const node = {
|
|
type: "File",
|
|
program,
|
|
comments,
|
|
tokens
|
|
};
|
|
const defs = NODE_FIELDS.File;
|
|
validate(defs.program, node, "program", program, 1);
|
|
validate(defs.comments, node, "comments", comments, 1);
|
|
validate(defs.tokens, node, "tokens", tokens);
|
|
return node;
|
|
}
|
|
function forInStatement(left, right, body) {
|
|
const node = {
|
|
type: "ForInStatement",
|
|
left,
|
|
right,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.ForInStatement;
|
|
validate(defs.left, node, "left", left, 1);
|
|
validate(defs.right, node, "right", right, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function forStatement(init = null, test = null, update = null, body) {
|
|
const node = {
|
|
type: "ForStatement",
|
|
init,
|
|
test,
|
|
update,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.ForStatement;
|
|
validate(defs.init, node, "init", init, 1);
|
|
validate(defs.test, node, "test", test, 1);
|
|
validate(defs.update, node, "update", update, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function functionDeclaration(id = null, params, body, generator = false, async = false) {
|
|
const node = {
|
|
type: "FunctionDeclaration",
|
|
id,
|
|
params,
|
|
body,
|
|
generator,
|
|
async
|
|
};
|
|
const defs = NODE_FIELDS.FunctionDeclaration;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.params, node, "params", params, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.generator, node, "generator", generator);
|
|
validate(defs.async, node, "async", async);
|
|
return node;
|
|
}
|
|
function functionExpression(id = null, params, body, generator = false, async = false) {
|
|
const node = {
|
|
type: "FunctionExpression",
|
|
id,
|
|
params,
|
|
body,
|
|
generator,
|
|
async
|
|
};
|
|
const defs = NODE_FIELDS.FunctionExpression;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.params, node, "params", params, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.generator, node, "generator", generator);
|
|
validate(defs.async, node, "async", async);
|
|
return node;
|
|
}
|
|
function identifier(name) {
|
|
const node = {
|
|
type: "Identifier",
|
|
name
|
|
};
|
|
const defs = NODE_FIELDS.Identifier;
|
|
validate(defs.name, node, "name", name);
|
|
return node;
|
|
}
|
|
function ifStatement(test, consequent, alternate = null) {
|
|
const node = {
|
|
type: "IfStatement",
|
|
test,
|
|
consequent,
|
|
alternate
|
|
};
|
|
const defs = NODE_FIELDS.IfStatement;
|
|
validate(defs.test, node, "test", test, 1);
|
|
validate(defs.consequent, node, "consequent", consequent, 1);
|
|
validate(defs.alternate, node, "alternate", alternate, 1);
|
|
return node;
|
|
}
|
|
function labeledStatement(label, body) {
|
|
const node = {
|
|
type: "LabeledStatement",
|
|
label,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.LabeledStatement;
|
|
validate(defs.label, node, "label", label, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function stringLiteral(value) {
|
|
const node = {
|
|
type: "StringLiteral",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.StringLiteral;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function numericLiteral(value) {
|
|
const node = {
|
|
type: "NumericLiteral",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.NumericLiteral;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function nullLiteral() {
|
|
return {
|
|
type: "NullLiteral"
|
|
};
|
|
}
|
|
function booleanLiteral(value) {
|
|
const node = {
|
|
type: "BooleanLiteral",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.BooleanLiteral;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function regExpLiteral(pattern, flags = "") {
|
|
const node = {
|
|
type: "RegExpLiteral",
|
|
pattern,
|
|
flags
|
|
};
|
|
const defs = NODE_FIELDS.RegExpLiteral;
|
|
validate(defs.pattern, node, "pattern", pattern);
|
|
validate(defs.flags, node, "flags", flags);
|
|
return node;
|
|
}
|
|
function logicalExpression(operator, left, right) {
|
|
const node = {
|
|
type: "LogicalExpression",
|
|
operator,
|
|
left,
|
|
right
|
|
};
|
|
const defs = NODE_FIELDS.LogicalExpression;
|
|
validate(defs.operator, node, "operator", operator);
|
|
validate(defs.left, node, "left", left, 1);
|
|
validate(defs.right, node, "right", right, 1);
|
|
return node;
|
|
}
|
|
function memberExpression(object, property, computed = false, optional = null) {
|
|
const node = {
|
|
type: "MemberExpression",
|
|
object,
|
|
property,
|
|
computed,
|
|
optional
|
|
};
|
|
const defs = NODE_FIELDS.MemberExpression;
|
|
validate(defs.object, node, "object", object, 1);
|
|
validate(defs.property, node, "property", property, 1);
|
|
validate(defs.computed, node, "computed", computed);
|
|
validate(defs.optional, node, "optional", optional);
|
|
return node;
|
|
}
|
|
function newExpression(callee, _arguments) {
|
|
const node = {
|
|
type: "NewExpression",
|
|
callee,
|
|
arguments: _arguments
|
|
};
|
|
const defs = NODE_FIELDS.NewExpression;
|
|
validate(defs.callee, node, "callee", callee, 1);
|
|
validate(defs.arguments, node, "arguments", _arguments, 1);
|
|
return node;
|
|
}
|
|
function program(body, directives = [], sourceType = "script", interpreter = null) {
|
|
const node = {
|
|
type: "Program",
|
|
body,
|
|
directives,
|
|
sourceType,
|
|
interpreter
|
|
};
|
|
const defs = NODE_FIELDS.Program;
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.directives, node, "directives", directives, 1);
|
|
validate(defs.sourceType, node, "sourceType", sourceType);
|
|
validate(defs.interpreter, node, "interpreter", interpreter, 1);
|
|
return node;
|
|
}
|
|
function objectExpression(properties) {
|
|
const node = {
|
|
type: "ObjectExpression",
|
|
properties
|
|
};
|
|
const defs = NODE_FIELDS.ObjectExpression;
|
|
validate(defs.properties, node, "properties", properties, 1);
|
|
return node;
|
|
}
|
|
function objectMethod(kind = "method", key, params, body, computed = false, generator = false, async = false) {
|
|
const node = {
|
|
type: "ObjectMethod",
|
|
kind,
|
|
key,
|
|
params,
|
|
body,
|
|
computed,
|
|
generator,
|
|
async
|
|
};
|
|
const defs = NODE_FIELDS.ObjectMethod;
|
|
validate(defs.kind, node, "kind", kind);
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.params, node, "params", params, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.computed, node, "computed", computed);
|
|
validate(defs.generator, node, "generator", generator);
|
|
validate(defs.async, node, "async", async);
|
|
return node;
|
|
}
|
|
function objectProperty(key, value, computed = false, shorthand = false, decorators = null) {
|
|
const node = {
|
|
type: "ObjectProperty",
|
|
key,
|
|
value,
|
|
computed,
|
|
shorthand,
|
|
decorators
|
|
};
|
|
const defs = NODE_FIELDS.ObjectProperty;
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.value, node, "value", value, 1);
|
|
validate(defs.computed, node, "computed", computed);
|
|
validate(defs.shorthand, node, "shorthand", shorthand);
|
|
validate(defs.decorators, node, "decorators", decorators, 1);
|
|
return node;
|
|
}
|
|
function restElement(argument) {
|
|
const node = {
|
|
type: "RestElement",
|
|
argument
|
|
};
|
|
const defs = NODE_FIELDS.RestElement;
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
return node;
|
|
}
|
|
function returnStatement(argument = null) {
|
|
const node = {
|
|
type: "ReturnStatement",
|
|
argument
|
|
};
|
|
const defs = NODE_FIELDS.ReturnStatement;
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
return node;
|
|
}
|
|
function sequenceExpression(expressions) {
|
|
const node = {
|
|
type: "SequenceExpression",
|
|
expressions
|
|
};
|
|
const defs = NODE_FIELDS.SequenceExpression;
|
|
validate(defs.expressions, node, "expressions", expressions, 1);
|
|
return node;
|
|
}
|
|
function parenthesizedExpression(expression) {
|
|
const node = {
|
|
type: "ParenthesizedExpression",
|
|
expression
|
|
};
|
|
const defs = NODE_FIELDS.ParenthesizedExpression;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
return node;
|
|
}
|
|
function switchCase(test = null, consequent) {
|
|
const node = {
|
|
type: "SwitchCase",
|
|
test,
|
|
consequent
|
|
};
|
|
const defs = NODE_FIELDS.SwitchCase;
|
|
validate(defs.test, node, "test", test, 1);
|
|
validate(defs.consequent, node, "consequent", consequent, 1);
|
|
return node;
|
|
}
|
|
function switchStatement(discriminant, cases) {
|
|
const node = {
|
|
type: "SwitchStatement",
|
|
discriminant,
|
|
cases
|
|
};
|
|
const defs = NODE_FIELDS.SwitchStatement;
|
|
validate(defs.discriminant, node, "discriminant", discriminant, 1);
|
|
validate(defs.cases, node, "cases", cases, 1);
|
|
return node;
|
|
}
|
|
function thisExpression() {
|
|
return {
|
|
type: "ThisExpression"
|
|
};
|
|
}
|
|
function throwStatement(argument) {
|
|
const node = {
|
|
type: "ThrowStatement",
|
|
argument
|
|
};
|
|
const defs = NODE_FIELDS.ThrowStatement;
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
return node;
|
|
}
|
|
function tryStatement(block, handler = null, finalizer = null) {
|
|
const node = {
|
|
type: "TryStatement",
|
|
block,
|
|
handler,
|
|
finalizer
|
|
};
|
|
const defs = NODE_FIELDS.TryStatement;
|
|
validate(defs.block, node, "block", block, 1);
|
|
validate(defs.handler, node, "handler", handler, 1);
|
|
validate(defs.finalizer, node, "finalizer", finalizer, 1);
|
|
return node;
|
|
}
|
|
function unaryExpression(operator, argument, prefix = true) {
|
|
const node = {
|
|
type: "UnaryExpression",
|
|
operator,
|
|
argument,
|
|
prefix
|
|
};
|
|
const defs = NODE_FIELDS.UnaryExpression;
|
|
validate(defs.operator, node, "operator", operator);
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
validate(defs.prefix, node, "prefix", prefix);
|
|
return node;
|
|
}
|
|
function updateExpression(operator, argument, prefix = false) {
|
|
const node = {
|
|
type: "UpdateExpression",
|
|
operator,
|
|
argument,
|
|
prefix
|
|
};
|
|
const defs = NODE_FIELDS.UpdateExpression;
|
|
validate(defs.operator, node, "operator", operator);
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
validate(defs.prefix, node, "prefix", prefix);
|
|
return node;
|
|
}
|
|
function variableDeclaration(kind, declarations) {
|
|
const node = {
|
|
type: "VariableDeclaration",
|
|
kind,
|
|
declarations
|
|
};
|
|
const defs = NODE_FIELDS.VariableDeclaration;
|
|
validate(defs.kind, node, "kind", kind);
|
|
validate(defs.declarations, node, "declarations", declarations, 1);
|
|
return node;
|
|
}
|
|
function variableDeclarator(id, init = null) {
|
|
const node = {
|
|
type: "VariableDeclarator",
|
|
id,
|
|
init
|
|
};
|
|
const defs = NODE_FIELDS.VariableDeclarator;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.init, node, "init", init, 1);
|
|
return node;
|
|
}
|
|
function whileStatement(test, body) {
|
|
const node = {
|
|
type: "WhileStatement",
|
|
test,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.WhileStatement;
|
|
validate(defs.test, node, "test", test, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function withStatement(object, body) {
|
|
const node = {
|
|
type: "WithStatement",
|
|
object,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.WithStatement;
|
|
validate(defs.object, node, "object", object, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function assignmentPattern(left, right) {
|
|
const node = {
|
|
type: "AssignmentPattern",
|
|
left,
|
|
right
|
|
};
|
|
const defs = NODE_FIELDS.AssignmentPattern;
|
|
validate(defs.left, node, "left", left, 1);
|
|
validate(defs.right, node, "right", right, 1);
|
|
return node;
|
|
}
|
|
function arrayPattern(elements) {
|
|
const node = {
|
|
type: "ArrayPattern",
|
|
elements
|
|
};
|
|
const defs = NODE_FIELDS.ArrayPattern;
|
|
validate(defs.elements, node, "elements", elements, 1);
|
|
return node;
|
|
}
|
|
function arrowFunctionExpression(params, body, async = false) {
|
|
const node = {
|
|
type: "ArrowFunctionExpression",
|
|
params,
|
|
body,
|
|
async,
|
|
expression: null
|
|
};
|
|
const defs = NODE_FIELDS.ArrowFunctionExpression;
|
|
validate(defs.params, node, "params", params, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.async, node, "async", async);
|
|
return node;
|
|
}
|
|
function classBody(body) {
|
|
const node = {
|
|
type: "ClassBody",
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.ClassBody;
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function classExpression(id = null, superClass = null, body, decorators = null) {
|
|
const node = {
|
|
type: "ClassExpression",
|
|
id,
|
|
superClass,
|
|
body,
|
|
decorators
|
|
};
|
|
const defs = NODE_FIELDS.ClassExpression;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.superClass, node, "superClass", superClass, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.decorators, node, "decorators", decorators, 1);
|
|
return node;
|
|
}
|
|
function classDeclaration(id = null, superClass = null, body, decorators = null) {
|
|
const node = {
|
|
type: "ClassDeclaration",
|
|
id,
|
|
superClass,
|
|
body,
|
|
decorators
|
|
};
|
|
const defs = NODE_FIELDS.ClassDeclaration;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.superClass, node, "superClass", superClass, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.decorators, node, "decorators", decorators, 1);
|
|
return node;
|
|
}
|
|
function exportAllDeclaration(source) {
|
|
const node = {
|
|
type: "ExportAllDeclaration",
|
|
source
|
|
};
|
|
const defs = NODE_FIELDS.ExportAllDeclaration;
|
|
validate(defs.source, node, "source", source, 1);
|
|
return node;
|
|
}
|
|
function exportDefaultDeclaration(declaration) {
|
|
const node = {
|
|
type: "ExportDefaultDeclaration",
|
|
declaration
|
|
};
|
|
const defs = NODE_FIELDS.ExportDefaultDeclaration;
|
|
validate(defs.declaration, node, "declaration", declaration, 1);
|
|
return node;
|
|
}
|
|
function exportNamedDeclaration(declaration = null, specifiers = [], source = null) {
|
|
const node = {
|
|
type: "ExportNamedDeclaration",
|
|
declaration,
|
|
specifiers,
|
|
source
|
|
};
|
|
const defs = NODE_FIELDS.ExportNamedDeclaration;
|
|
validate(defs.declaration, node, "declaration", declaration, 1);
|
|
validate(defs.specifiers, node, "specifiers", specifiers, 1);
|
|
validate(defs.source, node, "source", source, 1);
|
|
return node;
|
|
}
|
|
function exportSpecifier(local, exported) {
|
|
const node = {
|
|
type: "ExportSpecifier",
|
|
local,
|
|
exported
|
|
};
|
|
const defs = NODE_FIELDS.ExportSpecifier;
|
|
validate(defs.local, node, "local", local, 1);
|
|
validate(defs.exported, node, "exported", exported, 1);
|
|
return node;
|
|
}
|
|
function forOfStatement(left, right, body, _await = false) {
|
|
const node = {
|
|
type: "ForOfStatement",
|
|
left,
|
|
right,
|
|
body,
|
|
await: _await
|
|
};
|
|
const defs = NODE_FIELDS.ForOfStatement;
|
|
validate(defs.left, node, "left", left, 1);
|
|
validate(defs.right, node, "right", right, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.await, node, "await", _await);
|
|
return node;
|
|
}
|
|
function importDeclaration(specifiers, source) {
|
|
const node = {
|
|
type: "ImportDeclaration",
|
|
specifiers,
|
|
source
|
|
};
|
|
const defs = NODE_FIELDS.ImportDeclaration;
|
|
validate(defs.specifiers, node, "specifiers", specifiers, 1);
|
|
validate(defs.source, node, "source", source, 1);
|
|
return node;
|
|
}
|
|
function importDefaultSpecifier(local) {
|
|
const node = {
|
|
type: "ImportDefaultSpecifier",
|
|
local
|
|
};
|
|
const defs = NODE_FIELDS.ImportDefaultSpecifier;
|
|
validate(defs.local, node, "local", local, 1);
|
|
return node;
|
|
}
|
|
function importNamespaceSpecifier(local) {
|
|
const node = {
|
|
type: "ImportNamespaceSpecifier",
|
|
local
|
|
};
|
|
const defs = NODE_FIELDS.ImportNamespaceSpecifier;
|
|
validate(defs.local, node, "local", local, 1);
|
|
return node;
|
|
}
|
|
function importSpecifier(local, imported) {
|
|
const node = {
|
|
type: "ImportSpecifier",
|
|
local,
|
|
imported
|
|
};
|
|
const defs = NODE_FIELDS.ImportSpecifier;
|
|
validate(defs.local, node, "local", local, 1);
|
|
validate(defs.imported, node, "imported", imported, 1);
|
|
return node;
|
|
}
|
|
function importExpression(source, options = null) {
|
|
const node = {
|
|
type: "ImportExpression",
|
|
source,
|
|
options
|
|
};
|
|
const defs = NODE_FIELDS.ImportExpression;
|
|
validate(defs.source, node, "source", source, 1);
|
|
validate(defs.options, node, "options", options, 1);
|
|
return node;
|
|
}
|
|
function metaProperty(meta, property) {
|
|
const node = {
|
|
type: "MetaProperty",
|
|
meta,
|
|
property
|
|
};
|
|
const defs = NODE_FIELDS.MetaProperty;
|
|
validate(defs.meta, node, "meta", meta, 1);
|
|
validate(defs.property, node, "property", property, 1);
|
|
return node;
|
|
}
|
|
function classMethod(kind = "method", key, params, body, computed = false, _static = false, generator = false, async = false) {
|
|
const node = {
|
|
type: "ClassMethod",
|
|
kind,
|
|
key,
|
|
params,
|
|
body,
|
|
computed,
|
|
static: _static,
|
|
generator,
|
|
async
|
|
};
|
|
const defs = NODE_FIELDS.ClassMethod;
|
|
validate(defs.kind, node, "kind", kind);
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.params, node, "params", params, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.computed, node, "computed", computed);
|
|
validate(defs.static, node, "static", _static);
|
|
validate(defs.generator, node, "generator", generator);
|
|
validate(defs.async, node, "async", async);
|
|
return node;
|
|
}
|
|
function objectPattern(properties) {
|
|
const node = {
|
|
type: "ObjectPattern",
|
|
properties
|
|
};
|
|
const defs = NODE_FIELDS.ObjectPattern;
|
|
validate(defs.properties, node, "properties", properties, 1);
|
|
return node;
|
|
}
|
|
function spreadElement(argument) {
|
|
const node = {
|
|
type: "SpreadElement",
|
|
argument
|
|
};
|
|
const defs = NODE_FIELDS.SpreadElement;
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
return node;
|
|
}
|
|
function _super() {
|
|
return {
|
|
type: "Super"
|
|
};
|
|
}
|
|
function taggedTemplateExpression(tag, quasi) {
|
|
const node = {
|
|
type: "TaggedTemplateExpression",
|
|
tag,
|
|
quasi
|
|
};
|
|
const defs = NODE_FIELDS.TaggedTemplateExpression;
|
|
validate(defs.tag, node, "tag", tag, 1);
|
|
validate(defs.quasi, node, "quasi", quasi, 1);
|
|
return node;
|
|
}
|
|
function templateElement(value, tail = false) {
|
|
const node = {
|
|
type: "TemplateElement",
|
|
value,
|
|
tail
|
|
};
|
|
const defs = NODE_FIELDS.TemplateElement;
|
|
validate(defs.value, node, "value", value);
|
|
validate(defs.tail, node, "tail", tail);
|
|
return node;
|
|
}
|
|
function templateLiteral(quasis, expressions) {
|
|
const node = {
|
|
type: "TemplateLiteral",
|
|
quasis,
|
|
expressions
|
|
};
|
|
const defs = NODE_FIELDS.TemplateLiteral;
|
|
validate(defs.quasis, node, "quasis", quasis, 1);
|
|
validate(defs.expressions, node, "expressions", expressions, 1);
|
|
return node;
|
|
}
|
|
function yieldExpression(argument = null, delegate = false) {
|
|
const node = {
|
|
type: "YieldExpression",
|
|
argument,
|
|
delegate
|
|
};
|
|
const defs = NODE_FIELDS.YieldExpression;
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
validate(defs.delegate, node, "delegate", delegate);
|
|
return node;
|
|
}
|
|
function awaitExpression(argument) {
|
|
const node = {
|
|
type: "AwaitExpression",
|
|
argument
|
|
};
|
|
const defs = NODE_FIELDS.AwaitExpression;
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
return node;
|
|
}
|
|
function _import() {
|
|
return {
|
|
type: "Import"
|
|
};
|
|
}
|
|
function bigIntLiteral(value) {
|
|
const node = {
|
|
type: "BigIntLiteral",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.BigIntLiteral;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function exportNamespaceSpecifier(exported) {
|
|
const node = {
|
|
type: "ExportNamespaceSpecifier",
|
|
exported
|
|
};
|
|
const defs = NODE_FIELDS.ExportNamespaceSpecifier;
|
|
validate(defs.exported, node, "exported", exported, 1);
|
|
return node;
|
|
}
|
|
function optionalMemberExpression(object, property, computed = false, optional) {
|
|
const node = {
|
|
type: "OptionalMemberExpression",
|
|
object,
|
|
property,
|
|
computed,
|
|
optional
|
|
};
|
|
const defs = NODE_FIELDS.OptionalMemberExpression;
|
|
validate(defs.object, node, "object", object, 1);
|
|
validate(defs.property, node, "property", property, 1);
|
|
validate(defs.computed, node, "computed", computed);
|
|
validate(defs.optional, node, "optional", optional);
|
|
return node;
|
|
}
|
|
function optionalCallExpression(callee, _arguments, optional) {
|
|
const node = {
|
|
type: "OptionalCallExpression",
|
|
callee,
|
|
arguments: _arguments,
|
|
optional
|
|
};
|
|
const defs = NODE_FIELDS.OptionalCallExpression;
|
|
validate(defs.callee, node, "callee", callee, 1);
|
|
validate(defs.arguments, node, "arguments", _arguments, 1);
|
|
validate(defs.optional, node, "optional", optional);
|
|
return node;
|
|
}
|
|
function classProperty(key, value = null, typeAnnotation = null, decorators = null, computed = false, _static = false) {
|
|
const node = {
|
|
type: "ClassProperty",
|
|
key,
|
|
value,
|
|
typeAnnotation,
|
|
decorators,
|
|
computed,
|
|
static: _static
|
|
};
|
|
const defs = NODE_FIELDS.ClassProperty;
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.value, node, "value", value, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
validate(defs.decorators, node, "decorators", decorators, 1);
|
|
validate(defs.computed, node, "computed", computed);
|
|
validate(defs.static, node, "static", _static);
|
|
return node;
|
|
}
|
|
function classAccessorProperty(key, value = null, typeAnnotation = null, decorators = null, computed = false, _static = false) {
|
|
const node = {
|
|
type: "ClassAccessorProperty",
|
|
key,
|
|
value,
|
|
typeAnnotation,
|
|
decorators,
|
|
computed,
|
|
static: _static
|
|
};
|
|
const defs = NODE_FIELDS.ClassAccessorProperty;
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.value, node, "value", value, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
validate(defs.decorators, node, "decorators", decorators, 1);
|
|
validate(defs.computed, node, "computed", computed);
|
|
validate(defs.static, node, "static", _static);
|
|
return node;
|
|
}
|
|
function classPrivateProperty(key, value = null, decorators = null, _static = false) {
|
|
const node = {
|
|
type: "ClassPrivateProperty",
|
|
key,
|
|
value,
|
|
decorators,
|
|
static: _static
|
|
};
|
|
const defs = NODE_FIELDS.ClassPrivateProperty;
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.value, node, "value", value, 1);
|
|
validate(defs.decorators, node, "decorators", decorators, 1);
|
|
validate(defs.static, node, "static", _static);
|
|
return node;
|
|
}
|
|
function classPrivateMethod(kind = "method", key, params, body, _static = false) {
|
|
const node = {
|
|
type: "ClassPrivateMethod",
|
|
kind,
|
|
key,
|
|
params,
|
|
body,
|
|
static: _static
|
|
};
|
|
const defs = NODE_FIELDS.ClassPrivateMethod;
|
|
validate(defs.kind, node, "kind", kind);
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.params, node, "params", params, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.static, node, "static", _static);
|
|
return node;
|
|
}
|
|
function privateName(id) {
|
|
const node = {
|
|
type: "PrivateName",
|
|
id
|
|
};
|
|
const defs = NODE_FIELDS.PrivateName;
|
|
validate(defs.id, node, "id", id, 1);
|
|
return node;
|
|
}
|
|
function staticBlock(body) {
|
|
const node = {
|
|
type: "StaticBlock",
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.StaticBlock;
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function anyTypeAnnotation() {
|
|
return {
|
|
type: "AnyTypeAnnotation"
|
|
};
|
|
}
|
|
function arrayTypeAnnotation(elementType) {
|
|
const node = {
|
|
type: "ArrayTypeAnnotation",
|
|
elementType
|
|
};
|
|
const defs = NODE_FIELDS.ArrayTypeAnnotation;
|
|
validate(defs.elementType, node, "elementType", elementType, 1);
|
|
return node;
|
|
}
|
|
function booleanTypeAnnotation() {
|
|
return {
|
|
type: "BooleanTypeAnnotation"
|
|
};
|
|
}
|
|
function booleanLiteralTypeAnnotation(value) {
|
|
const node = {
|
|
type: "BooleanLiteralTypeAnnotation",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.BooleanLiteralTypeAnnotation;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function nullLiteralTypeAnnotation() {
|
|
return {
|
|
type: "NullLiteralTypeAnnotation"
|
|
};
|
|
}
|
|
function classImplements(id, typeParameters = null) {
|
|
const node = {
|
|
type: "ClassImplements",
|
|
id,
|
|
typeParameters
|
|
};
|
|
const defs = NODE_FIELDS.ClassImplements;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
return node;
|
|
}
|
|
function declareClass(id, typeParameters = null, _extends = null, body) {
|
|
const node = {
|
|
type: "DeclareClass",
|
|
id,
|
|
typeParameters,
|
|
extends: _extends,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.DeclareClass;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.extends, node, "extends", _extends, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function declareFunction(id) {
|
|
const node = {
|
|
type: "DeclareFunction",
|
|
id
|
|
};
|
|
const defs = NODE_FIELDS.DeclareFunction;
|
|
validate(defs.id, node, "id", id, 1);
|
|
return node;
|
|
}
|
|
function declareInterface(id, typeParameters = null, _extends = null, body) {
|
|
const node = {
|
|
type: "DeclareInterface",
|
|
id,
|
|
typeParameters,
|
|
extends: _extends,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.DeclareInterface;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.extends, node, "extends", _extends, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function declareModule(id, body, kind = null) {
|
|
const node = {
|
|
type: "DeclareModule",
|
|
id,
|
|
body,
|
|
kind
|
|
};
|
|
const defs = NODE_FIELDS.DeclareModule;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.kind, node, "kind", kind);
|
|
return node;
|
|
}
|
|
function declareModuleExports(typeAnnotation) {
|
|
const node = {
|
|
type: "DeclareModuleExports",
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.DeclareModuleExports;
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function declareTypeAlias(id, typeParameters = null, right) {
|
|
const node = {
|
|
type: "DeclareTypeAlias",
|
|
id,
|
|
typeParameters,
|
|
right
|
|
};
|
|
const defs = NODE_FIELDS.DeclareTypeAlias;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.right, node, "right", right, 1);
|
|
return node;
|
|
}
|
|
function declareOpaqueType(id, typeParameters = null, supertype = null) {
|
|
const node = {
|
|
type: "DeclareOpaqueType",
|
|
id,
|
|
typeParameters,
|
|
supertype
|
|
};
|
|
const defs = NODE_FIELDS.DeclareOpaqueType;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.supertype, node, "supertype", supertype, 1);
|
|
return node;
|
|
}
|
|
function declareVariable(id) {
|
|
const node = {
|
|
type: "DeclareVariable",
|
|
id
|
|
};
|
|
const defs = NODE_FIELDS.DeclareVariable;
|
|
validate(defs.id, node, "id", id, 1);
|
|
return node;
|
|
}
|
|
function declareExportDeclaration(declaration = null, specifiers = null, source = null, attributes = null) {
|
|
const node = {
|
|
type: "DeclareExportDeclaration",
|
|
declaration,
|
|
specifiers,
|
|
source,
|
|
attributes
|
|
};
|
|
const defs = NODE_FIELDS.DeclareExportDeclaration;
|
|
validate(defs.declaration, node, "declaration", declaration, 1);
|
|
validate(defs.specifiers, node, "specifiers", specifiers, 1);
|
|
validate(defs.source, node, "source", source, 1);
|
|
validate(defs.attributes, node, "attributes", attributes, 1);
|
|
return node;
|
|
}
|
|
function declareExportAllDeclaration(source, attributes = null) {
|
|
const node = {
|
|
type: "DeclareExportAllDeclaration",
|
|
source,
|
|
attributes
|
|
};
|
|
const defs = NODE_FIELDS.DeclareExportAllDeclaration;
|
|
validate(defs.source, node, "source", source, 1);
|
|
validate(defs.attributes, node, "attributes", attributes, 1);
|
|
return node;
|
|
}
|
|
function declaredPredicate(value) {
|
|
const node = {
|
|
type: "DeclaredPredicate",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.DeclaredPredicate;
|
|
validate(defs.value, node, "value", value, 1);
|
|
return node;
|
|
}
|
|
function existsTypeAnnotation() {
|
|
return {
|
|
type: "ExistsTypeAnnotation"
|
|
};
|
|
}
|
|
function functionTypeAnnotation(typeParameters = null, params, rest = null, returnType) {
|
|
const node = {
|
|
type: "FunctionTypeAnnotation",
|
|
typeParameters,
|
|
params,
|
|
rest,
|
|
returnType
|
|
};
|
|
const defs = NODE_FIELDS.FunctionTypeAnnotation;
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.params, node, "params", params, 1);
|
|
validate(defs.rest, node, "rest", rest, 1);
|
|
validate(defs.returnType, node, "returnType", returnType, 1);
|
|
return node;
|
|
}
|
|
function functionTypeParam(name = null, typeAnnotation) {
|
|
const node = {
|
|
type: "FunctionTypeParam",
|
|
name,
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.FunctionTypeParam;
|
|
validate(defs.name, node, "name", name, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function genericTypeAnnotation(id, typeParameters = null) {
|
|
const node = {
|
|
type: "GenericTypeAnnotation",
|
|
id,
|
|
typeParameters
|
|
};
|
|
const defs = NODE_FIELDS.GenericTypeAnnotation;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
return node;
|
|
}
|
|
function inferredPredicate() {
|
|
return {
|
|
type: "InferredPredicate"
|
|
};
|
|
}
|
|
function interfaceExtends(id, typeParameters = null) {
|
|
const node = {
|
|
type: "InterfaceExtends",
|
|
id,
|
|
typeParameters
|
|
};
|
|
const defs = NODE_FIELDS.InterfaceExtends;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
return node;
|
|
}
|
|
function interfaceDeclaration(id, typeParameters = null, _extends = null, body) {
|
|
const node = {
|
|
type: "InterfaceDeclaration",
|
|
id,
|
|
typeParameters,
|
|
extends: _extends,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.InterfaceDeclaration;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.extends, node, "extends", _extends, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function interfaceTypeAnnotation(_extends = null, body) {
|
|
const node = {
|
|
type: "InterfaceTypeAnnotation",
|
|
extends: _extends,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.InterfaceTypeAnnotation;
|
|
validate(defs.extends, node, "extends", _extends, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function intersectionTypeAnnotation(types) {
|
|
const node = {
|
|
type: "IntersectionTypeAnnotation",
|
|
types
|
|
};
|
|
const defs = NODE_FIELDS.IntersectionTypeAnnotation;
|
|
validate(defs.types, node, "types", types, 1);
|
|
return node;
|
|
}
|
|
function mixedTypeAnnotation() {
|
|
return {
|
|
type: "MixedTypeAnnotation"
|
|
};
|
|
}
|
|
function emptyTypeAnnotation() {
|
|
return {
|
|
type: "EmptyTypeAnnotation"
|
|
};
|
|
}
|
|
function nullableTypeAnnotation(typeAnnotation) {
|
|
const node = {
|
|
type: "NullableTypeAnnotation",
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.NullableTypeAnnotation;
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function numberLiteralTypeAnnotation(value) {
|
|
const node = {
|
|
type: "NumberLiteralTypeAnnotation",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.NumberLiteralTypeAnnotation;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function numberTypeAnnotation() {
|
|
return {
|
|
type: "NumberTypeAnnotation"
|
|
};
|
|
}
|
|
function objectTypeAnnotation(properties, indexers = [], callProperties = [], internalSlots = [], exact = false) {
|
|
const node = {
|
|
type: "ObjectTypeAnnotation",
|
|
properties,
|
|
indexers,
|
|
callProperties,
|
|
internalSlots,
|
|
exact
|
|
};
|
|
const defs = NODE_FIELDS.ObjectTypeAnnotation;
|
|
validate(defs.properties, node, "properties", properties, 1);
|
|
validate(defs.indexers, node, "indexers", indexers, 1);
|
|
validate(defs.callProperties, node, "callProperties", callProperties, 1);
|
|
validate(defs.internalSlots, node, "internalSlots", internalSlots, 1);
|
|
validate(defs.exact, node, "exact", exact);
|
|
return node;
|
|
}
|
|
function objectTypeInternalSlot(id, value, optional, _static, method) {
|
|
const node = {
|
|
type: "ObjectTypeInternalSlot",
|
|
id,
|
|
value,
|
|
optional,
|
|
static: _static,
|
|
method
|
|
};
|
|
const defs = NODE_FIELDS.ObjectTypeInternalSlot;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.value, node, "value", value, 1);
|
|
validate(defs.optional, node, "optional", optional);
|
|
validate(defs.static, node, "static", _static);
|
|
validate(defs.method, node, "method", method);
|
|
return node;
|
|
}
|
|
function objectTypeCallProperty(value) {
|
|
const node = {
|
|
type: "ObjectTypeCallProperty",
|
|
value,
|
|
static: null
|
|
};
|
|
const defs = NODE_FIELDS.ObjectTypeCallProperty;
|
|
validate(defs.value, node, "value", value, 1);
|
|
return node;
|
|
}
|
|
function objectTypeIndexer(id = null, key, value, variance = null) {
|
|
const node = {
|
|
type: "ObjectTypeIndexer",
|
|
id,
|
|
key,
|
|
value,
|
|
variance,
|
|
static: null
|
|
};
|
|
const defs = NODE_FIELDS.ObjectTypeIndexer;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.value, node, "value", value, 1);
|
|
validate(defs.variance, node, "variance", variance, 1);
|
|
return node;
|
|
}
|
|
function objectTypeProperty(key, value, variance = null) {
|
|
const node = {
|
|
type: "ObjectTypeProperty",
|
|
key,
|
|
value,
|
|
variance,
|
|
kind: null,
|
|
method: null,
|
|
optional: null,
|
|
proto: null,
|
|
static: null
|
|
};
|
|
const defs = NODE_FIELDS.ObjectTypeProperty;
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.value, node, "value", value, 1);
|
|
validate(defs.variance, node, "variance", variance, 1);
|
|
return node;
|
|
}
|
|
function objectTypeSpreadProperty(argument) {
|
|
const node = {
|
|
type: "ObjectTypeSpreadProperty",
|
|
argument
|
|
};
|
|
const defs = NODE_FIELDS.ObjectTypeSpreadProperty;
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
return node;
|
|
}
|
|
function opaqueType(id, typeParameters = null, supertype = null, impltype) {
|
|
const node = {
|
|
type: "OpaqueType",
|
|
id,
|
|
typeParameters,
|
|
supertype,
|
|
impltype
|
|
};
|
|
const defs = NODE_FIELDS.OpaqueType;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.supertype, node, "supertype", supertype, 1);
|
|
validate(defs.impltype, node, "impltype", impltype, 1);
|
|
return node;
|
|
}
|
|
function qualifiedTypeIdentifier(id, qualification) {
|
|
const node = {
|
|
type: "QualifiedTypeIdentifier",
|
|
id,
|
|
qualification
|
|
};
|
|
const defs = NODE_FIELDS.QualifiedTypeIdentifier;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.qualification, node, "qualification", qualification, 1);
|
|
return node;
|
|
}
|
|
function stringLiteralTypeAnnotation(value) {
|
|
const node = {
|
|
type: "StringLiteralTypeAnnotation",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.StringLiteralTypeAnnotation;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function stringTypeAnnotation() {
|
|
return {
|
|
type: "StringTypeAnnotation"
|
|
};
|
|
}
|
|
function symbolTypeAnnotation() {
|
|
return {
|
|
type: "SymbolTypeAnnotation"
|
|
};
|
|
}
|
|
function thisTypeAnnotation() {
|
|
return {
|
|
type: "ThisTypeAnnotation"
|
|
};
|
|
}
|
|
function tupleTypeAnnotation(types) {
|
|
const node = {
|
|
type: "TupleTypeAnnotation",
|
|
types
|
|
};
|
|
const defs = NODE_FIELDS.TupleTypeAnnotation;
|
|
validate(defs.types, node, "types", types, 1);
|
|
return node;
|
|
}
|
|
function typeofTypeAnnotation(argument) {
|
|
const node = {
|
|
type: "TypeofTypeAnnotation",
|
|
argument
|
|
};
|
|
const defs = NODE_FIELDS.TypeofTypeAnnotation;
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
return node;
|
|
}
|
|
function typeAlias(id, typeParameters = null, right) {
|
|
const node = {
|
|
type: "TypeAlias",
|
|
id,
|
|
typeParameters,
|
|
right
|
|
};
|
|
const defs = NODE_FIELDS.TypeAlias;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.right, node, "right", right, 1);
|
|
return node;
|
|
}
|
|
function typeAnnotation(typeAnnotation) {
|
|
const node = {
|
|
type: "TypeAnnotation",
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TypeAnnotation;
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function typeCastExpression(expression, typeAnnotation) {
|
|
const node = {
|
|
type: "TypeCastExpression",
|
|
expression,
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TypeCastExpression;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function typeParameter(bound = null, _default = null, variance = null) {
|
|
const node = {
|
|
type: "TypeParameter",
|
|
bound,
|
|
default: _default,
|
|
variance,
|
|
name: null
|
|
};
|
|
const defs = NODE_FIELDS.TypeParameter;
|
|
validate(defs.bound, node, "bound", bound, 1);
|
|
validate(defs.default, node, "default", _default, 1);
|
|
validate(defs.variance, node, "variance", variance, 1);
|
|
return node;
|
|
}
|
|
function typeParameterDeclaration(params) {
|
|
const node = {
|
|
type: "TypeParameterDeclaration",
|
|
params
|
|
};
|
|
const defs = NODE_FIELDS.TypeParameterDeclaration;
|
|
validate(defs.params, node, "params", params, 1);
|
|
return node;
|
|
}
|
|
function typeParameterInstantiation(params) {
|
|
const node = {
|
|
type: "TypeParameterInstantiation",
|
|
params
|
|
};
|
|
const defs = NODE_FIELDS.TypeParameterInstantiation;
|
|
validate(defs.params, node, "params", params, 1);
|
|
return node;
|
|
}
|
|
function unionTypeAnnotation(types) {
|
|
const node = {
|
|
type: "UnionTypeAnnotation",
|
|
types
|
|
};
|
|
const defs = NODE_FIELDS.UnionTypeAnnotation;
|
|
validate(defs.types, node, "types", types, 1);
|
|
return node;
|
|
}
|
|
function variance(kind) {
|
|
const node = {
|
|
type: "Variance",
|
|
kind
|
|
};
|
|
const defs = NODE_FIELDS.Variance;
|
|
validate(defs.kind, node, "kind", kind);
|
|
return node;
|
|
}
|
|
function voidTypeAnnotation() {
|
|
return {
|
|
type: "VoidTypeAnnotation"
|
|
};
|
|
}
|
|
function enumDeclaration(id, body) {
|
|
const node = {
|
|
type: "EnumDeclaration",
|
|
id,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.EnumDeclaration;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function enumBooleanBody(members) {
|
|
const node = {
|
|
type: "EnumBooleanBody",
|
|
members,
|
|
explicitType: null,
|
|
hasUnknownMembers: null
|
|
};
|
|
const defs = NODE_FIELDS.EnumBooleanBody;
|
|
validate(defs.members, node, "members", members, 1);
|
|
return node;
|
|
}
|
|
function enumNumberBody(members) {
|
|
const node = {
|
|
type: "EnumNumberBody",
|
|
members,
|
|
explicitType: null,
|
|
hasUnknownMembers: null
|
|
};
|
|
const defs = NODE_FIELDS.EnumNumberBody;
|
|
validate(defs.members, node, "members", members, 1);
|
|
return node;
|
|
}
|
|
function enumStringBody(members) {
|
|
const node = {
|
|
type: "EnumStringBody",
|
|
members,
|
|
explicitType: null,
|
|
hasUnknownMembers: null
|
|
};
|
|
const defs = NODE_FIELDS.EnumStringBody;
|
|
validate(defs.members, node, "members", members, 1);
|
|
return node;
|
|
}
|
|
function enumSymbolBody(members) {
|
|
const node = {
|
|
type: "EnumSymbolBody",
|
|
members,
|
|
hasUnknownMembers: null
|
|
};
|
|
const defs = NODE_FIELDS.EnumSymbolBody;
|
|
validate(defs.members, node, "members", members, 1);
|
|
return node;
|
|
}
|
|
function enumBooleanMember(id) {
|
|
const node = {
|
|
type: "EnumBooleanMember",
|
|
id,
|
|
init: null
|
|
};
|
|
const defs = NODE_FIELDS.EnumBooleanMember;
|
|
validate(defs.id, node, "id", id, 1);
|
|
return node;
|
|
}
|
|
function enumNumberMember(id, init) {
|
|
const node = {
|
|
type: "EnumNumberMember",
|
|
id,
|
|
init
|
|
};
|
|
const defs = NODE_FIELDS.EnumNumberMember;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.init, node, "init", init, 1);
|
|
return node;
|
|
}
|
|
function enumStringMember(id, init) {
|
|
const node = {
|
|
type: "EnumStringMember",
|
|
id,
|
|
init
|
|
};
|
|
const defs = NODE_FIELDS.EnumStringMember;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.init, node, "init", init, 1);
|
|
return node;
|
|
}
|
|
function enumDefaultedMember(id) {
|
|
const node = {
|
|
type: "EnumDefaultedMember",
|
|
id
|
|
};
|
|
const defs = NODE_FIELDS.EnumDefaultedMember;
|
|
validate(defs.id, node, "id", id, 1);
|
|
return node;
|
|
}
|
|
function indexedAccessType(objectType, indexType) {
|
|
const node = {
|
|
type: "IndexedAccessType",
|
|
objectType,
|
|
indexType
|
|
};
|
|
const defs = NODE_FIELDS.IndexedAccessType;
|
|
validate(defs.objectType, node, "objectType", objectType, 1);
|
|
validate(defs.indexType, node, "indexType", indexType, 1);
|
|
return node;
|
|
}
|
|
function optionalIndexedAccessType(objectType, indexType) {
|
|
const node = {
|
|
type: "OptionalIndexedAccessType",
|
|
objectType,
|
|
indexType,
|
|
optional: null
|
|
};
|
|
const defs = NODE_FIELDS.OptionalIndexedAccessType;
|
|
validate(defs.objectType, node, "objectType", objectType, 1);
|
|
validate(defs.indexType, node, "indexType", indexType, 1);
|
|
return node;
|
|
}
|
|
function jsxAttribute(name, value = null) {
|
|
const node = {
|
|
type: "JSXAttribute",
|
|
name,
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.JSXAttribute;
|
|
validate(defs.name, node, "name", name, 1);
|
|
validate(defs.value, node, "value", value, 1);
|
|
return node;
|
|
}
|
|
function jsxClosingElement(name) {
|
|
const node = {
|
|
type: "JSXClosingElement",
|
|
name
|
|
};
|
|
const defs = NODE_FIELDS.JSXClosingElement;
|
|
validate(defs.name, node, "name", name, 1);
|
|
return node;
|
|
}
|
|
function jsxElement(openingElement, closingElement = null, children, selfClosing = null) {
|
|
const node = {
|
|
type: "JSXElement",
|
|
openingElement,
|
|
closingElement,
|
|
children,
|
|
selfClosing
|
|
};
|
|
const defs = NODE_FIELDS.JSXElement;
|
|
validate(defs.openingElement, node, "openingElement", openingElement, 1);
|
|
validate(defs.closingElement, node, "closingElement", closingElement, 1);
|
|
validate(defs.children, node, "children", children, 1);
|
|
validate(defs.selfClosing, node, "selfClosing", selfClosing);
|
|
return node;
|
|
}
|
|
function jsxEmptyExpression() {
|
|
return {
|
|
type: "JSXEmptyExpression"
|
|
};
|
|
}
|
|
function jsxExpressionContainer(expression) {
|
|
const node = {
|
|
type: "JSXExpressionContainer",
|
|
expression
|
|
};
|
|
const defs = NODE_FIELDS.JSXExpressionContainer;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
return node;
|
|
}
|
|
function jsxSpreadChild(expression) {
|
|
const node = {
|
|
type: "JSXSpreadChild",
|
|
expression
|
|
};
|
|
const defs = NODE_FIELDS.JSXSpreadChild;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
return node;
|
|
}
|
|
function jsxIdentifier(name) {
|
|
const node = {
|
|
type: "JSXIdentifier",
|
|
name
|
|
};
|
|
const defs = NODE_FIELDS.JSXIdentifier;
|
|
validate(defs.name, node, "name", name);
|
|
return node;
|
|
}
|
|
function jsxMemberExpression(object, property) {
|
|
const node = {
|
|
type: "JSXMemberExpression",
|
|
object,
|
|
property
|
|
};
|
|
const defs = NODE_FIELDS.JSXMemberExpression;
|
|
validate(defs.object, node, "object", object, 1);
|
|
validate(defs.property, node, "property", property, 1);
|
|
return node;
|
|
}
|
|
function jsxNamespacedName(namespace, name) {
|
|
const node = {
|
|
type: "JSXNamespacedName",
|
|
namespace,
|
|
name
|
|
};
|
|
const defs = NODE_FIELDS.JSXNamespacedName;
|
|
validate(defs.namespace, node, "namespace", namespace, 1);
|
|
validate(defs.name, node, "name", name, 1);
|
|
return node;
|
|
}
|
|
function jsxOpeningElement(name, attributes, selfClosing = false) {
|
|
const node = {
|
|
type: "JSXOpeningElement",
|
|
name,
|
|
attributes,
|
|
selfClosing
|
|
};
|
|
const defs = NODE_FIELDS.JSXOpeningElement;
|
|
validate(defs.name, node, "name", name, 1);
|
|
validate(defs.attributes, node, "attributes", attributes, 1);
|
|
validate(defs.selfClosing, node, "selfClosing", selfClosing);
|
|
return node;
|
|
}
|
|
function jsxSpreadAttribute(argument) {
|
|
const node = {
|
|
type: "JSXSpreadAttribute",
|
|
argument
|
|
};
|
|
const defs = NODE_FIELDS.JSXSpreadAttribute;
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
return node;
|
|
}
|
|
function jsxText(value) {
|
|
const node = {
|
|
type: "JSXText",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.JSXText;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function jsxFragment(openingFragment, closingFragment, children) {
|
|
const node = {
|
|
type: "JSXFragment",
|
|
openingFragment,
|
|
closingFragment,
|
|
children
|
|
};
|
|
const defs = NODE_FIELDS.JSXFragment;
|
|
validate(defs.openingFragment, node, "openingFragment", openingFragment, 1);
|
|
validate(defs.closingFragment, node, "closingFragment", closingFragment, 1);
|
|
validate(defs.children, node, "children", children, 1);
|
|
return node;
|
|
}
|
|
function jsxOpeningFragment() {
|
|
return {
|
|
type: "JSXOpeningFragment"
|
|
};
|
|
}
|
|
function jsxClosingFragment() {
|
|
return {
|
|
type: "JSXClosingFragment"
|
|
};
|
|
}
|
|
function noop() {
|
|
return {
|
|
type: "Noop"
|
|
};
|
|
}
|
|
function placeholder(expectedNode, name) {
|
|
const node = {
|
|
type: "Placeholder",
|
|
expectedNode,
|
|
name
|
|
};
|
|
const defs = NODE_FIELDS.Placeholder;
|
|
validate(defs.expectedNode, node, "expectedNode", expectedNode);
|
|
validate(defs.name, node, "name", name, 1);
|
|
return node;
|
|
}
|
|
function v8IntrinsicIdentifier(name) {
|
|
const node = {
|
|
type: "V8IntrinsicIdentifier",
|
|
name
|
|
};
|
|
const defs = NODE_FIELDS.V8IntrinsicIdentifier;
|
|
validate(defs.name, node, "name", name);
|
|
return node;
|
|
}
|
|
function argumentPlaceholder() {
|
|
return {
|
|
type: "ArgumentPlaceholder"
|
|
};
|
|
}
|
|
function bindExpression(object, callee) {
|
|
const node = {
|
|
type: "BindExpression",
|
|
object,
|
|
callee
|
|
};
|
|
const defs = NODE_FIELDS.BindExpression;
|
|
validate(defs.object, node, "object", object, 1);
|
|
validate(defs.callee, node, "callee", callee, 1);
|
|
return node;
|
|
}
|
|
function importAttribute(key, value) {
|
|
const node = {
|
|
type: "ImportAttribute",
|
|
key,
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.ImportAttribute;
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.value, node, "value", value, 1);
|
|
return node;
|
|
}
|
|
function decorator(expression) {
|
|
const node = {
|
|
type: "Decorator",
|
|
expression
|
|
};
|
|
const defs = NODE_FIELDS.Decorator;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
return node;
|
|
}
|
|
function doExpression(body, async = false) {
|
|
const node = {
|
|
type: "DoExpression",
|
|
body,
|
|
async
|
|
};
|
|
const defs = NODE_FIELDS.DoExpression;
|
|
validate(defs.body, node, "body", body, 1);
|
|
validate(defs.async, node, "async", async);
|
|
return node;
|
|
}
|
|
function exportDefaultSpecifier(exported) {
|
|
const node = {
|
|
type: "ExportDefaultSpecifier",
|
|
exported
|
|
};
|
|
const defs = NODE_FIELDS.ExportDefaultSpecifier;
|
|
validate(defs.exported, node, "exported", exported, 1);
|
|
return node;
|
|
}
|
|
function recordExpression(properties) {
|
|
const node = {
|
|
type: "RecordExpression",
|
|
properties
|
|
};
|
|
const defs = NODE_FIELDS.RecordExpression;
|
|
validate(defs.properties, node, "properties", properties, 1);
|
|
return node;
|
|
}
|
|
function tupleExpression(elements = []) {
|
|
const node = {
|
|
type: "TupleExpression",
|
|
elements
|
|
};
|
|
const defs = NODE_FIELDS.TupleExpression;
|
|
validate(defs.elements, node, "elements", elements, 1);
|
|
return node;
|
|
}
|
|
function decimalLiteral(value) {
|
|
const node = {
|
|
type: "DecimalLiteral",
|
|
value
|
|
};
|
|
const defs = NODE_FIELDS.DecimalLiteral;
|
|
validate(defs.value, node, "value", value);
|
|
return node;
|
|
}
|
|
function moduleExpression(body) {
|
|
const node = {
|
|
type: "ModuleExpression",
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.ModuleExpression;
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function topicReference() {
|
|
return {
|
|
type: "TopicReference"
|
|
};
|
|
}
|
|
function pipelineTopicExpression(expression) {
|
|
const node = {
|
|
type: "PipelineTopicExpression",
|
|
expression
|
|
};
|
|
const defs = NODE_FIELDS.PipelineTopicExpression;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
return node;
|
|
}
|
|
function pipelineBareFunction(callee) {
|
|
const node = {
|
|
type: "PipelineBareFunction",
|
|
callee
|
|
};
|
|
const defs = NODE_FIELDS.PipelineBareFunction;
|
|
validate(defs.callee, node, "callee", callee, 1);
|
|
return node;
|
|
}
|
|
function pipelinePrimaryTopicReference() {
|
|
return {
|
|
type: "PipelinePrimaryTopicReference"
|
|
};
|
|
}
|
|
function tsParameterProperty(parameter) {
|
|
const node = {
|
|
type: "TSParameterProperty",
|
|
parameter
|
|
};
|
|
const defs = NODE_FIELDS.TSParameterProperty;
|
|
validate(defs.parameter, node, "parameter", parameter, 1);
|
|
return node;
|
|
}
|
|
function tsDeclareFunction(id = null, typeParameters = null, params, returnType = null) {
|
|
const node = {
|
|
type: "TSDeclareFunction",
|
|
id,
|
|
typeParameters,
|
|
params,
|
|
returnType
|
|
};
|
|
const defs = NODE_FIELDS.TSDeclareFunction;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.params, node, "params", params, 1);
|
|
validate(defs.returnType, node, "returnType", returnType, 1);
|
|
return node;
|
|
}
|
|
function tsDeclareMethod(decorators = null, key, typeParameters = null, params, returnType = null) {
|
|
const node = {
|
|
type: "TSDeclareMethod",
|
|
decorators,
|
|
key,
|
|
typeParameters,
|
|
params,
|
|
returnType
|
|
};
|
|
const defs = NODE_FIELDS.TSDeclareMethod;
|
|
validate(defs.decorators, node, "decorators", decorators, 1);
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.params, node, "params", params, 1);
|
|
validate(defs.returnType, node, "returnType", returnType, 1);
|
|
return node;
|
|
}
|
|
function tsQualifiedName(left, right) {
|
|
const node = {
|
|
type: "TSQualifiedName",
|
|
left,
|
|
right
|
|
};
|
|
const defs = NODE_FIELDS.TSQualifiedName;
|
|
validate(defs.left, node, "left", left, 1);
|
|
validate(defs.right, node, "right", right, 1);
|
|
return node;
|
|
}
|
|
function tsCallSignatureDeclaration(typeParameters = null, parameters, typeAnnotation = null) {
|
|
const node = {
|
|
type: "TSCallSignatureDeclaration",
|
|
typeParameters,
|
|
parameters,
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSCallSignatureDeclaration;
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.parameters, node, "parameters", parameters, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsConstructSignatureDeclaration(typeParameters = null, parameters, typeAnnotation = null) {
|
|
const node = {
|
|
type: "TSConstructSignatureDeclaration",
|
|
typeParameters,
|
|
parameters,
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSConstructSignatureDeclaration;
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.parameters, node, "parameters", parameters, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsPropertySignature(key, typeAnnotation = null) {
|
|
const node = {
|
|
type: "TSPropertySignature",
|
|
key,
|
|
typeAnnotation,
|
|
kind: null
|
|
};
|
|
const defs = NODE_FIELDS.TSPropertySignature;
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsMethodSignature(key, typeParameters = null, parameters, typeAnnotation = null) {
|
|
const node = {
|
|
type: "TSMethodSignature",
|
|
key,
|
|
typeParameters,
|
|
parameters,
|
|
typeAnnotation,
|
|
kind: null
|
|
};
|
|
const defs = NODE_FIELDS.TSMethodSignature;
|
|
validate(defs.key, node, "key", key, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.parameters, node, "parameters", parameters, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsIndexSignature(parameters, typeAnnotation = null) {
|
|
const node = {
|
|
type: "TSIndexSignature",
|
|
parameters,
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSIndexSignature;
|
|
validate(defs.parameters, node, "parameters", parameters, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsAnyKeyword() {
|
|
return {
|
|
type: "TSAnyKeyword"
|
|
};
|
|
}
|
|
function tsBooleanKeyword() {
|
|
return {
|
|
type: "TSBooleanKeyword"
|
|
};
|
|
}
|
|
function tsBigIntKeyword() {
|
|
return {
|
|
type: "TSBigIntKeyword"
|
|
};
|
|
}
|
|
function tsIntrinsicKeyword() {
|
|
return {
|
|
type: "TSIntrinsicKeyword"
|
|
};
|
|
}
|
|
function tsNeverKeyword() {
|
|
return {
|
|
type: "TSNeverKeyword"
|
|
};
|
|
}
|
|
function tsNullKeyword() {
|
|
return {
|
|
type: "TSNullKeyword"
|
|
};
|
|
}
|
|
function tsNumberKeyword() {
|
|
return {
|
|
type: "TSNumberKeyword"
|
|
};
|
|
}
|
|
function tsObjectKeyword() {
|
|
return {
|
|
type: "TSObjectKeyword"
|
|
};
|
|
}
|
|
function tsStringKeyword() {
|
|
return {
|
|
type: "TSStringKeyword"
|
|
};
|
|
}
|
|
function tsSymbolKeyword() {
|
|
return {
|
|
type: "TSSymbolKeyword"
|
|
};
|
|
}
|
|
function tsUndefinedKeyword() {
|
|
return {
|
|
type: "TSUndefinedKeyword"
|
|
};
|
|
}
|
|
function tsUnknownKeyword() {
|
|
return {
|
|
type: "TSUnknownKeyword"
|
|
};
|
|
}
|
|
function tsVoidKeyword() {
|
|
return {
|
|
type: "TSVoidKeyword"
|
|
};
|
|
}
|
|
function tsThisType() {
|
|
return {
|
|
type: "TSThisType"
|
|
};
|
|
}
|
|
function tsFunctionType(typeParameters = null, parameters, typeAnnotation = null) {
|
|
const node = {
|
|
type: "TSFunctionType",
|
|
typeParameters,
|
|
parameters,
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSFunctionType;
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.parameters, node, "parameters", parameters, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsConstructorType(typeParameters = null, parameters, typeAnnotation = null) {
|
|
const node = {
|
|
type: "TSConstructorType",
|
|
typeParameters,
|
|
parameters,
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSConstructorType;
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.parameters, node, "parameters", parameters, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsTypeReference(typeName, typeParameters = null) {
|
|
const node = {
|
|
type: "TSTypeReference",
|
|
typeName,
|
|
typeParameters
|
|
};
|
|
const defs = NODE_FIELDS.TSTypeReference;
|
|
validate(defs.typeName, node, "typeName", typeName, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
return node;
|
|
}
|
|
function tsTypePredicate(parameterName, typeAnnotation = null, asserts = null) {
|
|
const node = {
|
|
type: "TSTypePredicate",
|
|
parameterName,
|
|
typeAnnotation,
|
|
asserts
|
|
};
|
|
const defs = NODE_FIELDS.TSTypePredicate;
|
|
validate(defs.parameterName, node, "parameterName", parameterName, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
validate(defs.asserts, node, "asserts", asserts);
|
|
return node;
|
|
}
|
|
function tsTypeQuery(exprName, typeParameters = null) {
|
|
const node = {
|
|
type: "TSTypeQuery",
|
|
exprName,
|
|
typeParameters
|
|
};
|
|
const defs = NODE_FIELDS.TSTypeQuery;
|
|
validate(defs.exprName, node, "exprName", exprName, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
return node;
|
|
}
|
|
function tsTypeLiteral(members) {
|
|
const node = {
|
|
type: "TSTypeLiteral",
|
|
members
|
|
};
|
|
const defs = NODE_FIELDS.TSTypeLiteral;
|
|
validate(defs.members, node, "members", members, 1);
|
|
return node;
|
|
}
|
|
function tsArrayType(elementType) {
|
|
const node = {
|
|
type: "TSArrayType",
|
|
elementType
|
|
};
|
|
const defs = NODE_FIELDS.TSArrayType;
|
|
validate(defs.elementType, node, "elementType", elementType, 1);
|
|
return node;
|
|
}
|
|
function tsTupleType(elementTypes) {
|
|
const node = {
|
|
type: "TSTupleType",
|
|
elementTypes
|
|
};
|
|
const defs = NODE_FIELDS.TSTupleType;
|
|
validate(defs.elementTypes, node, "elementTypes", elementTypes, 1);
|
|
return node;
|
|
}
|
|
function tsOptionalType(typeAnnotation) {
|
|
const node = {
|
|
type: "TSOptionalType",
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSOptionalType;
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsRestType(typeAnnotation) {
|
|
const node = {
|
|
type: "TSRestType",
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSRestType;
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsNamedTupleMember(label, elementType, optional = false) {
|
|
const node = {
|
|
type: "TSNamedTupleMember",
|
|
label,
|
|
elementType,
|
|
optional
|
|
};
|
|
const defs = NODE_FIELDS.TSNamedTupleMember;
|
|
validate(defs.label, node, "label", label, 1);
|
|
validate(defs.elementType, node, "elementType", elementType, 1);
|
|
validate(defs.optional, node, "optional", optional);
|
|
return node;
|
|
}
|
|
function tsUnionType(types) {
|
|
const node = {
|
|
type: "TSUnionType",
|
|
types
|
|
};
|
|
const defs = NODE_FIELDS.TSUnionType;
|
|
validate(defs.types, node, "types", types, 1);
|
|
return node;
|
|
}
|
|
function tsIntersectionType(types) {
|
|
const node = {
|
|
type: "TSIntersectionType",
|
|
types
|
|
};
|
|
const defs = NODE_FIELDS.TSIntersectionType;
|
|
validate(defs.types, node, "types", types, 1);
|
|
return node;
|
|
}
|
|
function tsConditionalType(checkType, extendsType, trueType, falseType) {
|
|
const node = {
|
|
type: "TSConditionalType",
|
|
checkType,
|
|
extendsType,
|
|
trueType,
|
|
falseType
|
|
};
|
|
const defs = NODE_FIELDS.TSConditionalType;
|
|
validate(defs.checkType, node, "checkType", checkType, 1);
|
|
validate(defs.extendsType, node, "extendsType", extendsType, 1);
|
|
validate(defs.trueType, node, "trueType", trueType, 1);
|
|
validate(defs.falseType, node, "falseType", falseType, 1);
|
|
return node;
|
|
}
|
|
function tsInferType(typeParameter) {
|
|
const node = {
|
|
type: "TSInferType",
|
|
typeParameter
|
|
};
|
|
const defs = NODE_FIELDS.TSInferType;
|
|
validate(defs.typeParameter, node, "typeParameter", typeParameter, 1);
|
|
return node;
|
|
}
|
|
function tsParenthesizedType(typeAnnotation) {
|
|
const node = {
|
|
type: "TSParenthesizedType",
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSParenthesizedType;
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsTypeOperator(typeAnnotation) {
|
|
const node = {
|
|
type: "TSTypeOperator",
|
|
typeAnnotation,
|
|
operator: null
|
|
};
|
|
const defs = NODE_FIELDS.TSTypeOperator;
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsIndexedAccessType(objectType, indexType) {
|
|
const node = {
|
|
type: "TSIndexedAccessType",
|
|
objectType,
|
|
indexType
|
|
};
|
|
const defs = NODE_FIELDS.TSIndexedAccessType;
|
|
validate(defs.objectType, node, "objectType", objectType, 1);
|
|
validate(defs.indexType, node, "indexType", indexType, 1);
|
|
return node;
|
|
}
|
|
function tsMappedType(typeParameter, typeAnnotation = null, nameType = null) {
|
|
const node = {
|
|
type: "TSMappedType",
|
|
typeParameter,
|
|
typeAnnotation,
|
|
nameType
|
|
};
|
|
const defs = NODE_FIELDS.TSMappedType;
|
|
validate(defs.typeParameter, node, "typeParameter", typeParameter, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
validate(defs.nameType, node, "nameType", nameType, 1);
|
|
return node;
|
|
}
|
|
function tsLiteralType(literal) {
|
|
const node = {
|
|
type: "TSLiteralType",
|
|
literal
|
|
};
|
|
const defs = NODE_FIELDS.TSLiteralType;
|
|
validate(defs.literal, node, "literal", literal, 1);
|
|
return node;
|
|
}
|
|
function tsExpressionWithTypeArguments(expression, typeParameters = null) {
|
|
const node = {
|
|
type: "TSExpressionWithTypeArguments",
|
|
expression,
|
|
typeParameters
|
|
};
|
|
const defs = NODE_FIELDS.TSExpressionWithTypeArguments;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
return node;
|
|
}
|
|
function tsInterfaceDeclaration(id, typeParameters = null, _extends = null, body) {
|
|
const node = {
|
|
type: "TSInterfaceDeclaration",
|
|
id,
|
|
typeParameters,
|
|
extends: _extends,
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.TSInterfaceDeclaration;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.extends, node, "extends", _extends, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function tsInterfaceBody(body) {
|
|
const node = {
|
|
type: "TSInterfaceBody",
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.TSInterfaceBody;
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function tsTypeAliasDeclaration(id, typeParameters = null, typeAnnotation) {
|
|
const node = {
|
|
type: "TSTypeAliasDeclaration",
|
|
id,
|
|
typeParameters,
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSTypeAliasDeclaration;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsInstantiationExpression(expression, typeParameters = null) {
|
|
const node = {
|
|
type: "TSInstantiationExpression",
|
|
expression,
|
|
typeParameters
|
|
};
|
|
const defs = NODE_FIELDS.TSInstantiationExpression;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
return node;
|
|
}
|
|
function tsAsExpression(expression, typeAnnotation) {
|
|
const node = {
|
|
type: "TSAsExpression",
|
|
expression,
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSAsExpression;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsSatisfiesExpression(expression, typeAnnotation) {
|
|
const node = {
|
|
type: "TSSatisfiesExpression",
|
|
expression,
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSSatisfiesExpression;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsTypeAssertion(typeAnnotation, expression) {
|
|
const node = {
|
|
type: "TSTypeAssertion",
|
|
typeAnnotation,
|
|
expression
|
|
};
|
|
const defs = NODE_FIELDS.TSTypeAssertion;
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
return node;
|
|
}
|
|
function tsEnumDeclaration(id, members) {
|
|
const node = {
|
|
type: "TSEnumDeclaration",
|
|
id,
|
|
members
|
|
};
|
|
const defs = NODE_FIELDS.TSEnumDeclaration;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.members, node, "members", members, 1);
|
|
return node;
|
|
}
|
|
function tsEnumMember(id, initializer = null) {
|
|
const node = {
|
|
type: "TSEnumMember",
|
|
id,
|
|
initializer
|
|
};
|
|
const defs = NODE_FIELDS.TSEnumMember;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.initializer, node, "initializer", initializer, 1);
|
|
return node;
|
|
}
|
|
function tsModuleDeclaration(id, body) {
|
|
const node = {
|
|
type: "TSModuleDeclaration",
|
|
id,
|
|
body,
|
|
kind: null
|
|
};
|
|
const defs = NODE_FIELDS.TSModuleDeclaration;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function tsModuleBlock(body) {
|
|
const node = {
|
|
type: "TSModuleBlock",
|
|
body
|
|
};
|
|
const defs = NODE_FIELDS.TSModuleBlock;
|
|
validate(defs.body, node, "body", body, 1);
|
|
return node;
|
|
}
|
|
function tsImportType(argument, qualifier = null, typeParameters = null) {
|
|
const node = {
|
|
type: "TSImportType",
|
|
argument,
|
|
qualifier,
|
|
typeParameters
|
|
};
|
|
const defs = NODE_FIELDS.TSImportType;
|
|
validate(defs.argument, node, "argument", argument, 1);
|
|
validate(defs.qualifier, node, "qualifier", qualifier, 1);
|
|
validate(defs.typeParameters, node, "typeParameters", typeParameters, 1);
|
|
return node;
|
|
}
|
|
function tsImportEqualsDeclaration(id, moduleReference) {
|
|
const node = {
|
|
type: "TSImportEqualsDeclaration",
|
|
id,
|
|
moduleReference,
|
|
isExport: null
|
|
};
|
|
const defs = NODE_FIELDS.TSImportEqualsDeclaration;
|
|
validate(defs.id, node, "id", id, 1);
|
|
validate(defs.moduleReference, node, "moduleReference", moduleReference, 1);
|
|
return node;
|
|
}
|
|
function tsExternalModuleReference(expression) {
|
|
const node = {
|
|
type: "TSExternalModuleReference",
|
|
expression
|
|
};
|
|
const defs = NODE_FIELDS.TSExternalModuleReference;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
return node;
|
|
}
|
|
function tsNonNullExpression(expression) {
|
|
const node = {
|
|
type: "TSNonNullExpression",
|
|
expression
|
|
};
|
|
const defs = NODE_FIELDS.TSNonNullExpression;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
return node;
|
|
}
|
|
function tsExportAssignment(expression) {
|
|
const node = {
|
|
type: "TSExportAssignment",
|
|
expression
|
|
};
|
|
const defs = NODE_FIELDS.TSExportAssignment;
|
|
validate(defs.expression, node, "expression", expression, 1);
|
|
return node;
|
|
}
|
|
function tsNamespaceExportDeclaration(id) {
|
|
const node = {
|
|
type: "TSNamespaceExportDeclaration",
|
|
id
|
|
};
|
|
const defs = NODE_FIELDS.TSNamespaceExportDeclaration;
|
|
validate(defs.id, node, "id", id, 1);
|
|
return node;
|
|
}
|
|
function tsTypeAnnotation(typeAnnotation) {
|
|
const node = {
|
|
type: "TSTypeAnnotation",
|
|
typeAnnotation
|
|
};
|
|
const defs = NODE_FIELDS.TSTypeAnnotation;
|
|
validate(defs.typeAnnotation, node, "typeAnnotation", typeAnnotation, 1);
|
|
return node;
|
|
}
|
|
function tsTypeParameterInstantiation(params) {
|
|
const node = {
|
|
type: "TSTypeParameterInstantiation",
|
|
params
|
|
};
|
|
const defs = NODE_FIELDS.TSTypeParameterInstantiation;
|
|
validate(defs.params, node, "params", params, 1);
|
|
return node;
|
|
}
|
|
function tsTypeParameterDeclaration(params) {
|
|
const node = {
|
|
type: "TSTypeParameterDeclaration",
|
|
params
|
|
};
|
|
const defs = NODE_FIELDS.TSTypeParameterDeclaration;
|
|
validate(defs.params, node, "params", params, 1);
|
|
return node;
|
|
}
|
|
function tsTypeParameter(constraint = null, _default = null, name) {
|
|
const node = {
|
|
type: "TSTypeParameter",
|
|
constraint,
|
|
default: _default,
|
|
name
|
|
};
|
|
const defs = NODE_FIELDS.TSTypeParameter;
|
|
validate(defs.constraint, node, "constraint", constraint, 1);
|
|
validate(defs.default, node, "default", _default, 1);
|
|
validate(defs.name, node, "name", name);
|
|
return node;
|
|
}
|
|
function NumberLiteral(value) {
|
|
(0, _deprecationWarning.default)("NumberLiteral", "NumericLiteral", "The node type ");
|
|
return numericLiteral(value);
|
|
}
|
|
function RegexLiteral(pattern, flags = "") {
|
|
(0, _deprecationWarning.default)("RegexLiteral", "RegExpLiteral", "The node type ");
|
|
return regExpLiteral(pattern, flags);
|
|
}
|
|
function RestProperty(argument) {
|
|
(0, _deprecationWarning.default)("RestProperty", "RestElement", "The node type ");
|
|
return restElement(argument);
|
|
}
|
|
function SpreadProperty(argument) {
|
|
(0, _deprecationWarning.default)("SpreadProperty", "SpreadElement", "The node type ");
|
|
return spreadElement(argument);
|
|
}
|
|
|
|
|
|
return generated$2;
|
|
}
|
|
|
|
var hasRequiredCleanJSXElementLiteralChild;
|
|
|
|
function requireCleanJSXElementLiteralChild () {
|
|
if (hasRequiredCleanJSXElementLiteralChild) return cleanJSXElementLiteralChild;
|
|
hasRequiredCleanJSXElementLiteralChild = 1;
|
|
|
|
Object.defineProperty(cleanJSXElementLiteralChild, "__esModule", {
|
|
value: true
|
|
});
|
|
cleanJSXElementLiteralChild.default = cleanJSXElementLiteralChild$1;
|
|
var _index = requireGenerated$2();
|
|
var _index2 = requireLib$1();
|
|
function cleanJSXElementLiteralChild$1(child, args) {
|
|
const lines = child.value.split(/\r\n|\n|\r/);
|
|
let lastNonEmptyLine = 0;
|
|
for (let i = 0; i < lines.length; i++) {
|
|
if (/[^ \t]/.exec(lines[i])) {
|
|
lastNonEmptyLine = i;
|
|
}
|
|
}
|
|
let str = "";
|
|
for (let i = 0; i < lines.length; i++) {
|
|
const line = lines[i];
|
|
const isFirstLine = i === 0;
|
|
const isLastLine = i === lines.length - 1;
|
|
const isLastNonEmptyLine = i === lastNonEmptyLine;
|
|
let trimmedLine = line.replace(/\t/g, " ");
|
|
if (!isFirstLine) {
|
|
trimmedLine = trimmedLine.replace(/^ +/, "");
|
|
}
|
|
if (!isLastLine) {
|
|
trimmedLine = trimmedLine.replace(/ +$/, "");
|
|
}
|
|
if (trimmedLine) {
|
|
if (!isLastNonEmptyLine) {
|
|
trimmedLine += " ";
|
|
}
|
|
str += trimmedLine;
|
|
}
|
|
}
|
|
if (str) args.push((0, _index2.inherits)((0, _index.stringLiteral)(str), child));
|
|
}
|
|
|
|
|
|
return cleanJSXElementLiteralChild;
|
|
}
|
|
|
|
var hasRequiredBuildChildren;
|
|
|
|
function requireBuildChildren () {
|
|
if (hasRequiredBuildChildren) return buildChildren;
|
|
hasRequiredBuildChildren = 1;
|
|
|
|
Object.defineProperty(buildChildren, "__esModule", {
|
|
value: true
|
|
});
|
|
buildChildren.default = buildChildren$1;
|
|
var _index = requireGenerated$3();
|
|
var _cleanJSXElementLiteralChild = requireCleanJSXElementLiteralChild();
|
|
function buildChildren$1(node) {
|
|
const elements = [];
|
|
for (let i = 0; i < node.children.length; i++) {
|
|
let child = node.children[i];
|
|
if ((0, _index.isJSXText)(child)) {
|
|
(0, _cleanJSXElementLiteralChild.default)(child, elements);
|
|
continue;
|
|
}
|
|
if ((0, _index.isJSXExpressionContainer)(child)) child = child.expression;
|
|
if ((0, _index.isJSXEmptyExpression)(child)) continue;
|
|
elements.push(child);
|
|
}
|
|
return elements;
|
|
}
|
|
|
|
|
|
return buildChildren;
|
|
}
|
|
|
|
var assertNode = {};
|
|
|
|
var isNode = {};
|
|
|
|
var hasRequiredIsNode;
|
|
|
|
function requireIsNode () {
|
|
if (hasRequiredIsNode) return isNode;
|
|
hasRequiredIsNode = 1;
|
|
|
|
Object.defineProperty(isNode, "__esModule", {
|
|
value: true
|
|
});
|
|
isNode.default = isNode$1;
|
|
var _index = requireDefinitions();
|
|
function isNode$1(node) {
|
|
return !!(node && _index.VISITOR_KEYS[node.type]);
|
|
}
|
|
|
|
|
|
return isNode;
|
|
}
|
|
|
|
var hasRequiredAssertNode;
|
|
|
|
function requireAssertNode () {
|
|
if (hasRequiredAssertNode) return assertNode;
|
|
hasRequiredAssertNode = 1;
|
|
|
|
Object.defineProperty(assertNode, "__esModule", {
|
|
value: true
|
|
});
|
|
assertNode.default = assertNode$1;
|
|
var _isNode = requireIsNode();
|
|
function assertNode$1(node) {
|
|
if (!(0, _isNode.default)(node)) {
|
|
var _node$type;
|
|
const type = (_node$type = node == null ? void 0 : node.type) != null ? _node$type : JSON.stringify(node);
|
|
throw new TypeError(`Not a valid node of type "${type}"`);
|
|
}
|
|
}
|
|
|
|
|
|
return assertNode;
|
|
}
|
|
|
|
var generated$1 = {};
|
|
|
|
var hasRequiredGenerated$1;
|
|
|
|
function requireGenerated$1 () {
|
|
if (hasRequiredGenerated$1) return generated$1;
|
|
hasRequiredGenerated$1 = 1;
|
|
|
|
Object.defineProperty(generated$1, "__esModule", {
|
|
value: true
|
|
});
|
|
generated$1.assertAccessor = assertAccessor;
|
|
generated$1.assertAnyTypeAnnotation = assertAnyTypeAnnotation;
|
|
generated$1.assertArgumentPlaceholder = assertArgumentPlaceholder;
|
|
generated$1.assertArrayExpression = assertArrayExpression;
|
|
generated$1.assertArrayPattern = assertArrayPattern;
|
|
generated$1.assertArrayTypeAnnotation = assertArrayTypeAnnotation;
|
|
generated$1.assertArrowFunctionExpression = assertArrowFunctionExpression;
|
|
generated$1.assertAssignmentExpression = assertAssignmentExpression;
|
|
generated$1.assertAssignmentPattern = assertAssignmentPattern;
|
|
generated$1.assertAwaitExpression = assertAwaitExpression;
|
|
generated$1.assertBigIntLiteral = assertBigIntLiteral;
|
|
generated$1.assertBinary = assertBinary;
|
|
generated$1.assertBinaryExpression = assertBinaryExpression;
|
|
generated$1.assertBindExpression = assertBindExpression;
|
|
generated$1.assertBlock = assertBlock;
|
|
generated$1.assertBlockParent = assertBlockParent;
|
|
generated$1.assertBlockStatement = assertBlockStatement;
|
|
generated$1.assertBooleanLiteral = assertBooleanLiteral;
|
|
generated$1.assertBooleanLiteralTypeAnnotation = assertBooleanLiteralTypeAnnotation;
|
|
generated$1.assertBooleanTypeAnnotation = assertBooleanTypeAnnotation;
|
|
generated$1.assertBreakStatement = assertBreakStatement;
|
|
generated$1.assertCallExpression = assertCallExpression;
|
|
generated$1.assertCatchClause = assertCatchClause;
|
|
generated$1.assertClass = assertClass;
|
|
generated$1.assertClassAccessorProperty = assertClassAccessorProperty;
|
|
generated$1.assertClassBody = assertClassBody;
|
|
generated$1.assertClassDeclaration = assertClassDeclaration;
|
|
generated$1.assertClassExpression = assertClassExpression;
|
|
generated$1.assertClassImplements = assertClassImplements;
|
|
generated$1.assertClassMethod = assertClassMethod;
|
|
generated$1.assertClassPrivateMethod = assertClassPrivateMethod;
|
|
generated$1.assertClassPrivateProperty = assertClassPrivateProperty;
|
|
generated$1.assertClassProperty = assertClassProperty;
|
|
generated$1.assertCompletionStatement = assertCompletionStatement;
|
|
generated$1.assertConditional = assertConditional;
|
|
generated$1.assertConditionalExpression = assertConditionalExpression;
|
|
generated$1.assertContinueStatement = assertContinueStatement;
|
|
generated$1.assertDebuggerStatement = assertDebuggerStatement;
|
|
generated$1.assertDecimalLiteral = assertDecimalLiteral;
|
|
generated$1.assertDeclaration = assertDeclaration;
|
|
generated$1.assertDeclareClass = assertDeclareClass;
|
|
generated$1.assertDeclareExportAllDeclaration = assertDeclareExportAllDeclaration;
|
|
generated$1.assertDeclareExportDeclaration = assertDeclareExportDeclaration;
|
|
generated$1.assertDeclareFunction = assertDeclareFunction;
|
|
generated$1.assertDeclareInterface = assertDeclareInterface;
|
|
generated$1.assertDeclareModule = assertDeclareModule;
|
|
generated$1.assertDeclareModuleExports = assertDeclareModuleExports;
|
|
generated$1.assertDeclareOpaqueType = assertDeclareOpaqueType;
|
|
generated$1.assertDeclareTypeAlias = assertDeclareTypeAlias;
|
|
generated$1.assertDeclareVariable = assertDeclareVariable;
|
|
generated$1.assertDeclaredPredicate = assertDeclaredPredicate;
|
|
generated$1.assertDecorator = assertDecorator;
|
|
generated$1.assertDirective = assertDirective;
|
|
generated$1.assertDirectiveLiteral = assertDirectiveLiteral;
|
|
generated$1.assertDoExpression = assertDoExpression;
|
|
generated$1.assertDoWhileStatement = assertDoWhileStatement;
|
|
generated$1.assertEmptyStatement = assertEmptyStatement;
|
|
generated$1.assertEmptyTypeAnnotation = assertEmptyTypeAnnotation;
|
|
generated$1.assertEnumBody = assertEnumBody;
|
|
generated$1.assertEnumBooleanBody = assertEnumBooleanBody;
|
|
generated$1.assertEnumBooleanMember = assertEnumBooleanMember;
|
|
generated$1.assertEnumDeclaration = assertEnumDeclaration;
|
|
generated$1.assertEnumDefaultedMember = assertEnumDefaultedMember;
|
|
generated$1.assertEnumMember = assertEnumMember;
|
|
generated$1.assertEnumNumberBody = assertEnumNumberBody;
|
|
generated$1.assertEnumNumberMember = assertEnumNumberMember;
|
|
generated$1.assertEnumStringBody = assertEnumStringBody;
|
|
generated$1.assertEnumStringMember = assertEnumStringMember;
|
|
generated$1.assertEnumSymbolBody = assertEnumSymbolBody;
|
|
generated$1.assertExistsTypeAnnotation = assertExistsTypeAnnotation;
|
|
generated$1.assertExportAllDeclaration = assertExportAllDeclaration;
|
|
generated$1.assertExportDeclaration = assertExportDeclaration;
|
|
generated$1.assertExportDefaultDeclaration = assertExportDefaultDeclaration;
|
|
generated$1.assertExportDefaultSpecifier = assertExportDefaultSpecifier;
|
|
generated$1.assertExportNamedDeclaration = assertExportNamedDeclaration;
|
|
generated$1.assertExportNamespaceSpecifier = assertExportNamespaceSpecifier;
|
|
generated$1.assertExportSpecifier = assertExportSpecifier;
|
|
generated$1.assertExpression = assertExpression;
|
|
generated$1.assertExpressionStatement = assertExpressionStatement;
|
|
generated$1.assertExpressionWrapper = assertExpressionWrapper;
|
|
generated$1.assertFile = assertFile;
|
|
generated$1.assertFlow = assertFlow;
|
|
generated$1.assertFlowBaseAnnotation = assertFlowBaseAnnotation;
|
|
generated$1.assertFlowDeclaration = assertFlowDeclaration;
|
|
generated$1.assertFlowPredicate = assertFlowPredicate;
|
|
generated$1.assertFlowType = assertFlowType;
|
|
generated$1.assertFor = assertFor;
|
|
generated$1.assertForInStatement = assertForInStatement;
|
|
generated$1.assertForOfStatement = assertForOfStatement;
|
|
generated$1.assertForStatement = assertForStatement;
|
|
generated$1.assertForXStatement = assertForXStatement;
|
|
generated$1.assertFunction = assertFunction;
|
|
generated$1.assertFunctionDeclaration = assertFunctionDeclaration;
|
|
generated$1.assertFunctionExpression = assertFunctionExpression;
|
|
generated$1.assertFunctionParent = assertFunctionParent;
|
|
generated$1.assertFunctionTypeAnnotation = assertFunctionTypeAnnotation;
|
|
generated$1.assertFunctionTypeParam = assertFunctionTypeParam;
|
|
generated$1.assertGenericTypeAnnotation = assertGenericTypeAnnotation;
|
|
generated$1.assertIdentifier = assertIdentifier;
|
|
generated$1.assertIfStatement = assertIfStatement;
|
|
generated$1.assertImmutable = assertImmutable;
|
|
generated$1.assertImport = assertImport;
|
|
generated$1.assertImportAttribute = assertImportAttribute;
|
|
generated$1.assertImportDeclaration = assertImportDeclaration;
|
|
generated$1.assertImportDefaultSpecifier = assertImportDefaultSpecifier;
|
|
generated$1.assertImportExpression = assertImportExpression;
|
|
generated$1.assertImportNamespaceSpecifier = assertImportNamespaceSpecifier;
|
|
generated$1.assertImportOrExportDeclaration = assertImportOrExportDeclaration;
|
|
generated$1.assertImportSpecifier = assertImportSpecifier;
|
|
generated$1.assertIndexedAccessType = assertIndexedAccessType;
|
|
generated$1.assertInferredPredicate = assertInferredPredicate;
|
|
generated$1.assertInterfaceDeclaration = assertInterfaceDeclaration;
|
|
generated$1.assertInterfaceExtends = assertInterfaceExtends;
|
|
generated$1.assertInterfaceTypeAnnotation = assertInterfaceTypeAnnotation;
|
|
generated$1.assertInterpreterDirective = assertInterpreterDirective;
|
|
generated$1.assertIntersectionTypeAnnotation = assertIntersectionTypeAnnotation;
|
|
generated$1.assertJSX = assertJSX;
|
|
generated$1.assertJSXAttribute = assertJSXAttribute;
|
|
generated$1.assertJSXClosingElement = assertJSXClosingElement;
|
|
generated$1.assertJSXClosingFragment = assertJSXClosingFragment;
|
|
generated$1.assertJSXElement = assertJSXElement;
|
|
generated$1.assertJSXEmptyExpression = assertJSXEmptyExpression;
|
|
generated$1.assertJSXExpressionContainer = assertJSXExpressionContainer;
|
|
generated$1.assertJSXFragment = assertJSXFragment;
|
|
generated$1.assertJSXIdentifier = assertJSXIdentifier;
|
|
generated$1.assertJSXMemberExpression = assertJSXMemberExpression;
|
|
generated$1.assertJSXNamespacedName = assertJSXNamespacedName;
|
|
generated$1.assertJSXOpeningElement = assertJSXOpeningElement;
|
|
generated$1.assertJSXOpeningFragment = assertJSXOpeningFragment;
|
|
generated$1.assertJSXSpreadAttribute = assertJSXSpreadAttribute;
|
|
generated$1.assertJSXSpreadChild = assertJSXSpreadChild;
|
|
generated$1.assertJSXText = assertJSXText;
|
|
generated$1.assertLVal = assertLVal;
|
|
generated$1.assertLabeledStatement = assertLabeledStatement;
|
|
generated$1.assertLiteral = assertLiteral;
|
|
generated$1.assertLogicalExpression = assertLogicalExpression;
|
|
generated$1.assertLoop = assertLoop;
|
|
generated$1.assertMemberExpression = assertMemberExpression;
|
|
generated$1.assertMetaProperty = assertMetaProperty;
|
|
generated$1.assertMethod = assertMethod;
|
|
generated$1.assertMiscellaneous = assertMiscellaneous;
|
|
generated$1.assertMixedTypeAnnotation = assertMixedTypeAnnotation;
|
|
generated$1.assertModuleDeclaration = assertModuleDeclaration;
|
|
generated$1.assertModuleExpression = assertModuleExpression;
|
|
generated$1.assertModuleSpecifier = assertModuleSpecifier;
|
|
generated$1.assertNewExpression = assertNewExpression;
|
|
generated$1.assertNoop = assertNoop;
|
|
generated$1.assertNullLiteral = assertNullLiteral;
|
|
generated$1.assertNullLiteralTypeAnnotation = assertNullLiteralTypeAnnotation;
|
|
generated$1.assertNullableTypeAnnotation = assertNullableTypeAnnotation;
|
|
generated$1.assertNumberLiteral = assertNumberLiteral;
|
|
generated$1.assertNumberLiteralTypeAnnotation = assertNumberLiteralTypeAnnotation;
|
|
generated$1.assertNumberTypeAnnotation = assertNumberTypeAnnotation;
|
|
generated$1.assertNumericLiteral = assertNumericLiteral;
|
|
generated$1.assertObjectExpression = assertObjectExpression;
|
|
generated$1.assertObjectMember = assertObjectMember;
|
|
generated$1.assertObjectMethod = assertObjectMethod;
|
|
generated$1.assertObjectPattern = assertObjectPattern;
|
|
generated$1.assertObjectProperty = assertObjectProperty;
|
|
generated$1.assertObjectTypeAnnotation = assertObjectTypeAnnotation;
|
|
generated$1.assertObjectTypeCallProperty = assertObjectTypeCallProperty;
|
|
generated$1.assertObjectTypeIndexer = assertObjectTypeIndexer;
|
|
generated$1.assertObjectTypeInternalSlot = assertObjectTypeInternalSlot;
|
|
generated$1.assertObjectTypeProperty = assertObjectTypeProperty;
|
|
generated$1.assertObjectTypeSpreadProperty = assertObjectTypeSpreadProperty;
|
|
generated$1.assertOpaqueType = assertOpaqueType;
|
|
generated$1.assertOptionalCallExpression = assertOptionalCallExpression;
|
|
generated$1.assertOptionalIndexedAccessType = assertOptionalIndexedAccessType;
|
|
generated$1.assertOptionalMemberExpression = assertOptionalMemberExpression;
|
|
generated$1.assertParenthesizedExpression = assertParenthesizedExpression;
|
|
generated$1.assertPattern = assertPattern;
|
|
generated$1.assertPatternLike = assertPatternLike;
|
|
generated$1.assertPipelineBareFunction = assertPipelineBareFunction;
|
|
generated$1.assertPipelinePrimaryTopicReference = assertPipelinePrimaryTopicReference;
|
|
generated$1.assertPipelineTopicExpression = assertPipelineTopicExpression;
|
|
generated$1.assertPlaceholder = assertPlaceholder;
|
|
generated$1.assertPrivate = assertPrivate;
|
|
generated$1.assertPrivateName = assertPrivateName;
|
|
generated$1.assertProgram = assertProgram;
|
|
generated$1.assertProperty = assertProperty;
|
|
generated$1.assertPureish = assertPureish;
|
|
generated$1.assertQualifiedTypeIdentifier = assertQualifiedTypeIdentifier;
|
|
generated$1.assertRecordExpression = assertRecordExpression;
|
|
generated$1.assertRegExpLiteral = assertRegExpLiteral;
|
|
generated$1.assertRegexLiteral = assertRegexLiteral;
|
|
generated$1.assertRestElement = assertRestElement;
|
|
generated$1.assertRestProperty = assertRestProperty;
|
|
generated$1.assertReturnStatement = assertReturnStatement;
|
|
generated$1.assertScopable = assertScopable;
|
|
generated$1.assertSequenceExpression = assertSequenceExpression;
|
|
generated$1.assertSpreadElement = assertSpreadElement;
|
|
generated$1.assertSpreadProperty = assertSpreadProperty;
|
|
generated$1.assertStandardized = assertStandardized;
|
|
generated$1.assertStatement = assertStatement;
|
|
generated$1.assertStaticBlock = assertStaticBlock;
|
|
generated$1.assertStringLiteral = assertStringLiteral;
|
|
generated$1.assertStringLiteralTypeAnnotation = assertStringLiteralTypeAnnotation;
|
|
generated$1.assertStringTypeAnnotation = assertStringTypeAnnotation;
|
|
generated$1.assertSuper = assertSuper;
|
|
generated$1.assertSwitchCase = assertSwitchCase;
|
|
generated$1.assertSwitchStatement = assertSwitchStatement;
|
|
generated$1.assertSymbolTypeAnnotation = assertSymbolTypeAnnotation;
|
|
generated$1.assertTSAnyKeyword = assertTSAnyKeyword;
|
|
generated$1.assertTSArrayType = assertTSArrayType;
|
|
generated$1.assertTSAsExpression = assertTSAsExpression;
|
|
generated$1.assertTSBaseType = assertTSBaseType;
|
|
generated$1.assertTSBigIntKeyword = assertTSBigIntKeyword;
|
|
generated$1.assertTSBooleanKeyword = assertTSBooleanKeyword;
|
|
generated$1.assertTSCallSignatureDeclaration = assertTSCallSignatureDeclaration;
|
|
generated$1.assertTSConditionalType = assertTSConditionalType;
|
|
generated$1.assertTSConstructSignatureDeclaration = assertTSConstructSignatureDeclaration;
|
|
generated$1.assertTSConstructorType = assertTSConstructorType;
|
|
generated$1.assertTSDeclareFunction = assertTSDeclareFunction;
|
|
generated$1.assertTSDeclareMethod = assertTSDeclareMethod;
|
|
generated$1.assertTSEntityName = assertTSEntityName;
|
|
generated$1.assertTSEnumDeclaration = assertTSEnumDeclaration;
|
|
generated$1.assertTSEnumMember = assertTSEnumMember;
|
|
generated$1.assertTSExportAssignment = assertTSExportAssignment;
|
|
generated$1.assertTSExpressionWithTypeArguments = assertTSExpressionWithTypeArguments;
|
|
generated$1.assertTSExternalModuleReference = assertTSExternalModuleReference;
|
|
generated$1.assertTSFunctionType = assertTSFunctionType;
|
|
generated$1.assertTSImportEqualsDeclaration = assertTSImportEqualsDeclaration;
|
|
generated$1.assertTSImportType = assertTSImportType;
|
|
generated$1.assertTSIndexSignature = assertTSIndexSignature;
|
|
generated$1.assertTSIndexedAccessType = assertTSIndexedAccessType;
|
|
generated$1.assertTSInferType = assertTSInferType;
|
|
generated$1.assertTSInstantiationExpression = assertTSInstantiationExpression;
|
|
generated$1.assertTSInterfaceBody = assertTSInterfaceBody;
|
|
generated$1.assertTSInterfaceDeclaration = assertTSInterfaceDeclaration;
|
|
generated$1.assertTSIntersectionType = assertTSIntersectionType;
|
|
generated$1.assertTSIntrinsicKeyword = assertTSIntrinsicKeyword;
|
|
generated$1.assertTSLiteralType = assertTSLiteralType;
|
|
generated$1.assertTSMappedType = assertTSMappedType;
|
|
generated$1.assertTSMethodSignature = assertTSMethodSignature;
|
|
generated$1.assertTSModuleBlock = assertTSModuleBlock;
|
|
generated$1.assertTSModuleDeclaration = assertTSModuleDeclaration;
|
|
generated$1.assertTSNamedTupleMember = assertTSNamedTupleMember;
|
|
generated$1.assertTSNamespaceExportDeclaration = assertTSNamespaceExportDeclaration;
|
|
generated$1.assertTSNeverKeyword = assertTSNeverKeyword;
|
|
generated$1.assertTSNonNullExpression = assertTSNonNullExpression;
|
|
generated$1.assertTSNullKeyword = assertTSNullKeyword;
|
|
generated$1.assertTSNumberKeyword = assertTSNumberKeyword;
|
|
generated$1.assertTSObjectKeyword = assertTSObjectKeyword;
|
|
generated$1.assertTSOptionalType = assertTSOptionalType;
|
|
generated$1.assertTSParameterProperty = assertTSParameterProperty;
|
|
generated$1.assertTSParenthesizedType = assertTSParenthesizedType;
|
|
generated$1.assertTSPropertySignature = assertTSPropertySignature;
|
|
generated$1.assertTSQualifiedName = assertTSQualifiedName;
|
|
generated$1.assertTSRestType = assertTSRestType;
|
|
generated$1.assertTSSatisfiesExpression = assertTSSatisfiesExpression;
|
|
generated$1.assertTSStringKeyword = assertTSStringKeyword;
|
|
generated$1.assertTSSymbolKeyword = assertTSSymbolKeyword;
|
|
generated$1.assertTSThisType = assertTSThisType;
|
|
generated$1.assertTSTupleType = assertTSTupleType;
|
|
generated$1.assertTSType = assertTSType;
|
|
generated$1.assertTSTypeAliasDeclaration = assertTSTypeAliasDeclaration;
|
|
generated$1.assertTSTypeAnnotation = assertTSTypeAnnotation;
|
|
generated$1.assertTSTypeAssertion = assertTSTypeAssertion;
|
|
generated$1.assertTSTypeElement = assertTSTypeElement;
|
|
generated$1.assertTSTypeLiteral = assertTSTypeLiteral;
|
|
generated$1.assertTSTypeOperator = assertTSTypeOperator;
|
|
generated$1.assertTSTypeParameter = assertTSTypeParameter;
|
|
generated$1.assertTSTypeParameterDeclaration = assertTSTypeParameterDeclaration;
|
|
generated$1.assertTSTypeParameterInstantiation = assertTSTypeParameterInstantiation;
|
|
generated$1.assertTSTypePredicate = assertTSTypePredicate;
|
|
generated$1.assertTSTypeQuery = assertTSTypeQuery;
|
|
generated$1.assertTSTypeReference = assertTSTypeReference;
|
|
generated$1.assertTSUndefinedKeyword = assertTSUndefinedKeyword;
|
|
generated$1.assertTSUnionType = assertTSUnionType;
|
|
generated$1.assertTSUnknownKeyword = assertTSUnknownKeyword;
|
|
generated$1.assertTSVoidKeyword = assertTSVoidKeyword;
|
|
generated$1.assertTaggedTemplateExpression = assertTaggedTemplateExpression;
|
|
generated$1.assertTemplateElement = assertTemplateElement;
|
|
generated$1.assertTemplateLiteral = assertTemplateLiteral;
|
|
generated$1.assertTerminatorless = assertTerminatorless;
|
|
generated$1.assertThisExpression = assertThisExpression;
|
|
generated$1.assertThisTypeAnnotation = assertThisTypeAnnotation;
|
|
generated$1.assertThrowStatement = assertThrowStatement;
|
|
generated$1.assertTopicReference = assertTopicReference;
|
|
generated$1.assertTryStatement = assertTryStatement;
|
|
generated$1.assertTupleExpression = assertTupleExpression;
|
|
generated$1.assertTupleTypeAnnotation = assertTupleTypeAnnotation;
|
|
generated$1.assertTypeAlias = assertTypeAlias;
|
|
generated$1.assertTypeAnnotation = assertTypeAnnotation;
|
|
generated$1.assertTypeCastExpression = assertTypeCastExpression;
|
|
generated$1.assertTypeParameter = assertTypeParameter;
|
|
generated$1.assertTypeParameterDeclaration = assertTypeParameterDeclaration;
|
|
generated$1.assertTypeParameterInstantiation = assertTypeParameterInstantiation;
|
|
generated$1.assertTypeScript = assertTypeScript;
|
|
generated$1.assertTypeofTypeAnnotation = assertTypeofTypeAnnotation;
|
|
generated$1.assertUnaryExpression = assertUnaryExpression;
|
|
generated$1.assertUnaryLike = assertUnaryLike;
|
|
generated$1.assertUnionTypeAnnotation = assertUnionTypeAnnotation;
|
|
generated$1.assertUpdateExpression = assertUpdateExpression;
|
|
generated$1.assertUserWhitespacable = assertUserWhitespacable;
|
|
generated$1.assertV8IntrinsicIdentifier = assertV8IntrinsicIdentifier;
|
|
generated$1.assertVariableDeclaration = assertVariableDeclaration;
|
|
generated$1.assertVariableDeclarator = assertVariableDeclarator;
|
|
generated$1.assertVariance = assertVariance;
|
|
generated$1.assertVoidTypeAnnotation = assertVoidTypeAnnotation;
|
|
generated$1.assertWhile = assertWhile;
|
|
generated$1.assertWhileStatement = assertWhileStatement;
|
|
generated$1.assertWithStatement = assertWithStatement;
|
|
generated$1.assertYieldExpression = assertYieldExpression;
|
|
var _is = requireIs();
|
|
var _deprecationWarning = requireDeprecationWarning();
|
|
function assert(type, node, opts) {
|
|
if (!(0, _is.default)(type, node, opts)) {
|
|
throw new Error(`Expected type "${type}" with option ${JSON.stringify(opts)}, ` + `but instead got "${node.type}".`);
|
|
}
|
|
}
|
|
function assertArrayExpression(node, opts) {
|
|
assert("ArrayExpression", node, opts);
|
|
}
|
|
function assertAssignmentExpression(node, opts) {
|
|
assert("AssignmentExpression", node, opts);
|
|
}
|
|
function assertBinaryExpression(node, opts) {
|
|
assert("BinaryExpression", node, opts);
|
|
}
|
|
function assertInterpreterDirective(node, opts) {
|
|
assert("InterpreterDirective", node, opts);
|
|
}
|
|
function assertDirective(node, opts) {
|
|
assert("Directive", node, opts);
|
|
}
|
|
function assertDirectiveLiteral(node, opts) {
|
|
assert("DirectiveLiteral", node, opts);
|
|
}
|
|
function assertBlockStatement(node, opts) {
|
|
assert("BlockStatement", node, opts);
|
|
}
|
|
function assertBreakStatement(node, opts) {
|
|
assert("BreakStatement", node, opts);
|
|
}
|
|
function assertCallExpression(node, opts) {
|
|
assert("CallExpression", node, opts);
|
|
}
|
|
function assertCatchClause(node, opts) {
|
|
assert("CatchClause", node, opts);
|
|
}
|
|
function assertConditionalExpression(node, opts) {
|
|
assert("ConditionalExpression", node, opts);
|
|
}
|
|
function assertContinueStatement(node, opts) {
|
|
assert("ContinueStatement", node, opts);
|
|
}
|
|
function assertDebuggerStatement(node, opts) {
|
|
assert("DebuggerStatement", node, opts);
|
|
}
|
|
function assertDoWhileStatement(node, opts) {
|
|
assert("DoWhileStatement", node, opts);
|
|
}
|
|
function assertEmptyStatement(node, opts) {
|
|
assert("EmptyStatement", node, opts);
|
|
}
|
|
function assertExpressionStatement(node, opts) {
|
|
assert("ExpressionStatement", node, opts);
|
|
}
|
|
function assertFile(node, opts) {
|
|
assert("File", node, opts);
|
|
}
|
|
function assertForInStatement(node, opts) {
|
|
assert("ForInStatement", node, opts);
|
|
}
|
|
function assertForStatement(node, opts) {
|
|
assert("ForStatement", node, opts);
|
|
}
|
|
function assertFunctionDeclaration(node, opts) {
|
|
assert("FunctionDeclaration", node, opts);
|
|
}
|
|
function assertFunctionExpression(node, opts) {
|
|
assert("FunctionExpression", node, opts);
|
|
}
|
|
function assertIdentifier(node, opts) {
|
|
assert("Identifier", node, opts);
|
|
}
|
|
function assertIfStatement(node, opts) {
|
|
assert("IfStatement", node, opts);
|
|
}
|
|
function assertLabeledStatement(node, opts) {
|
|
assert("LabeledStatement", node, opts);
|
|
}
|
|
function assertStringLiteral(node, opts) {
|
|
assert("StringLiteral", node, opts);
|
|
}
|
|
function assertNumericLiteral(node, opts) {
|
|
assert("NumericLiteral", node, opts);
|
|
}
|
|
function assertNullLiteral(node, opts) {
|
|
assert("NullLiteral", node, opts);
|
|
}
|
|
function assertBooleanLiteral(node, opts) {
|
|
assert("BooleanLiteral", node, opts);
|
|
}
|
|
function assertRegExpLiteral(node, opts) {
|
|
assert("RegExpLiteral", node, opts);
|
|
}
|
|
function assertLogicalExpression(node, opts) {
|
|
assert("LogicalExpression", node, opts);
|
|
}
|
|
function assertMemberExpression(node, opts) {
|
|
assert("MemberExpression", node, opts);
|
|
}
|
|
function assertNewExpression(node, opts) {
|
|
assert("NewExpression", node, opts);
|
|
}
|
|
function assertProgram(node, opts) {
|
|
assert("Program", node, opts);
|
|
}
|
|
function assertObjectExpression(node, opts) {
|
|
assert("ObjectExpression", node, opts);
|
|
}
|
|
function assertObjectMethod(node, opts) {
|
|
assert("ObjectMethod", node, opts);
|
|
}
|
|
function assertObjectProperty(node, opts) {
|
|
assert("ObjectProperty", node, opts);
|
|
}
|
|
function assertRestElement(node, opts) {
|
|
assert("RestElement", node, opts);
|
|
}
|
|
function assertReturnStatement(node, opts) {
|
|
assert("ReturnStatement", node, opts);
|
|
}
|
|
function assertSequenceExpression(node, opts) {
|
|
assert("SequenceExpression", node, opts);
|
|
}
|
|
function assertParenthesizedExpression(node, opts) {
|
|
assert("ParenthesizedExpression", node, opts);
|
|
}
|
|
function assertSwitchCase(node, opts) {
|
|
assert("SwitchCase", node, opts);
|
|
}
|
|
function assertSwitchStatement(node, opts) {
|
|
assert("SwitchStatement", node, opts);
|
|
}
|
|
function assertThisExpression(node, opts) {
|
|
assert("ThisExpression", node, opts);
|
|
}
|
|
function assertThrowStatement(node, opts) {
|
|
assert("ThrowStatement", node, opts);
|
|
}
|
|
function assertTryStatement(node, opts) {
|
|
assert("TryStatement", node, opts);
|
|
}
|
|
function assertUnaryExpression(node, opts) {
|
|
assert("UnaryExpression", node, opts);
|
|
}
|
|
function assertUpdateExpression(node, opts) {
|
|
assert("UpdateExpression", node, opts);
|
|
}
|
|
function assertVariableDeclaration(node, opts) {
|
|
assert("VariableDeclaration", node, opts);
|
|
}
|
|
function assertVariableDeclarator(node, opts) {
|
|
assert("VariableDeclarator", node, opts);
|
|
}
|
|
function assertWhileStatement(node, opts) {
|
|
assert("WhileStatement", node, opts);
|
|
}
|
|
function assertWithStatement(node, opts) {
|
|
assert("WithStatement", node, opts);
|
|
}
|
|
function assertAssignmentPattern(node, opts) {
|
|
assert("AssignmentPattern", node, opts);
|
|
}
|
|
function assertArrayPattern(node, opts) {
|
|
assert("ArrayPattern", node, opts);
|
|
}
|
|
function assertArrowFunctionExpression(node, opts) {
|
|
assert("ArrowFunctionExpression", node, opts);
|
|
}
|
|
function assertClassBody(node, opts) {
|
|
assert("ClassBody", node, opts);
|
|
}
|
|
function assertClassExpression(node, opts) {
|
|
assert("ClassExpression", node, opts);
|
|
}
|
|
function assertClassDeclaration(node, opts) {
|
|
assert("ClassDeclaration", node, opts);
|
|
}
|
|
function assertExportAllDeclaration(node, opts) {
|
|
assert("ExportAllDeclaration", node, opts);
|
|
}
|
|
function assertExportDefaultDeclaration(node, opts) {
|
|
assert("ExportDefaultDeclaration", node, opts);
|
|
}
|
|
function assertExportNamedDeclaration(node, opts) {
|
|
assert("ExportNamedDeclaration", node, opts);
|
|
}
|
|
function assertExportSpecifier(node, opts) {
|
|
assert("ExportSpecifier", node, opts);
|
|
}
|
|
function assertForOfStatement(node, opts) {
|
|
assert("ForOfStatement", node, opts);
|
|
}
|
|
function assertImportDeclaration(node, opts) {
|
|
assert("ImportDeclaration", node, opts);
|
|
}
|
|
function assertImportDefaultSpecifier(node, opts) {
|
|
assert("ImportDefaultSpecifier", node, opts);
|
|
}
|
|
function assertImportNamespaceSpecifier(node, opts) {
|
|
assert("ImportNamespaceSpecifier", node, opts);
|
|
}
|
|
function assertImportSpecifier(node, opts) {
|
|
assert("ImportSpecifier", node, opts);
|
|
}
|
|
function assertImportExpression(node, opts) {
|
|
assert("ImportExpression", node, opts);
|
|
}
|
|
function assertMetaProperty(node, opts) {
|
|
assert("MetaProperty", node, opts);
|
|
}
|
|
function assertClassMethod(node, opts) {
|
|
assert("ClassMethod", node, opts);
|
|
}
|
|
function assertObjectPattern(node, opts) {
|
|
assert("ObjectPattern", node, opts);
|
|
}
|
|
function assertSpreadElement(node, opts) {
|
|
assert("SpreadElement", node, opts);
|
|
}
|
|
function assertSuper(node, opts) {
|
|
assert("Super", node, opts);
|
|
}
|
|
function assertTaggedTemplateExpression(node, opts) {
|
|
assert("TaggedTemplateExpression", node, opts);
|
|
}
|
|
function assertTemplateElement(node, opts) {
|
|
assert("TemplateElement", node, opts);
|
|
}
|
|
function assertTemplateLiteral(node, opts) {
|
|
assert("TemplateLiteral", node, opts);
|
|
}
|
|
function assertYieldExpression(node, opts) {
|
|
assert("YieldExpression", node, opts);
|
|
}
|
|
function assertAwaitExpression(node, opts) {
|
|
assert("AwaitExpression", node, opts);
|
|
}
|
|
function assertImport(node, opts) {
|
|
assert("Import", node, opts);
|
|
}
|
|
function assertBigIntLiteral(node, opts) {
|
|
assert("BigIntLiteral", node, opts);
|
|
}
|
|
function assertExportNamespaceSpecifier(node, opts) {
|
|
assert("ExportNamespaceSpecifier", node, opts);
|
|
}
|
|
function assertOptionalMemberExpression(node, opts) {
|
|
assert("OptionalMemberExpression", node, opts);
|
|
}
|
|
function assertOptionalCallExpression(node, opts) {
|
|
assert("OptionalCallExpression", node, opts);
|
|
}
|
|
function assertClassProperty(node, opts) {
|
|
assert("ClassProperty", node, opts);
|
|
}
|
|
function assertClassAccessorProperty(node, opts) {
|
|
assert("ClassAccessorProperty", node, opts);
|
|
}
|
|
function assertClassPrivateProperty(node, opts) {
|
|
assert("ClassPrivateProperty", node, opts);
|
|
}
|
|
function assertClassPrivateMethod(node, opts) {
|
|
assert("ClassPrivateMethod", node, opts);
|
|
}
|
|
function assertPrivateName(node, opts) {
|
|
assert("PrivateName", node, opts);
|
|
}
|
|
function assertStaticBlock(node, opts) {
|
|
assert("StaticBlock", node, opts);
|
|
}
|
|
function assertAnyTypeAnnotation(node, opts) {
|
|
assert("AnyTypeAnnotation", node, opts);
|
|
}
|
|
function assertArrayTypeAnnotation(node, opts) {
|
|
assert("ArrayTypeAnnotation", node, opts);
|
|
}
|
|
function assertBooleanTypeAnnotation(node, opts) {
|
|
assert("BooleanTypeAnnotation", node, opts);
|
|
}
|
|
function assertBooleanLiteralTypeAnnotation(node, opts) {
|
|
assert("BooleanLiteralTypeAnnotation", node, opts);
|
|
}
|
|
function assertNullLiteralTypeAnnotation(node, opts) {
|
|
assert("NullLiteralTypeAnnotation", node, opts);
|
|
}
|
|
function assertClassImplements(node, opts) {
|
|
assert("ClassImplements", node, opts);
|
|
}
|
|
function assertDeclareClass(node, opts) {
|
|
assert("DeclareClass", node, opts);
|
|
}
|
|
function assertDeclareFunction(node, opts) {
|
|
assert("DeclareFunction", node, opts);
|
|
}
|
|
function assertDeclareInterface(node, opts) {
|
|
assert("DeclareInterface", node, opts);
|
|
}
|
|
function assertDeclareModule(node, opts) {
|
|
assert("DeclareModule", node, opts);
|
|
}
|
|
function assertDeclareModuleExports(node, opts) {
|
|
assert("DeclareModuleExports", node, opts);
|
|
}
|
|
function assertDeclareTypeAlias(node, opts) {
|
|
assert("DeclareTypeAlias", node, opts);
|
|
}
|
|
function assertDeclareOpaqueType(node, opts) {
|
|
assert("DeclareOpaqueType", node, opts);
|
|
}
|
|
function assertDeclareVariable(node, opts) {
|
|
assert("DeclareVariable", node, opts);
|
|
}
|
|
function assertDeclareExportDeclaration(node, opts) {
|
|
assert("DeclareExportDeclaration", node, opts);
|
|
}
|
|
function assertDeclareExportAllDeclaration(node, opts) {
|
|
assert("DeclareExportAllDeclaration", node, opts);
|
|
}
|
|
function assertDeclaredPredicate(node, opts) {
|
|
assert("DeclaredPredicate", node, opts);
|
|
}
|
|
function assertExistsTypeAnnotation(node, opts) {
|
|
assert("ExistsTypeAnnotation", node, opts);
|
|
}
|
|
function assertFunctionTypeAnnotation(node, opts) {
|
|
assert("FunctionTypeAnnotation", node, opts);
|
|
}
|
|
function assertFunctionTypeParam(node, opts) {
|
|
assert("FunctionTypeParam", node, opts);
|
|
}
|
|
function assertGenericTypeAnnotation(node, opts) {
|
|
assert("GenericTypeAnnotation", node, opts);
|
|
}
|
|
function assertInferredPredicate(node, opts) {
|
|
assert("InferredPredicate", node, opts);
|
|
}
|
|
function assertInterfaceExtends(node, opts) {
|
|
assert("InterfaceExtends", node, opts);
|
|
}
|
|
function assertInterfaceDeclaration(node, opts) {
|
|
assert("InterfaceDeclaration", node, opts);
|
|
}
|
|
function assertInterfaceTypeAnnotation(node, opts) {
|
|
assert("InterfaceTypeAnnotation", node, opts);
|
|
}
|
|
function assertIntersectionTypeAnnotation(node, opts) {
|
|
assert("IntersectionTypeAnnotation", node, opts);
|
|
}
|
|
function assertMixedTypeAnnotation(node, opts) {
|
|
assert("MixedTypeAnnotation", node, opts);
|
|
}
|
|
function assertEmptyTypeAnnotation(node, opts) {
|
|
assert("EmptyTypeAnnotation", node, opts);
|
|
}
|
|
function assertNullableTypeAnnotation(node, opts) {
|
|
assert("NullableTypeAnnotation", node, opts);
|
|
}
|
|
function assertNumberLiteralTypeAnnotation(node, opts) {
|
|
assert("NumberLiteralTypeAnnotation", node, opts);
|
|
}
|
|
function assertNumberTypeAnnotation(node, opts) {
|
|
assert("NumberTypeAnnotation", node, opts);
|
|
}
|
|
function assertObjectTypeAnnotation(node, opts) {
|
|
assert("ObjectTypeAnnotation", node, opts);
|
|
}
|
|
function assertObjectTypeInternalSlot(node, opts) {
|
|
assert("ObjectTypeInternalSlot", node, opts);
|
|
}
|
|
function assertObjectTypeCallProperty(node, opts) {
|
|
assert("ObjectTypeCallProperty", node, opts);
|
|
}
|
|
function assertObjectTypeIndexer(node, opts) {
|
|
assert("ObjectTypeIndexer", node, opts);
|
|
}
|
|
function assertObjectTypeProperty(node, opts) {
|
|
assert("ObjectTypeProperty", node, opts);
|
|
}
|
|
function assertObjectTypeSpreadProperty(node, opts) {
|
|
assert("ObjectTypeSpreadProperty", node, opts);
|
|
}
|
|
function assertOpaqueType(node, opts) {
|
|
assert("OpaqueType", node, opts);
|
|
}
|
|
function assertQualifiedTypeIdentifier(node, opts) {
|
|
assert("QualifiedTypeIdentifier", node, opts);
|
|
}
|
|
function assertStringLiteralTypeAnnotation(node, opts) {
|
|
assert("StringLiteralTypeAnnotation", node, opts);
|
|
}
|
|
function assertStringTypeAnnotation(node, opts) {
|
|
assert("StringTypeAnnotation", node, opts);
|
|
}
|
|
function assertSymbolTypeAnnotation(node, opts) {
|
|
assert("SymbolTypeAnnotation", node, opts);
|
|
}
|
|
function assertThisTypeAnnotation(node, opts) {
|
|
assert("ThisTypeAnnotation", node, opts);
|
|
}
|
|
function assertTupleTypeAnnotation(node, opts) {
|
|
assert("TupleTypeAnnotation", node, opts);
|
|
}
|
|
function assertTypeofTypeAnnotation(node, opts) {
|
|
assert("TypeofTypeAnnotation", node, opts);
|
|
}
|
|
function assertTypeAlias(node, opts) {
|
|
assert("TypeAlias", node, opts);
|
|
}
|
|
function assertTypeAnnotation(node, opts) {
|
|
assert("TypeAnnotation", node, opts);
|
|
}
|
|
function assertTypeCastExpression(node, opts) {
|
|
assert("TypeCastExpression", node, opts);
|
|
}
|
|
function assertTypeParameter(node, opts) {
|
|
assert("TypeParameter", node, opts);
|
|
}
|
|
function assertTypeParameterDeclaration(node, opts) {
|
|
assert("TypeParameterDeclaration", node, opts);
|
|
}
|
|
function assertTypeParameterInstantiation(node, opts) {
|
|
assert("TypeParameterInstantiation", node, opts);
|
|
}
|
|
function assertUnionTypeAnnotation(node, opts) {
|
|
assert("UnionTypeAnnotation", node, opts);
|
|
}
|
|
function assertVariance(node, opts) {
|
|
assert("Variance", node, opts);
|
|
}
|
|
function assertVoidTypeAnnotation(node, opts) {
|
|
assert("VoidTypeAnnotation", node, opts);
|
|
}
|
|
function assertEnumDeclaration(node, opts) {
|
|
assert("EnumDeclaration", node, opts);
|
|
}
|
|
function assertEnumBooleanBody(node, opts) {
|
|
assert("EnumBooleanBody", node, opts);
|
|
}
|
|
function assertEnumNumberBody(node, opts) {
|
|
assert("EnumNumberBody", node, opts);
|
|
}
|
|
function assertEnumStringBody(node, opts) {
|
|
assert("EnumStringBody", node, opts);
|
|
}
|
|
function assertEnumSymbolBody(node, opts) {
|
|
assert("EnumSymbolBody", node, opts);
|
|
}
|
|
function assertEnumBooleanMember(node, opts) {
|
|
assert("EnumBooleanMember", node, opts);
|
|
}
|
|
function assertEnumNumberMember(node, opts) {
|
|
assert("EnumNumberMember", node, opts);
|
|
}
|
|
function assertEnumStringMember(node, opts) {
|
|
assert("EnumStringMember", node, opts);
|
|
}
|
|
function assertEnumDefaultedMember(node, opts) {
|
|
assert("EnumDefaultedMember", node, opts);
|
|
}
|
|
function assertIndexedAccessType(node, opts) {
|
|
assert("IndexedAccessType", node, opts);
|
|
}
|
|
function assertOptionalIndexedAccessType(node, opts) {
|
|
assert("OptionalIndexedAccessType", node, opts);
|
|
}
|
|
function assertJSXAttribute(node, opts) {
|
|
assert("JSXAttribute", node, opts);
|
|
}
|
|
function assertJSXClosingElement(node, opts) {
|
|
assert("JSXClosingElement", node, opts);
|
|
}
|
|
function assertJSXElement(node, opts) {
|
|
assert("JSXElement", node, opts);
|
|
}
|
|
function assertJSXEmptyExpression(node, opts) {
|
|
assert("JSXEmptyExpression", node, opts);
|
|
}
|
|
function assertJSXExpressionContainer(node, opts) {
|
|
assert("JSXExpressionContainer", node, opts);
|
|
}
|
|
function assertJSXSpreadChild(node, opts) {
|
|
assert("JSXSpreadChild", node, opts);
|
|
}
|
|
function assertJSXIdentifier(node, opts) {
|
|
assert("JSXIdentifier", node, opts);
|
|
}
|
|
function assertJSXMemberExpression(node, opts) {
|
|
assert("JSXMemberExpression", node, opts);
|
|
}
|
|
function assertJSXNamespacedName(node, opts) {
|
|
assert("JSXNamespacedName", node, opts);
|
|
}
|
|
function assertJSXOpeningElement(node, opts) {
|
|
assert("JSXOpeningElement", node, opts);
|
|
}
|
|
function assertJSXSpreadAttribute(node, opts) {
|
|
assert("JSXSpreadAttribute", node, opts);
|
|
}
|
|
function assertJSXText(node, opts) {
|
|
assert("JSXText", node, opts);
|
|
}
|
|
function assertJSXFragment(node, opts) {
|
|
assert("JSXFragment", node, opts);
|
|
}
|
|
function assertJSXOpeningFragment(node, opts) {
|
|
assert("JSXOpeningFragment", node, opts);
|
|
}
|
|
function assertJSXClosingFragment(node, opts) {
|
|
assert("JSXClosingFragment", node, opts);
|
|
}
|
|
function assertNoop(node, opts) {
|
|
assert("Noop", node, opts);
|
|
}
|
|
function assertPlaceholder(node, opts) {
|
|
assert("Placeholder", node, opts);
|
|
}
|
|
function assertV8IntrinsicIdentifier(node, opts) {
|
|
assert("V8IntrinsicIdentifier", node, opts);
|
|
}
|
|
function assertArgumentPlaceholder(node, opts) {
|
|
assert("ArgumentPlaceholder", node, opts);
|
|
}
|
|
function assertBindExpression(node, opts) {
|
|
assert("BindExpression", node, opts);
|
|
}
|
|
function assertImportAttribute(node, opts) {
|
|
assert("ImportAttribute", node, opts);
|
|
}
|
|
function assertDecorator(node, opts) {
|
|
assert("Decorator", node, opts);
|
|
}
|
|
function assertDoExpression(node, opts) {
|
|
assert("DoExpression", node, opts);
|
|
}
|
|
function assertExportDefaultSpecifier(node, opts) {
|
|
assert("ExportDefaultSpecifier", node, opts);
|
|
}
|
|
function assertRecordExpression(node, opts) {
|
|
assert("RecordExpression", node, opts);
|
|
}
|
|
function assertTupleExpression(node, opts) {
|
|
assert("TupleExpression", node, opts);
|
|
}
|
|
function assertDecimalLiteral(node, opts) {
|
|
assert("DecimalLiteral", node, opts);
|
|
}
|
|
function assertModuleExpression(node, opts) {
|
|
assert("ModuleExpression", node, opts);
|
|
}
|
|
function assertTopicReference(node, opts) {
|
|
assert("TopicReference", node, opts);
|
|
}
|
|
function assertPipelineTopicExpression(node, opts) {
|
|
assert("PipelineTopicExpression", node, opts);
|
|
}
|
|
function assertPipelineBareFunction(node, opts) {
|
|
assert("PipelineBareFunction", node, opts);
|
|
}
|
|
function assertPipelinePrimaryTopicReference(node, opts) {
|
|
assert("PipelinePrimaryTopicReference", node, opts);
|
|
}
|
|
function assertTSParameterProperty(node, opts) {
|
|
assert("TSParameterProperty", node, opts);
|
|
}
|
|
function assertTSDeclareFunction(node, opts) {
|
|
assert("TSDeclareFunction", node, opts);
|
|
}
|
|
function assertTSDeclareMethod(node, opts) {
|
|
assert("TSDeclareMethod", node, opts);
|
|
}
|
|
function assertTSQualifiedName(node, opts) {
|
|
assert("TSQualifiedName", node, opts);
|
|
}
|
|
function assertTSCallSignatureDeclaration(node, opts) {
|
|
assert("TSCallSignatureDeclaration", node, opts);
|
|
}
|
|
function assertTSConstructSignatureDeclaration(node, opts) {
|
|
assert("TSConstructSignatureDeclaration", node, opts);
|
|
}
|
|
function assertTSPropertySignature(node, opts) {
|
|
assert("TSPropertySignature", node, opts);
|
|
}
|
|
function assertTSMethodSignature(node, opts) {
|
|
assert("TSMethodSignature", node, opts);
|
|
}
|
|
function assertTSIndexSignature(node, opts) {
|
|
assert("TSIndexSignature", node, opts);
|
|
}
|
|
function assertTSAnyKeyword(node, opts) {
|
|
assert("TSAnyKeyword", node, opts);
|
|
}
|
|
function assertTSBooleanKeyword(node, opts) {
|
|
assert("TSBooleanKeyword", node, opts);
|
|
}
|
|
function assertTSBigIntKeyword(node, opts) {
|
|
assert("TSBigIntKeyword", node, opts);
|
|
}
|
|
function assertTSIntrinsicKeyword(node, opts) {
|
|
assert("TSIntrinsicKeyword", node, opts);
|
|
}
|
|
function assertTSNeverKeyword(node, opts) {
|
|
assert("TSNeverKeyword", node, opts);
|
|
}
|
|
function assertTSNullKeyword(node, opts) {
|
|
assert("TSNullKeyword", node, opts);
|
|
}
|
|
function assertTSNumberKeyword(node, opts) {
|
|
assert("TSNumberKeyword", node, opts);
|
|
}
|
|
function assertTSObjectKeyword(node, opts) {
|
|
assert("TSObjectKeyword", node, opts);
|
|
}
|
|
function assertTSStringKeyword(node, opts) {
|
|
assert("TSStringKeyword", node, opts);
|
|
}
|
|
function assertTSSymbolKeyword(node, opts) {
|
|
assert("TSSymbolKeyword", node, opts);
|
|
}
|
|
function assertTSUndefinedKeyword(node, opts) {
|
|
assert("TSUndefinedKeyword", node, opts);
|
|
}
|
|
function assertTSUnknownKeyword(node, opts) {
|
|
assert("TSUnknownKeyword", node, opts);
|
|
}
|
|
function assertTSVoidKeyword(node, opts) {
|
|
assert("TSVoidKeyword", node, opts);
|
|
}
|
|
function assertTSThisType(node, opts) {
|
|
assert("TSThisType", node, opts);
|
|
}
|
|
function assertTSFunctionType(node, opts) {
|
|
assert("TSFunctionType", node, opts);
|
|
}
|
|
function assertTSConstructorType(node, opts) {
|
|
assert("TSConstructorType", node, opts);
|
|
}
|
|
function assertTSTypeReference(node, opts) {
|
|
assert("TSTypeReference", node, opts);
|
|
}
|
|
function assertTSTypePredicate(node, opts) {
|
|
assert("TSTypePredicate", node, opts);
|
|
}
|
|
function assertTSTypeQuery(node, opts) {
|
|
assert("TSTypeQuery", node, opts);
|
|
}
|
|
function assertTSTypeLiteral(node, opts) {
|
|
assert("TSTypeLiteral", node, opts);
|
|
}
|
|
function assertTSArrayType(node, opts) {
|
|
assert("TSArrayType", node, opts);
|
|
}
|
|
function assertTSTupleType(node, opts) {
|
|
assert("TSTupleType", node, opts);
|
|
}
|
|
function assertTSOptionalType(node, opts) {
|
|
assert("TSOptionalType", node, opts);
|
|
}
|
|
function assertTSRestType(node, opts) {
|
|
assert("TSRestType", node, opts);
|
|
}
|
|
function assertTSNamedTupleMember(node, opts) {
|
|
assert("TSNamedTupleMember", node, opts);
|
|
}
|
|
function assertTSUnionType(node, opts) {
|
|
assert("TSUnionType", node, opts);
|
|
}
|
|
function assertTSIntersectionType(node, opts) {
|
|
assert("TSIntersectionType", node, opts);
|
|
}
|
|
function assertTSConditionalType(node, opts) {
|
|
assert("TSConditionalType", node, opts);
|
|
}
|
|
function assertTSInferType(node, opts) {
|
|
assert("TSInferType", node, opts);
|
|
}
|
|
function assertTSParenthesizedType(node, opts) {
|
|
assert("TSParenthesizedType", node, opts);
|
|
}
|
|
function assertTSTypeOperator(node, opts) {
|
|
assert("TSTypeOperator", node, opts);
|
|
}
|
|
function assertTSIndexedAccessType(node, opts) {
|
|
assert("TSIndexedAccessType", node, opts);
|
|
}
|
|
function assertTSMappedType(node, opts) {
|
|
assert("TSMappedType", node, opts);
|
|
}
|
|
function assertTSLiteralType(node, opts) {
|
|
assert("TSLiteralType", node, opts);
|
|
}
|
|
function assertTSExpressionWithTypeArguments(node, opts) {
|
|
assert("TSExpressionWithTypeArguments", node, opts);
|
|
}
|
|
function assertTSInterfaceDeclaration(node, opts) {
|
|
assert("TSInterfaceDeclaration", node, opts);
|
|
}
|
|
function assertTSInterfaceBody(node, opts) {
|
|
assert("TSInterfaceBody", node, opts);
|
|
}
|
|
function assertTSTypeAliasDeclaration(node, opts) {
|
|
assert("TSTypeAliasDeclaration", node, opts);
|
|
}
|
|
function assertTSInstantiationExpression(node, opts) {
|
|
assert("TSInstantiationExpression", node, opts);
|
|
}
|
|
function assertTSAsExpression(node, opts) {
|
|
assert("TSAsExpression", node, opts);
|
|
}
|
|
function assertTSSatisfiesExpression(node, opts) {
|
|
assert("TSSatisfiesExpression", node, opts);
|
|
}
|
|
function assertTSTypeAssertion(node, opts) {
|
|
assert("TSTypeAssertion", node, opts);
|
|
}
|
|
function assertTSEnumDeclaration(node, opts) {
|
|
assert("TSEnumDeclaration", node, opts);
|
|
}
|
|
function assertTSEnumMember(node, opts) {
|
|
assert("TSEnumMember", node, opts);
|
|
}
|
|
function assertTSModuleDeclaration(node, opts) {
|
|
assert("TSModuleDeclaration", node, opts);
|
|
}
|
|
function assertTSModuleBlock(node, opts) {
|
|
assert("TSModuleBlock", node, opts);
|
|
}
|
|
function assertTSImportType(node, opts) {
|
|
assert("TSImportType", node, opts);
|
|
}
|
|
function assertTSImportEqualsDeclaration(node, opts) {
|
|
assert("TSImportEqualsDeclaration", node, opts);
|
|
}
|
|
function assertTSExternalModuleReference(node, opts) {
|
|
assert("TSExternalModuleReference", node, opts);
|
|
}
|
|
function assertTSNonNullExpression(node, opts) {
|
|
assert("TSNonNullExpression", node, opts);
|
|
}
|
|
function assertTSExportAssignment(node, opts) {
|
|
assert("TSExportAssignment", node, opts);
|
|
}
|
|
function assertTSNamespaceExportDeclaration(node, opts) {
|
|
assert("TSNamespaceExportDeclaration", node, opts);
|
|
}
|
|
function assertTSTypeAnnotation(node, opts) {
|
|
assert("TSTypeAnnotation", node, opts);
|
|
}
|
|
function assertTSTypeParameterInstantiation(node, opts) {
|
|
assert("TSTypeParameterInstantiation", node, opts);
|
|
}
|
|
function assertTSTypeParameterDeclaration(node, opts) {
|
|
assert("TSTypeParameterDeclaration", node, opts);
|
|
}
|
|
function assertTSTypeParameter(node, opts) {
|
|
assert("TSTypeParameter", node, opts);
|
|
}
|
|
function assertStandardized(node, opts) {
|
|
assert("Standardized", node, opts);
|
|
}
|
|
function assertExpression(node, opts) {
|
|
assert("Expression", node, opts);
|
|
}
|
|
function assertBinary(node, opts) {
|
|
assert("Binary", node, opts);
|
|
}
|
|
function assertScopable(node, opts) {
|
|
assert("Scopable", node, opts);
|
|
}
|
|
function assertBlockParent(node, opts) {
|
|
assert("BlockParent", node, opts);
|
|
}
|
|
function assertBlock(node, opts) {
|
|
assert("Block", node, opts);
|
|
}
|
|
function assertStatement(node, opts) {
|
|
assert("Statement", node, opts);
|
|
}
|
|
function assertTerminatorless(node, opts) {
|
|
assert("Terminatorless", node, opts);
|
|
}
|
|
function assertCompletionStatement(node, opts) {
|
|
assert("CompletionStatement", node, opts);
|
|
}
|
|
function assertConditional(node, opts) {
|
|
assert("Conditional", node, opts);
|
|
}
|
|
function assertLoop(node, opts) {
|
|
assert("Loop", node, opts);
|
|
}
|
|
function assertWhile(node, opts) {
|
|
assert("While", node, opts);
|
|
}
|
|
function assertExpressionWrapper(node, opts) {
|
|
assert("ExpressionWrapper", node, opts);
|
|
}
|
|
function assertFor(node, opts) {
|
|
assert("For", node, opts);
|
|
}
|
|
function assertForXStatement(node, opts) {
|
|
assert("ForXStatement", node, opts);
|
|
}
|
|
function assertFunction(node, opts) {
|
|
assert("Function", node, opts);
|
|
}
|
|
function assertFunctionParent(node, opts) {
|
|
assert("FunctionParent", node, opts);
|
|
}
|
|
function assertPureish(node, opts) {
|
|
assert("Pureish", node, opts);
|
|
}
|
|
function assertDeclaration(node, opts) {
|
|
assert("Declaration", node, opts);
|
|
}
|
|
function assertPatternLike(node, opts) {
|
|
assert("PatternLike", node, opts);
|
|
}
|
|
function assertLVal(node, opts) {
|
|
assert("LVal", node, opts);
|
|
}
|
|
function assertTSEntityName(node, opts) {
|
|
assert("TSEntityName", node, opts);
|
|
}
|
|
function assertLiteral(node, opts) {
|
|
assert("Literal", node, opts);
|
|
}
|
|
function assertImmutable(node, opts) {
|
|
assert("Immutable", node, opts);
|
|
}
|
|
function assertUserWhitespacable(node, opts) {
|
|
assert("UserWhitespacable", node, opts);
|
|
}
|
|
function assertMethod(node, opts) {
|
|
assert("Method", node, opts);
|
|
}
|
|
function assertObjectMember(node, opts) {
|
|
assert("ObjectMember", node, opts);
|
|
}
|
|
function assertProperty(node, opts) {
|
|
assert("Property", node, opts);
|
|
}
|
|
function assertUnaryLike(node, opts) {
|
|
assert("UnaryLike", node, opts);
|
|
}
|
|
function assertPattern(node, opts) {
|
|
assert("Pattern", node, opts);
|
|
}
|
|
function assertClass(node, opts) {
|
|
assert("Class", node, opts);
|
|
}
|
|
function assertImportOrExportDeclaration(node, opts) {
|
|
assert("ImportOrExportDeclaration", node, opts);
|
|
}
|
|
function assertExportDeclaration(node, opts) {
|
|
assert("ExportDeclaration", node, opts);
|
|
}
|
|
function assertModuleSpecifier(node, opts) {
|
|
assert("ModuleSpecifier", node, opts);
|
|
}
|
|
function assertAccessor(node, opts) {
|
|
assert("Accessor", node, opts);
|
|
}
|
|
function assertPrivate(node, opts) {
|
|
assert("Private", node, opts);
|
|
}
|
|
function assertFlow(node, opts) {
|
|
assert("Flow", node, opts);
|
|
}
|
|
function assertFlowType(node, opts) {
|
|
assert("FlowType", node, opts);
|
|
}
|
|
function assertFlowBaseAnnotation(node, opts) {
|
|
assert("FlowBaseAnnotation", node, opts);
|
|
}
|
|
function assertFlowDeclaration(node, opts) {
|
|
assert("FlowDeclaration", node, opts);
|
|
}
|
|
function assertFlowPredicate(node, opts) {
|
|
assert("FlowPredicate", node, opts);
|
|
}
|
|
function assertEnumBody(node, opts) {
|
|
assert("EnumBody", node, opts);
|
|
}
|
|
function assertEnumMember(node, opts) {
|
|
assert("EnumMember", node, opts);
|
|
}
|
|
function assertJSX(node, opts) {
|
|
assert("JSX", node, opts);
|
|
}
|
|
function assertMiscellaneous(node, opts) {
|
|
assert("Miscellaneous", node, opts);
|
|
}
|
|
function assertTypeScript(node, opts) {
|
|
assert("TypeScript", node, opts);
|
|
}
|
|
function assertTSTypeElement(node, opts) {
|
|
assert("TSTypeElement", node, opts);
|
|
}
|
|
function assertTSType(node, opts) {
|
|
assert("TSType", node, opts);
|
|
}
|
|
function assertTSBaseType(node, opts) {
|
|
assert("TSBaseType", node, opts);
|
|
}
|
|
function assertNumberLiteral(node, opts) {
|
|
(0, _deprecationWarning.default)("assertNumberLiteral", "assertNumericLiteral");
|
|
assert("NumberLiteral", node, opts);
|
|
}
|
|
function assertRegexLiteral(node, opts) {
|
|
(0, _deprecationWarning.default)("assertRegexLiteral", "assertRegExpLiteral");
|
|
assert("RegexLiteral", node, opts);
|
|
}
|
|
function assertRestProperty(node, opts) {
|
|
(0, _deprecationWarning.default)("assertRestProperty", "assertRestElement");
|
|
assert("RestProperty", node, opts);
|
|
}
|
|
function assertSpreadProperty(node, opts) {
|
|
(0, _deprecationWarning.default)("assertSpreadProperty", "assertSpreadElement");
|
|
assert("SpreadProperty", node, opts);
|
|
}
|
|
function assertModuleDeclaration(node, opts) {
|
|
(0, _deprecationWarning.default)("assertModuleDeclaration", "assertImportOrExportDeclaration");
|
|
assert("ModuleDeclaration", node, opts);
|
|
}
|
|
|
|
|
|
return generated$1;
|
|
}
|
|
|
|
var createTypeAnnotationBasedOnTypeof = {};
|
|
|
|
var hasRequiredCreateTypeAnnotationBasedOnTypeof;
|
|
|
|
function requireCreateTypeAnnotationBasedOnTypeof () {
|
|
if (hasRequiredCreateTypeAnnotationBasedOnTypeof) return createTypeAnnotationBasedOnTypeof;
|
|
hasRequiredCreateTypeAnnotationBasedOnTypeof = 1;
|
|
|
|
Object.defineProperty(createTypeAnnotationBasedOnTypeof, "__esModule", {
|
|
value: true
|
|
});
|
|
createTypeAnnotationBasedOnTypeof.default = void 0;
|
|
var _index = requireGenerated$2();
|
|
createTypeAnnotationBasedOnTypeof.default = createTypeAnnotationBasedOnTypeof$1;
|
|
function createTypeAnnotationBasedOnTypeof$1(type) {
|
|
switch (type) {
|
|
case "string":
|
|
return (0, _index.stringTypeAnnotation)();
|
|
case "number":
|
|
return (0, _index.numberTypeAnnotation)();
|
|
case "undefined":
|
|
return (0, _index.voidTypeAnnotation)();
|
|
case "boolean":
|
|
return (0, _index.booleanTypeAnnotation)();
|
|
case "function":
|
|
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Function"));
|
|
case "object":
|
|
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Object"));
|
|
case "symbol":
|
|
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Symbol"));
|
|
case "bigint":
|
|
return (0, _index.anyTypeAnnotation)();
|
|
}
|
|
throw new Error("Invalid typeof value: " + type);
|
|
}
|
|
|
|
|
|
return createTypeAnnotationBasedOnTypeof;
|
|
}
|
|
|
|
var createFlowUnionType = {};
|
|
|
|
var removeTypeDuplicates$1 = {};
|
|
|
|
var hasRequiredRemoveTypeDuplicates$1;
|
|
|
|
function requireRemoveTypeDuplicates$1 () {
|
|
if (hasRequiredRemoveTypeDuplicates$1) return removeTypeDuplicates$1;
|
|
hasRequiredRemoveTypeDuplicates$1 = 1;
|
|
|
|
Object.defineProperty(removeTypeDuplicates$1, "__esModule", {
|
|
value: true
|
|
});
|
|
removeTypeDuplicates$1.default = removeTypeDuplicates;
|
|
var _index = requireGenerated$3();
|
|
function getQualifiedName(node) {
|
|
return (0, _index.isIdentifier)(node) ? node.name : `${node.id.name}.${getQualifiedName(node.qualification)}`;
|
|
}
|
|
function removeTypeDuplicates(nodesIn) {
|
|
const nodes = Array.from(nodesIn);
|
|
const generics = new Map();
|
|
const bases = new Map();
|
|
const typeGroups = new Set();
|
|
const types = [];
|
|
for (let i = 0; i < nodes.length; i++) {
|
|
const node = nodes[i];
|
|
if (!node) continue;
|
|
if (types.includes(node)) {
|
|
continue;
|
|
}
|
|
if ((0, _index.isAnyTypeAnnotation)(node)) {
|
|
return [node];
|
|
}
|
|
if ((0, _index.isFlowBaseAnnotation)(node)) {
|
|
bases.set(node.type, node);
|
|
continue;
|
|
}
|
|
if ((0, _index.isUnionTypeAnnotation)(node)) {
|
|
if (!typeGroups.has(node.types)) {
|
|
nodes.push(...node.types);
|
|
typeGroups.add(node.types);
|
|
}
|
|
continue;
|
|
}
|
|
if ((0, _index.isGenericTypeAnnotation)(node)) {
|
|
const name = getQualifiedName(node.id);
|
|
if (generics.has(name)) {
|
|
let existing = generics.get(name);
|
|
if (existing.typeParameters) {
|
|
if (node.typeParameters) {
|
|
existing.typeParameters.params.push(...node.typeParameters.params);
|
|
existing.typeParameters.params = removeTypeDuplicates(existing.typeParameters.params);
|
|
}
|
|
} else {
|
|
existing = node.typeParameters;
|
|
}
|
|
} else {
|
|
generics.set(name, node);
|
|
}
|
|
continue;
|
|
}
|
|
types.push(node);
|
|
}
|
|
for (const [, baseType] of bases) {
|
|
types.push(baseType);
|
|
}
|
|
for (const [, genericName] of generics) {
|
|
types.push(genericName);
|
|
}
|
|
return types;
|
|
}
|
|
|
|
|
|
return removeTypeDuplicates$1;
|
|
}
|
|
|
|
var hasRequiredCreateFlowUnionType;
|
|
|
|
function requireCreateFlowUnionType () {
|
|
if (hasRequiredCreateFlowUnionType) return createFlowUnionType;
|
|
hasRequiredCreateFlowUnionType = 1;
|
|
|
|
Object.defineProperty(createFlowUnionType, "__esModule", {
|
|
value: true
|
|
});
|
|
createFlowUnionType.default = createFlowUnionType$1;
|
|
var _index = requireGenerated$2();
|
|
var _removeTypeDuplicates = requireRemoveTypeDuplicates$1();
|
|
function createFlowUnionType$1(types) {
|
|
const flattened = (0, _removeTypeDuplicates.default)(types);
|
|
if (flattened.length === 1) {
|
|
return flattened[0];
|
|
} else {
|
|
return (0, _index.unionTypeAnnotation)(flattened);
|
|
}
|
|
}
|
|
|
|
|
|
return createFlowUnionType;
|
|
}
|
|
|
|
var createTSUnionType = {};
|
|
|
|
var removeTypeDuplicates = {};
|
|
|
|
var hasRequiredRemoveTypeDuplicates;
|
|
|
|
function requireRemoveTypeDuplicates () {
|
|
if (hasRequiredRemoveTypeDuplicates) return removeTypeDuplicates;
|
|
hasRequiredRemoveTypeDuplicates = 1;
|
|
|
|
Object.defineProperty(removeTypeDuplicates, "__esModule", {
|
|
value: true
|
|
});
|
|
removeTypeDuplicates.default = removeTypeDuplicates$1;
|
|
var _index = requireGenerated$3();
|
|
function getQualifiedName(node) {
|
|
return (0, _index.isIdentifier)(node) ? node.name : `${node.right.name}.${getQualifiedName(node.left)}`;
|
|
}
|
|
function removeTypeDuplicates$1(nodesIn) {
|
|
const nodes = Array.from(nodesIn);
|
|
const generics = new Map();
|
|
const bases = new Map();
|
|
const typeGroups = new Set();
|
|
const types = [];
|
|
for (let i = 0; i < nodes.length; i++) {
|
|
const node = nodes[i];
|
|
if (!node) continue;
|
|
if (types.includes(node)) {
|
|
continue;
|
|
}
|
|
if ((0, _index.isTSAnyKeyword)(node)) {
|
|
return [node];
|
|
}
|
|
if ((0, _index.isTSBaseType)(node)) {
|
|
bases.set(node.type, node);
|
|
continue;
|
|
}
|
|
if ((0, _index.isTSUnionType)(node)) {
|
|
if (!typeGroups.has(node.types)) {
|
|
nodes.push(...node.types);
|
|
typeGroups.add(node.types);
|
|
}
|
|
continue;
|
|
}
|
|
if ((0, _index.isTSTypeReference)(node) && node.typeParameters) {
|
|
const name = getQualifiedName(node.typeName);
|
|
if (generics.has(name)) {
|
|
let existing = generics.get(name);
|
|
if (existing.typeParameters) {
|
|
if (node.typeParameters) {
|
|
existing.typeParameters.params.push(...node.typeParameters.params);
|
|
existing.typeParameters.params = removeTypeDuplicates$1(existing.typeParameters.params);
|
|
}
|
|
} else {
|
|
existing = node.typeParameters;
|
|
}
|
|
} else {
|
|
generics.set(name, node);
|
|
}
|
|
continue;
|
|
}
|
|
types.push(node);
|
|
}
|
|
for (const [, baseType] of bases) {
|
|
types.push(baseType);
|
|
}
|
|
for (const [, genericName] of generics) {
|
|
types.push(genericName);
|
|
}
|
|
return types;
|
|
}
|
|
|
|
|
|
return removeTypeDuplicates;
|
|
}
|
|
|
|
var hasRequiredCreateTSUnionType;
|
|
|
|
function requireCreateTSUnionType () {
|
|
if (hasRequiredCreateTSUnionType) return createTSUnionType;
|
|
hasRequiredCreateTSUnionType = 1;
|
|
|
|
Object.defineProperty(createTSUnionType, "__esModule", {
|
|
value: true
|
|
});
|
|
createTSUnionType.default = createTSUnionType$1;
|
|
var _index = requireGenerated$2();
|
|
var _removeTypeDuplicates = requireRemoveTypeDuplicates();
|
|
var _index2 = requireGenerated$3();
|
|
function createTSUnionType$1(typeAnnotations) {
|
|
const types = typeAnnotations.map(type => {
|
|
return (0, _index2.isTSTypeAnnotation)(type) ? type.typeAnnotation : type;
|
|
});
|
|
const flattened = (0, _removeTypeDuplicates.default)(types);
|
|
if (flattened.length === 1) {
|
|
return flattened[0];
|
|
} else {
|
|
return (0, _index.tsUnionType)(flattened);
|
|
}
|
|
}
|
|
|
|
|
|
return createTSUnionType;
|
|
}
|
|
|
|
var uppercase = {};
|
|
|
|
var hasRequiredUppercase;
|
|
|
|
function requireUppercase () {
|
|
if (hasRequiredUppercase) return uppercase;
|
|
hasRequiredUppercase = 1;
|
|
(function (exports) {
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
Object.defineProperty(exports, "AnyTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.anyTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ArgumentPlaceholder", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.argumentPlaceholder;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ArrayExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.arrayExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ArrayPattern", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.arrayPattern;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ArrayTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.arrayTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ArrowFunctionExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.arrowFunctionExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "AssignmentExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.assignmentExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "AssignmentPattern", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.assignmentPattern;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "AwaitExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.awaitExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "BigIntLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.bigIntLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "BinaryExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.binaryExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "BindExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.bindExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "BlockStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.blockStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "BooleanLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.booleanLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "BooleanLiteralTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.booleanLiteralTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "BooleanTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.booleanTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "BreakStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.breakStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "CallExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.callExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "CatchClause", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.catchClause;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ClassAccessorProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.classAccessorProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ClassBody", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.classBody;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ClassDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.classDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ClassExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.classExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ClassImplements", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.classImplements;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ClassMethod", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.classMethod;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ClassPrivateMethod", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.classPrivateMethod;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ClassPrivateProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.classPrivateProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ClassProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.classProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ConditionalExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.conditionalExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ContinueStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.continueStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DebuggerStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.debuggerStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DecimalLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.decimalLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclareClass", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declareClass;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclareExportAllDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declareExportAllDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclareExportDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declareExportDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclareFunction", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declareFunction;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclareInterface", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declareInterface;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclareModule", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declareModule;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclareModuleExports", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declareModuleExports;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclareOpaqueType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declareOpaqueType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclareTypeAlias", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declareTypeAlias;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclareVariable", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declareVariable;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DeclaredPredicate", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.declaredPredicate;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "Decorator", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.decorator;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "Directive", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.directive;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DirectiveLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.directiveLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DoExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.doExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "DoWhileStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.doWhileStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EmptyStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.emptyStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EmptyTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.emptyTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EnumBooleanBody", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.enumBooleanBody;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EnumBooleanMember", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.enumBooleanMember;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EnumDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.enumDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EnumDefaultedMember", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.enumDefaultedMember;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EnumNumberBody", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.enumNumberBody;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EnumNumberMember", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.enumNumberMember;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EnumStringBody", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.enumStringBody;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EnumStringMember", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.enumStringMember;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "EnumSymbolBody", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.enumSymbolBody;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ExistsTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.existsTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ExportAllDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.exportAllDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ExportDefaultDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.exportDefaultDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ExportDefaultSpecifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.exportDefaultSpecifier;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ExportNamedDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.exportNamedDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ExportNamespaceSpecifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.exportNamespaceSpecifier;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ExportSpecifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.exportSpecifier;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ExpressionStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.expressionStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "File", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.file;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ForInStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.forInStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ForOfStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.forOfStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ForStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.forStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "FunctionDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.functionDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "FunctionExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.functionExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "FunctionTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.functionTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "FunctionTypeParam", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.functionTypeParam;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "GenericTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.genericTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "Identifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.identifier;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "IfStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.ifStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "Import", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.import;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ImportAttribute", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.importAttribute;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ImportDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.importDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ImportDefaultSpecifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.importDefaultSpecifier;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ImportExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.importExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ImportNamespaceSpecifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.importNamespaceSpecifier;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ImportSpecifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.importSpecifier;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "IndexedAccessType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.indexedAccessType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "InferredPredicate", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.inferredPredicate;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "InterfaceDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.interfaceDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "InterfaceExtends", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.interfaceExtends;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "InterfaceTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.interfaceTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "InterpreterDirective", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.interpreterDirective;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "IntersectionTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.intersectionTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXAttribute", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxAttribute;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXClosingElement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxClosingElement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXClosingFragment", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxClosingFragment;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXElement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxElement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXEmptyExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxEmptyExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXExpressionContainer", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxExpressionContainer;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXFragment", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxFragment;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXIdentifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxIdentifier;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXMemberExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxMemberExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXNamespacedName", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxNamespacedName;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXOpeningElement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxOpeningElement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXOpeningFragment", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxOpeningFragment;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXSpreadAttribute", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxSpreadAttribute;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXSpreadChild", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxSpreadChild;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "JSXText", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.jsxText;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "LabeledStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.labeledStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "LogicalExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.logicalExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "MemberExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.memberExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "MetaProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.metaProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "MixedTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.mixedTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ModuleExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.moduleExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "NewExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.newExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "Noop", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.noop;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "NullLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.nullLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "NullLiteralTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.nullLiteralTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "NullableTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.nullableTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "NumberLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.numberLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "NumberLiteralTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.numberLiteralTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "NumberTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.numberTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "NumericLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.numericLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ObjectExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.objectExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ObjectMethod", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.objectMethod;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ObjectPattern", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.objectPattern;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ObjectProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.objectProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ObjectTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.objectTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ObjectTypeCallProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.objectTypeCallProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ObjectTypeIndexer", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.objectTypeIndexer;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ObjectTypeInternalSlot", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.objectTypeInternalSlot;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ObjectTypeProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.objectTypeProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ObjectTypeSpreadProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.objectTypeSpreadProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "OpaqueType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.opaqueType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "OptionalCallExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.optionalCallExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "OptionalIndexedAccessType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.optionalIndexedAccessType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "OptionalMemberExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.optionalMemberExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ParenthesizedExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.parenthesizedExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "PipelineBareFunction", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.pipelineBareFunction;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "PipelinePrimaryTopicReference", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.pipelinePrimaryTopicReference;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "PipelineTopicExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.pipelineTopicExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "Placeholder", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.placeholder;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "PrivateName", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.privateName;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "Program", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.program;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "QualifiedTypeIdentifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.qualifiedTypeIdentifier;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "RecordExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.recordExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "RegExpLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.regExpLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "RegexLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.regexLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "RestElement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.restElement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "RestProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.restProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ReturnStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.returnStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "SequenceExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.sequenceExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "SpreadElement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.spreadElement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "SpreadProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.spreadProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "StaticBlock", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.staticBlock;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "StringLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.stringLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "StringLiteralTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.stringLiteralTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "StringTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.stringTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "Super", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.super;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "SwitchCase", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.switchCase;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "SwitchStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.switchStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "SymbolTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.symbolTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSAnyKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsAnyKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSArrayType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsArrayType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSAsExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsAsExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSBigIntKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsBigIntKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSBooleanKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsBooleanKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSCallSignatureDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsCallSignatureDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSConditionalType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsConditionalType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSConstructSignatureDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsConstructSignatureDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSConstructorType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsConstructorType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSDeclareFunction", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsDeclareFunction;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSDeclareMethod", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsDeclareMethod;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSEnumDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsEnumDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSEnumMember", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsEnumMember;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSExportAssignment", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsExportAssignment;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSExpressionWithTypeArguments", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsExpressionWithTypeArguments;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSExternalModuleReference", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsExternalModuleReference;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSFunctionType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsFunctionType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSImportEqualsDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsImportEqualsDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSImportType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsImportType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSIndexSignature", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsIndexSignature;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSIndexedAccessType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsIndexedAccessType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSInferType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsInferType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSInstantiationExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsInstantiationExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSInterfaceBody", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsInterfaceBody;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSInterfaceDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsInterfaceDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSIntersectionType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsIntersectionType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSIntrinsicKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsIntrinsicKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSLiteralType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsLiteralType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSMappedType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsMappedType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSMethodSignature", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsMethodSignature;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSModuleBlock", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsModuleBlock;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSModuleDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsModuleDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSNamedTupleMember", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsNamedTupleMember;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSNamespaceExportDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsNamespaceExportDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSNeverKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsNeverKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSNonNullExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsNonNullExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSNullKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsNullKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSNumberKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsNumberKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSObjectKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsObjectKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSOptionalType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsOptionalType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSParameterProperty", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsParameterProperty;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSParenthesizedType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsParenthesizedType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSPropertySignature", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsPropertySignature;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSQualifiedName", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsQualifiedName;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSRestType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsRestType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSSatisfiesExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsSatisfiesExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSStringKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsStringKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSSymbolKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsSymbolKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSThisType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsThisType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTupleType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTupleType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypeAliasDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypeAliasDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypeAssertion", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypeAssertion;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypeLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypeLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypeOperator", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypeOperator;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypeParameter", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypeParameter;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypeParameterDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypeParameterDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypeParameterInstantiation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypeParameterInstantiation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypePredicate", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypePredicate;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypeQuery", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypeQuery;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSTypeReference", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsTypeReference;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSUndefinedKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsUndefinedKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSUnionType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsUnionType;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSUnknownKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsUnknownKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TSVoidKeyword", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tsVoidKeyword;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TaggedTemplateExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.taggedTemplateExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TemplateElement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.templateElement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TemplateLiteral", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.templateLiteral;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ThisExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.thisExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ThisTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.thisTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ThrowStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.throwStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TopicReference", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.topicReference;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TryStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tryStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TupleExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tupleExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TupleTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.tupleTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TypeAlias", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.typeAlias;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.typeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TypeCastExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.typeCastExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TypeParameter", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.typeParameter;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TypeParameterDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.typeParameterDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TypeParameterInstantiation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.typeParameterInstantiation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "TypeofTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.typeofTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "UnaryExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.unaryExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "UnionTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.unionTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "UpdateExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.updateExpression;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "V8IntrinsicIdentifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.v8IntrinsicIdentifier;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "VariableDeclaration", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.variableDeclaration;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "VariableDeclarator", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.variableDeclarator;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "Variance", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.variance;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "VoidTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.voidTypeAnnotation;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "WhileStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.whileStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "WithStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.withStatement;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "YieldExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index.yieldExpression;
|
|
}
|
|
});
|
|
var _index = requireGenerated$2();
|
|
|
|
|
|
} (uppercase));
|
|
return uppercase;
|
|
}
|
|
|
|
var productions = {};
|
|
|
|
var hasRequiredProductions;
|
|
|
|
function requireProductions () {
|
|
if (hasRequiredProductions) return productions;
|
|
hasRequiredProductions = 1;
|
|
|
|
Object.defineProperty(productions, "__esModule", {
|
|
value: true
|
|
});
|
|
productions.buildUndefinedNode = buildUndefinedNode;
|
|
var _index = requireGenerated$2();
|
|
function buildUndefinedNode() {
|
|
return (0, _index.unaryExpression)("void", (0, _index.numericLiteral)(0), true);
|
|
}
|
|
|
|
|
|
return productions;
|
|
}
|
|
|
|
var cloneNode = {};
|
|
|
|
var hasRequiredCloneNode;
|
|
|
|
function requireCloneNode () {
|
|
if (hasRequiredCloneNode) return cloneNode;
|
|
hasRequiredCloneNode = 1;
|
|
|
|
Object.defineProperty(cloneNode, "__esModule", {
|
|
value: true
|
|
});
|
|
cloneNode.default = cloneNode$1;
|
|
var _index = requireDefinitions();
|
|
var _index2 = requireGenerated$3();
|
|
const {
|
|
hasOwn
|
|
} = {
|
|
hasOwn: Function.call.bind(Object.prototype.hasOwnProperty)
|
|
};
|
|
function cloneIfNode(obj, deep, withoutLoc, commentsCache) {
|
|
if (obj && typeof obj.type === "string") {
|
|
return cloneNodeInternal(obj, deep, withoutLoc, commentsCache);
|
|
}
|
|
return obj;
|
|
}
|
|
function cloneIfNodeOrArray(obj, deep, withoutLoc, commentsCache) {
|
|
if (Array.isArray(obj)) {
|
|
return obj.map(node => cloneIfNode(node, deep, withoutLoc, commentsCache));
|
|
}
|
|
return cloneIfNode(obj, deep, withoutLoc, commentsCache);
|
|
}
|
|
function cloneNode$1(node, deep = true, withoutLoc = false) {
|
|
return cloneNodeInternal(node, deep, withoutLoc, new Map());
|
|
}
|
|
function cloneNodeInternal(node, deep = true, withoutLoc = false, commentsCache) {
|
|
if (!node) return node;
|
|
const {
|
|
type
|
|
} = node;
|
|
const newNode = {
|
|
type: node.type
|
|
};
|
|
if ((0, _index2.isIdentifier)(node)) {
|
|
newNode.name = node.name;
|
|
if (hasOwn(node, "optional") && typeof node.optional === "boolean") {
|
|
newNode.optional = node.optional;
|
|
}
|
|
if (hasOwn(node, "typeAnnotation")) {
|
|
newNode.typeAnnotation = deep ? cloneIfNodeOrArray(node.typeAnnotation, true, withoutLoc, commentsCache) : node.typeAnnotation;
|
|
}
|
|
if (hasOwn(node, "decorators")) {
|
|
newNode.decorators = deep ? cloneIfNodeOrArray(node.decorators, true, withoutLoc, commentsCache) : node.decorators;
|
|
}
|
|
} else if (!hasOwn(_index.NODE_FIELDS, type)) {
|
|
throw new Error(`Unknown node type: "${type}"`);
|
|
} else {
|
|
for (const field of Object.keys(_index.NODE_FIELDS[type])) {
|
|
if (hasOwn(node, field)) {
|
|
if (deep) {
|
|
newNode[field] = (0, _index2.isFile)(node) && field === "comments" ? maybeCloneComments(node.comments, deep, withoutLoc, commentsCache) : cloneIfNodeOrArray(node[field], true, withoutLoc, commentsCache);
|
|
} else {
|
|
newNode[field] = node[field];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (hasOwn(node, "loc")) {
|
|
if (withoutLoc) {
|
|
newNode.loc = null;
|
|
} else {
|
|
newNode.loc = node.loc;
|
|
}
|
|
}
|
|
if (hasOwn(node, "leadingComments")) {
|
|
newNode.leadingComments = maybeCloneComments(node.leadingComments, deep, withoutLoc, commentsCache);
|
|
}
|
|
if (hasOwn(node, "innerComments")) {
|
|
newNode.innerComments = maybeCloneComments(node.innerComments, deep, withoutLoc, commentsCache);
|
|
}
|
|
if (hasOwn(node, "trailingComments")) {
|
|
newNode.trailingComments = maybeCloneComments(node.trailingComments, deep, withoutLoc, commentsCache);
|
|
}
|
|
if (hasOwn(node, "extra")) {
|
|
newNode.extra = Object.assign({}, node.extra);
|
|
}
|
|
return newNode;
|
|
}
|
|
function maybeCloneComments(comments, deep, withoutLoc, commentsCache) {
|
|
if (!comments || !deep) {
|
|
return comments;
|
|
}
|
|
return comments.map(comment => {
|
|
const cache = commentsCache.get(comment);
|
|
if (cache) return cache;
|
|
const {
|
|
type,
|
|
value,
|
|
loc
|
|
} = comment;
|
|
const ret = {
|
|
type,
|
|
value,
|
|
loc
|
|
};
|
|
if (withoutLoc) {
|
|
ret.loc = null;
|
|
}
|
|
commentsCache.set(comment, ret);
|
|
return ret;
|
|
});
|
|
}
|
|
|
|
|
|
return cloneNode;
|
|
}
|
|
|
|
var clone = {};
|
|
|
|
var hasRequiredClone;
|
|
|
|
function requireClone () {
|
|
if (hasRequiredClone) return clone;
|
|
hasRequiredClone = 1;
|
|
|
|
Object.defineProperty(clone, "__esModule", {
|
|
value: true
|
|
});
|
|
clone.default = clone$1;
|
|
var _cloneNode = requireCloneNode();
|
|
function clone$1(node) {
|
|
return (0, _cloneNode.default)(node, false);
|
|
}
|
|
|
|
|
|
return clone;
|
|
}
|
|
|
|
var cloneDeep = {};
|
|
|
|
var hasRequiredCloneDeep;
|
|
|
|
function requireCloneDeep () {
|
|
if (hasRequiredCloneDeep) return cloneDeep;
|
|
hasRequiredCloneDeep = 1;
|
|
|
|
Object.defineProperty(cloneDeep, "__esModule", {
|
|
value: true
|
|
});
|
|
cloneDeep.default = cloneDeep$1;
|
|
var _cloneNode = requireCloneNode();
|
|
function cloneDeep$1(node) {
|
|
return (0, _cloneNode.default)(node);
|
|
}
|
|
|
|
|
|
return cloneDeep;
|
|
}
|
|
|
|
var cloneDeepWithoutLoc = {};
|
|
|
|
var hasRequiredCloneDeepWithoutLoc;
|
|
|
|
function requireCloneDeepWithoutLoc () {
|
|
if (hasRequiredCloneDeepWithoutLoc) return cloneDeepWithoutLoc;
|
|
hasRequiredCloneDeepWithoutLoc = 1;
|
|
|
|
Object.defineProperty(cloneDeepWithoutLoc, "__esModule", {
|
|
value: true
|
|
});
|
|
cloneDeepWithoutLoc.default = cloneDeepWithoutLoc$1;
|
|
var _cloneNode = requireCloneNode();
|
|
function cloneDeepWithoutLoc$1(node) {
|
|
return (0, _cloneNode.default)(node, true, true);
|
|
}
|
|
|
|
|
|
return cloneDeepWithoutLoc;
|
|
}
|
|
|
|
var cloneWithoutLoc = {};
|
|
|
|
var hasRequiredCloneWithoutLoc;
|
|
|
|
function requireCloneWithoutLoc () {
|
|
if (hasRequiredCloneWithoutLoc) return cloneWithoutLoc;
|
|
hasRequiredCloneWithoutLoc = 1;
|
|
|
|
Object.defineProperty(cloneWithoutLoc, "__esModule", {
|
|
value: true
|
|
});
|
|
cloneWithoutLoc.default = cloneWithoutLoc$1;
|
|
var _cloneNode = requireCloneNode();
|
|
function cloneWithoutLoc$1(node) {
|
|
return (0, _cloneNode.default)(node, false, true);
|
|
}
|
|
|
|
|
|
return cloneWithoutLoc;
|
|
}
|
|
|
|
var addComment = {};
|
|
|
|
var addComments = {};
|
|
|
|
var hasRequiredAddComments;
|
|
|
|
function requireAddComments () {
|
|
if (hasRequiredAddComments) return addComments;
|
|
hasRequiredAddComments = 1;
|
|
|
|
Object.defineProperty(addComments, "__esModule", {
|
|
value: true
|
|
});
|
|
addComments.default = addComments$1;
|
|
function addComments$1(node, type, comments) {
|
|
if (!comments || !node) return node;
|
|
const key = `${type}Comments`;
|
|
if (node[key]) {
|
|
if (type === "leading") {
|
|
node[key] = comments.concat(node[key]);
|
|
} else {
|
|
node[key].push(...comments);
|
|
}
|
|
} else {
|
|
node[key] = comments;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
|
|
return addComments;
|
|
}
|
|
|
|
var hasRequiredAddComment;
|
|
|
|
function requireAddComment () {
|
|
if (hasRequiredAddComment) return addComment;
|
|
hasRequiredAddComment = 1;
|
|
|
|
Object.defineProperty(addComment, "__esModule", {
|
|
value: true
|
|
});
|
|
addComment.default = addComment$1;
|
|
var _addComments = requireAddComments();
|
|
function addComment$1(node, type, content, line) {
|
|
return (0, _addComments.default)(node, type, [{
|
|
type: line ? "CommentLine" : "CommentBlock",
|
|
value: content
|
|
}]);
|
|
}
|
|
|
|
|
|
return addComment;
|
|
}
|
|
|
|
var inheritInnerComments = {};
|
|
|
|
var inherit = {};
|
|
|
|
var hasRequiredInherit;
|
|
|
|
function requireInherit () {
|
|
if (hasRequiredInherit) return inherit;
|
|
hasRequiredInherit = 1;
|
|
|
|
Object.defineProperty(inherit, "__esModule", {
|
|
value: true
|
|
});
|
|
inherit.default = inherit$1;
|
|
function inherit$1(key, child, parent) {
|
|
if (child && parent) {
|
|
child[key] = Array.from(new Set([].concat(child[key], parent[key]).filter(Boolean)));
|
|
}
|
|
}
|
|
|
|
|
|
return inherit;
|
|
}
|
|
|
|
var hasRequiredInheritInnerComments;
|
|
|
|
function requireInheritInnerComments () {
|
|
if (hasRequiredInheritInnerComments) return inheritInnerComments;
|
|
hasRequiredInheritInnerComments = 1;
|
|
|
|
Object.defineProperty(inheritInnerComments, "__esModule", {
|
|
value: true
|
|
});
|
|
inheritInnerComments.default = inheritInnerComments$1;
|
|
var _inherit = requireInherit();
|
|
function inheritInnerComments$1(child, parent) {
|
|
(0, _inherit.default)("innerComments", child, parent);
|
|
}
|
|
|
|
|
|
return inheritInnerComments;
|
|
}
|
|
|
|
var inheritLeadingComments = {};
|
|
|
|
var hasRequiredInheritLeadingComments;
|
|
|
|
function requireInheritLeadingComments () {
|
|
if (hasRequiredInheritLeadingComments) return inheritLeadingComments;
|
|
hasRequiredInheritLeadingComments = 1;
|
|
|
|
Object.defineProperty(inheritLeadingComments, "__esModule", {
|
|
value: true
|
|
});
|
|
inheritLeadingComments.default = inheritLeadingComments$1;
|
|
var _inherit = requireInherit();
|
|
function inheritLeadingComments$1(child, parent) {
|
|
(0, _inherit.default)("leadingComments", child, parent);
|
|
}
|
|
|
|
|
|
return inheritLeadingComments;
|
|
}
|
|
|
|
var inheritsComments = {};
|
|
|
|
var inheritTrailingComments = {};
|
|
|
|
var hasRequiredInheritTrailingComments;
|
|
|
|
function requireInheritTrailingComments () {
|
|
if (hasRequiredInheritTrailingComments) return inheritTrailingComments;
|
|
hasRequiredInheritTrailingComments = 1;
|
|
|
|
Object.defineProperty(inheritTrailingComments, "__esModule", {
|
|
value: true
|
|
});
|
|
inheritTrailingComments.default = inheritTrailingComments$1;
|
|
var _inherit = requireInherit();
|
|
function inheritTrailingComments$1(child, parent) {
|
|
(0, _inherit.default)("trailingComments", child, parent);
|
|
}
|
|
|
|
|
|
return inheritTrailingComments;
|
|
}
|
|
|
|
var hasRequiredInheritsComments;
|
|
|
|
function requireInheritsComments () {
|
|
if (hasRequiredInheritsComments) return inheritsComments;
|
|
hasRequiredInheritsComments = 1;
|
|
|
|
Object.defineProperty(inheritsComments, "__esModule", {
|
|
value: true
|
|
});
|
|
inheritsComments.default = inheritsComments$1;
|
|
var _inheritTrailingComments = requireInheritTrailingComments();
|
|
var _inheritLeadingComments = requireInheritLeadingComments();
|
|
var _inheritInnerComments = requireInheritInnerComments();
|
|
function inheritsComments$1(child, parent) {
|
|
(0, _inheritTrailingComments.default)(child, parent);
|
|
(0, _inheritLeadingComments.default)(child, parent);
|
|
(0, _inheritInnerComments.default)(child, parent);
|
|
return child;
|
|
}
|
|
|
|
|
|
return inheritsComments;
|
|
}
|
|
|
|
var removeComments = {};
|
|
|
|
var hasRequiredRemoveComments;
|
|
|
|
function requireRemoveComments () {
|
|
if (hasRequiredRemoveComments) return removeComments;
|
|
hasRequiredRemoveComments = 1;
|
|
|
|
Object.defineProperty(removeComments, "__esModule", {
|
|
value: true
|
|
});
|
|
removeComments.default = removeComments$1;
|
|
var _index = requireConstants();
|
|
function removeComments$1(node) {
|
|
_index.COMMENT_KEYS.forEach(key => {
|
|
node[key] = null;
|
|
});
|
|
return node;
|
|
}
|
|
|
|
|
|
return removeComments;
|
|
}
|
|
|
|
var generated = {};
|
|
|
|
var hasRequiredGenerated;
|
|
|
|
function requireGenerated () {
|
|
if (hasRequiredGenerated) return generated;
|
|
hasRequiredGenerated = 1;
|
|
|
|
Object.defineProperty(generated, "__esModule", {
|
|
value: true
|
|
});
|
|
generated.WHILE_TYPES = generated.USERWHITESPACABLE_TYPES = generated.UNARYLIKE_TYPES = generated.TYPESCRIPT_TYPES = generated.TSTYPE_TYPES = generated.TSTYPEELEMENT_TYPES = generated.TSENTITYNAME_TYPES = generated.TSBASETYPE_TYPES = generated.TERMINATORLESS_TYPES = generated.STATEMENT_TYPES = generated.STANDARDIZED_TYPES = generated.SCOPABLE_TYPES = generated.PUREISH_TYPES = generated.PROPERTY_TYPES = generated.PRIVATE_TYPES = generated.PATTERN_TYPES = generated.PATTERNLIKE_TYPES = generated.OBJECTMEMBER_TYPES = generated.MODULESPECIFIER_TYPES = generated.MODULEDECLARATION_TYPES = generated.MISCELLANEOUS_TYPES = generated.METHOD_TYPES = generated.LVAL_TYPES = generated.LOOP_TYPES = generated.LITERAL_TYPES = generated.JSX_TYPES = generated.IMPORTOREXPORTDECLARATION_TYPES = generated.IMMUTABLE_TYPES = generated.FUNCTION_TYPES = generated.FUNCTIONPARENT_TYPES = generated.FOR_TYPES = generated.FORXSTATEMENT_TYPES = generated.FLOW_TYPES = generated.FLOWTYPE_TYPES = generated.FLOWPREDICATE_TYPES = generated.FLOWDECLARATION_TYPES = generated.FLOWBASEANNOTATION_TYPES = generated.EXPRESSION_TYPES = generated.EXPRESSIONWRAPPER_TYPES = generated.EXPORTDECLARATION_TYPES = generated.ENUMMEMBER_TYPES = generated.ENUMBODY_TYPES = generated.DECLARATION_TYPES = generated.CONDITIONAL_TYPES = generated.COMPLETIONSTATEMENT_TYPES = generated.CLASS_TYPES = generated.BLOCK_TYPES = generated.BLOCKPARENT_TYPES = generated.BINARY_TYPES = generated.ACCESSOR_TYPES = void 0;
|
|
var _index = requireDefinitions();
|
|
generated.STANDARDIZED_TYPES = _index.FLIPPED_ALIAS_KEYS["Standardized"];
|
|
generated.EXPRESSION_TYPES = _index.FLIPPED_ALIAS_KEYS["Expression"];
|
|
generated.BINARY_TYPES = _index.FLIPPED_ALIAS_KEYS["Binary"];
|
|
generated.SCOPABLE_TYPES = _index.FLIPPED_ALIAS_KEYS["Scopable"];
|
|
generated.BLOCKPARENT_TYPES = _index.FLIPPED_ALIAS_KEYS["BlockParent"];
|
|
generated.BLOCK_TYPES = _index.FLIPPED_ALIAS_KEYS["Block"];
|
|
generated.STATEMENT_TYPES = _index.FLIPPED_ALIAS_KEYS["Statement"];
|
|
generated.TERMINATORLESS_TYPES = _index.FLIPPED_ALIAS_KEYS["Terminatorless"];
|
|
generated.COMPLETIONSTATEMENT_TYPES = _index.FLIPPED_ALIAS_KEYS["CompletionStatement"];
|
|
generated.CONDITIONAL_TYPES = _index.FLIPPED_ALIAS_KEYS["Conditional"];
|
|
generated.LOOP_TYPES = _index.FLIPPED_ALIAS_KEYS["Loop"];
|
|
generated.WHILE_TYPES = _index.FLIPPED_ALIAS_KEYS["While"];
|
|
generated.EXPRESSIONWRAPPER_TYPES = _index.FLIPPED_ALIAS_KEYS["ExpressionWrapper"];
|
|
generated.FOR_TYPES = _index.FLIPPED_ALIAS_KEYS["For"];
|
|
generated.FORXSTATEMENT_TYPES = _index.FLIPPED_ALIAS_KEYS["ForXStatement"];
|
|
generated.FUNCTION_TYPES = _index.FLIPPED_ALIAS_KEYS["Function"];
|
|
generated.FUNCTIONPARENT_TYPES = _index.FLIPPED_ALIAS_KEYS["FunctionParent"];
|
|
generated.PUREISH_TYPES = _index.FLIPPED_ALIAS_KEYS["Pureish"];
|
|
generated.DECLARATION_TYPES = _index.FLIPPED_ALIAS_KEYS["Declaration"];
|
|
generated.PATTERNLIKE_TYPES = _index.FLIPPED_ALIAS_KEYS["PatternLike"];
|
|
generated.LVAL_TYPES = _index.FLIPPED_ALIAS_KEYS["LVal"];
|
|
generated.TSENTITYNAME_TYPES = _index.FLIPPED_ALIAS_KEYS["TSEntityName"];
|
|
generated.LITERAL_TYPES = _index.FLIPPED_ALIAS_KEYS["Literal"];
|
|
generated.IMMUTABLE_TYPES = _index.FLIPPED_ALIAS_KEYS["Immutable"];
|
|
generated.USERWHITESPACABLE_TYPES = _index.FLIPPED_ALIAS_KEYS["UserWhitespacable"];
|
|
generated.METHOD_TYPES = _index.FLIPPED_ALIAS_KEYS["Method"];
|
|
generated.OBJECTMEMBER_TYPES = _index.FLIPPED_ALIAS_KEYS["ObjectMember"];
|
|
generated.PROPERTY_TYPES = _index.FLIPPED_ALIAS_KEYS["Property"];
|
|
generated.UNARYLIKE_TYPES = _index.FLIPPED_ALIAS_KEYS["UnaryLike"];
|
|
generated.PATTERN_TYPES = _index.FLIPPED_ALIAS_KEYS["Pattern"];
|
|
generated.CLASS_TYPES = _index.FLIPPED_ALIAS_KEYS["Class"];
|
|
const IMPORTOREXPORTDECLARATION_TYPES = generated.IMPORTOREXPORTDECLARATION_TYPES = _index.FLIPPED_ALIAS_KEYS["ImportOrExportDeclaration"];
|
|
generated.EXPORTDECLARATION_TYPES = _index.FLIPPED_ALIAS_KEYS["ExportDeclaration"];
|
|
generated.MODULESPECIFIER_TYPES = _index.FLIPPED_ALIAS_KEYS["ModuleSpecifier"];
|
|
generated.ACCESSOR_TYPES = _index.FLIPPED_ALIAS_KEYS["Accessor"];
|
|
generated.PRIVATE_TYPES = _index.FLIPPED_ALIAS_KEYS["Private"];
|
|
generated.FLOW_TYPES = _index.FLIPPED_ALIAS_KEYS["Flow"];
|
|
generated.FLOWTYPE_TYPES = _index.FLIPPED_ALIAS_KEYS["FlowType"];
|
|
generated.FLOWBASEANNOTATION_TYPES = _index.FLIPPED_ALIAS_KEYS["FlowBaseAnnotation"];
|
|
generated.FLOWDECLARATION_TYPES = _index.FLIPPED_ALIAS_KEYS["FlowDeclaration"];
|
|
generated.FLOWPREDICATE_TYPES = _index.FLIPPED_ALIAS_KEYS["FlowPredicate"];
|
|
generated.ENUMBODY_TYPES = _index.FLIPPED_ALIAS_KEYS["EnumBody"];
|
|
generated.ENUMMEMBER_TYPES = _index.FLIPPED_ALIAS_KEYS["EnumMember"];
|
|
generated.JSX_TYPES = _index.FLIPPED_ALIAS_KEYS["JSX"];
|
|
generated.MISCELLANEOUS_TYPES = _index.FLIPPED_ALIAS_KEYS["Miscellaneous"];
|
|
generated.TYPESCRIPT_TYPES = _index.FLIPPED_ALIAS_KEYS["TypeScript"];
|
|
generated.TSTYPEELEMENT_TYPES = _index.FLIPPED_ALIAS_KEYS["TSTypeElement"];
|
|
generated.TSTYPE_TYPES = _index.FLIPPED_ALIAS_KEYS["TSType"];
|
|
generated.TSBASETYPE_TYPES = _index.FLIPPED_ALIAS_KEYS["TSBaseType"];
|
|
generated.MODULEDECLARATION_TYPES = IMPORTOREXPORTDECLARATION_TYPES;
|
|
|
|
|
|
return generated;
|
|
}
|
|
|
|
var ensureBlock = {};
|
|
|
|
var toBlock = {};
|
|
|
|
var hasRequiredToBlock;
|
|
|
|
function requireToBlock () {
|
|
if (hasRequiredToBlock) return toBlock;
|
|
hasRequiredToBlock = 1;
|
|
|
|
Object.defineProperty(toBlock, "__esModule", {
|
|
value: true
|
|
});
|
|
toBlock.default = toBlock$1;
|
|
var _index = requireGenerated$3();
|
|
var _index2 = requireGenerated$2();
|
|
function toBlock$1(node, parent) {
|
|
if ((0, _index.isBlockStatement)(node)) {
|
|
return node;
|
|
}
|
|
let blockNodes = [];
|
|
if ((0, _index.isEmptyStatement)(node)) {
|
|
blockNodes = [];
|
|
} else {
|
|
if (!(0, _index.isStatement)(node)) {
|
|
if ((0, _index.isFunction)(parent)) {
|
|
node = (0, _index2.returnStatement)(node);
|
|
} else {
|
|
node = (0, _index2.expressionStatement)(node);
|
|
}
|
|
}
|
|
blockNodes = [node];
|
|
}
|
|
return (0, _index2.blockStatement)(blockNodes);
|
|
}
|
|
|
|
|
|
return toBlock;
|
|
}
|
|
|
|
var hasRequiredEnsureBlock;
|
|
|
|
function requireEnsureBlock () {
|
|
if (hasRequiredEnsureBlock) return ensureBlock;
|
|
hasRequiredEnsureBlock = 1;
|
|
|
|
Object.defineProperty(ensureBlock, "__esModule", {
|
|
value: true
|
|
});
|
|
ensureBlock.default = ensureBlock$1;
|
|
var _toBlock = requireToBlock();
|
|
function ensureBlock$1(node, key = "body") {
|
|
const result = (0, _toBlock.default)(node[key], node);
|
|
node[key] = result;
|
|
return result;
|
|
}
|
|
|
|
|
|
return ensureBlock;
|
|
}
|
|
|
|
var toBindingIdentifierName = {};
|
|
|
|
var toIdentifier = {};
|
|
|
|
var hasRequiredToIdentifier;
|
|
|
|
function requireToIdentifier () {
|
|
if (hasRequiredToIdentifier) return toIdentifier;
|
|
hasRequiredToIdentifier = 1;
|
|
|
|
Object.defineProperty(toIdentifier, "__esModule", {
|
|
value: true
|
|
});
|
|
toIdentifier.default = toIdentifier$1;
|
|
var _isValidIdentifier = requireIsValidIdentifier();
|
|
var _helperValidatorIdentifier = requireLib$3();
|
|
function toIdentifier$1(input) {
|
|
input = input + "";
|
|
let name = "";
|
|
for (const c of input) {
|
|
name += (0, _helperValidatorIdentifier.isIdentifierChar)(c.codePointAt(0)) ? c : "-";
|
|
}
|
|
name = name.replace(/^[-0-9]+/, "");
|
|
name = name.replace(/[-\s]+(.)?/g, function (match, c) {
|
|
return c ? c.toUpperCase() : "";
|
|
});
|
|
if (!(0, _isValidIdentifier.default)(name)) {
|
|
name = `_${name}`;
|
|
}
|
|
return name || "_";
|
|
}
|
|
|
|
|
|
return toIdentifier;
|
|
}
|
|
|
|
var hasRequiredToBindingIdentifierName;
|
|
|
|
function requireToBindingIdentifierName () {
|
|
if (hasRequiredToBindingIdentifierName) return toBindingIdentifierName;
|
|
hasRequiredToBindingIdentifierName = 1;
|
|
|
|
Object.defineProperty(toBindingIdentifierName, "__esModule", {
|
|
value: true
|
|
});
|
|
toBindingIdentifierName.default = toBindingIdentifierName$1;
|
|
var _toIdentifier = requireToIdentifier();
|
|
function toBindingIdentifierName$1(name) {
|
|
name = (0, _toIdentifier.default)(name);
|
|
if (name === "eval" || name === "arguments") name = "_" + name;
|
|
return name;
|
|
}
|
|
|
|
|
|
return toBindingIdentifierName;
|
|
}
|
|
|
|
var toComputedKey = {};
|
|
|
|
var hasRequiredToComputedKey;
|
|
|
|
function requireToComputedKey () {
|
|
if (hasRequiredToComputedKey) return toComputedKey;
|
|
hasRequiredToComputedKey = 1;
|
|
|
|
Object.defineProperty(toComputedKey, "__esModule", {
|
|
value: true
|
|
});
|
|
toComputedKey.default = toComputedKey$1;
|
|
var _index = requireGenerated$3();
|
|
var _index2 = requireGenerated$2();
|
|
function toComputedKey$1(node, key = node.key || node.property) {
|
|
if (!node.computed && (0, _index.isIdentifier)(key)) key = (0, _index2.stringLiteral)(key.name);
|
|
return key;
|
|
}
|
|
|
|
|
|
return toComputedKey;
|
|
}
|
|
|
|
var toExpression = {};
|
|
|
|
var hasRequiredToExpression;
|
|
|
|
function requireToExpression () {
|
|
if (hasRequiredToExpression) return toExpression;
|
|
hasRequiredToExpression = 1;
|
|
|
|
Object.defineProperty(toExpression, "__esModule", {
|
|
value: true
|
|
});
|
|
toExpression.default = void 0;
|
|
var _index = requireGenerated$3();
|
|
toExpression.default = toExpression$1;
|
|
function toExpression$1(node) {
|
|
if ((0, _index.isExpressionStatement)(node)) {
|
|
node = node.expression;
|
|
}
|
|
if ((0, _index.isExpression)(node)) {
|
|
return node;
|
|
}
|
|
if ((0, _index.isClass)(node)) {
|
|
node.type = "ClassExpression";
|
|
} else if ((0, _index.isFunction)(node)) {
|
|
node.type = "FunctionExpression";
|
|
}
|
|
if (!(0, _index.isExpression)(node)) {
|
|
throw new Error(`cannot turn ${node.type} to an expression`);
|
|
}
|
|
return node;
|
|
}
|
|
|
|
|
|
return toExpression;
|
|
}
|
|
|
|
var toKeyAlias = {};
|
|
|
|
var removePropertiesDeep = {};
|
|
|
|
var traverseFast = {};
|
|
|
|
var hasRequiredTraverseFast;
|
|
|
|
function requireTraverseFast () {
|
|
if (hasRequiredTraverseFast) return traverseFast;
|
|
hasRequiredTraverseFast = 1;
|
|
|
|
Object.defineProperty(traverseFast, "__esModule", {
|
|
value: true
|
|
});
|
|
traverseFast.default = traverseFast$1;
|
|
var _index = requireDefinitions();
|
|
function traverseFast$1(node, enter, opts) {
|
|
if (!node) return;
|
|
const keys = _index.VISITOR_KEYS[node.type];
|
|
if (!keys) return;
|
|
opts = opts || {};
|
|
enter(node, opts);
|
|
for (const key of keys) {
|
|
const subNode = node[key];
|
|
if (Array.isArray(subNode)) {
|
|
for (const node of subNode) {
|
|
traverseFast$1(node, enter, opts);
|
|
}
|
|
} else {
|
|
traverseFast$1(subNode, enter, opts);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return traverseFast;
|
|
}
|
|
|
|
var removeProperties = {};
|
|
|
|
var hasRequiredRemoveProperties;
|
|
|
|
function requireRemoveProperties () {
|
|
if (hasRequiredRemoveProperties) return removeProperties;
|
|
hasRequiredRemoveProperties = 1;
|
|
|
|
Object.defineProperty(removeProperties, "__esModule", {
|
|
value: true
|
|
});
|
|
removeProperties.default = removeProperties$1;
|
|
var _index = requireConstants();
|
|
const CLEAR_KEYS = ["tokens", "start", "end", "loc", "raw", "rawValue"];
|
|
const CLEAR_KEYS_PLUS_COMMENTS = [..._index.COMMENT_KEYS, "comments", ...CLEAR_KEYS];
|
|
function removeProperties$1(node, opts = {}) {
|
|
const map = opts.preserveComments ? CLEAR_KEYS : CLEAR_KEYS_PLUS_COMMENTS;
|
|
for (const key of map) {
|
|
if (node[key] != null) node[key] = undefined;
|
|
}
|
|
for (const key of Object.keys(node)) {
|
|
if (key[0] === "_" && node[key] != null) node[key] = undefined;
|
|
}
|
|
const symbols = Object.getOwnPropertySymbols(node);
|
|
for (const sym of symbols) {
|
|
node[sym] = null;
|
|
}
|
|
}
|
|
|
|
|
|
return removeProperties;
|
|
}
|
|
|
|
var hasRequiredRemovePropertiesDeep;
|
|
|
|
function requireRemovePropertiesDeep () {
|
|
if (hasRequiredRemovePropertiesDeep) return removePropertiesDeep;
|
|
hasRequiredRemovePropertiesDeep = 1;
|
|
|
|
Object.defineProperty(removePropertiesDeep, "__esModule", {
|
|
value: true
|
|
});
|
|
removePropertiesDeep.default = removePropertiesDeep$1;
|
|
var _traverseFast = requireTraverseFast();
|
|
var _removeProperties = requireRemoveProperties();
|
|
function removePropertiesDeep$1(tree, opts) {
|
|
(0, _traverseFast.default)(tree, _removeProperties.default, opts);
|
|
return tree;
|
|
}
|
|
|
|
|
|
return removePropertiesDeep;
|
|
}
|
|
|
|
var hasRequiredToKeyAlias;
|
|
|
|
function requireToKeyAlias () {
|
|
if (hasRequiredToKeyAlias) return toKeyAlias;
|
|
hasRequiredToKeyAlias = 1;
|
|
|
|
Object.defineProperty(toKeyAlias, "__esModule", {
|
|
value: true
|
|
});
|
|
toKeyAlias.default = toKeyAlias$1;
|
|
var _index = requireGenerated$3();
|
|
var _cloneNode = requireCloneNode();
|
|
var _removePropertiesDeep = requireRemovePropertiesDeep();
|
|
function toKeyAlias$1(node, key = node.key) {
|
|
let alias;
|
|
if (node.kind === "method") {
|
|
return toKeyAlias$1.increment() + "";
|
|
} else if ((0, _index.isIdentifier)(key)) {
|
|
alias = key.name;
|
|
} else if ((0, _index.isStringLiteral)(key)) {
|
|
alias = JSON.stringify(key.value);
|
|
} else {
|
|
alias = JSON.stringify((0, _removePropertiesDeep.default)((0, _cloneNode.default)(key)));
|
|
}
|
|
if (node.computed) {
|
|
alias = `[${alias}]`;
|
|
}
|
|
if (node.static) {
|
|
alias = `static:${alias}`;
|
|
}
|
|
return alias;
|
|
}
|
|
toKeyAlias$1.uid = 0;
|
|
toKeyAlias$1.increment = function () {
|
|
if (toKeyAlias$1.uid >= Number.MAX_SAFE_INTEGER) {
|
|
return toKeyAlias$1.uid = 0;
|
|
} else {
|
|
return toKeyAlias$1.uid++;
|
|
}
|
|
};
|
|
|
|
|
|
return toKeyAlias;
|
|
}
|
|
|
|
var toStatement = {};
|
|
|
|
var hasRequiredToStatement;
|
|
|
|
function requireToStatement () {
|
|
if (hasRequiredToStatement) return toStatement;
|
|
hasRequiredToStatement = 1;
|
|
|
|
Object.defineProperty(toStatement, "__esModule", {
|
|
value: true
|
|
});
|
|
toStatement.default = void 0;
|
|
var _index = requireGenerated$3();
|
|
var _index2 = requireGenerated$2();
|
|
toStatement.default = toStatement$1;
|
|
function toStatement$1(node, ignore) {
|
|
if ((0, _index.isStatement)(node)) {
|
|
return node;
|
|
}
|
|
let mustHaveId = false;
|
|
let newType;
|
|
if ((0, _index.isClass)(node)) {
|
|
mustHaveId = true;
|
|
newType = "ClassDeclaration";
|
|
} else if ((0, _index.isFunction)(node)) {
|
|
mustHaveId = true;
|
|
newType = "FunctionDeclaration";
|
|
} else if ((0, _index.isAssignmentExpression)(node)) {
|
|
return (0, _index2.expressionStatement)(node);
|
|
}
|
|
if (mustHaveId && !node.id) {
|
|
newType = false;
|
|
}
|
|
if (!newType) {
|
|
if (ignore) {
|
|
return false;
|
|
} else {
|
|
throw new Error(`cannot turn ${node.type} to a statement`);
|
|
}
|
|
}
|
|
node.type = newType;
|
|
return node;
|
|
}
|
|
|
|
|
|
return toStatement;
|
|
}
|
|
|
|
var valueToNode = {};
|
|
|
|
var hasRequiredValueToNode;
|
|
|
|
function requireValueToNode () {
|
|
if (hasRequiredValueToNode) return valueToNode;
|
|
hasRequiredValueToNode = 1;
|
|
|
|
Object.defineProperty(valueToNode, "__esModule", {
|
|
value: true
|
|
});
|
|
valueToNode.default = void 0;
|
|
var _isValidIdentifier = requireIsValidIdentifier();
|
|
var _index = requireGenerated$2();
|
|
valueToNode.default = valueToNode$1;
|
|
const objectToString = Function.call.bind(Object.prototype.toString);
|
|
function isRegExp(value) {
|
|
return objectToString(value) === "[object RegExp]";
|
|
}
|
|
function isPlainObject(value) {
|
|
if (typeof value !== "object" || value === null || Object.prototype.toString.call(value) !== "[object Object]") {
|
|
return false;
|
|
}
|
|
const proto = Object.getPrototypeOf(value);
|
|
return proto === null || Object.getPrototypeOf(proto) === null;
|
|
}
|
|
function valueToNode$1(value) {
|
|
if (value === undefined) {
|
|
return (0, _index.identifier)("undefined");
|
|
}
|
|
if (value === true || value === false) {
|
|
return (0, _index.booleanLiteral)(value);
|
|
}
|
|
if (value === null) {
|
|
return (0, _index.nullLiteral)();
|
|
}
|
|
if (typeof value === "string") {
|
|
return (0, _index.stringLiteral)(value);
|
|
}
|
|
if (typeof value === "number") {
|
|
let result;
|
|
if (Number.isFinite(value)) {
|
|
result = (0, _index.numericLiteral)(Math.abs(value));
|
|
} else {
|
|
let numerator;
|
|
if (Number.isNaN(value)) {
|
|
numerator = (0, _index.numericLiteral)(0);
|
|
} else {
|
|
numerator = (0, _index.numericLiteral)(1);
|
|
}
|
|
result = (0, _index.binaryExpression)("/", numerator, (0, _index.numericLiteral)(0));
|
|
}
|
|
if (value < 0 || Object.is(value, -0)) {
|
|
result = (0, _index.unaryExpression)("-", result);
|
|
}
|
|
return result;
|
|
}
|
|
if (isRegExp(value)) {
|
|
const pattern = value.source;
|
|
const flags = /\/([a-z]*)$/.exec(value.toString())[1];
|
|
return (0, _index.regExpLiteral)(pattern, flags);
|
|
}
|
|
if (Array.isArray(value)) {
|
|
return (0, _index.arrayExpression)(value.map(valueToNode$1));
|
|
}
|
|
if (isPlainObject(value)) {
|
|
const props = [];
|
|
for (const key of Object.keys(value)) {
|
|
let nodeKey;
|
|
if ((0, _isValidIdentifier.default)(key)) {
|
|
nodeKey = (0, _index.identifier)(key);
|
|
} else {
|
|
nodeKey = (0, _index.stringLiteral)(key);
|
|
}
|
|
props.push((0, _index.objectProperty)(nodeKey, valueToNode$1(value[key])));
|
|
}
|
|
return (0, _index.objectExpression)(props);
|
|
}
|
|
throw new Error("don't know how to turn this value into a node");
|
|
}
|
|
|
|
|
|
return valueToNode;
|
|
}
|
|
|
|
var appendToMemberExpression = {};
|
|
|
|
var hasRequiredAppendToMemberExpression;
|
|
|
|
function requireAppendToMemberExpression () {
|
|
if (hasRequiredAppendToMemberExpression) return appendToMemberExpression;
|
|
hasRequiredAppendToMemberExpression = 1;
|
|
|
|
Object.defineProperty(appendToMemberExpression, "__esModule", {
|
|
value: true
|
|
});
|
|
appendToMemberExpression.default = appendToMemberExpression$1;
|
|
var _index = requireGenerated$2();
|
|
function appendToMemberExpression$1(member, append, computed = false) {
|
|
member.object = (0, _index.memberExpression)(member.object, member.property, member.computed);
|
|
member.property = append;
|
|
member.computed = !!computed;
|
|
return member;
|
|
}
|
|
|
|
|
|
return appendToMemberExpression;
|
|
}
|
|
|
|
var inherits = {};
|
|
|
|
var hasRequiredInherits;
|
|
|
|
function requireInherits () {
|
|
if (hasRequiredInherits) return inherits;
|
|
hasRequiredInherits = 1;
|
|
|
|
Object.defineProperty(inherits, "__esModule", {
|
|
value: true
|
|
});
|
|
inherits.default = inherits$1;
|
|
var _index = requireConstants();
|
|
var _inheritsComments = requireInheritsComments();
|
|
function inherits$1(child, parent) {
|
|
if (!child || !parent) return child;
|
|
for (const key of _index.INHERIT_KEYS.optional) {
|
|
if (child[key] == null) {
|
|
child[key] = parent[key];
|
|
}
|
|
}
|
|
for (const key of Object.keys(parent)) {
|
|
if (key[0] === "_" && key !== "__clone") {
|
|
child[key] = parent[key];
|
|
}
|
|
}
|
|
for (const key of _index.INHERIT_KEYS.force) {
|
|
child[key] = parent[key];
|
|
}
|
|
(0, _inheritsComments.default)(child, parent);
|
|
return child;
|
|
}
|
|
|
|
|
|
return inherits;
|
|
}
|
|
|
|
var prependToMemberExpression = {};
|
|
|
|
var hasRequiredPrependToMemberExpression;
|
|
|
|
function requirePrependToMemberExpression () {
|
|
if (hasRequiredPrependToMemberExpression) return prependToMemberExpression;
|
|
hasRequiredPrependToMemberExpression = 1;
|
|
|
|
Object.defineProperty(prependToMemberExpression, "__esModule", {
|
|
value: true
|
|
});
|
|
prependToMemberExpression.default = prependToMemberExpression$1;
|
|
var _index = requireGenerated$2();
|
|
var _index2 = requireLib$1();
|
|
function prependToMemberExpression$1(member, prepend) {
|
|
if ((0, _index2.isSuper)(member.object)) {
|
|
throw new Error("Cannot prepend node to super property access (`super.foo`).");
|
|
}
|
|
member.object = (0, _index.memberExpression)(prepend, member.object);
|
|
return member;
|
|
}
|
|
|
|
|
|
return prependToMemberExpression;
|
|
}
|
|
|
|
var getAssignmentIdentifiers = {};
|
|
|
|
var hasRequiredGetAssignmentIdentifiers;
|
|
|
|
function requireGetAssignmentIdentifiers () {
|
|
if (hasRequiredGetAssignmentIdentifiers) return getAssignmentIdentifiers;
|
|
hasRequiredGetAssignmentIdentifiers = 1;
|
|
|
|
Object.defineProperty(getAssignmentIdentifiers, "__esModule", {
|
|
value: true
|
|
});
|
|
getAssignmentIdentifiers.default = getAssignmentIdentifiers$1;
|
|
function getAssignmentIdentifiers$1(node) {
|
|
const search = [].concat(node);
|
|
const ids = Object.create(null);
|
|
while (search.length) {
|
|
const id = search.pop();
|
|
if (!id) continue;
|
|
switch (id.type) {
|
|
case "ArrayPattern":
|
|
search.push(...id.elements);
|
|
break;
|
|
case "AssignmentExpression":
|
|
case "AssignmentPattern":
|
|
case "ForInStatement":
|
|
case "ForOfStatement":
|
|
search.push(id.left);
|
|
break;
|
|
case "ObjectPattern":
|
|
search.push(...id.properties);
|
|
break;
|
|
case "ObjectProperty":
|
|
search.push(id.value);
|
|
break;
|
|
case "RestElement":
|
|
case "UpdateExpression":
|
|
search.push(id.argument);
|
|
break;
|
|
case "UnaryExpression":
|
|
if (id.operator === "delete") {
|
|
search.push(id.argument);
|
|
}
|
|
break;
|
|
case "Identifier":
|
|
ids[id.name] = id;
|
|
break;
|
|
}
|
|
}
|
|
return ids;
|
|
}
|
|
|
|
|
|
return getAssignmentIdentifiers;
|
|
}
|
|
|
|
var getBindingIdentifiers = {};
|
|
|
|
var hasRequiredGetBindingIdentifiers;
|
|
|
|
function requireGetBindingIdentifiers () {
|
|
if (hasRequiredGetBindingIdentifiers) return getBindingIdentifiers;
|
|
hasRequiredGetBindingIdentifiers = 1;
|
|
|
|
Object.defineProperty(getBindingIdentifiers, "__esModule", {
|
|
value: true
|
|
});
|
|
getBindingIdentifiers.default = getBindingIdentifiers$1;
|
|
var _index = requireGenerated$3();
|
|
function getBindingIdentifiers$1(node, duplicates, outerOnly, newBindingsOnly) {
|
|
const search = [].concat(node);
|
|
const ids = Object.create(null);
|
|
while (search.length) {
|
|
const id = search.shift();
|
|
if (!id) continue;
|
|
if (newBindingsOnly && ((0, _index.isAssignmentExpression)(id) || (0, _index.isUnaryExpression)(id) || (0, _index.isUpdateExpression)(id))) {
|
|
continue;
|
|
}
|
|
if ((0, _index.isIdentifier)(id)) {
|
|
if (duplicates) {
|
|
const _ids = ids[id.name] = ids[id.name] || [];
|
|
_ids.push(id);
|
|
} else {
|
|
ids[id.name] = id;
|
|
}
|
|
continue;
|
|
}
|
|
if ((0, _index.isExportDeclaration)(id) && !(0, _index.isExportAllDeclaration)(id)) {
|
|
if ((0, _index.isDeclaration)(id.declaration)) {
|
|
search.push(id.declaration);
|
|
}
|
|
continue;
|
|
}
|
|
if (outerOnly) {
|
|
if ((0, _index.isFunctionDeclaration)(id)) {
|
|
search.push(id.id);
|
|
continue;
|
|
}
|
|
if ((0, _index.isFunctionExpression)(id)) {
|
|
continue;
|
|
}
|
|
}
|
|
const keys = getBindingIdentifiers$1.keys[id.type];
|
|
if (keys) {
|
|
for (let i = 0; i < keys.length; i++) {
|
|
const key = keys[i];
|
|
const nodes = id[key];
|
|
if (nodes) {
|
|
if (Array.isArray(nodes)) {
|
|
search.push(...nodes);
|
|
} else {
|
|
search.push(nodes);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ids;
|
|
}
|
|
const keys = {
|
|
DeclareClass: ["id"],
|
|
DeclareFunction: ["id"],
|
|
DeclareModule: ["id"],
|
|
DeclareVariable: ["id"],
|
|
DeclareInterface: ["id"],
|
|
DeclareTypeAlias: ["id"],
|
|
DeclareOpaqueType: ["id"],
|
|
InterfaceDeclaration: ["id"],
|
|
TypeAlias: ["id"],
|
|
OpaqueType: ["id"],
|
|
CatchClause: ["param"],
|
|
LabeledStatement: ["label"],
|
|
UnaryExpression: ["argument"],
|
|
AssignmentExpression: ["left"],
|
|
ImportSpecifier: ["local"],
|
|
ImportNamespaceSpecifier: ["local"],
|
|
ImportDefaultSpecifier: ["local"],
|
|
ImportDeclaration: ["specifiers"],
|
|
ExportSpecifier: ["exported"],
|
|
ExportNamespaceSpecifier: ["exported"],
|
|
ExportDefaultSpecifier: ["exported"],
|
|
FunctionDeclaration: ["id", "params"],
|
|
FunctionExpression: ["id", "params"],
|
|
ArrowFunctionExpression: ["params"],
|
|
ObjectMethod: ["params"],
|
|
ClassMethod: ["params"],
|
|
ClassPrivateMethod: ["params"],
|
|
ForInStatement: ["left"],
|
|
ForOfStatement: ["left"],
|
|
ClassDeclaration: ["id"],
|
|
ClassExpression: ["id"],
|
|
RestElement: ["argument"],
|
|
UpdateExpression: ["argument"],
|
|
ObjectProperty: ["value"],
|
|
AssignmentPattern: ["left"],
|
|
ArrayPattern: ["elements"],
|
|
ObjectPattern: ["properties"],
|
|
VariableDeclaration: ["declarations"],
|
|
VariableDeclarator: ["id"]
|
|
};
|
|
getBindingIdentifiers$1.keys = keys;
|
|
|
|
|
|
return getBindingIdentifiers;
|
|
}
|
|
|
|
var getOuterBindingIdentifiers = {};
|
|
|
|
var hasRequiredGetOuterBindingIdentifiers;
|
|
|
|
function requireGetOuterBindingIdentifiers () {
|
|
if (hasRequiredGetOuterBindingIdentifiers) return getOuterBindingIdentifiers;
|
|
hasRequiredGetOuterBindingIdentifiers = 1;
|
|
|
|
Object.defineProperty(getOuterBindingIdentifiers, "__esModule", {
|
|
value: true
|
|
});
|
|
getOuterBindingIdentifiers.default = void 0;
|
|
var _getBindingIdentifiers = requireGetBindingIdentifiers();
|
|
getOuterBindingIdentifiers.default = getOuterBindingIdentifiers$1;
|
|
function getOuterBindingIdentifiers$1(node, duplicates) {
|
|
return (0, _getBindingIdentifiers.default)(node, duplicates, true);
|
|
}
|
|
|
|
|
|
return getOuterBindingIdentifiers;
|
|
}
|
|
|
|
var getFunctionName$3 = {};
|
|
|
|
var hasRequiredGetFunctionName;
|
|
|
|
function requireGetFunctionName () {
|
|
if (hasRequiredGetFunctionName) return getFunctionName$3;
|
|
hasRequiredGetFunctionName = 1;
|
|
|
|
Object.defineProperty(getFunctionName$3, "__esModule", {
|
|
value: true
|
|
});
|
|
getFunctionName$3.default = getFunctionName;
|
|
var _index = requireGenerated$3();
|
|
function getNameFromLiteralId(id) {
|
|
if ((0, _index.isNullLiteral)(id)) {
|
|
return "null";
|
|
}
|
|
if ((0, _index.isRegExpLiteral)(id)) {
|
|
return `/${id.pattern}/${id.flags}`;
|
|
}
|
|
if ((0, _index.isTemplateLiteral)(id)) {
|
|
return id.quasis.map(quasi => quasi.value.raw).join("");
|
|
}
|
|
if (id.value !== undefined) {
|
|
return String(id.value);
|
|
}
|
|
return null;
|
|
}
|
|
function getObjectMemberKey(node) {
|
|
if (!node.computed || (0, _index.isLiteral)(node.key)) {
|
|
return node.key;
|
|
}
|
|
}
|
|
function getFunctionName(node, parent) {
|
|
if ("id" in node && node.id) {
|
|
return {
|
|
name: node.id.name,
|
|
originalNode: node.id
|
|
};
|
|
}
|
|
let prefix = "";
|
|
let id;
|
|
if ((0, _index.isObjectProperty)(parent, {
|
|
value: node
|
|
})) {
|
|
id = getObjectMemberKey(parent);
|
|
} else if ((0, _index.isObjectMethod)(node) || (0, _index.isClassMethod)(node)) {
|
|
id = getObjectMemberKey(node);
|
|
if (node.kind === "get") prefix = "get ";else if (node.kind === "set") prefix = "set ";
|
|
} else if ((0, _index.isVariableDeclarator)(parent, {
|
|
init: node
|
|
})) {
|
|
id = parent.id;
|
|
} else if ((0, _index.isAssignmentExpression)(parent, {
|
|
operator: "=",
|
|
right: node
|
|
})) {
|
|
id = parent.left;
|
|
}
|
|
if (!id) return null;
|
|
const name = (0, _index.isLiteral)(id) ? getNameFromLiteralId(id) : (0, _index.isIdentifier)(id) ? id.name : (0, _index.isPrivateName)(id) ? id.id.name : null;
|
|
if (name == null) return null;
|
|
return {
|
|
name: prefix + name,
|
|
originalNode: id
|
|
};
|
|
}
|
|
|
|
|
|
return getFunctionName$3;
|
|
}
|
|
|
|
var traverse = {};
|
|
|
|
var hasRequiredTraverse;
|
|
|
|
function requireTraverse () {
|
|
if (hasRequiredTraverse) return traverse;
|
|
hasRequiredTraverse = 1;
|
|
|
|
Object.defineProperty(traverse, "__esModule", {
|
|
value: true
|
|
});
|
|
traverse.default = traverse$1;
|
|
var _index = requireDefinitions();
|
|
function traverse$1(node, handlers, state) {
|
|
if (typeof handlers === "function") {
|
|
handlers = {
|
|
enter: handlers
|
|
};
|
|
}
|
|
const {
|
|
enter,
|
|
exit
|
|
} = handlers;
|
|
traverseSimpleImpl(node, enter, exit, state, []);
|
|
}
|
|
function traverseSimpleImpl(node, enter, exit, state, ancestors) {
|
|
const keys = _index.VISITOR_KEYS[node.type];
|
|
if (!keys) return;
|
|
if (enter) enter(node, ancestors, state);
|
|
for (const key of keys) {
|
|
const subNode = node[key];
|
|
if (Array.isArray(subNode)) {
|
|
for (let i = 0; i < subNode.length; i++) {
|
|
const child = subNode[i];
|
|
if (!child) continue;
|
|
ancestors.push({
|
|
node,
|
|
key,
|
|
index: i
|
|
});
|
|
traverseSimpleImpl(child, enter, exit, state, ancestors);
|
|
ancestors.pop();
|
|
}
|
|
} else if (subNode) {
|
|
ancestors.push({
|
|
node,
|
|
key
|
|
});
|
|
traverseSimpleImpl(subNode, enter, exit, state, ancestors);
|
|
ancestors.pop();
|
|
}
|
|
}
|
|
if (exit) exit(node, ancestors, state);
|
|
}
|
|
|
|
|
|
return traverse;
|
|
}
|
|
|
|
var isBinding = {};
|
|
|
|
var hasRequiredIsBinding;
|
|
|
|
function requireIsBinding () {
|
|
if (hasRequiredIsBinding) return isBinding;
|
|
hasRequiredIsBinding = 1;
|
|
|
|
Object.defineProperty(isBinding, "__esModule", {
|
|
value: true
|
|
});
|
|
isBinding.default = isBinding$1;
|
|
var _getBindingIdentifiers = requireGetBindingIdentifiers();
|
|
function isBinding$1(node, parent, grandparent) {
|
|
if (grandparent && node.type === "Identifier" && parent.type === "ObjectProperty" && grandparent.type === "ObjectExpression") {
|
|
return false;
|
|
}
|
|
const keys = _getBindingIdentifiers.default.keys[parent.type];
|
|
if (keys) {
|
|
for (let i = 0; i < keys.length; i++) {
|
|
const key = keys[i];
|
|
const val = parent[key];
|
|
if (Array.isArray(val)) {
|
|
if (val.includes(node)) return true;
|
|
} else {
|
|
if (val === node) return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
return isBinding;
|
|
}
|
|
|
|
var isBlockScoped = {};
|
|
|
|
var isLet = {};
|
|
|
|
var hasRequiredIsLet;
|
|
|
|
function requireIsLet () {
|
|
if (hasRequiredIsLet) return isLet;
|
|
hasRequiredIsLet = 1;
|
|
|
|
Object.defineProperty(isLet, "__esModule", {
|
|
value: true
|
|
});
|
|
isLet.default = isLet$1;
|
|
var _index = requireGenerated$3();
|
|
var _index2 = requireConstants();
|
|
function isLet$1(node) {
|
|
return (0, _index.isVariableDeclaration)(node) && (node.kind !== "var" || node[_index2.BLOCK_SCOPED_SYMBOL]);
|
|
}
|
|
|
|
|
|
return isLet;
|
|
}
|
|
|
|
var hasRequiredIsBlockScoped;
|
|
|
|
function requireIsBlockScoped () {
|
|
if (hasRequiredIsBlockScoped) return isBlockScoped;
|
|
hasRequiredIsBlockScoped = 1;
|
|
|
|
Object.defineProperty(isBlockScoped, "__esModule", {
|
|
value: true
|
|
});
|
|
isBlockScoped.default = isBlockScoped$1;
|
|
var _index = requireGenerated$3();
|
|
var _isLet = requireIsLet();
|
|
function isBlockScoped$1(node) {
|
|
return (0, _index.isFunctionDeclaration)(node) || (0, _index.isClassDeclaration)(node) || (0, _isLet.default)(node);
|
|
}
|
|
|
|
|
|
return isBlockScoped;
|
|
}
|
|
|
|
var isImmutable = {};
|
|
|
|
var hasRequiredIsImmutable;
|
|
|
|
function requireIsImmutable () {
|
|
if (hasRequiredIsImmutable) return isImmutable;
|
|
hasRequiredIsImmutable = 1;
|
|
|
|
Object.defineProperty(isImmutable, "__esModule", {
|
|
value: true
|
|
});
|
|
isImmutable.default = isImmutable$1;
|
|
var _isType = requireIsType();
|
|
var _index = requireGenerated$3();
|
|
function isImmutable$1(node) {
|
|
if ((0, _isType.default)(node.type, "Immutable")) return true;
|
|
if ((0, _index.isIdentifier)(node)) {
|
|
if (node.name === "undefined") {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
return isImmutable;
|
|
}
|
|
|
|
var isNodesEquivalent = {};
|
|
|
|
var hasRequiredIsNodesEquivalent;
|
|
|
|
function requireIsNodesEquivalent () {
|
|
if (hasRequiredIsNodesEquivalent) return isNodesEquivalent;
|
|
hasRequiredIsNodesEquivalent = 1;
|
|
|
|
Object.defineProperty(isNodesEquivalent, "__esModule", {
|
|
value: true
|
|
});
|
|
isNodesEquivalent.default = isNodesEquivalent$1;
|
|
var _index = requireDefinitions();
|
|
function isNodesEquivalent$1(a, b) {
|
|
if (typeof a !== "object" || typeof b !== "object" || a == null || b == null) {
|
|
return a === b;
|
|
}
|
|
if (a.type !== b.type) {
|
|
return false;
|
|
}
|
|
const fields = Object.keys(_index.NODE_FIELDS[a.type] || a.type);
|
|
const visitorKeys = _index.VISITOR_KEYS[a.type];
|
|
for (const field of fields) {
|
|
const val_a = a[field];
|
|
const val_b = b[field];
|
|
if (typeof val_a !== typeof val_b) {
|
|
return false;
|
|
}
|
|
if (val_a == null && val_b == null) {
|
|
continue;
|
|
} else if (val_a == null || val_b == null) {
|
|
return false;
|
|
}
|
|
if (Array.isArray(val_a)) {
|
|
if (!Array.isArray(val_b)) {
|
|
return false;
|
|
}
|
|
if (val_a.length !== val_b.length) {
|
|
return false;
|
|
}
|
|
for (let i = 0; i < val_a.length; i++) {
|
|
if (!isNodesEquivalent$1(val_a[i], val_b[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
if (typeof val_a === "object" && !(visitorKeys != null && visitorKeys.includes(field))) {
|
|
for (const key of Object.keys(val_a)) {
|
|
if (val_a[key] !== val_b[key]) {
|
|
return false;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
if (!isNodesEquivalent$1(val_a, val_b)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
return isNodesEquivalent;
|
|
}
|
|
|
|
var isReferenced = {};
|
|
|
|
var hasRequiredIsReferenced;
|
|
|
|
function requireIsReferenced () {
|
|
if (hasRequiredIsReferenced) return isReferenced;
|
|
hasRequiredIsReferenced = 1;
|
|
|
|
Object.defineProperty(isReferenced, "__esModule", {
|
|
value: true
|
|
});
|
|
isReferenced.default = isReferenced$1;
|
|
function isReferenced$1(node, parent, grandparent) {
|
|
switch (parent.type) {
|
|
case "MemberExpression":
|
|
case "OptionalMemberExpression":
|
|
if (parent.property === node) {
|
|
return !!parent.computed;
|
|
}
|
|
return parent.object === node;
|
|
case "JSXMemberExpression":
|
|
return parent.object === node;
|
|
case "VariableDeclarator":
|
|
return parent.init === node;
|
|
case "ArrowFunctionExpression":
|
|
return parent.body === node;
|
|
case "PrivateName":
|
|
return false;
|
|
case "ClassMethod":
|
|
case "ClassPrivateMethod":
|
|
case "ObjectMethod":
|
|
if (parent.key === node) {
|
|
return !!parent.computed;
|
|
}
|
|
return false;
|
|
case "ObjectProperty":
|
|
if (parent.key === node) {
|
|
return !!parent.computed;
|
|
}
|
|
return !grandparent || grandparent.type !== "ObjectPattern";
|
|
case "ClassProperty":
|
|
case "ClassAccessorProperty":
|
|
if (parent.key === node) {
|
|
return !!parent.computed;
|
|
}
|
|
return true;
|
|
case "ClassPrivateProperty":
|
|
return parent.key !== node;
|
|
case "ClassDeclaration":
|
|
case "ClassExpression":
|
|
return parent.superClass === node;
|
|
case "AssignmentExpression":
|
|
return parent.right === node;
|
|
case "AssignmentPattern":
|
|
return parent.right === node;
|
|
case "LabeledStatement":
|
|
return false;
|
|
case "CatchClause":
|
|
return false;
|
|
case "RestElement":
|
|
return false;
|
|
case "BreakStatement":
|
|
case "ContinueStatement":
|
|
return false;
|
|
case "FunctionDeclaration":
|
|
case "FunctionExpression":
|
|
return false;
|
|
case "ExportNamespaceSpecifier":
|
|
case "ExportDefaultSpecifier":
|
|
return false;
|
|
case "ExportSpecifier":
|
|
if (grandparent != null && grandparent.source) {
|
|
return false;
|
|
}
|
|
return parent.local === node;
|
|
case "ImportDefaultSpecifier":
|
|
case "ImportNamespaceSpecifier":
|
|
case "ImportSpecifier":
|
|
return false;
|
|
case "ImportAttribute":
|
|
return false;
|
|
case "JSXAttribute":
|
|
return false;
|
|
case "ObjectPattern":
|
|
case "ArrayPattern":
|
|
return false;
|
|
case "MetaProperty":
|
|
return false;
|
|
case "ObjectTypeProperty":
|
|
return parent.key !== node;
|
|
case "TSEnumMember":
|
|
return parent.id !== node;
|
|
case "TSPropertySignature":
|
|
if (parent.key === node) {
|
|
return !!parent.computed;
|
|
}
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
return isReferenced;
|
|
}
|
|
|
|
var isScope = {};
|
|
|
|
var hasRequiredIsScope;
|
|
|
|
function requireIsScope () {
|
|
if (hasRequiredIsScope) return isScope;
|
|
hasRequiredIsScope = 1;
|
|
|
|
Object.defineProperty(isScope, "__esModule", {
|
|
value: true
|
|
});
|
|
isScope.default = isScope$1;
|
|
var _index = requireGenerated$3();
|
|
function isScope$1(node, parent) {
|
|
if ((0, _index.isBlockStatement)(node) && ((0, _index.isFunction)(parent) || (0, _index.isCatchClause)(parent))) {
|
|
return false;
|
|
}
|
|
if ((0, _index.isPattern)(node) && ((0, _index.isFunction)(parent) || (0, _index.isCatchClause)(parent))) {
|
|
return true;
|
|
}
|
|
return (0, _index.isScopable)(node);
|
|
}
|
|
|
|
|
|
return isScope;
|
|
}
|
|
|
|
var isSpecifierDefault = {};
|
|
|
|
var hasRequiredIsSpecifierDefault;
|
|
|
|
function requireIsSpecifierDefault () {
|
|
if (hasRequiredIsSpecifierDefault) return isSpecifierDefault;
|
|
hasRequiredIsSpecifierDefault = 1;
|
|
|
|
Object.defineProperty(isSpecifierDefault, "__esModule", {
|
|
value: true
|
|
});
|
|
isSpecifierDefault.default = isSpecifierDefault$1;
|
|
var _index = requireGenerated$3();
|
|
function isSpecifierDefault$1(specifier) {
|
|
return (0, _index.isImportDefaultSpecifier)(specifier) || (0, _index.isIdentifier)(specifier.imported || specifier.exported, {
|
|
name: "default"
|
|
});
|
|
}
|
|
|
|
|
|
return isSpecifierDefault;
|
|
}
|
|
|
|
var isValidES3Identifier = {};
|
|
|
|
var hasRequiredIsValidES3Identifier;
|
|
|
|
function requireIsValidES3Identifier () {
|
|
if (hasRequiredIsValidES3Identifier) return isValidES3Identifier;
|
|
hasRequiredIsValidES3Identifier = 1;
|
|
|
|
Object.defineProperty(isValidES3Identifier, "__esModule", {
|
|
value: true
|
|
});
|
|
isValidES3Identifier.default = isValidES3Identifier$1;
|
|
var _isValidIdentifier = requireIsValidIdentifier();
|
|
const RESERVED_WORDS_ES3_ONLY = new Set(["abstract", "boolean", "byte", "char", "double", "enum", "final", "float", "goto", "implements", "int", "interface", "long", "native", "package", "private", "protected", "public", "short", "static", "synchronized", "throws", "transient", "volatile"]);
|
|
function isValidES3Identifier$1(name) {
|
|
return (0, _isValidIdentifier.default)(name) && !RESERVED_WORDS_ES3_ONLY.has(name);
|
|
}
|
|
|
|
|
|
return isValidES3Identifier;
|
|
}
|
|
|
|
var isVar = {};
|
|
|
|
var hasRequiredIsVar;
|
|
|
|
function requireIsVar () {
|
|
if (hasRequiredIsVar) return isVar;
|
|
hasRequiredIsVar = 1;
|
|
|
|
Object.defineProperty(isVar, "__esModule", {
|
|
value: true
|
|
});
|
|
isVar.default = isVar$1;
|
|
var _index = requireGenerated$3();
|
|
var _index2 = requireConstants();
|
|
function isVar$1(node) {
|
|
return (0, _index.isVariableDeclaration)(node, {
|
|
kind: "var"
|
|
}) && !node[_index2.BLOCK_SCOPED_SYMBOL];
|
|
}
|
|
|
|
|
|
return isVar;
|
|
}
|
|
|
|
var toSequenceExpression = {};
|
|
|
|
var gatherSequenceExpressions = {};
|
|
|
|
var hasRequiredGatherSequenceExpressions;
|
|
|
|
function requireGatherSequenceExpressions () {
|
|
if (hasRequiredGatherSequenceExpressions) return gatherSequenceExpressions;
|
|
hasRequiredGatherSequenceExpressions = 1;
|
|
|
|
Object.defineProperty(gatherSequenceExpressions, "__esModule", {
|
|
value: true
|
|
});
|
|
gatherSequenceExpressions.default = gatherSequenceExpressions$1;
|
|
var _getBindingIdentifiers = requireGetBindingIdentifiers();
|
|
var _index = requireGenerated$3();
|
|
var _index2 = requireGenerated$2();
|
|
var _productions = requireProductions();
|
|
var _cloneNode = requireCloneNode();
|
|
function gatherSequenceExpressions$1(nodes, declars) {
|
|
const exprs = [];
|
|
let ensureLastUndefined = true;
|
|
for (const node of nodes) {
|
|
if (!(0, _index.isEmptyStatement)(node)) {
|
|
ensureLastUndefined = false;
|
|
}
|
|
if ((0, _index.isExpression)(node)) {
|
|
exprs.push(node);
|
|
} else if ((0, _index.isExpressionStatement)(node)) {
|
|
exprs.push(node.expression);
|
|
} else if ((0, _index.isVariableDeclaration)(node)) {
|
|
if (node.kind !== "var") return;
|
|
for (const declar of node.declarations) {
|
|
const bindings = (0, _getBindingIdentifiers.default)(declar);
|
|
for (const key of Object.keys(bindings)) {
|
|
declars.push({
|
|
kind: node.kind,
|
|
id: (0, _cloneNode.default)(bindings[key])
|
|
});
|
|
}
|
|
if (declar.init) {
|
|
exprs.push((0, _index2.assignmentExpression)("=", declar.id, declar.init));
|
|
}
|
|
}
|
|
ensureLastUndefined = true;
|
|
} else if ((0, _index.isIfStatement)(node)) {
|
|
const consequent = node.consequent ? gatherSequenceExpressions$1([node.consequent], declars) : (0, _productions.buildUndefinedNode)();
|
|
const alternate = node.alternate ? gatherSequenceExpressions$1([node.alternate], declars) : (0, _productions.buildUndefinedNode)();
|
|
if (!consequent || !alternate) return;
|
|
exprs.push((0, _index2.conditionalExpression)(node.test, consequent, alternate));
|
|
} else if ((0, _index.isBlockStatement)(node)) {
|
|
const body = gatherSequenceExpressions$1(node.body, declars);
|
|
if (!body) return;
|
|
exprs.push(body);
|
|
} else if ((0, _index.isEmptyStatement)(node)) {
|
|
if (nodes.indexOf(node) === 0) {
|
|
ensureLastUndefined = true;
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
if (ensureLastUndefined) {
|
|
exprs.push((0, _productions.buildUndefinedNode)());
|
|
}
|
|
if (exprs.length === 1) {
|
|
return exprs[0];
|
|
} else {
|
|
return (0, _index2.sequenceExpression)(exprs);
|
|
}
|
|
}
|
|
|
|
|
|
return gatherSequenceExpressions;
|
|
}
|
|
|
|
var hasRequiredToSequenceExpression;
|
|
|
|
function requireToSequenceExpression () {
|
|
if (hasRequiredToSequenceExpression) return toSequenceExpression;
|
|
hasRequiredToSequenceExpression = 1;
|
|
|
|
Object.defineProperty(toSequenceExpression, "__esModule", {
|
|
value: true
|
|
});
|
|
toSequenceExpression.default = toSequenceExpression$1;
|
|
var _gatherSequenceExpressions = requireGatherSequenceExpressions();
|
|
function toSequenceExpression$1(nodes, scope) {
|
|
if (!(nodes != null && nodes.length)) return;
|
|
const declars = [];
|
|
const result = (0, _gatherSequenceExpressions.default)(nodes, declars);
|
|
if (!result) return;
|
|
for (const declar of declars) {
|
|
scope.push(declar);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
return toSequenceExpression;
|
|
}
|
|
|
|
var hasRequiredLib$1;
|
|
|
|
function requireLib$1 () {
|
|
if (hasRequiredLib$1) return lib$3;
|
|
hasRequiredLib$1 = 1;
|
|
(function (exports) {
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
var _exportNames = {
|
|
react: true,
|
|
assertNode: true,
|
|
createTypeAnnotationBasedOnTypeof: true,
|
|
createUnionTypeAnnotation: true,
|
|
createFlowUnionType: true,
|
|
createTSUnionType: true,
|
|
cloneNode: true,
|
|
clone: true,
|
|
cloneDeep: true,
|
|
cloneDeepWithoutLoc: true,
|
|
cloneWithoutLoc: true,
|
|
addComment: true,
|
|
addComments: true,
|
|
inheritInnerComments: true,
|
|
inheritLeadingComments: true,
|
|
inheritsComments: true,
|
|
inheritTrailingComments: true,
|
|
removeComments: true,
|
|
ensureBlock: true,
|
|
toBindingIdentifierName: true,
|
|
toBlock: true,
|
|
toComputedKey: true,
|
|
toExpression: true,
|
|
toIdentifier: true,
|
|
toKeyAlias: true,
|
|
toStatement: true,
|
|
valueToNode: true,
|
|
appendToMemberExpression: true,
|
|
inherits: true,
|
|
prependToMemberExpression: true,
|
|
removeProperties: true,
|
|
removePropertiesDeep: true,
|
|
removeTypeDuplicates: true,
|
|
getAssignmentIdentifiers: true,
|
|
getBindingIdentifiers: true,
|
|
getOuterBindingIdentifiers: true,
|
|
getFunctionName: true,
|
|
traverse: true,
|
|
traverseFast: true,
|
|
shallowEqual: true,
|
|
is: true,
|
|
isBinding: true,
|
|
isBlockScoped: true,
|
|
isImmutable: true,
|
|
isLet: true,
|
|
isNode: true,
|
|
isNodesEquivalent: true,
|
|
isPlaceholderType: true,
|
|
isReferenced: true,
|
|
isScope: true,
|
|
isSpecifierDefault: true,
|
|
isType: true,
|
|
isValidES3Identifier: true,
|
|
isValidIdentifier: true,
|
|
isVar: true,
|
|
matchesPattern: true,
|
|
validate: true,
|
|
buildMatchMemberExpression: true,
|
|
__internal__deprecationWarning: true
|
|
};
|
|
Object.defineProperty(exports, "__internal__deprecationWarning", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _deprecationWarning.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "addComment", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _addComment.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "addComments", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _addComments.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "appendToMemberExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _appendToMemberExpression.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "assertNode", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _assertNode.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "buildMatchMemberExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _buildMatchMemberExpression.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "clone", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _clone.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "cloneDeep", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _cloneDeep.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "cloneDeepWithoutLoc", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _cloneDeepWithoutLoc.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "cloneNode", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _cloneNode.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "cloneWithoutLoc", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _cloneWithoutLoc.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "createFlowUnionType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _createFlowUnionType.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "createTSUnionType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _createTSUnionType.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "createTypeAnnotationBasedOnTypeof", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _createTypeAnnotationBasedOnTypeof.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "createUnionTypeAnnotation", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _createFlowUnionType.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "ensureBlock", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _ensureBlock.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "getAssignmentIdentifiers", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _getAssignmentIdentifiers.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "getBindingIdentifiers", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _getBindingIdentifiers.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "getFunctionName", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _getFunctionName.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "getOuterBindingIdentifiers", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _getOuterBindingIdentifiers.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "inheritInnerComments", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _inheritInnerComments.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "inheritLeadingComments", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _inheritLeadingComments.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "inheritTrailingComments", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _inheritTrailingComments.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "inherits", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _inherits.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "inheritsComments", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _inheritsComments.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "is", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _is.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isBinding", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isBinding.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isBlockScoped", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isBlockScoped.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isImmutable", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isImmutable.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isLet", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isLet.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isNode", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isNode.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isNodesEquivalent", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isNodesEquivalent.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isPlaceholderType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isPlaceholderType.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isReferenced", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isReferenced.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isScope", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isScope.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isSpecifierDefault", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isSpecifierDefault.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isType", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isType.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isValidES3Identifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isValidES3Identifier.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isValidIdentifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isValidIdentifier.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "isVar", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _isVar.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "matchesPattern", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _matchesPattern.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "prependToMemberExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _prependToMemberExpression.default;
|
|
}
|
|
});
|
|
exports.react = void 0;
|
|
Object.defineProperty(exports, "removeComments", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _removeComments.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "removeProperties", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _removeProperties.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "removePropertiesDeep", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _removePropertiesDeep.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "removeTypeDuplicates", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _removeTypeDuplicates.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "shallowEqual", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _shallowEqual.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "toBindingIdentifierName", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _toBindingIdentifierName.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "toBlock", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _toBlock.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "toComputedKey", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _toComputedKey.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "toExpression", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _toExpression.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "toIdentifier", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _toIdentifier.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "toKeyAlias", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _toKeyAlias.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "toStatement", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _toStatement.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "traverse", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _traverse.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "traverseFast", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _traverseFast.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "validate", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _validate.default;
|
|
}
|
|
});
|
|
Object.defineProperty(exports, "valueToNode", {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _valueToNode.default;
|
|
}
|
|
});
|
|
var _isReactComponent = requireIsReactComponent();
|
|
var _isCompatTag = requireIsCompatTag();
|
|
var _buildChildren = requireBuildChildren();
|
|
var _assertNode = requireAssertNode();
|
|
var _index = requireGenerated$1();
|
|
Object.keys(_index).forEach(function (key) {
|
|
if (key === "default" || key === "__esModule") return;
|
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
if (key in exports && exports[key] === _index[key]) return;
|
|
Object.defineProperty(exports, key, {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index[key];
|
|
}
|
|
});
|
|
});
|
|
var _createTypeAnnotationBasedOnTypeof = requireCreateTypeAnnotationBasedOnTypeof();
|
|
var _createFlowUnionType = requireCreateFlowUnionType();
|
|
var _createTSUnionType = requireCreateTSUnionType();
|
|
var _index2 = requireGenerated$2();
|
|
Object.keys(_index2).forEach(function (key) {
|
|
if (key === "default" || key === "__esModule") return;
|
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
if (key in exports && exports[key] === _index2[key]) return;
|
|
Object.defineProperty(exports, key, {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index2[key];
|
|
}
|
|
});
|
|
});
|
|
var _uppercase = requireUppercase();
|
|
Object.keys(_uppercase).forEach(function (key) {
|
|
if (key === "default" || key === "__esModule") return;
|
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
if (key in exports && exports[key] === _uppercase[key]) return;
|
|
Object.defineProperty(exports, key, {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _uppercase[key];
|
|
}
|
|
});
|
|
});
|
|
var _productions = requireProductions();
|
|
Object.keys(_productions).forEach(function (key) {
|
|
if (key === "default" || key === "__esModule") return;
|
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
if (key in exports && exports[key] === _productions[key]) return;
|
|
Object.defineProperty(exports, key, {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _productions[key];
|
|
}
|
|
});
|
|
});
|
|
var _cloneNode = requireCloneNode();
|
|
var _clone = requireClone();
|
|
var _cloneDeep = requireCloneDeep();
|
|
var _cloneDeepWithoutLoc = requireCloneDeepWithoutLoc();
|
|
var _cloneWithoutLoc = requireCloneWithoutLoc();
|
|
var _addComment = requireAddComment();
|
|
var _addComments = requireAddComments();
|
|
var _inheritInnerComments = requireInheritInnerComments();
|
|
var _inheritLeadingComments = requireInheritLeadingComments();
|
|
var _inheritsComments = requireInheritsComments();
|
|
var _inheritTrailingComments = requireInheritTrailingComments();
|
|
var _removeComments = requireRemoveComments();
|
|
var _index3 = requireGenerated();
|
|
Object.keys(_index3).forEach(function (key) {
|
|
if (key === "default" || key === "__esModule") return;
|
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
if (key in exports && exports[key] === _index3[key]) return;
|
|
Object.defineProperty(exports, key, {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index3[key];
|
|
}
|
|
});
|
|
});
|
|
var _index4 = requireConstants();
|
|
Object.keys(_index4).forEach(function (key) {
|
|
if (key === "default" || key === "__esModule") return;
|
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
if (key in exports && exports[key] === _index4[key]) return;
|
|
Object.defineProperty(exports, key, {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index4[key];
|
|
}
|
|
});
|
|
});
|
|
var _ensureBlock = requireEnsureBlock();
|
|
var _toBindingIdentifierName = requireToBindingIdentifierName();
|
|
var _toBlock = requireToBlock();
|
|
var _toComputedKey = requireToComputedKey();
|
|
var _toExpression = requireToExpression();
|
|
var _toIdentifier = requireToIdentifier();
|
|
var _toKeyAlias = requireToKeyAlias();
|
|
var _toStatement = requireToStatement();
|
|
var _valueToNode = requireValueToNode();
|
|
var _index5 = requireDefinitions();
|
|
Object.keys(_index5).forEach(function (key) {
|
|
if (key === "default" || key === "__esModule") return;
|
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
if (key in exports && exports[key] === _index5[key]) return;
|
|
Object.defineProperty(exports, key, {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index5[key];
|
|
}
|
|
});
|
|
});
|
|
var _appendToMemberExpression = requireAppendToMemberExpression();
|
|
var _inherits = requireInherits();
|
|
var _prependToMemberExpression = requirePrependToMemberExpression();
|
|
var _removeProperties = requireRemoveProperties();
|
|
var _removePropertiesDeep = requireRemovePropertiesDeep();
|
|
var _removeTypeDuplicates = requireRemoveTypeDuplicates$1();
|
|
var _getAssignmentIdentifiers = requireGetAssignmentIdentifiers();
|
|
var _getBindingIdentifiers = requireGetBindingIdentifiers();
|
|
var _getOuterBindingIdentifiers = requireGetOuterBindingIdentifiers();
|
|
var _getFunctionName = requireGetFunctionName();
|
|
var _traverse = requireTraverse();
|
|
Object.keys(_traverse).forEach(function (key) {
|
|
if (key === "default" || key === "__esModule") return;
|
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
if (key in exports && exports[key] === _traverse[key]) return;
|
|
Object.defineProperty(exports, key, {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _traverse[key];
|
|
}
|
|
});
|
|
});
|
|
var _traverseFast = requireTraverseFast();
|
|
var _shallowEqual = requireShallowEqual();
|
|
var _is = requireIs();
|
|
var _isBinding = requireIsBinding();
|
|
var _isBlockScoped = requireIsBlockScoped();
|
|
var _isImmutable = requireIsImmutable();
|
|
var _isLet = requireIsLet();
|
|
var _isNode = requireIsNode();
|
|
var _isNodesEquivalent = requireIsNodesEquivalent();
|
|
var _isPlaceholderType = requireIsPlaceholderType();
|
|
var _isReferenced = requireIsReferenced();
|
|
var _isScope = requireIsScope();
|
|
var _isSpecifierDefault = requireIsSpecifierDefault();
|
|
var _isType = requireIsType();
|
|
var _isValidES3Identifier = requireIsValidES3Identifier();
|
|
var _isValidIdentifier = requireIsValidIdentifier();
|
|
var _isVar = requireIsVar();
|
|
var _matchesPattern = requireMatchesPattern();
|
|
var _validate = requireValidate();
|
|
var _buildMatchMemberExpression = requireBuildMatchMemberExpression();
|
|
var _index6 = requireGenerated$3();
|
|
Object.keys(_index6).forEach(function (key) {
|
|
if (key === "default" || key === "__esModule") return;
|
|
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
if (key in exports && exports[key] === _index6[key]) return;
|
|
Object.defineProperty(exports, key, {
|
|
enumerable: true,
|
|
get: function () {
|
|
return _index6[key];
|
|
}
|
|
});
|
|
});
|
|
var _deprecationWarning = requireDeprecationWarning();
|
|
exports.react = {
|
|
isReactComponent: _isReactComponent.default,
|
|
isCompatTag: _isCompatTag.default,
|
|
buildChildren: _buildChildren.default
|
|
};
|
|
{
|
|
exports.toSequenceExpression = requireToSequenceExpression().default;
|
|
}
|
|
if (process.env.BABEL_TYPES_8_BREAKING) {
|
|
console.warn("BABEL_TYPES_8_BREAKING is not supported anymore. Use the latest Babel 8.0.0 pre-release instead!");
|
|
}
|
|
|
|
|
|
} (lib$3));
|
|
return lib$3;
|
|
}
|
|
|
|
var libExports$1 = requireLib$1();
|
|
|
|
var lib = {};
|
|
|
|
var picocolorsExports = {};
|
|
var picocolors = {
|
|
get exports(){ return picocolorsExports; },
|
|
set exports(v){ picocolorsExports = v; },
|
|
};
|
|
|
|
var hasRequiredPicocolors;
|
|
|
|
function requirePicocolors () {
|
|
if (hasRequiredPicocolors) return picocolorsExports;
|
|
hasRequiredPicocolors = 1;
|
|
let p = process || {}, argv = p.argv || [], env = p.env || {};
|
|
let isColorSupported =
|
|
!(!!env.NO_COLOR || argv.includes("--no-color")) &&
|
|
(!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || ((p.stdout || {}).isTTY && env.TERM !== "dumb") || !!env.CI);
|
|
|
|
let formatter = (open, close, replace = open) =>
|
|
input => {
|
|
let string = "" + input, index = string.indexOf(close, open.length);
|
|
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close
|
|
};
|
|
|
|
let replaceClose = (string, close, replace, index) => {
|
|
let result = "", cursor = 0;
|
|
do {
|
|
result += string.substring(cursor, index) + replace;
|
|
cursor = index + close.length;
|
|
index = string.indexOf(close, cursor);
|
|
} while (~index)
|
|
return result + string.substring(cursor)
|
|
};
|
|
|
|
let createColors = (enabled = isColorSupported) => {
|
|
let f = enabled ? formatter : () => String;
|
|
return {
|
|
isColorSupported: enabled,
|
|
reset: f("\x1b[0m", "\x1b[0m"),
|
|
bold: f("\x1b[1m", "\x1b[22m", "\x1b[22m\x1b[1m"),
|
|
dim: f("\x1b[2m", "\x1b[22m", "\x1b[22m\x1b[2m"),
|
|
italic: f("\x1b[3m", "\x1b[23m"),
|
|
underline: f("\x1b[4m", "\x1b[24m"),
|
|
inverse: f("\x1b[7m", "\x1b[27m"),
|
|
hidden: f("\x1b[8m", "\x1b[28m"),
|
|
strikethrough: f("\x1b[9m", "\x1b[29m"),
|
|
|
|
black: f("\x1b[30m", "\x1b[39m"),
|
|
red: f("\x1b[31m", "\x1b[39m"),
|
|
green: f("\x1b[32m", "\x1b[39m"),
|
|
yellow: f("\x1b[33m", "\x1b[39m"),
|
|
blue: f("\x1b[34m", "\x1b[39m"),
|
|
magenta: f("\x1b[35m", "\x1b[39m"),
|
|
cyan: f("\x1b[36m", "\x1b[39m"),
|
|
white: f("\x1b[37m", "\x1b[39m"),
|
|
gray: f("\x1b[90m", "\x1b[39m"),
|
|
|
|
bgBlack: f("\x1b[40m", "\x1b[49m"),
|
|
bgRed: f("\x1b[41m", "\x1b[49m"),
|
|
bgGreen: f("\x1b[42m", "\x1b[49m"),
|
|
bgYellow: f("\x1b[43m", "\x1b[49m"),
|
|
bgBlue: f("\x1b[44m", "\x1b[49m"),
|
|
bgMagenta: f("\x1b[45m", "\x1b[49m"),
|
|
bgCyan: f("\x1b[46m", "\x1b[49m"),
|
|
bgWhite: f("\x1b[47m", "\x1b[49m"),
|
|
|
|
blackBright: f("\x1b[90m", "\x1b[39m"),
|
|
redBright: f("\x1b[91m", "\x1b[39m"),
|
|
greenBright: f("\x1b[92m", "\x1b[39m"),
|
|
yellowBright: f("\x1b[93m", "\x1b[39m"),
|
|
blueBright: f("\x1b[94m", "\x1b[39m"),
|
|
magentaBright: f("\x1b[95m", "\x1b[39m"),
|
|
cyanBright: f("\x1b[96m", "\x1b[39m"),
|
|
whiteBright: f("\x1b[97m", "\x1b[39m"),
|
|
|
|
bgBlackBright: f("\x1b[100m", "\x1b[49m"),
|
|
bgRedBright: f("\x1b[101m", "\x1b[49m"),
|
|
bgGreenBright: f("\x1b[102m", "\x1b[49m"),
|
|
bgYellowBright: f("\x1b[103m", "\x1b[49m"),
|
|
bgBlueBright: f("\x1b[104m", "\x1b[49m"),
|
|
bgMagentaBright: f("\x1b[105m", "\x1b[49m"),
|
|
bgCyanBright: f("\x1b[106m", "\x1b[49m"),
|
|
bgWhiteBright: f("\x1b[107m", "\x1b[49m"),
|
|
}
|
|
};
|
|
|
|
picocolors.exports = createColors();
|
|
picocolorsExports.createColors = createColors;
|
|
return picocolorsExports;
|
|
}
|
|
|
|
var jsTokens = {};
|
|
|
|
var hasRequiredJsTokens;
|
|
|
|
function requireJsTokens () {
|
|
if (hasRequiredJsTokens) return jsTokens;
|
|
hasRequiredJsTokens = 1;
|
|
// Copyright 2014, 2015, 2016, 2017, 2018 Simon Lydell
|
|
// License: MIT. (See LICENSE.)
|
|
|
|
Object.defineProperty(jsTokens, "__esModule", {
|
|
value: true
|
|
});
|
|
|
|
// This regex comes from regex.coffee, and is inserted here by generate-index.js
|
|
// (run `npm run build`).
|
|
jsTokens.default = /((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyus]{1,6}\b(?![\u0080-\uFFFF$\\]|\s*(?:[+\-*%&|^<>!=?({]|\/(?![\/*])))))|(0[xX][\da-fA-F]+|0[oO][0-7]+|0[bB][01]+|(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?)|((?!\d)(?:(?!\s)[$\w\u0080-\uFFFF]|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+)|(--|\+\+|&&|\|\||=>|\.{3}|(?:[+\-\/%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2})=?|[?~.,:;[\](){}])|(\s+)|(^$|[\s\S])/g;
|
|
|
|
jsTokens.matchToToken = function(match) {
|
|
var token = {type: "invalid", value: match[0], closed: undefined};
|
|
if (match[ 1]) token.type = "string" , token.closed = !!(match[3] || match[4]);
|
|
else if (match[ 5]) token.type = "comment";
|
|
else if (match[ 6]) token.type = "comment", token.closed = !!match[7];
|
|
else if (match[ 8]) token.type = "regex";
|
|
else if (match[ 9]) token.type = "number";
|
|
else if (match[10]) token.type = "name";
|
|
else if (match[11]) token.type = "punctuator";
|
|
else if (match[12]) token.type = "whitespace";
|
|
return token
|
|
};
|
|
return jsTokens;
|
|
}
|
|
|
|
var hasRequiredLib;
|
|
|
|
function requireLib () {
|
|
if (hasRequiredLib) return lib;
|
|
hasRequiredLib = 1;
|
|
|
|
Object.defineProperty(lib, '__esModule', { value: true });
|
|
|
|
var picocolors = requirePicocolors();
|
|
var jsTokens = requireJsTokens();
|
|
var helperValidatorIdentifier = requireLib$3();
|
|
|
|
function isColorSupported() {
|
|
return (typeof process === "object" && (process.env.FORCE_COLOR === "0" || process.env.FORCE_COLOR === "false") ? false : picocolors.isColorSupported
|
|
);
|
|
}
|
|
const compose = (f, g) => v => f(g(v));
|
|
function buildDefs(colors) {
|
|
return {
|
|
keyword: colors.cyan,
|
|
capitalized: colors.yellow,
|
|
jsxIdentifier: colors.yellow,
|
|
punctuator: colors.yellow,
|
|
number: colors.magenta,
|
|
string: colors.green,
|
|
regex: colors.magenta,
|
|
comment: colors.gray,
|
|
invalid: compose(compose(colors.white, colors.bgRed), colors.bold),
|
|
gutter: colors.gray,
|
|
marker: compose(colors.red, colors.bold),
|
|
message: compose(colors.red, colors.bold),
|
|
reset: colors.reset
|
|
};
|
|
}
|
|
const defsOn = buildDefs(picocolors.createColors(true));
|
|
const defsOff = buildDefs(picocolors.createColors(false));
|
|
function getDefs(enabled) {
|
|
return enabled ? defsOn : defsOff;
|
|
}
|
|
|
|
const sometimesKeywords = new Set(["as", "async", "from", "get", "of", "set"]);
|
|
const NEWLINE$1 = /\r\n|[\n\r\u2028\u2029]/;
|
|
const BRACKET = /^[()[\]{}]$/;
|
|
let tokenize;
|
|
{
|
|
const JSX_TAG = /^[a-z][\w-]*$/i;
|
|
const getTokenType = function (token, offset, text) {
|
|
if (token.type === "name") {
|
|
if (helperValidatorIdentifier.isKeyword(token.value) || helperValidatorIdentifier.isStrictReservedWord(token.value, true) || sometimesKeywords.has(token.value)) {
|
|
return "keyword";
|
|
}
|
|
if (JSX_TAG.test(token.value) && (text[offset - 1] === "<" || text.slice(offset - 2, offset) === "</")) {
|
|
return "jsxIdentifier";
|
|
}
|
|
if (token.value[0] !== token.value[0].toLowerCase()) {
|
|
return "capitalized";
|
|
}
|
|
}
|
|
if (token.type === "punctuator" && BRACKET.test(token.value)) {
|
|
return "bracket";
|
|
}
|
|
if (token.type === "invalid" && (token.value === "@" || token.value === "#")) {
|
|
return "punctuator";
|
|
}
|
|
return token.type;
|
|
};
|
|
tokenize = function* (text) {
|
|
let match;
|
|
while (match = jsTokens.default.exec(text)) {
|
|
const token = jsTokens.matchToToken(match);
|
|
yield {
|
|
type: getTokenType(token, match.index, text),
|
|
value: token.value
|
|
};
|
|
}
|
|
};
|
|
}
|
|
function highlight(text) {
|
|
if (text === "") return "";
|
|
const defs = getDefs(true);
|
|
let highlighted = "";
|
|
for (const {
|
|
type,
|
|
value
|
|
} of tokenize(text)) {
|
|
if (type in defs) {
|
|
highlighted += value.split(NEWLINE$1).map(str => defs[type](str)).join("\n");
|
|
} else {
|
|
highlighted += value;
|
|
}
|
|
}
|
|
return highlighted;
|
|
}
|
|
|
|
let deprecationWarningShown = false;
|
|
const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
|
|
function getMarkerLines(loc, source, opts) {
|
|
const startLoc = Object.assign({
|
|
column: 0,
|
|
line: -1
|
|
}, loc.start);
|
|
const endLoc = Object.assign({}, startLoc, loc.end);
|
|
const {
|
|
linesAbove = 2,
|
|
linesBelow = 3
|
|
} = opts || {};
|
|
const startLine = startLoc.line;
|
|
const startColumn = startLoc.column;
|
|
const endLine = endLoc.line;
|
|
const endColumn = endLoc.column;
|
|
let start = Math.max(startLine - (linesAbove + 1), 0);
|
|
let end = Math.min(source.length, endLine + linesBelow);
|
|
if (startLine === -1) {
|
|
start = 0;
|
|
}
|
|
if (endLine === -1) {
|
|
end = source.length;
|
|
}
|
|
const lineDiff = endLine - startLine;
|
|
const markerLines = {};
|
|
if (lineDiff) {
|
|
for (let i = 0; i <= lineDiff; i++) {
|
|
const lineNumber = i + startLine;
|
|
if (!startColumn) {
|
|
markerLines[lineNumber] = true;
|
|
} else if (i === 0) {
|
|
const sourceLength = source[lineNumber - 1].length;
|
|
markerLines[lineNumber] = [startColumn, sourceLength - startColumn + 1];
|
|
} else if (i === lineDiff) {
|
|
markerLines[lineNumber] = [0, endColumn];
|
|
} else {
|
|
const sourceLength = source[lineNumber - i].length;
|
|
markerLines[lineNumber] = [0, sourceLength];
|
|
}
|
|
}
|
|
} else {
|
|
if (startColumn === endColumn) {
|
|
if (startColumn) {
|
|
markerLines[startLine] = [startColumn, 0];
|
|
} else {
|
|
markerLines[startLine] = true;
|
|
}
|
|
} else {
|
|
markerLines[startLine] = [startColumn, endColumn - startColumn];
|
|
}
|
|
}
|
|
return {
|
|
start,
|
|
end,
|
|
markerLines
|
|
};
|
|
}
|
|
function codeFrameColumns(rawLines, loc, opts = {}) {
|
|
const shouldHighlight = opts.forceColor || isColorSupported() && opts.highlightCode;
|
|
const defs = getDefs(shouldHighlight);
|
|
const lines = rawLines.split(NEWLINE);
|
|
const {
|
|
start,
|
|
end,
|
|
markerLines
|
|
} = getMarkerLines(loc, lines, opts);
|
|
const hasColumns = loc.start && typeof loc.start.column === "number";
|
|
const numberMaxWidth = String(end).length;
|
|
const highlightedLines = shouldHighlight ? highlight(rawLines) : rawLines;
|
|
let frame = highlightedLines.split(NEWLINE, end).slice(start, end).map((line, index) => {
|
|
const number = start + 1 + index;
|
|
const paddedNumber = ` ${number}`.slice(-numberMaxWidth);
|
|
const gutter = ` ${paddedNumber} |`;
|
|
const hasMarker = markerLines[number];
|
|
const lastMarkerLine = !markerLines[number + 1];
|
|
if (hasMarker) {
|
|
let markerLine = "";
|
|
if (Array.isArray(hasMarker)) {
|
|
const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, " ");
|
|
const numberOfMarkers = hasMarker[1] || 1;
|
|
markerLine = ["\n ", defs.gutter(gutter.replace(/\d/g, " ")), " ", markerSpacing, defs.marker("^").repeat(numberOfMarkers)].join("");
|
|
if (lastMarkerLine && opts.message) {
|
|
markerLine += " " + defs.message(opts.message);
|
|
}
|
|
}
|
|
return [defs.marker(">"), defs.gutter(gutter), line.length > 0 ? ` ${line}` : "", markerLine].join("");
|
|
} else {
|
|
return ` ${defs.gutter(gutter)}${line.length > 0 ? ` ${line}` : ""}`;
|
|
}
|
|
}).join("\n");
|
|
if (opts.message && !hasColumns) {
|
|
frame = `${" ".repeat(numberMaxWidth + 1)}${opts.message}\n${frame}`;
|
|
}
|
|
if (shouldHighlight) {
|
|
return defs.reset(frame);
|
|
} else {
|
|
return frame;
|
|
}
|
|
}
|
|
function index (rawLines, lineNumber, colNumber, opts = {}) {
|
|
if (!deprecationWarningShown) {
|
|
deprecationWarningShown = true;
|
|
const message = "Passing lineNumber and colNumber is deprecated to @babel/code-frame. Please use `codeFrameColumns`.";
|
|
if (process.emitWarning) {
|
|
process.emitWarning(message, "DeprecationWarning");
|
|
} else {
|
|
const deprecationError = new Error(message);
|
|
deprecationError.name = "DeprecationWarning";
|
|
console.warn(new Error(message));
|
|
}
|
|
}
|
|
colNumber = Math.max(colNumber, 0);
|
|
const location = {
|
|
start: {
|
|
column: colNumber,
|
|
line: lineNumber
|
|
}
|
|
};
|
|
return codeFrameColumns(rawLines, location, opts);
|
|
}
|
|
|
|
lib.codeFrameColumns = codeFrameColumns;
|
|
lib.default = index;
|
|
lib.highlight = highlight;
|
|
|
|
return lib;
|
|
}
|
|
|
|
var libExports = requireLib();
|
|
|
|
/*! *****************************************************************************
|
|
Copyright (c) Microsoft Corporation.
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
***************************************************************************** */
|
|
/* global Reflect, Promise */
|
|
|
|
|
|
function __classPrivateFieldGet(receiver, state, kind, f) {
|
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
}
|
|
|
|
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
}
|
|
|
|
var _OkImpl_val, _ErrImpl_val;
|
|
function Ok(val) {
|
|
return new OkImpl(val);
|
|
}
|
|
class OkImpl {
|
|
constructor(val) {
|
|
_OkImpl_val.set(this, void 0);
|
|
__classPrivateFieldSet(this, _OkImpl_val, val, "f");
|
|
}
|
|
map(fn) {
|
|
return new OkImpl(fn(__classPrivateFieldGet(this, _OkImpl_val, "f")));
|
|
}
|
|
mapErr(_fn) {
|
|
return this;
|
|
}
|
|
mapOr(_fallback, fn) {
|
|
return fn(__classPrivateFieldGet(this, _OkImpl_val, "f"));
|
|
}
|
|
mapOrElse(_fallback, fn) {
|
|
return fn(__classPrivateFieldGet(this, _OkImpl_val, "f"));
|
|
}
|
|
andThen(fn) {
|
|
return fn(__classPrivateFieldGet(this, _OkImpl_val, "f"));
|
|
}
|
|
and(res) {
|
|
return res;
|
|
}
|
|
or(_res) {
|
|
return this;
|
|
}
|
|
orElse(_fn) {
|
|
return this;
|
|
}
|
|
isOk() {
|
|
return true;
|
|
}
|
|
isErr() {
|
|
return false;
|
|
}
|
|
expect(_msg) {
|
|
return __classPrivateFieldGet(this, _OkImpl_val, "f");
|
|
}
|
|
expectErr(msg) {
|
|
throw new Error(`${msg}: ${__classPrivateFieldGet(this, _OkImpl_val, "f")}`);
|
|
}
|
|
unwrap() {
|
|
return __classPrivateFieldGet(this, _OkImpl_val, "f");
|
|
}
|
|
unwrapOr(_fallback) {
|
|
return __classPrivateFieldGet(this, _OkImpl_val, "f");
|
|
}
|
|
unwrapOrElse(_fallback) {
|
|
return __classPrivateFieldGet(this, _OkImpl_val, "f");
|
|
}
|
|
unwrapErr() {
|
|
if (__classPrivateFieldGet(this, _OkImpl_val, "f") instanceof Error) {
|
|
throw __classPrivateFieldGet(this, _OkImpl_val, "f");
|
|
}
|
|
throw new Error(`Can't unwrap \`Ok\` to \`Err\`: ${__classPrivateFieldGet(this, _OkImpl_val, "f")}`);
|
|
}
|
|
}
|
|
_OkImpl_val = new WeakMap();
|
|
function Err(val) {
|
|
return new ErrImpl(val);
|
|
}
|
|
class ErrImpl {
|
|
constructor(val) {
|
|
_ErrImpl_val.set(this, void 0);
|
|
__classPrivateFieldSet(this, _ErrImpl_val, val, "f");
|
|
}
|
|
map(_fn) {
|
|
return this;
|
|
}
|
|
mapErr(fn) {
|
|
return new ErrImpl(fn(__classPrivateFieldGet(this, _ErrImpl_val, "f")));
|
|
}
|
|
mapOr(fallback, _fn) {
|
|
return fallback;
|
|
}
|
|
mapOrElse(fallback, _fn) {
|
|
return fallback();
|
|
}
|
|
andThen(_fn) {
|
|
return this;
|
|
}
|
|
and(_res) {
|
|
return this;
|
|
}
|
|
or(res) {
|
|
return res;
|
|
}
|
|
orElse(fn) {
|
|
return fn(__classPrivateFieldGet(this, _ErrImpl_val, "f"));
|
|
}
|
|
isOk() {
|
|
return false;
|
|
}
|
|
isErr() {
|
|
return true;
|
|
}
|
|
expect(msg) {
|
|
throw new Error(`${msg}: ${__classPrivateFieldGet(this, _ErrImpl_val, "f")}`);
|
|
}
|
|
expectErr(_msg) {
|
|
return __classPrivateFieldGet(this, _ErrImpl_val, "f");
|
|
}
|
|
unwrap() {
|
|
if (__classPrivateFieldGet(this, _ErrImpl_val, "f") instanceof Error) {
|
|
throw __classPrivateFieldGet(this, _ErrImpl_val, "f");
|
|
}
|
|
throw new Error(`Can't unwrap \`Err\` to \`Ok\`: ${__classPrivateFieldGet(this, _ErrImpl_val, "f")}`);
|
|
}
|
|
unwrapOr(fallback) {
|
|
return fallback;
|
|
}
|
|
unwrapOrElse(fallback) {
|
|
return fallback(__classPrivateFieldGet(this, _ErrImpl_val, "f"));
|
|
}
|
|
unwrapErr() {
|
|
return __classPrivateFieldGet(this, _ErrImpl_val, "f");
|
|
}
|
|
}
|
|
_ErrImpl_val = new WeakMap();
|
|
|
|
function assertExhaustive$1(_, errorMsg) {
|
|
throw new Error(errorMsg);
|
|
}
|
|
function retainWhere(array, predicate) {
|
|
let writeIndex = 0;
|
|
for (let readIndex = 0; readIndex < array.length; readIndex++) {
|
|
const item = array[readIndex];
|
|
if (predicate(item, readIndex) === true) {
|
|
array[writeIndex++] = item;
|
|
}
|
|
}
|
|
array.length = writeIndex;
|
|
}
|
|
function retainWhere_Set(items, predicate) {
|
|
for (const item of items) {
|
|
if (!predicate(item)) {
|
|
items.delete(item);
|
|
}
|
|
}
|
|
}
|
|
function getOrInsertWith(m, key, makeDefault) {
|
|
if (m.has(key)) {
|
|
return m.get(key);
|
|
}
|
|
else {
|
|
const defaultValue = makeDefault();
|
|
m.set(key, defaultValue);
|
|
return defaultValue;
|
|
}
|
|
}
|
|
function getOrInsertDefault(m, key, defaultValue) {
|
|
if (m.has(key)) {
|
|
return m.get(key);
|
|
}
|
|
else {
|
|
m.set(key, defaultValue);
|
|
return defaultValue;
|
|
}
|
|
}
|
|
function Set_equal(a, b) {
|
|
if (a.size !== b.size) {
|
|
return false;
|
|
}
|
|
for (const item of a) {
|
|
if (!b.has(item)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function Set_union(a, b) {
|
|
const union = new Set(a);
|
|
for (const item of b) {
|
|
union.add(item);
|
|
}
|
|
return union;
|
|
}
|
|
function Set_intersect(sets) {
|
|
if (sets.length === 0 || sets.some(s => s.size === 0)) {
|
|
return new Set();
|
|
}
|
|
else if (sets.length === 1) {
|
|
return new Set(sets[0]);
|
|
}
|
|
const result = new Set();
|
|
const first = sets[0];
|
|
outer: for (const e of first) {
|
|
for (let i = 1; i < sets.length; i++) {
|
|
if (!sets[i].has(e)) {
|
|
continue outer;
|
|
}
|
|
}
|
|
result.add(e);
|
|
}
|
|
return result;
|
|
}
|
|
function Set_isSuperset(a, b) {
|
|
for (const v of b) {
|
|
if (!a.has(v)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function Iterable_some(iter, pred) {
|
|
for (const item of iter) {
|
|
if (pred(item)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function Set_filter(source, fn) {
|
|
const result = new Set();
|
|
for (const entry of source) {
|
|
if (fn(entry)) {
|
|
result.add(entry);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function hasNode(input) {
|
|
return input.node != null;
|
|
}
|
|
function hasOwnProperty$1(obj, key) {
|
|
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
}
|
|
|
|
const CODEFRAME_LINES_ABOVE = 2;
|
|
const CODEFRAME_LINES_BELOW = 3;
|
|
const CODEFRAME_MAX_LINES = 10;
|
|
const CODEFRAME_ABBREVIATED_SOURCE_LINES = 5;
|
|
var ErrorSeverity;
|
|
(function (ErrorSeverity) {
|
|
ErrorSeverity["Error"] = "Error";
|
|
ErrorSeverity["Warning"] = "Warning";
|
|
ErrorSeverity["Hint"] = "Hint";
|
|
ErrorSeverity["Off"] = "Off";
|
|
})(ErrorSeverity || (ErrorSeverity = {}));
|
|
var CompilerSuggestionOperation;
|
|
(function (CompilerSuggestionOperation) {
|
|
CompilerSuggestionOperation[CompilerSuggestionOperation["InsertBefore"] = 0] = "InsertBefore";
|
|
CompilerSuggestionOperation[CompilerSuggestionOperation["InsertAfter"] = 1] = "InsertAfter";
|
|
CompilerSuggestionOperation[CompilerSuggestionOperation["Remove"] = 2] = "Remove";
|
|
CompilerSuggestionOperation[CompilerSuggestionOperation["Replace"] = 3] = "Replace";
|
|
})(CompilerSuggestionOperation || (CompilerSuggestionOperation = {}));
|
|
class CompilerDiagnostic {
|
|
constructor(options) {
|
|
this.options = options;
|
|
}
|
|
static create(options) {
|
|
return new CompilerDiagnostic(Object.assign(Object.assign({}, options), { details: [] }));
|
|
}
|
|
get reason() {
|
|
return this.options.reason;
|
|
}
|
|
get description() {
|
|
return this.options.description;
|
|
}
|
|
get severity() {
|
|
return getRuleForCategory(this.category).severity;
|
|
}
|
|
get suggestions() {
|
|
return this.options.suggestions;
|
|
}
|
|
get category() {
|
|
return this.options.category;
|
|
}
|
|
withDetails(...details) {
|
|
this.options.details.push(...details);
|
|
return this;
|
|
}
|
|
primaryLocation() {
|
|
const firstErrorDetail = this.options.details.filter(d => d.kind === 'error')[0];
|
|
return firstErrorDetail != null && firstErrorDetail.kind === 'error'
|
|
? firstErrorDetail.loc
|
|
: null;
|
|
}
|
|
printErrorMessage(source, options) {
|
|
var _a, _b;
|
|
const buffer = [printErrorSummary(this.category, this.reason)];
|
|
if (this.description != null) {
|
|
buffer.push('\n\n', `${this.description}.`);
|
|
}
|
|
for (const detail of this.options.details) {
|
|
switch (detail.kind) {
|
|
case 'error': {
|
|
const loc = detail.loc;
|
|
if (loc == null || typeof loc === 'symbol') {
|
|
continue;
|
|
}
|
|
let codeFrame;
|
|
try {
|
|
codeFrame = printCodeFrame(source, loc, (_a = detail.message) !== null && _a !== void 0 ? _a : '');
|
|
}
|
|
catch (e) {
|
|
codeFrame = (_b = detail.message) !== null && _b !== void 0 ? _b : '';
|
|
}
|
|
buffer.push('\n\n');
|
|
if (loc.filename != null) {
|
|
const line = loc.start.line;
|
|
const column = options.eslint
|
|
? loc.start.column + 1
|
|
: loc.start.column;
|
|
buffer.push(`${loc.filename}:${line}:${column}\n`);
|
|
}
|
|
buffer.push(codeFrame);
|
|
break;
|
|
}
|
|
case 'hint': {
|
|
buffer.push('\n\n');
|
|
buffer.push(detail.message);
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(detail, `Unexpected detail kind ${detail.kind}`);
|
|
}
|
|
}
|
|
}
|
|
return buffer.join('');
|
|
}
|
|
toString() {
|
|
const buffer = [printErrorSummary(this.category, this.reason)];
|
|
if (this.description != null) {
|
|
buffer.push(`. ${this.description}.`);
|
|
}
|
|
const loc = this.primaryLocation();
|
|
if (loc != null && typeof loc !== 'symbol') {
|
|
buffer.push(` (${loc.start.line}:${loc.start.column})`);
|
|
}
|
|
return buffer.join('');
|
|
}
|
|
}
|
|
class CompilerErrorDetail {
|
|
constructor(options) {
|
|
this.options = options;
|
|
}
|
|
get reason() {
|
|
return this.options.reason;
|
|
}
|
|
get description() {
|
|
return this.options.description;
|
|
}
|
|
get severity() {
|
|
return getRuleForCategory(this.category).severity;
|
|
}
|
|
get loc() {
|
|
return this.options.loc;
|
|
}
|
|
get suggestions() {
|
|
return this.options.suggestions;
|
|
}
|
|
get category() {
|
|
return this.options.category;
|
|
}
|
|
primaryLocation() {
|
|
return this.loc;
|
|
}
|
|
printErrorMessage(source, options) {
|
|
const buffer = [printErrorSummary(this.category, this.reason)];
|
|
if (this.description != null) {
|
|
buffer.push(`\n\n${this.description}.`);
|
|
}
|
|
const loc = this.loc;
|
|
if (loc != null && typeof loc !== 'symbol') {
|
|
let codeFrame;
|
|
try {
|
|
codeFrame = printCodeFrame(source, loc, this.reason);
|
|
}
|
|
catch (e) {
|
|
codeFrame = '';
|
|
}
|
|
buffer.push(`\n\n`);
|
|
if (loc.filename != null) {
|
|
const line = loc.start.line;
|
|
const column = options.eslint ? loc.start.column + 1 : loc.start.column;
|
|
buffer.push(`${loc.filename}:${line}:${column}\n`);
|
|
}
|
|
buffer.push(codeFrame);
|
|
buffer.push('\n\n');
|
|
}
|
|
return buffer.join('');
|
|
}
|
|
toString() {
|
|
const buffer = [printErrorSummary(this.category, this.reason)];
|
|
if (this.description != null) {
|
|
buffer.push(`. ${this.description}.`);
|
|
}
|
|
const loc = this.loc;
|
|
if (loc != null && typeof loc !== 'symbol') {
|
|
buffer.push(` (${loc.start.line}:${loc.start.column})`);
|
|
}
|
|
return buffer.join('');
|
|
}
|
|
}
|
|
class CompilerError extends Error {
|
|
static invariant(condition, options) {
|
|
var _a, _b;
|
|
if (!condition) {
|
|
const errors = new CompilerError();
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
reason: options.reason,
|
|
description: (_a = options.description) !== null && _a !== void 0 ? _a : null,
|
|
category: ErrorCategory.Invariant,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: options.loc,
|
|
message: (_b = options.message) !== null && _b !== void 0 ? _b : options.reason,
|
|
}));
|
|
throw errors;
|
|
}
|
|
}
|
|
static throwDiagnostic(options) {
|
|
const errors = new CompilerError();
|
|
errors.pushDiagnostic(new CompilerDiagnostic(options));
|
|
throw errors;
|
|
}
|
|
static throwTodo(options) {
|
|
const errors = new CompilerError();
|
|
errors.pushErrorDetail(new CompilerErrorDetail(Object.assign(Object.assign({}, options), { category: ErrorCategory.Todo })));
|
|
throw errors;
|
|
}
|
|
static throwInvalidJS(options) {
|
|
const errors = new CompilerError();
|
|
errors.pushErrorDetail(new CompilerErrorDetail(Object.assign(Object.assign({}, options), { category: ErrorCategory.Syntax })));
|
|
throw errors;
|
|
}
|
|
static throwInvalidReact(options) {
|
|
const errors = new CompilerError();
|
|
errors.pushErrorDetail(new CompilerErrorDetail(options));
|
|
throw errors;
|
|
}
|
|
static throwInvalidConfig(options) {
|
|
const errors = new CompilerError();
|
|
errors.pushErrorDetail(new CompilerErrorDetail(Object.assign(Object.assign({}, options), { category: ErrorCategory.Config })));
|
|
throw errors;
|
|
}
|
|
static throw(options) {
|
|
const errors = new CompilerError();
|
|
errors.pushErrorDetail(new CompilerErrorDetail(options));
|
|
throw errors;
|
|
}
|
|
constructor(...args) {
|
|
super(...args);
|
|
this.details = [];
|
|
this.disabledDetails = [];
|
|
this.printedMessage = null;
|
|
this.name = 'ReactCompilerError';
|
|
this.details = [];
|
|
this.disabledDetails = [];
|
|
}
|
|
get message() {
|
|
var _a;
|
|
return (_a = this.printedMessage) !== null && _a !== void 0 ? _a : this.toString();
|
|
}
|
|
set message(_message) { }
|
|
toString() {
|
|
if (this.printedMessage) {
|
|
return this.printedMessage;
|
|
}
|
|
if (Array.isArray(this.details)) {
|
|
return this.details.map(detail => detail.toString()).join('\n\n');
|
|
}
|
|
return this.name;
|
|
}
|
|
withPrintedMessage(source, options) {
|
|
this.printedMessage = this.printErrorMessage(source, options);
|
|
return this;
|
|
}
|
|
printErrorMessage(source, options) {
|
|
if (options.eslint && this.details.length === 1) {
|
|
return this.details[0].printErrorMessage(source, options);
|
|
}
|
|
return (`Found ${this.details.length} error${this.details.length === 1 ? '' : 's'}:\n\n` +
|
|
this.details
|
|
.map(detail => detail.printErrorMessage(source, options).trim())
|
|
.join('\n\n'));
|
|
}
|
|
merge(other) {
|
|
this.details.push(...other.details);
|
|
this.disabledDetails.push(...other.disabledDetails);
|
|
}
|
|
pushDiagnostic(diagnostic) {
|
|
if (diagnostic.severity === ErrorSeverity.Off) {
|
|
this.disabledDetails.push(diagnostic);
|
|
}
|
|
else {
|
|
this.details.push(diagnostic);
|
|
}
|
|
}
|
|
push(options) {
|
|
var _a;
|
|
const detail = new CompilerErrorDetail({
|
|
category: options.category,
|
|
reason: options.reason,
|
|
description: (_a = options.description) !== null && _a !== void 0 ? _a : null,
|
|
suggestions: options.suggestions,
|
|
loc: typeof options.loc === 'symbol' ? null : options.loc,
|
|
});
|
|
return this.pushErrorDetail(detail);
|
|
}
|
|
pushErrorDetail(detail) {
|
|
if (detail.severity === ErrorSeverity.Off) {
|
|
this.disabledDetails.push(detail);
|
|
}
|
|
else {
|
|
this.details.push(detail);
|
|
}
|
|
return detail;
|
|
}
|
|
hasAnyErrors() {
|
|
return this.details.length > 0;
|
|
}
|
|
asResult() {
|
|
return this.hasAnyErrors() ? Err(this) : Ok(undefined);
|
|
}
|
|
hasErrors() {
|
|
for (const detail of this.details) {
|
|
if (detail.severity === ErrorSeverity.Error) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
hasWarning() {
|
|
let res = false;
|
|
for (const detail of this.details) {
|
|
if (detail.severity === ErrorSeverity.Error) {
|
|
return false;
|
|
}
|
|
if (detail.severity === ErrorSeverity.Warning) {
|
|
res = true;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
hasHints() {
|
|
let res = false;
|
|
for (const detail of this.details) {
|
|
if (detail.severity === ErrorSeverity.Error) {
|
|
return false;
|
|
}
|
|
if (detail.severity === ErrorSeverity.Warning) {
|
|
return false;
|
|
}
|
|
if (detail.severity === ErrorSeverity.Hint) {
|
|
res = true;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
}
|
|
function printCodeFrame(source, loc, message) {
|
|
const printed = libExports.codeFrameColumns(source, {
|
|
start: {
|
|
line: loc.start.line,
|
|
column: loc.start.column + 1,
|
|
},
|
|
end: {
|
|
line: loc.end.line,
|
|
column: loc.end.column + 1,
|
|
},
|
|
}, {
|
|
message,
|
|
linesAbove: CODEFRAME_LINES_ABOVE,
|
|
linesBelow: CODEFRAME_LINES_BELOW,
|
|
});
|
|
const lines = printed.split(/\r?\n/);
|
|
if (loc.end.line - loc.start.line < CODEFRAME_MAX_LINES) {
|
|
return printed;
|
|
}
|
|
const pipeIndex = lines[0].indexOf('|');
|
|
return [
|
|
...lines.slice(0, CODEFRAME_LINES_ABOVE + CODEFRAME_ABBREVIATED_SOURCE_LINES),
|
|
' '.repeat(pipeIndex) + '…',
|
|
...lines.slice(-(CODEFRAME_LINES_BELOW + CODEFRAME_ABBREVIATED_SOURCE_LINES)),
|
|
].join('\n');
|
|
}
|
|
function printErrorSummary(category, message) {
|
|
let heading;
|
|
switch (category) {
|
|
case ErrorCategory.CapitalizedCalls:
|
|
case ErrorCategory.Config:
|
|
case ErrorCategory.EffectDerivationsOfState:
|
|
case ErrorCategory.EffectSetState:
|
|
case ErrorCategory.ErrorBoundaries:
|
|
case ErrorCategory.FBT:
|
|
case ErrorCategory.Gating:
|
|
case ErrorCategory.Globals:
|
|
case ErrorCategory.Hooks:
|
|
case ErrorCategory.Immutability:
|
|
case ErrorCategory.Purity:
|
|
case ErrorCategory.Refs:
|
|
case ErrorCategory.RenderSetState:
|
|
case ErrorCategory.StaticComponents:
|
|
case ErrorCategory.Suppression:
|
|
case ErrorCategory.Syntax:
|
|
case ErrorCategory.UseMemo:
|
|
case ErrorCategory.VoidUseMemo:
|
|
case ErrorCategory.MemoDependencies:
|
|
case ErrorCategory.EffectExhaustiveDependencies: {
|
|
heading = 'Error';
|
|
break;
|
|
}
|
|
case ErrorCategory.EffectDependencies:
|
|
case ErrorCategory.IncompatibleLibrary:
|
|
case ErrorCategory.PreserveManualMemo:
|
|
case ErrorCategory.UnsupportedSyntax: {
|
|
heading = 'Compilation Skipped';
|
|
break;
|
|
}
|
|
case ErrorCategory.Invariant: {
|
|
heading = 'Invariant';
|
|
break;
|
|
}
|
|
case ErrorCategory.Todo: {
|
|
heading = 'Todo';
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(category, `Unhandled category '${category}'`);
|
|
}
|
|
}
|
|
return `${heading}: ${message}`;
|
|
}
|
|
var ErrorCategory;
|
|
(function (ErrorCategory) {
|
|
ErrorCategory["Hooks"] = "Hooks";
|
|
ErrorCategory["CapitalizedCalls"] = "CapitalizedCalls";
|
|
ErrorCategory["StaticComponents"] = "StaticComponents";
|
|
ErrorCategory["UseMemo"] = "UseMemo";
|
|
ErrorCategory["VoidUseMemo"] = "VoidUseMemo";
|
|
ErrorCategory["PreserveManualMemo"] = "PreserveManualMemo";
|
|
ErrorCategory["MemoDependencies"] = "MemoDependencies";
|
|
ErrorCategory["IncompatibleLibrary"] = "IncompatibleLibrary";
|
|
ErrorCategory["Immutability"] = "Immutability";
|
|
ErrorCategory["Globals"] = "Globals";
|
|
ErrorCategory["Refs"] = "Refs";
|
|
ErrorCategory["EffectDependencies"] = "EffectDependencies";
|
|
ErrorCategory["EffectExhaustiveDependencies"] = "EffectExhaustiveDependencies";
|
|
ErrorCategory["EffectSetState"] = "EffectSetState";
|
|
ErrorCategory["EffectDerivationsOfState"] = "EffectDerivationsOfState";
|
|
ErrorCategory["ErrorBoundaries"] = "ErrorBoundaries";
|
|
ErrorCategory["Purity"] = "Purity";
|
|
ErrorCategory["RenderSetState"] = "RenderSetState";
|
|
ErrorCategory["Invariant"] = "Invariant";
|
|
ErrorCategory["Todo"] = "Todo";
|
|
ErrorCategory["Syntax"] = "Syntax";
|
|
ErrorCategory["UnsupportedSyntax"] = "UnsupportedSyntax";
|
|
ErrorCategory["Config"] = "Config";
|
|
ErrorCategory["Gating"] = "Gating";
|
|
ErrorCategory["Suppression"] = "Suppression";
|
|
ErrorCategory["FBT"] = "FBT";
|
|
})(ErrorCategory || (ErrorCategory = {}));
|
|
var LintRulePreset;
|
|
(function (LintRulePreset) {
|
|
LintRulePreset["Recommended"] = "recommended";
|
|
LintRulePreset["RecommendedLatest"] = "recommended-latest";
|
|
LintRulePreset["Off"] = "off";
|
|
})(LintRulePreset || (LintRulePreset = {}));
|
|
const RULE_NAME_PATTERN = /^[a-z]+(-[a-z]+)*$/;
|
|
function getRuleForCategory(category) {
|
|
const rule = getRuleForCategoryImpl(category);
|
|
invariant(RULE_NAME_PATTERN.test(rule.name), `Invalid rule name, got '${rule.name}' but rules must match ${RULE_NAME_PATTERN.toString()}`);
|
|
return rule;
|
|
}
|
|
function getRuleForCategoryImpl(category) {
|
|
switch (category) {
|
|
case ErrorCategory.CapitalizedCalls: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'capitalized-calls',
|
|
description: 'Validates against calling capitalized functions/methods instead of using JSX',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.Config: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'config',
|
|
description: 'Validates the compiler configuration options',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.EffectDependencies: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'memoized-effect-dependencies',
|
|
description: 'Validates that effect dependencies are memoized',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.EffectExhaustiveDependencies: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'exhaustive-effect-dependencies',
|
|
description: 'Validates that effect dependencies are exhaustive and without extraneous values',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.EffectDerivationsOfState: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'no-deriving-state-in-effects',
|
|
description: 'Validates against deriving values from state in an effect',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.EffectSetState: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'set-state-in-effect',
|
|
description: 'Validates against calling setState synchronously in an effect. ' +
|
|
'This can indicate non-local derived data, a derived event pattern, or ' +
|
|
'improper external data synchronization.',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.ErrorBoundaries: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'error-boundaries',
|
|
description: 'Validates usage of error boundaries instead of try/catch for errors in child components',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.FBT: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'fbt',
|
|
description: 'Validates usage of fbt',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.Gating: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'gating',
|
|
description: 'Validates configuration of [gating mode](https://react.dev/reference/react-compiler/gating)',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.Globals: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'globals',
|
|
description: 'Validates against assignment/mutation of globals during render, part of ensuring that ' +
|
|
'[side effects must render outside of render](https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.Hooks: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'hooks',
|
|
description: 'Validates the rules of hooks',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.Immutability: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'immutability',
|
|
description: 'Validates against mutating props, state, and other values that [are immutable](https://react.dev/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable)',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.Invariant: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'invariant',
|
|
description: 'Internal invariants',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.PreserveManualMemo: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'preserve-manual-memoization',
|
|
description: 'Validates that existing manual memoized is preserved by the compiler. ' +
|
|
'React Compiler will only compile components and hooks if its inference ' +
|
|
'[matches or exceeds the existing manual memoization](https://react.dev/learn/react-compiler/introduction#what-should-i-do-about-usememo-usecallback-and-reactmemo)',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.Purity: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'purity',
|
|
description: 'Validates that [components/hooks are pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure) by checking that they do not call known-impure functions',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.Refs: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'refs',
|
|
description: 'Validates correct usage of refs, not reading/writing during render. See the "pitfalls" section in [`useRef()` usage](https://react.dev/reference/react/useRef#usage)',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.RenderSetState: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'set-state-in-render',
|
|
description: 'Validates against setting state during render, which can trigger additional renders and potential infinite render loops',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.StaticComponents: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'static-components',
|
|
description: 'Validates that components are static, not recreated every render. Components that are recreated dynamically can reset state and trigger excessive re-rendering',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.Suppression: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'rule-suppression',
|
|
description: 'Validates against suppression of other rules',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.Syntax: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'syntax',
|
|
description: 'Validates against invalid syntax',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.Todo: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Hint,
|
|
name: 'todo',
|
|
description: 'Unimplemented features',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.UnsupportedSyntax: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Warning,
|
|
name: 'unsupported-syntax',
|
|
description: 'Validates against syntax that we do not plan to support in React Compiler',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.UseMemo: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'use-memo',
|
|
description: 'Validates usage of the useMemo() hook against common mistakes. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.VoidUseMemo: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'void-use-memo',
|
|
description: 'Validates that useMemos always return a value and that the result of the useMemo is used by the component/hook. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
|
|
preset: LintRulePreset.RecommendedLatest,
|
|
};
|
|
}
|
|
case ErrorCategory.MemoDependencies: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'memo-dependencies',
|
|
description: 'Validates that useMemo() and useCallback() specify comprehensive dependencies without extraneous values. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.IncompatibleLibrary: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Warning,
|
|
name: 'incompatible-library',
|
|
description: 'Validates against usage of libraries which are incompatible with memoization (manual or automatic)',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
default: {
|
|
assertExhaustive$1(category, `Unsupported category ${category}`);
|
|
}
|
|
}
|
|
}
|
|
const LintRules = Object.keys(ErrorCategory).map(category => getRuleForCategory(category));
|
|
|
|
function makeTypeId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected instruction id to be a non-negative integer',
|
|
loc: GeneratedSource,
|
|
});
|
|
return id;
|
|
}
|
|
let typeCounter = 0;
|
|
function makeType() {
|
|
return {
|
|
kind: 'Type',
|
|
id: makeTypeId(typeCounter++),
|
|
};
|
|
}
|
|
function typeEquals(tA, tB) {
|
|
if (tA.kind !== tB.kind)
|
|
return false;
|
|
return (typeVarEquals(tA, tB) ||
|
|
funcTypeEquals(tA, tB) ||
|
|
objectTypeEquals(tA, tB) ||
|
|
primitiveTypeEquals(tA, tB) ||
|
|
polyTypeEquals(tA, tB) ||
|
|
phiTypeEquals(tA, tB) ||
|
|
propTypeEquals(tA, tB) ||
|
|
objectMethodTypeEquals(tA, tB));
|
|
}
|
|
function typeVarEquals(tA, tB) {
|
|
if (tA.kind === 'Type' && tB.kind === 'Type') {
|
|
return tA.id === tB.id;
|
|
}
|
|
return false;
|
|
}
|
|
function typeKindCheck(tA, tb, type) {
|
|
return tA.kind === type && tb.kind === type;
|
|
}
|
|
function objectMethodTypeEquals(tA, tB) {
|
|
return typeKindCheck(tA, tB, 'ObjectMethod');
|
|
}
|
|
function propTypeEquals(tA, tB) {
|
|
if (tA.kind === 'Property' && tB.kind === 'Property') {
|
|
if (!typeEquals(tA.objectType, tB.objectType)) {
|
|
return false;
|
|
}
|
|
return (tA.propertyName === tB.propertyName && tA.objectName === tB.objectName);
|
|
}
|
|
return false;
|
|
}
|
|
function primitiveTypeEquals(tA, tB) {
|
|
return typeKindCheck(tA, tB, 'Primitive');
|
|
}
|
|
function polyTypeEquals(tA, tB) {
|
|
return typeKindCheck(tA, tB, 'Poly');
|
|
}
|
|
function objectTypeEquals(tA, tB) {
|
|
if (tA.kind === 'Object' && tB.kind == 'Object') {
|
|
return tA.shapeId === tB.shapeId;
|
|
}
|
|
return false;
|
|
}
|
|
function funcTypeEquals(tA, tB) {
|
|
if (tA.kind !== 'Function' || tB.kind !== 'Function') {
|
|
return false;
|
|
}
|
|
return typeEquals(tA.return, tB.return);
|
|
}
|
|
function phiTypeEquals(tA, tB) {
|
|
if (tA.kind === 'Phi' && tB.kind === 'Phi') {
|
|
if (tA.operands.length !== tB.operands.length) {
|
|
return false;
|
|
}
|
|
let operands = new Set(tA.operands);
|
|
for (let i = 0; i < tB.operands.length; i++) {
|
|
if (!operands.has(tB.operands[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const RESERVED_WORDS = new Set([
|
|
'break',
|
|
'case',
|
|
'catch',
|
|
'class',
|
|
'const',
|
|
'continue',
|
|
'debugger',
|
|
'default',
|
|
'delete',
|
|
'do',
|
|
'else',
|
|
'enum',
|
|
'export',
|
|
'extends',
|
|
'false',
|
|
'finally',
|
|
'for',
|
|
'function',
|
|
'if',
|
|
'import',
|
|
'in',
|
|
'instanceof',
|
|
'new',
|
|
'null',
|
|
'return',
|
|
'super',
|
|
'switch',
|
|
'this',
|
|
'throw',
|
|
'true',
|
|
'try',
|
|
'typeof',
|
|
'var',
|
|
'void',
|
|
'while',
|
|
'with',
|
|
]);
|
|
const STRICT_MODE_RESERVED_WORDS = new Set([
|
|
'let',
|
|
'static',
|
|
'implements',
|
|
'interface',
|
|
'package',
|
|
'private',
|
|
'protected',
|
|
'public',
|
|
]);
|
|
const STRICT_MODE_RESTRICTED_WORDS = new Set(['eval', 'arguments']);
|
|
function isReservedWord(identifierName) {
|
|
return (RESERVED_WORDS.has(identifierName) ||
|
|
STRICT_MODE_RESERVED_WORDS.has(identifierName) ||
|
|
STRICT_MODE_RESTRICTED_WORDS.has(identifierName));
|
|
}
|
|
|
|
const GeneratedSource = Symbol();
|
|
function isStatementBlockKind(kind) {
|
|
return kind === 'block' || kind === 'catch';
|
|
}
|
|
var GotoVariant;
|
|
(function (GotoVariant) {
|
|
GotoVariant["Break"] = "Break";
|
|
GotoVariant["Continue"] = "Continue";
|
|
GotoVariant["Try"] = "Try";
|
|
})(GotoVariant || (GotoVariant = {}));
|
|
var InstructionKind;
|
|
(function (InstructionKind) {
|
|
InstructionKind["Const"] = "Const";
|
|
InstructionKind["Let"] = "Let";
|
|
InstructionKind["Reassign"] = "Reassign";
|
|
InstructionKind["Catch"] = "Catch";
|
|
InstructionKind["HoistedConst"] = "HoistedConst";
|
|
InstructionKind["HoistedLet"] = "HoistedLet";
|
|
InstructionKind["HoistedFunction"] = "HoistedFunction";
|
|
InstructionKind["Function"] = "Function";
|
|
})(InstructionKind || (InstructionKind = {}));
|
|
function convertHoistedLValueKind(kind) {
|
|
switch (kind) {
|
|
case InstructionKind.HoistedLet:
|
|
return InstructionKind.Let;
|
|
case InstructionKind.HoistedConst:
|
|
return InstructionKind.Const;
|
|
case InstructionKind.HoistedFunction:
|
|
return InstructionKind.Function;
|
|
case InstructionKind.Let:
|
|
case InstructionKind.Const:
|
|
case InstructionKind.Function:
|
|
case InstructionKind.Reassign:
|
|
case InstructionKind.Catch:
|
|
return null;
|
|
default:
|
|
assertExhaustive$1(kind, 'Unexpected lvalue kind');
|
|
}
|
|
}
|
|
function makeTemporaryIdentifier(id, loc) {
|
|
return {
|
|
id,
|
|
name: null,
|
|
declarationId: makeDeclarationId(id),
|
|
mutableRange: { start: makeInstructionId(0), end: makeInstructionId(0) },
|
|
scope: null,
|
|
type: makeType(),
|
|
loc,
|
|
};
|
|
}
|
|
function validateIdentifierName(name) {
|
|
if (isReservedWord(name)) {
|
|
const error = new CompilerError();
|
|
error.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Syntax,
|
|
reason: 'Expected a non-reserved identifier name',
|
|
description: `\`${name}\` is a reserved word in JavaScript and cannot be used as an identifier name`,
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: 'reserved word',
|
|
}));
|
|
return Err(error);
|
|
}
|
|
else if (!libExports$1.isValidIdentifier(name)) {
|
|
const error = new CompilerError();
|
|
error.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Syntax,
|
|
reason: `Expected a valid identifier name`,
|
|
description: `\`${name}\` is not a valid JavaScript identifier`,
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: 'reserved word',
|
|
}));
|
|
}
|
|
return Ok({
|
|
kind: 'named',
|
|
value: name,
|
|
});
|
|
}
|
|
function makeIdentifierName(name) {
|
|
return validateIdentifierName(name).unwrap();
|
|
}
|
|
function promoteTemporary(identifier) {
|
|
CompilerError.invariant(identifier.name === null, {
|
|
reason: `Expected a temporary (unnamed) identifier`,
|
|
description: `Identifier already has a name, \`${identifier.name}\``,
|
|
loc: GeneratedSource,
|
|
});
|
|
identifier.name = {
|
|
kind: 'promoted',
|
|
value: `#t${identifier.declarationId}`,
|
|
};
|
|
}
|
|
function isPromotedTemporary(name) {
|
|
return name.startsWith('#t');
|
|
}
|
|
function promoteTemporaryJsxTag(identifier) {
|
|
CompilerError.invariant(identifier.name === null, {
|
|
reason: `Expected a temporary (unnamed) identifier`,
|
|
description: `Identifier already has a name, \`${identifier.name}\``,
|
|
loc: GeneratedSource,
|
|
});
|
|
identifier.name = {
|
|
kind: 'promoted',
|
|
value: `#T${identifier.declarationId}`,
|
|
};
|
|
}
|
|
function isPromotedJsxTemporary(name) {
|
|
return name.startsWith('#T');
|
|
}
|
|
var ValueReason;
|
|
(function (ValueReason) {
|
|
ValueReason["Global"] = "global";
|
|
ValueReason["JsxCaptured"] = "jsx-captured";
|
|
ValueReason["HookCaptured"] = "hook-captured";
|
|
ValueReason["HookReturn"] = "hook-return";
|
|
ValueReason["Effect"] = "effect";
|
|
ValueReason["KnownReturnSignature"] = "known-return-signature";
|
|
ValueReason["Context"] = "context";
|
|
ValueReason["State"] = "state";
|
|
ValueReason["ReducerState"] = "reducer-state";
|
|
ValueReason["ReactiveFunctionArgument"] = "reactive-function-argument";
|
|
ValueReason["Other"] = "other";
|
|
})(ValueReason || (ValueReason = {}));
|
|
var ValueKind;
|
|
(function (ValueKind) {
|
|
ValueKind["MaybeFrozen"] = "maybefrozen";
|
|
ValueKind["Frozen"] = "frozen";
|
|
ValueKind["Primitive"] = "primitive";
|
|
ValueKind["Global"] = "global";
|
|
ValueKind["Mutable"] = "mutable";
|
|
ValueKind["Context"] = "context";
|
|
})(ValueKind || (ValueKind = {}));
|
|
const ValueKindSchema = v4.z.enum([
|
|
ValueKind.MaybeFrozen,
|
|
ValueKind.Frozen,
|
|
ValueKind.Primitive,
|
|
ValueKind.Global,
|
|
ValueKind.Mutable,
|
|
ValueKind.Context,
|
|
]);
|
|
const ValueReasonSchema = v4.z.enum([
|
|
ValueReason.Context,
|
|
ValueReason.Effect,
|
|
ValueReason.Global,
|
|
ValueReason.HookCaptured,
|
|
ValueReason.HookReturn,
|
|
ValueReason.JsxCaptured,
|
|
ValueReason.KnownReturnSignature,
|
|
ValueReason.Other,
|
|
ValueReason.ReactiveFunctionArgument,
|
|
ValueReason.ReducerState,
|
|
ValueReason.State,
|
|
]);
|
|
var Effect;
|
|
(function (Effect) {
|
|
Effect["Unknown"] = "<unknown>";
|
|
Effect["Freeze"] = "freeze";
|
|
Effect["Read"] = "read";
|
|
Effect["Capture"] = "capture";
|
|
Effect["ConditionallyMutateIterator"] = "mutate-iterator?";
|
|
Effect["ConditionallyMutate"] = "mutate?";
|
|
Effect["Mutate"] = "mutate";
|
|
Effect["Store"] = "store";
|
|
})(Effect || (Effect = {}));
|
|
const EffectSchema = v4.z.enum([
|
|
Effect.Read,
|
|
Effect.Mutate,
|
|
Effect.ConditionallyMutate,
|
|
Effect.ConditionallyMutateIterator,
|
|
Effect.Capture,
|
|
Effect.Store,
|
|
Effect.Freeze,
|
|
]);
|
|
function isMutableEffect(effect, location) {
|
|
switch (effect) {
|
|
case Effect.Capture:
|
|
case Effect.Store:
|
|
case Effect.ConditionallyMutate:
|
|
case Effect.ConditionallyMutateIterator:
|
|
case Effect.Mutate: {
|
|
return true;
|
|
}
|
|
case Effect.Unknown: {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Unexpected unknown effect',
|
|
loc: location,
|
|
});
|
|
}
|
|
case Effect.Read:
|
|
case Effect.Freeze: {
|
|
return false;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(effect, `Unexpected effect \`${effect}\``);
|
|
}
|
|
}
|
|
}
|
|
function makePropertyLiteral(value) {
|
|
return value;
|
|
}
|
|
function areEqualPaths(a, b) {
|
|
return (a.length === b.length &&
|
|
a.every((item, ix) => item.property === b[ix].property && item.optional === b[ix].optional));
|
|
}
|
|
function isSubPath(subpath, path) {
|
|
return (subpath.length <= path.length &&
|
|
subpath.every((item, ix) => item.property === path[ix].property &&
|
|
item.optional === path[ix].optional));
|
|
}
|
|
function isSubPathIgnoringOptionals(subpath, path) {
|
|
return (subpath.length <= path.length &&
|
|
subpath.every((item, ix) => item.property === path[ix].property));
|
|
}
|
|
function getPlaceScope(id, place) {
|
|
const scope = place.identifier.scope;
|
|
if (scope !== null && isScopeActive(scope, id)) {
|
|
return scope;
|
|
}
|
|
return null;
|
|
}
|
|
function isScopeActive(scope, id) {
|
|
return id >= scope.range.start && id < scope.range.end;
|
|
}
|
|
function makeBlockId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected block id to be a non-negative integer',
|
|
loc: GeneratedSource,
|
|
});
|
|
return id;
|
|
}
|
|
function makeScopeId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected block id to be a non-negative integer',
|
|
loc: GeneratedSource,
|
|
});
|
|
return id;
|
|
}
|
|
function makeIdentifierId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected identifier id to be a non-negative integer',
|
|
loc: GeneratedSource,
|
|
});
|
|
return id;
|
|
}
|
|
function makeDeclarationId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected declaration id to be a non-negative integer',
|
|
loc: GeneratedSource,
|
|
});
|
|
return id;
|
|
}
|
|
function makeInstructionId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected instruction id to be a non-negative integer',
|
|
loc: GeneratedSource,
|
|
});
|
|
return id;
|
|
}
|
|
function isObjectMethodType(id) {
|
|
return id.type.kind == 'ObjectMethod';
|
|
}
|
|
function isPrimitiveType(id) {
|
|
return id.type.kind === 'Primitive';
|
|
}
|
|
function isPlainObjectType(id) {
|
|
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInObject';
|
|
}
|
|
function isArrayType(id) {
|
|
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInArray';
|
|
}
|
|
function isMapType(id) {
|
|
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInMap';
|
|
}
|
|
function isSetType(id) {
|
|
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInSet';
|
|
}
|
|
function isPropsType(id) {
|
|
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInProps';
|
|
}
|
|
function isRefValueType(id) {
|
|
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInRefValue';
|
|
}
|
|
function isUseRefType(id) {
|
|
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseRefId';
|
|
}
|
|
function isUseStateType(id) {
|
|
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseState';
|
|
}
|
|
function isJsxType(type) {
|
|
return type.kind === 'Object' && type.shapeId === 'BuiltInJsx';
|
|
}
|
|
function isRefOrRefValue(id) {
|
|
return isUseRefType(id) || isRefValueType(id);
|
|
}
|
|
function isRefOrRefLikeMutableType(type) {
|
|
return (type.kind === 'Object' &&
|
|
(type.shapeId === 'BuiltInUseRefId' ||
|
|
type.shapeId == 'ReanimatedSharedValueId'));
|
|
}
|
|
function isSetStateType(id) {
|
|
return id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetState';
|
|
}
|
|
function isUseActionStateType(id) {
|
|
return (id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseActionState');
|
|
}
|
|
function isStartTransitionType(id) {
|
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInStartTransition');
|
|
}
|
|
function isUseOptimisticType(id) {
|
|
return (id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseOptimistic');
|
|
}
|
|
function isSetOptimisticType(id) {
|
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetOptimistic');
|
|
}
|
|
function isSetActionStateType(id) {
|
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetActionState');
|
|
}
|
|
function isUseReducerType(id) {
|
|
return id.type.kind === 'Function' && id.type.shapeId === 'BuiltInUseReducer';
|
|
}
|
|
function isDispatcherType(id) {
|
|
return id.type.kind === 'Function' && id.type.shapeId === 'BuiltInDispatch';
|
|
}
|
|
function isEffectEventFunctionType(id) {
|
|
return (id.type.kind === 'Function' &&
|
|
id.type.shapeId === 'BuiltInEffectEventFunction');
|
|
}
|
|
function isStableType(id) {
|
|
return (isSetStateType(id) ||
|
|
isSetActionStateType(id) ||
|
|
isDispatcherType(id) ||
|
|
isUseRefType(id) ||
|
|
isStartTransitionType(id) ||
|
|
isSetOptimisticType(id));
|
|
}
|
|
function isStableTypeContainer(id) {
|
|
const type_ = id.type;
|
|
if (type_.kind !== 'Object') {
|
|
return false;
|
|
}
|
|
return (isUseStateType(id) ||
|
|
isUseActionStateType(id) ||
|
|
isUseReducerType(id) ||
|
|
isUseOptimisticType(id) ||
|
|
type_.shapeId === 'BuiltInUseTransition');
|
|
}
|
|
function evaluatesToStableTypeOrContainer(env, { value }) {
|
|
if (value.kind === 'CallExpression' || value.kind === 'MethodCall') {
|
|
const callee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
const calleeHookKind = getHookKind(env, callee.identifier);
|
|
switch (calleeHookKind) {
|
|
case 'useState':
|
|
case 'useReducer':
|
|
case 'useActionState':
|
|
case 'useRef':
|
|
case 'useTransition':
|
|
case 'useOptimistic':
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function isUseEffectHookType(id) {
|
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInUseEffectHook');
|
|
}
|
|
function isUseLayoutEffectHookType(id) {
|
|
return (id.type.kind === 'Function' &&
|
|
id.type.shapeId === 'BuiltInUseLayoutEffectHook');
|
|
}
|
|
function isUseInsertionEffectHookType(id) {
|
|
return (id.type.kind === 'Function' &&
|
|
id.type.shapeId === 'BuiltInUseInsertionEffectHook');
|
|
}
|
|
function isUseEffectEventType(id) {
|
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInUseEffectEvent');
|
|
}
|
|
function getHookKind(env, id) {
|
|
return getHookKindForType(env, id.type);
|
|
}
|
|
function isUseOperator(id) {
|
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInUseOperator');
|
|
}
|
|
function getHookKindForType(env, type) {
|
|
var _a;
|
|
if (type.kind === 'Function') {
|
|
const signature = env.getFunctionSignature(type);
|
|
return (_a = signature === null || signature === void 0 ? void 0 : signature.hookKind) !== null && _a !== void 0 ? _a : null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function printReactiveScopeSummary(scope) {
|
|
const items = [];
|
|
items.push('scope');
|
|
items.push(`@${scope.id}`);
|
|
items.push(`[${scope.range.start}:${scope.range.end}]`);
|
|
items.push(`dependencies=[${Array.from(scope.dependencies)
|
|
.map(dep => printDependency(dep))
|
|
.join(', ')}]`);
|
|
items.push(`declarations=[${Array.from(scope.declarations)
|
|
.map(([, decl]) => printIdentifier(Object.assign(Object.assign({}, decl.identifier), { scope: decl.scope })))
|
|
.join(', ')}]`);
|
|
items.push(`reassignments=[${Array.from(scope.reassignments).map(reassign => printIdentifier(reassign))}]`);
|
|
if (scope.earlyReturnValue !== null) {
|
|
items.push(`earlyReturn={id: ${printIdentifier(scope.earlyReturnValue.value)}, label: ${scope.earlyReturnValue.label}}}`);
|
|
}
|
|
return items.join(' ');
|
|
}
|
|
function printDependency(dependency) {
|
|
const identifier = printIdentifier(dependency.identifier) +
|
|
printType(dependency.identifier.type);
|
|
return `${identifier}${dependency.path.map(token => `${token.optional ? '?.' : '.'}${token.property}`).join('')}_${printSourceLocation(dependency.loc)}`;
|
|
}
|
|
|
|
function printFunction(fn) {
|
|
const output = [];
|
|
let definition = '';
|
|
if (fn.id !== null) {
|
|
definition += fn.id;
|
|
}
|
|
else {
|
|
definition += '<<anonymous>>';
|
|
}
|
|
if (fn.nameHint != null) {
|
|
definition += ` ${fn.nameHint}`;
|
|
}
|
|
if (fn.params.length !== 0) {
|
|
definition +=
|
|
'(' +
|
|
fn.params
|
|
.map(param => {
|
|
if (param.kind === 'Identifier') {
|
|
return printPlace(param);
|
|
}
|
|
else {
|
|
return `...${printPlace(param.place)}`;
|
|
}
|
|
})
|
|
.join(', ') +
|
|
')';
|
|
}
|
|
else {
|
|
definition += '()';
|
|
}
|
|
definition += `: ${printPlace(fn.returns)}`;
|
|
output.push(definition);
|
|
output.push(...fn.directives);
|
|
output.push(printHIR(fn.body));
|
|
return output.join('\n');
|
|
}
|
|
function printHIR(ir, options = null) {
|
|
var _a;
|
|
let output = [];
|
|
let indent = ' '.repeat((_a = options === null || options === void 0 ? void 0 : options.indent) !== null && _a !== void 0 ? _a : 0);
|
|
const push = (text, indent = ' ') => {
|
|
output.push(`${indent}${text}`);
|
|
};
|
|
for (const [blockId, block] of ir.blocks) {
|
|
output.push(`bb${blockId} (${block.kind}):`);
|
|
if (block.preds.size > 0) {
|
|
const preds = ['predecessor blocks:'];
|
|
for (const pred of block.preds) {
|
|
preds.push(`bb${pred}`);
|
|
}
|
|
push(preds.join(' '));
|
|
}
|
|
for (const phi of block.phis) {
|
|
push(printPhi(phi));
|
|
}
|
|
for (const instr of block.instructions) {
|
|
push(printInstruction(instr));
|
|
}
|
|
const terminal = printTerminal(block.terminal);
|
|
if (Array.isArray(terminal)) {
|
|
terminal.forEach(line => push(line));
|
|
}
|
|
else {
|
|
push(terminal);
|
|
}
|
|
}
|
|
return output.map(line => indent + line).join('\n');
|
|
}
|
|
function printInstruction(instr) {
|
|
const id = `[${instr.id}]`;
|
|
let value = printInstructionValue(instr.value);
|
|
if (instr.effects != null) {
|
|
value += `\n ${instr.effects.map(printAliasingEffect).join('\n ')}`;
|
|
}
|
|
if (instr.lvalue !== null) {
|
|
return `${id} ${printPlace(instr.lvalue)} = ${value}`;
|
|
}
|
|
else {
|
|
return `${id} ${value}`;
|
|
}
|
|
}
|
|
function printPhi(phi) {
|
|
const items = [];
|
|
items.push(printPlace(phi.place));
|
|
items.push(printMutableRange(phi.place.identifier));
|
|
items.push(printType(phi.place.identifier.type));
|
|
items.push(': phi(');
|
|
const phis = [];
|
|
for (const [blockId, place] of phi.operands) {
|
|
phis.push(`bb${blockId}: ${printPlace(place)}`);
|
|
}
|
|
items.push(phis.join(', '));
|
|
items.push(')');
|
|
return items.join('');
|
|
}
|
|
function printTerminal(terminal) {
|
|
let value;
|
|
switch (terminal.kind) {
|
|
case 'if': {
|
|
value = `[${terminal.id}] If (${printPlace(terminal.test)}) then:bb${terminal.consequent} else:bb${terminal.alternate}${terminal.fallthrough ? ` fallthrough=bb${terminal.fallthrough}` : ''}`;
|
|
break;
|
|
}
|
|
case 'branch': {
|
|
value = `[${terminal.id}] Branch (${printPlace(terminal.test)}) then:bb${terminal.consequent} else:bb${terminal.alternate} fallthrough:bb${terminal.fallthrough}`;
|
|
break;
|
|
}
|
|
case 'logical': {
|
|
value = `[${terminal.id}] Logical ${terminal.operator} test:bb${terminal.test} fallthrough=bb${terminal.fallthrough}`;
|
|
break;
|
|
}
|
|
case 'ternary': {
|
|
value = `[${terminal.id}] Ternary test:bb${terminal.test} fallthrough=bb${terminal.fallthrough}`;
|
|
break;
|
|
}
|
|
case 'optional': {
|
|
value = `[${terminal.id}] Optional (optional=${terminal.optional}) test:bb${terminal.test} fallthrough=bb${terminal.fallthrough}`;
|
|
break;
|
|
}
|
|
case 'throw': {
|
|
value = `[${terminal.id}] Throw ${printPlace(terminal.value)}`;
|
|
break;
|
|
}
|
|
case 'return': {
|
|
value = `[${terminal.id}] Return ${terminal.returnVariant}${terminal.value != null ? ' ' + printPlace(terminal.value) : ''}`;
|
|
if (terminal.effects != null) {
|
|
value += `\n ${terminal.effects.map(printAliasingEffect).join('\n ')}`;
|
|
}
|
|
break;
|
|
}
|
|
case 'goto': {
|
|
value = `[${terminal.id}] Goto${terminal.variant === GotoVariant.Continue ? '(Continue)' : ''} bb${terminal.block}`;
|
|
break;
|
|
}
|
|
case 'switch': {
|
|
const output = [];
|
|
output.push(`[${terminal.id}] Switch (${printPlace(terminal.test)})`);
|
|
terminal.cases.forEach(case_ => {
|
|
if (case_.test !== null) {
|
|
output.push(` Case ${printPlace(case_.test)}: bb${case_.block}`);
|
|
}
|
|
else {
|
|
output.push(` Default: bb${case_.block}`);
|
|
}
|
|
});
|
|
if (terminal.fallthrough) {
|
|
output.push(` Fallthrough: bb${terminal.fallthrough}`);
|
|
}
|
|
value = output;
|
|
break;
|
|
}
|
|
case 'do-while': {
|
|
value = `[${terminal.id}] DoWhile loop=${`bb${terminal.loop}`} test=bb${terminal.test} fallthrough=${`bb${terminal.fallthrough}`}`;
|
|
break;
|
|
}
|
|
case 'while': {
|
|
value = `[${terminal.id}] While test=bb${terminal.test} loop=${terminal.loop !== null ? `bb${terminal.loop}` : ''} fallthrough=${terminal.fallthrough ? `bb${terminal.fallthrough}` : ''}`;
|
|
break;
|
|
}
|
|
case 'for': {
|
|
value = `[${terminal.id}] For init=bb${terminal.init} test=bb${terminal.test} loop=bb${terminal.loop} update=bb${terminal.update} fallthrough=bb${terminal.fallthrough}`;
|
|
break;
|
|
}
|
|
case 'for-of': {
|
|
value = `[${terminal.id}] ForOf init=bb${terminal.init} test=bb${terminal.test} loop=bb${terminal.loop} fallthrough=bb${terminal.fallthrough}`;
|
|
break;
|
|
}
|
|
case 'for-in': {
|
|
value = `[${terminal.id}] ForIn init=bb${terminal.init} loop=bb${terminal.loop} fallthrough=bb${terminal.fallthrough}`;
|
|
break;
|
|
}
|
|
case 'label': {
|
|
value = `[${terminal.id}] Label block=bb${terminal.block} fallthrough=${terminal.fallthrough ? `bb${terminal.fallthrough}` : ''}`;
|
|
break;
|
|
}
|
|
case 'sequence': {
|
|
value = `[${terminal.id}] Sequence block=bb${terminal.block} fallthrough=bb${terminal.fallthrough}`;
|
|
break;
|
|
}
|
|
case 'unreachable': {
|
|
value = `[${terminal.id}] Unreachable`;
|
|
break;
|
|
}
|
|
case 'unsupported': {
|
|
value = `[${terminal.id}] Unsupported`;
|
|
break;
|
|
}
|
|
case 'maybe-throw': {
|
|
const handlerStr = terminal.handler !== null ? `bb${terminal.handler}` : '(none)';
|
|
value = `[${terminal.id}] MaybeThrow continuation=bb${terminal.continuation} handler=${handlerStr}`;
|
|
if (terminal.effects != null) {
|
|
value += `\n ${terminal.effects.map(printAliasingEffect).join('\n ')}`;
|
|
}
|
|
break;
|
|
}
|
|
case 'scope': {
|
|
value = `[${terminal.id}] Scope ${printReactiveScopeSummary(terminal.scope)} block=bb${terminal.block} fallthrough=bb${terminal.fallthrough}`;
|
|
break;
|
|
}
|
|
case 'pruned-scope': {
|
|
value = `[${terminal.id}] <pruned> Scope ${printReactiveScopeSummary(terminal.scope)} block=bb${terminal.block} fallthrough=bb${terminal.fallthrough}`;
|
|
break;
|
|
}
|
|
case 'try': {
|
|
value = `[${terminal.id}] Try block=bb${terminal.block} handler=bb${terminal.handler}${terminal.handlerBinding !== null
|
|
? ` handlerBinding=(${printPlace(terminal.handlerBinding)})`
|
|
: ''} fallthrough=${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : ''}`;
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, `Unexpected terminal kind \`${terminal}\``);
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
function printHole() {
|
|
return '<hole>';
|
|
}
|
|
function printObjectPropertyKey(key) {
|
|
switch (key.kind) {
|
|
case 'identifier':
|
|
return key.name;
|
|
case 'string':
|
|
return `"${key.name}"`;
|
|
case 'computed': {
|
|
return `[${printPlace(key.name)}]`;
|
|
}
|
|
case 'number': {
|
|
return String(key.name);
|
|
}
|
|
}
|
|
}
|
|
function printInstructionValue(instrValue) {
|
|
var _a, _b, _c, _d, _e;
|
|
let value = '';
|
|
switch (instrValue.kind) {
|
|
case 'ArrayExpression': {
|
|
value = `Array [${instrValue.elements
|
|
.map(element => {
|
|
if (element.kind === 'Identifier') {
|
|
return printPlace(element);
|
|
}
|
|
else if (element.kind === 'Hole') {
|
|
return printHole();
|
|
}
|
|
else {
|
|
return `...${printPlace(element.place)}`;
|
|
}
|
|
})
|
|
.join(', ')}]`;
|
|
break;
|
|
}
|
|
case 'ObjectExpression': {
|
|
const properties = [];
|
|
if (instrValue.properties !== null) {
|
|
for (const property of instrValue.properties) {
|
|
if (property.kind === 'ObjectProperty') {
|
|
properties.push(`${printObjectPropertyKey(property.key)}: ${printPlace(property.place)}`);
|
|
}
|
|
else {
|
|
properties.push(`...${printPlace(property.place)}`);
|
|
}
|
|
}
|
|
}
|
|
value = `Object { ${properties.join(', ')} }`;
|
|
break;
|
|
}
|
|
case 'UnaryExpression': {
|
|
value = `Unary ${printPlace(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'BinaryExpression': {
|
|
value = `Binary ${printPlace(instrValue.left)} ${instrValue.operator} ${printPlace(instrValue.right)}`;
|
|
break;
|
|
}
|
|
case 'NewExpression': {
|
|
value = `New ${printPlace(instrValue.callee)}(${instrValue.args
|
|
.map(arg => printPattern(arg))
|
|
.join(', ')})`;
|
|
break;
|
|
}
|
|
case 'CallExpression': {
|
|
value = `Call ${printPlace(instrValue.callee)}(${instrValue.args
|
|
.map(arg => printPattern(arg))
|
|
.join(', ')})`;
|
|
break;
|
|
}
|
|
case 'MethodCall': {
|
|
value = `MethodCall ${printPlace(instrValue.receiver)}.${printPlace(instrValue.property)}(${instrValue.args.map(arg => printPattern(arg)).join(', ')})`;
|
|
break;
|
|
}
|
|
case 'JSXText': {
|
|
value = `JSXText ${JSON.stringify(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'Primitive': {
|
|
if (instrValue.value === undefined) {
|
|
value = '<undefined>';
|
|
}
|
|
else {
|
|
value = JSON.stringify(instrValue.value);
|
|
}
|
|
break;
|
|
}
|
|
case 'TypeCastExpression': {
|
|
value = `TypeCast ${printPlace(instrValue.value)}: ${printType(instrValue.type)}`;
|
|
break;
|
|
}
|
|
case 'JsxExpression': {
|
|
const propItems = [];
|
|
for (const attribute of instrValue.props) {
|
|
if (attribute.kind === 'JsxAttribute') {
|
|
propItems.push(`${attribute.name}={${attribute.place !== null ? printPlace(attribute.place) : '<empty>'}}`);
|
|
}
|
|
else {
|
|
propItems.push(`...${printPlace(attribute.argument)}`);
|
|
}
|
|
}
|
|
const tag = instrValue.tag.kind === 'Identifier'
|
|
? printPlace(instrValue.tag)
|
|
: instrValue.tag.name;
|
|
const props = propItems.length !== 0 ? ' ' + propItems.join(' ') : '';
|
|
if (instrValue.children !== null) {
|
|
const children = instrValue.children.map(child => {
|
|
return `{${printPlace(child)}}`;
|
|
});
|
|
value = `JSX <${tag}${props}${props.length > 0 ? ' ' : ''}>${children.join('')}</${tag}>`;
|
|
}
|
|
else {
|
|
value = `JSX <${tag}${props}${props.length > 0 ? ' ' : ''}/>`;
|
|
}
|
|
break;
|
|
}
|
|
case 'JsxFragment': {
|
|
value = `JsxFragment [${instrValue.children
|
|
.map(child => printPlace(child))
|
|
.join(', ')}]`;
|
|
break;
|
|
}
|
|
case 'UnsupportedNode': {
|
|
value = `UnsupportedNode ${instrValue.node.type}`;
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
value = `LoadLocal ${printPlace(instrValue.place)}`;
|
|
break;
|
|
}
|
|
case 'DeclareLocal': {
|
|
value = `DeclareLocal ${instrValue.lvalue.kind} ${printPlace(instrValue.lvalue.place)}`;
|
|
break;
|
|
}
|
|
case 'DeclareContext': {
|
|
value = `DeclareContext ${instrValue.lvalue.kind} ${printPlace(instrValue.lvalue.place)}`;
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
value = `StoreLocal ${instrValue.lvalue.kind} ${printPlace(instrValue.lvalue.place)} = ${printPlace(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'LoadContext': {
|
|
value = `LoadContext ${printPlace(instrValue.place)}`;
|
|
break;
|
|
}
|
|
case 'StoreContext': {
|
|
value = `StoreContext ${instrValue.lvalue.kind} ${printPlace(instrValue.lvalue.place)} = ${printPlace(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
value = `Destructure ${instrValue.lvalue.kind} ${printPattern(instrValue.lvalue.pattern)} = ${printPlace(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
value = `PropertyLoad ${printPlace(instrValue.object)}.${instrValue.property}`;
|
|
break;
|
|
}
|
|
case 'PropertyStore': {
|
|
value = `PropertyStore ${printPlace(instrValue.object)}.${instrValue.property} = ${printPlace(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'PropertyDelete': {
|
|
value = `PropertyDelete ${printPlace(instrValue.object)}.${instrValue.property}`;
|
|
break;
|
|
}
|
|
case 'ComputedLoad': {
|
|
value = `ComputedLoad ${printPlace(instrValue.object)}[${printPlace(instrValue.property)}]`;
|
|
break;
|
|
}
|
|
case 'ComputedStore': {
|
|
value = `ComputedStore ${printPlace(instrValue.object)}[${printPlace(instrValue.property)}] = ${printPlace(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'ComputedDelete': {
|
|
value = `ComputedDelete ${printPlace(instrValue.object)}[${printPlace(instrValue.property)}]`;
|
|
break;
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
const kind = instrValue.kind === 'FunctionExpression' ? 'Function' : 'ObjectMethod';
|
|
const name = getFunctionName$2(instrValue, '');
|
|
const fn = printFunction(instrValue.loweredFunc.func)
|
|
.split('\n')
|
|
.map(line => ` ${line}`)
|
|
.join('\n');
|
|
const context = instrValue.loweredFunc.func.context
|
|
.map(dep => printPlace(dep))
|
|
.join(',');
|
|
const aliasingEffects = (_c = (_b = (_a = instrValue.loweredFunc.func.aliasingEffects) === null || _a === void 0 ? void 0 : _a.map(printAliasingEffect)) === null || _b === void 0 ? void 0 : _b.join(', ')) !== null && _c !== void 0 ? _c : '';
|
|
value = `${kind} ${name} @context[${context}] @aliasingEffects=[${aliasingEffects}]\n${fn}`;
|
|
break;
|
|
}
|
|
case 'TaggedTemplateExpression': {
|
|
value = `${printPlace(instrValue.tag)}\`${instrValue.value.raw}\``;
|
|
break;
|
|
}
|
|
case 'LogicalExpression': {
|
|
value = `Logical ${printInstructionValue(instrValue.left)} ${instrValue.operator} ${printInstructionValue(instrValue.right)}`;
|
|
break;
|
|
}
|
|
case 'SequenceExpression': {
|
|
value = [
|
|
`Sequence`,
|
|
...instrValue.instructions.map(instr => ` ${printInstruction(instr)}`),
|
|
` ${printInstructionValue(instrValue.value)}`,
|
|
].join('\n');
|
|
break;
|
|
}
|
|
case 'ConditionalExpression': {
|
|
value = `Ternary ${printInstructionValue(instrValue.test)} ? ${printInstructionValue(instrValue.consequent)} : ${printInstructionValue(instrValue.alternate)}`;
|
|
break;
|
|
}
|
|
case 'TemplateLiteral': {
|
|
value = '`';
|
|
CompilerError.invariant(instrValue.subexprs.length === instrValue.quasis.length - 1, {
|
|
reason: 'Bad assumption about quasi length.',
|
|
loc: instrValue.loc,
|
|
});
|
|
for (let i = 0; i < instrValue.subexprs.length; i++) {
|
|
value += instrValue.quasis[i].raw;
|
|
value += `\${${printPlace(instrValue.subexprs[i])}}`;
|
|
}
|
|
value += instrValue.quasis.at(-1).raw + '`';
|
|
break;
|
|
}
|
|
case 'LoadGlobal': {
|
|
switch (instrValue.binding.kind) {
|
|
case 'Global': {
|
|
value = `LoadGlobal(global) ${instrValue.binding.name}`;
|
|
break;
|
|
}
|
|
case 'ModuleLocal': {
|
|
value = `LoadGlobal(module) ${instrValue.binding.name}`;
|
|
break;
|
|
}
|
|
case 'ImportDefault': {
|
|
value = `LoadGlobal import ${instrValue.binding.name} from '${instrValue.binding.module}'`;
|
|
break;
|
|
}
|
|
case 'ImportNamespace': {
|
|
value = `LoadGlobal import * as ${instrValue.binding.name} from '${instrValue.binding.module}'`;
|
|
break;
|
|
}
|
|
case 'ImportSpecifier': {
|
|
if (instrValue.binding.imported !== instrValue.binding.name) {
|
|
value = `LoadGlobal import { ${instrValue.binding.imported} as ${instrValue.binding.name} } from '${instrValue.binding.module}'`;
|
|
}
|
|
else {
|
|
value = `LoadGlobal import { ${instrValue.binding.name} } from '${instrValue.binding.module}'`;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(instrValue.binding, `Unexpected binding kind \`${instrValue.binding.kind}\``);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreGlobal': {
|
|
value = `StoreGlobal ${instrValue.name} = ${printPlace(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'OptionalExpression': {
|
|
value = `OptionalExpression ${printInstructionValue(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'RegExpLiteral': {
|
|
value = `RegExp /${instrValue.pattern}/${instrValue.flags}`;
|
|
break;
|
|
}
|
|
case 'MetaProperty': {
|
|
value = `MetaProperty ${instrValue.meta}.${instrValue.property}`;
|
|
break;
|
|
}
|
|
case 'Await': {
|
|
value = `Await ${printPlace(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'GetIterator': {
|
|
value = `GetIterator collection=${printPlace(instrValue.collection)}`;
|
|
break;
|
|
}
|
|
case 'IteratorNext': {
|
|
value = `IteratorNext iterator=${printPlace(instrValue.iterator)} collection=${printPlace(instrValue.collection)}`;
|
|
break;
|
|
}
|
|
case 'NextPropertyOf': {
|
|
value = `NextPropertyOf ${printPlace(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'Debugger': {
|
|
value = `Debugger`;
|
|
break;
|
|
}
|
|
case 'PostfixUpdate': {
|
|
value = `PostfixUpdate ${printPlace(instrValue.lvalue)} = ${printPlace(instrValue.value)} ${instrValue.operation}`;
|
|
break;
|
|
}
|
|
case 'PrefixUpdate': {
|
|
value = `PrefixUpdate ${printPlace(instrValue.lvalue)} = ${instrValue.operation} ${printPlace(instrValue.value)}`;
|
|
break;
|
|
}
|
|
case 'StartMemoize': {
|
|
value = `StartMemoize deps=${(_e = (_d = instrValue.deps) === null || _d === void 0 ? void 0 : _d.map(dep => printManualMemoDependency$1(dep, false))) !== null && _e !== void 0 ? _e : '(none)'}`;
|
|
break;
|
|
}
|
|
case 'FinishMemoize': {
|
|
value = `FinishMemoize decl=${printPlace(instrValue.decl)}${instrValue.pruned ? ' pruned' : ''}`;
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(instrValue, `Unexpected instruction kind '${instrValue.kind}'`);
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
function isMutable$1(range) {
|
|
return range.end > range.start + 1;
|
|
}
|
|
function printMutableRange(identifier) {
|
|
var _b, _c;
|
|
const range = (_c = (_b = identifier.scope) === null || _b === void 0 ? void 0 : _b.range) !== null && _c !== void 0 ? _c : identifier.mutableRange;
|
|
return isMutable$1(range) ? `[${range.start}:${range.end}]` : '';
|
|
}
|
|
function printPattern(pattern) {
|
|
switch (pattern.kind) {
|
|
case 'ArrayPattern': {
|
|
return ('[ ' +
|
|
pattern.items
|
|
.map(item => {
|
|
if (item.kind === 'Hole') {
|
|
return '<hole>';
|
|
}
|
|
return printPattern(item);
|
|
})
|
|
.join(', ') +
|
|
' ]');
|
|
}
|
|
case 'ObjectPattern': {
|
|
return ('{ ' +
|
|
pattern.properties
|
|
.map(item => {
|
|
switch (item.kind) {
|
|
case 'ObjectProperty': {
|
|
return `${printObjectPropertyKey(item.key)}: ${printPattern(item.place)}`;
|
|
}
|
|
case 'Spread': {
|
|
return printPattern(item);
|
|
}
|
|
default: {
|
|
assertExhaustive$1(item, 'Unexpected object property kind');
|
|
}
|
|
}
|
|
})
|
|
.join(', ') +
|
|
' }');
|
|
}
|
|
case 'Spread': {
|
|
return `...${printPlace(pattern.place)}`;
|
|
}
|
|
case 'Identifier': {
|
|
return printPlace(pattern);
|
|
}
|
|
default: {
|
|
assertExhaustive$1(pattern, `Unexpected pattern kind \`${pattern.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function printPlace(place) {
|
|
const items = [
|
|
place.effect,
|
|
' ',
|
|
printIdentifier(place.identifier),
|
|
printMutableRange(place.identifier),
|
|
printType(place.identifier.type),
|
|
place.reactive ? '{reactive}' : null,
|
|
];
|
|
return items.filter(x => x != null).join('');
|
|
}
|
|
function printIdentifier(id) {
|
|
return `${printName(id.name)}\$${id.id}${printScope(id.scope)}`;
|
|
}
|
|
function printName(name) {
|
|
if (name === null) {
|
|
return '';
|
|
}
|
|
return name.value;
|
|
}
|
|
function printScope(scope) {
|
|
return `${scope !== null ? `_@${scope.id}` : ''}`;
|
|
}
|
|
function printManualMemoDependency$1(val, nameOnly) {
|
|
var _a;
|
|
let rootStr;
|
|
if (val.root.kind === 'Global') {
|
|
rootStr = val.root.identifierName;
|
|
}
|
|
else {
|
|
CompilerError.invariant(((_a = val.root.value.identifier.name) === null || _a === void 0 ? void 0 : _a.kind) === 'named', {
|
|
reason: 'DepsValidation: expected named local variable in depslist',
|
|
loc: val.root.value.loc,
|
|
});
|
|
rootStr = nameOnly
|
|
? val.root.value.identifier.name.value
|
|
: printIdentifier(val.root.value.identifier);
|
|
}
|
|
return `${rootStr}${val.path.map(v => `${v.optional ? '?.' : '.'}${v.property}`).join('')}`;
|
|
}
|
|
function printType(type) {
|
|
if (type.kind === 'Type')
|
|
return '';
|
|
if (type.kind === 'Object' && type.shapeId != null) {
|
|
return `:T${type.kind}<${type.shapeId}>`;
|
|
}
|
|
else if (type.kind === 'Function' && type.shapeId != null) {
|
|
const returnType = printType(type.return);
|
|
return `:T${type.kind}<${type.shapeId}>()${returnType !== '' ? `: ${returnType}` : ''}`;
|
|
}
|
|
else {
|
|
return `:T${type.kind}`;
|
|
}
|
|
}
|
|
function printSourceLocation(loc) {
|
|
if (typeof loc === 'symbol') {
|
|
return 'generated';
|
|
}
|
|
else {
|
|
return `${loc.start.line}:${loc.start.column}:${loc.end.line}:${loc.end.column}`;
|
|
}
|
|
}
|
|
function getFunctionName$2(instrValue, defaultValue) {
|
|
var _a;
|
|
switch (instrValue.kind) {
|
|
case 'FunctionExpression':
|
|
return (_a = instrValue.name) !== null && _a !== void 0 ? _a : defaultValue;
|
|
case 'ObjectMethod':
|
|
return defaultValue;
|
|
}
|
|
}
|
|
function printAliasingEffect(effect) {
|
|
var _a;
|
|
switch (effect.kind) {
|
|
case 'Assign': {
|
|
return `Assign ${printPlaceForAliasEffect(effect.into)} = ${printPlaceForAliasEffect(effect.from)}`;
|
|
}
|
|
case 'Alias': {
|
|
return `Alias ${printPlaceForAliasEffect(effect.into)} <- ${printPlaceForAliasEffect(effect.from)}`;
|
|
}
|
|
case 'MaybeAlias': {
|
|
return `MaybeAlias ${printPlaceForAliasEffect(effect.into)} <- ${printPlaceForAliasEffect(effect.from)}`;
|
|
}
|
|
case 'Capture': {
|
|
return `Capture ${printPlaceForAliasEffect(effect.into)} <- ${printPlaceForAliasEffect(effect.from)}`;
|
|
}
|
|
case 'ImmutableCapture': {
|
|
return `ImmutableCapture ${printPlaceForAliasEffect(effect.into)} <- ${printPlaceForAliasEffect(effect.from)}`;
|
|
}
|
|
case 'Create': {
|
|
return `Create ${printPlaceForAliasEffect(effect.into)} = ${effect.value}`;
|
|
}
|
|
case 'CreateFrom': {
|
|
return `Create ${printPlaceForAliasEffect(effect.into)} = kindOf(${printPlaceForAliasEffect(effect.from)})`;
|
|
}
|
|
case 'CreateFunction': {
|
|
return `Function ${printPlaceForAliasEffect(effect.into)} = Function captures=[${effect.captures.map(printPlaceForAliasEffect).join(', ')}]`;
|
|
}
|
|
case 'Apply': {
|
|
const receiverCallee = effect.receiver.identifier.id === effect.function.identifier.id
|
|
? printPlaceForAliasEffect(effect.receiver)
|
|
: `${printPlaceForAliasEffect(effect.receiver)}.${printPlaceForAliasEffect(effect.function)}`;
|
|
const args = effect.args
|
|
.map(arg => {
|
|
if (arg.kind === 'Identifier') {
|
|
return printPlaceForAliasEffect(arg);
|
|
}
|
|
else if (arg.kind === 'Hole') {
|
|
return ' ';
|
|
}
|
|
return `...${printPlaceForAliasEffect(arg.place)}`;
|
|
})
|
|
.join(', ');
|
|
let signature = '';
|
|
if (effect.signature != null) {
|
|
if (effect.signature.aliasing != null) {
|
|
signature = printAliasingSignature(effect.signature.aliasing);
|
|
}
|
|
else {
|
|
signature = JSON.stringify(effect.signature, null, 2);
|
|
}
|
|
}
|
|
return `Apply ${printPlaceForAliasEffect(effect.into)} = ${receiverCallee}(${args})${signature != '' ? '\n ' : ''}${signature}`;
|
|
}
|
|
case 'Freeze': {
|
|
return `Freeze ${printPlaceForAliasEffect(effect.value)} ${effect.reason}`;
|
|
}
|
|
case 'Mutate':
|
|
case 'MutateConditionally':
|
|
case 'MutateTransitive':
|
|
case 'MutateTransitiveConditionally': {
|
|
return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}${effect.kind === 'Mutate' && ((_a = effect.reason) === null || _a === void 0 ? void 0 : _a.kind) === 'AssignCurrentProperty' ? ' (assign `.current`)' : ''}`;
|
|
}
|
|
case 'MutateFrozen': {
|
|
return `MutateFrozen ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;
|
|
}
|
|
case 'MutateGlobal': {
|
|
return `MutateGlobal ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;
|
|
}
|
|
case 'Impure': {
|
|
return `Impure ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;
|
|
}
|
|
case 'Render': {
|
|
return `Render ${printPlaceForAliasEffect(effect.place)}`;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(effect, `Unexpected kind '${effect.kind}'`);
|
|
}
|
|
}
|
|
}
|
|
function printPlaceForAliasEffect(place) {
|
|
return printIdentifier(place.identifier);
|
|
}
|
|
function printAliasingSignature(signature) {
|
|
const tokens = ['function '];
|
|
if (signature.temporaries.length !== 0) {
|
|
tokens.push('<');
|
|
tokens.push(signature.temporaries.map(temp => `$${temp.identifier.id}`).join(', '));
|
|
tokens.push('>');
|
|
}
|
|
tokens.push('(');
|
|
tokens.push('this=$' + String(signature.receiver));
|
|
for (const param of signature.params) {
|
|
tokens.push(', $' + String(param));
|
|
}
|
|
if (signature.rest != null) {
|
|
tokens.push(`, ...$${String(signature.rest)}`);
|
|
}
|
|
tokens.push('): ');
|
|
tokens.push('$' + String(signature.returns) + ':');
|
|
for (const effect of signature.effects) {
|
|
tokens.push('\n ' + printAliasingEffect(effect));
|
|
}
|
|
return tokens.join('');
|
|
}
|
|
|
|
var _ScopeBlockTraversal_activeScopes;
|
|
function* eachInstructionLValue(instr) {
|
|
if (instr.lvalue !== null) {
|
|
yield instr.lvalue;
|
|
}
|
|
yield* eachInstructionValueLValue(instr.value);
|
|
}
|
|
function* eachInstructionLValueWithKind(instr) {
|
|
switch (instr.value.kind) {
|
|
case 'DeclareContext':
|
|
case 'StoreContext':
|
|
case 'DeclareLocal':
|
|
case 'StoreLocal': {
|
|
yield [instr.value.lvalue.place, instr.value.lvalue.kind];
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
const kind = instr.value.lvalue.kind;
|
|
for (const place of eachPatternOperand(instr.value.lvalue.pattern)) {
|
|
yield [place, kind];
|
|
}
|
|
break;
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
yield [instr.value.lvalue, InstructionKind.Reassign];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
function* eachInstructionValueLValue(value) {
|
|
switch (value.kind) {
|
|
case 'DeclareContext':
|
|
case 'StoreContext':
|
|
case 'DeclareLocal':
|
|
case 'StoreLocal': {
|
|
yield value.lvalue.place;
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
yield* eachPatternOperand(value.lvalue.pattern);
|
|
break;
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
yield value.lvalue;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
function* eachInstructionOperand(instr) {
|
|
yield* eachInstructionValueOperand(instr.value);
|
|
}
|
|
function* eachInstructionValueOperand(instrValue) {
|
|
switch (instrValue.kind) {
|
|
case 'NewExpression':
|
|
case 'CallExpression': {
|
|
yield instrValue.callee;
|
|
yield* eachCallArgument(instrValue.args);
|
|
break;
|
|
}
|
|
case 'BinaryExpression': {
|
|
yield instrValue.left;
|
|
yield instrValue.right;
|
|
break;
|
|
}
|
|
case 'MethodCall': {
|
|
yield instrValue.receiver;
|
|
yield instrValue.property;
|
|
yield* eachCallArgument(instrValue.args);
|
|
break;
|
|
}
|
|
case 'DeclareContext':
|
|
case 'DeclareLocal': {
|
|
break;
|
|
}
|
|
case 'LoadLocal':
|
|
case 'LoadContext': {
|
|
yield instrValue.place;
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'StoreContext': {
|
|
yield instrValue.lvalue.place;
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'StoreGlobal': {
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
yield instrValue.object;
|
|
break;
|
|
}
|
|
case 'PropertyDelete': {
|
|
yield instrValue.object;
|
|
break;
|
|
}
|
|
case 'PropertyStore': {
|
|
yield instrValue.object;
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'ComputedLoad': {
|
|
yield instrValue.object;
|
|
yield instrValue.property;
|
|
break;
|
|
}
|
|
case 'ComputedDelete': {
|
|
yield instrValue.object;
|
|
yield instrValue.property;
|
|
break;
|
|
}
|
|
case 'ComputedStore': {
|
|
yield instrValue.object;
|
|
yield instrValue.property;
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'UnaryExpression': {
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'JsxExpression': {
|
|
if (instrValue.tag.kind === 'Identifier') {
|
|
yield instrValue.tag;
|
|
}
|
|
for (const attribute of instrValue.props) {
|
|
switch (attribute.kind) {
|
|
case 'JsxAttribute': {
|
|
yield attribute.place;
|
|
break;
|
|
}
|
|
case 'JsxSpreadAttribute': {
|
|
yield attribute.argument;
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(attribute, `Unexpected attribute kind \`${attribute.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
if (instrValue.children) {
|
|
yield* instrValue.children;
|
|
}
|
|
break;
|
|
}
|
|
case 'JsxFragment': {
|
|
yield* instrValue.children;
|
|
break;
|
|
}
|
|
case 'ObjectExpression': {
|
|
for (const property of instrValue.properties) {
|
|
if (property.kind === 'ObjectProperty' &&
|
|
property.key.kind === 'computed') {
|
|
yield property.key.name;
|
|
}
|
|
yield property.place;
|
|
}
|
|
break;
|
|
}
|
|
case 'ArrayExpression': {
|
|
for (const element of instrValue.elements) {
|
|
if (element.kind === 'Identifier') {
|
|
yield element;
|
|
}
|
|
else if (element.kind === 'Spread') {
|
|
yield element.place;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
yield* instrValue.loweredFunc.func.context;
|
|
break;
|
|
}
|
|
case 'TaggedTemplateExpression': {
|
|
yield instrValue.tag;
|
|
break;
|
|
}
|
|
case 'TypeCastExpression': {
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'TemplateLiteral': {
|
|
yield* instrValue.subexprs;
|
|
break;
|
|
}
|
|
case 'Await': {
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'GetIterator': {
|
|
yield instrValue.collection;
|
|
break;
|
|
}
|
|
case 'IteratorNext': {
|
|
yield instrValue.iterator;
|
|
yield instrValue.collection;
|
|
break;
|
|
}
|
|
case 'NextPropertyOf': {
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
yield instrValue.value;
|
|
break;
|
|
}
|
|
case 'StartMemoize': {
|
|
if (instrValue.deps != null) {
|
|
for (const dep of instrValue.deps) {
|
|
if (dep.root.kind === 'NamedLocal') {
|
|
yield dep.root.value;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'FinishMemoize': {
|
|
yield instrValue.decl;
|
|
break;
|
|
}
|
|
case 'Debugger':
|
|
case 'RegExpLiteral':
|
|
case 'MetaProperty':
|
|
case 'LoadGlobal':
|
|
case 'UnsupportedNode':
|
|
case 'Primitive':
|
|
case 'JSXText': {
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(instrValue, `Unexpected instruction kind \`${instrValue.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function* eachCallArgument(args) {
|
|
for (const arg of args) {
|
|
if (arg.kind === 'Identifier') {
|
|
yield arg;
|
|
}
|
|
else {
|
|
yield arg.place;
|
|
}
|
|
}
|
|
}
|
|
function doesPatternContainSpreadElement(pattern) {
|
|
switch (pattern.kind) {
|
|
case 'ArrayPattern': {
|
|
for (const item of pattern.items) {
|
|
if (item.kind === 'Spread') {
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectPattern': {
|
|
for (const property of pattern.properties) {
|
|
if (property.kind === 'Spread') {
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(pattern, `Unexpected pattern kind \`${pattern.kind}\``);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function* eachPatternOperand(pattern) {
|
|
switch (pattern.kind) {
|
|
case 'ArrayPattern': {
|
|
for (const item of pattern.items) {
|
|
if (item.kind === 'Identifier') {
|
|
yield item;
|
|
}
|
|
else if (item.kind === 'Spread') {
|
|
yield item.place;
|
|
}
|
|
else if (item.kind === 'Hole') {
|
|
continue;
|
|
}
|
|
else {
|
|
assertExhaustive$1(item, `Unexpected item kind \`${item.kind}\``);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectPattern': {
|
|
for (const property of pattern.properties) {
|
|
if (property.kind === 'ObjectProperty') {
|
|
yield property.place;
|
|
}
|
|
else if (property.kind === 'Spread') {
|
|
yield property.place;
|
|
}
|
|
else {
|
|
assertExhaustive$1(property, `Unexpected item kind \`${property.kind}\``);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(pattern, `Unexpected pattern kind \`${pattern.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function* eachPatternItem(pattern) {
|
|
switch (pattern.kind) {
|
|
case 'ArrayPattern': {
|
|
for (const item of pattern.items) {
|
|
if (item.kind === 'Identifier') {
|
|
yield item;
|
|
}
|
|
else if (item.kind === 'Spread') {
|
|
yield item;
|
|
}
|
|
else if (item.kind === 'Hole') {
|
|
continue;
|
|
}
|
|
else {
|
|
assertExhaustive$1(item, `Unexpected item kind \`${item.kind}\``);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectPattern': {
|
|
for (const property of pattern.properties) {
|
|
if (property.kind === 'ObjectProperty') {
|
|
yield property.place;
|
|
}
|
|
else if (property.kind === 'Spread') {
|
|
yield property;
|
|
}
|
|
else {
|
|
assertExhaustive$1(property, `Unexpected item kind \`${property.kind}\``);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(pattern, `Unexpected pattern kind \`${pattern.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function mapInstructionLValues(instr, fn) {
|
|
switch (instr.value.kind) {
|
|
case 'DeclareLocal':
|
|
case 'StoreLocal': {
|
|
const lvalue = instr.value.lvalue;
|
|
lvalue.place = fn(lvalue.place);
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
mapPatternOperands(instr.value.lvalue.pattern, fn);
|
|
break;
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
instr.value.lvalue = fn(instr.value.lvalue);
|
|
break;
|
|
}
|
|
}
|
|
if (instr.lvalue !== null) {
|
|
instr.lvalue = fn(instr.lvalue);
|
|
}
|
|
}
|
|
function mapInstructionOperands(instr, fn) {
|
|
mapInstructionValueOperands(instr.value, fn);
|
|
}
|
|
function mapInstructionValueOperands(instrValue, fn) {
|
|
switch (instrValue.kind) {
|
|
case 'BinaryExpression': {
|
|
instrValue.left = fn(instrValue.left);
|
|
instrValue.right = fn(instrValue.right);
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
instrValue.object = fn(instrValue.object);
|
|
break;
|
|
}
|
|
case 'PropertyDelete': {
|
|
instrValue.object = fn(instrValue.object);
|
|
break;
|
|
}
|
|
case 'PropertyStore': {
|
|
instrValue.object = fn(instrValue.object);
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'ComputedLoad': {
|
|
instrValue.object = fn(instrValue.object);
|
|
instrValue.property = fn(instrValue.property);
|
|
break;
|
|
}
|
|
case 'ComputedDelete': {
|
|
instrValue.object = fn(instrValue.object);
|
|
instrValue.property = fn(instrValue.property);
|
|
break;
|
|
}
|
|
case 'ComputedStore': {
|
|
instrValue.object = fn(instrValue.object);
|
|
instrValue.property = fn(instrValue.property);
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'DeclareContext':
|
|
case 'DeclareLocal': {
|
|
break;
|
|
}
|
|
case 'LoadLocal':
|
|
case 'LoadContext': {
|
|
instrValue.place = fn(instrValue.place);
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'StoreContext': {
|
|
instrValue.lvalue.place = fn(instrValue.lvalue.place);
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'StoreGlobal': {
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'NewExpression':
|
|
case 'CallExpression': {
|
|
instrValue.callee = fn(instrValue.callee);
|
|
instrValue.args = mapCallArguments(instrValue.args, fn);
|
|
break;
|
|
}
|
|
case 'MethodCall': {
|
|
instrValue.receiver = fn(instrValue.receiver);
|
|
instrValue.property = fn(instrValue.property);
|
|
instrValue.args = mapCallArguments(instrValue.args, fn);
|
|
break;
|
|
}
|
|
case 'UnaryExpression': {
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'JsxExpression': {
|
|
if (instrValue.tag.kind === 'Identifier') {
|
|
instrValue.tag = fn(instrValue.tag);
|
|
}
|
|
for (const attribute of instrValue.props) {
|
|
switch (attribute.kind) {
|
|
case 'JsxAttribute': {
|
|
attribute.place = fn(attribute.place);
|
|
break;
|
|
}
|
|
case 'JsxSpreadAttribute': {
|
|
attribute.argument = fn(attribute.argument);
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(attribute, `Unexpected attribute kind \`${attribute.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
if (instrValue.children) {
|
|
instrValue.children = instrValue.children.map(p => fn(p));
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectExpression': {
|
|
for (const property of instrValue.properties) {
|
|
if (property.kind === 'ObjectProperty' &&
|
|
property.key.kind === 'computed') {
|
|
property.key.name = fn(property.key.name);
|
|
}
|
|
property.place = fn(property.place);
|
|
}
|
|
break;
|
|
}
|
|
case 'ArrayExpression': {
|
|
instrValue.elements = instrValue.elements.map(element => {
|
|
if (element.kind === 'Identifier') {
|
|
return fn(element);
|
|
}
|
|
else if (element.kind === 'Spread') {
|
|
element.place = fn(element.place);
|
|
return element;
|
|
}
|
|
else {
|
|
return element;
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
case 'JsxFragment': {
|
|
instrValue.children = instrValue.children.map(e => fn(e));
|
|
break;
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
instrValue.loweredFunc.func.context =
|
|
instrValue.loweredFunc.func.context.map(d => fn(d));
|
|
break;
|
|
}
|
|
case 'TaggedTemplateExpression': {
|
|
instrValue.tag = fn(instrValue.tag);
|
|
break;
|
|
}
|
|
case 'TypeCastExpression': {
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'TemplateLiteral': {
|
|
instrValue.subexprs = instrValue.subexprs.map(fn);
|
|
break;
|
|
}
|
|
case 'Await': {
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'GetIterator': {
|
|
instrValue.collection = fn(instrValue.collection);
|
|
break;
|
|
}
|
|
case 'IteratorNext': {
|
|
instrValue.iterator = fn(instrValue.iterator);
|
|
instrValue.collection = fn(instrValue.collection);
|
|
break;
|
|
}
|
|
case 'NextPropertyOf': {
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
instrValue.value = fn(instrValue.value);
|
|
break;
|
|
}
|
|
case 'StartMemoize': {
|
|
if (instrValue.deps != null) {
|
|
for (const dep of instrValue.deps) {
|
|
if (dep.root.kind === 'NamedLocal') {
|
|
dep.root.value = fn(dep.root.value);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'FinishMemoize': {
|
|
instrValue.decl = fn(instrValue.decl);
|
|
break;
|
|
}
|
|
case 'Debugger':
|
|
case 'RegExpLiteral':
|
|
case 'MetaProperty':
|
|
case 'LoadGlobal':
|
|
case 'UnsupportedNode':
|
|
case 'Primitive':
|
|
case 'JSXText': {
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(instrValue, 'Unexpected instruction kind');
|
|
}
|
|
}
|
|
}
|
|
function mapCallArguments(args, fn) {
|
|
return args.map(arg => {
|
|
if (arg.kind === 'Identifier') {
|
|
return fn(arg);
|
|
}
|
|
else {
|
|
arg.place = fn(arg.place);
|
|
return arg;
|
|
}
|
|
});
|
|
}
|
|
function mapPatternOperands(pattern, fn) {
|
|
switch (pattern.kind) {
|
|
case 'ArrayPattern': {
|
|
pattern.items = pattern.items.map(item => {
|
|
if (item.kind === 'Identifier') {
|
|
return fn(item);
|
|
}
|
|
else if (item.kind === 'Spread') {
|
|
item.place = fn(item.place);
|
|
return item;
|
|
}
|
|
else {
|
|
return item;
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
case 'ObjectPattern': {
|
|
for (const property of pattern.properties) {
|
|
property.place = fn(property.place);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(pattern, `Unexpected pattern kind \`${pattern.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function mapTerminalSuccessors(terminal, fn) {
|
|
switch (terminal.kind) {
|
|
case 'goto': {
|
|
const target = fn(terminal.block);
|
|
return {
|
|
kind: 'goto',
|
|
block: target,
|
|
variant: terminal.variant,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'if': {
|
|
const consequent = fn(terminal.consequent);
|
|
const alternate = fn(terminal.alternate);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'if',
|
|
test: terminal.test,
|
|
consequent,
|
|
alternate,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'branch': {
|
|
const consequent = fn(terminal.consequent);
|
|
const alternate = fn(terminal.alternate);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'branch',
|
|
test: terminal.test,
|
|
consequent,
|
|
alternate,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'switch': {
|
|
const cases = terminal.cases.map(case_ => {
|
|
const target = fn(case_.block);
|
|
return {
|
|
test: case_.test,
|
|
block: target,
|
|
};
|
|
});
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'switch',
|
|
test: terminal.test,
|
|
cases,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'logical': {
|
|
const test = fn(terminal.test);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'logical',
|
|
test,
|
|
fallthrough,
|
|
operator: terminal.operator,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'ternary': {
|
|
const test = fn(terminal.test);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'ternary',
|
|
test,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'optional': {
|
|
const test = fn(terminal.test);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'optional',
|
|
optional: terminal.optional,
|
|
test,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'return': {
|
|
return {
|
|
kind: 'return',
|
|
returnVariant: terminal.returnVariant,
|
|
loc: terminal.loc,
|
|
value: terminal.value,
|
|
id: makeInstructionId(0),
|
|
effects: terminal.effects,
|
|
};
|
|
}
|
|
case 'throw': {
|
|
return terminal;
|
|
}
|
|
case 'do-while': {
|
|
const loop = fn(terminal.loop);
|
|
const test = fn(terminal.test);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'do-while',
|
|
loc: terminal.loc,
|
|
test,
|
|
loop,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
};
|
|
}
|
|
case 'while': {
|
|
const test = fn(terminal.test);
|
|
const loop = fn(terminal.loop);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'while',
|
|
loc: terminal.loc,
|
|
test,
|
|
loop,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
};
|
|
}
|
|
case 'for': {
|
|
const init = fn(terminal.init);
|
|
const test = fn(terminal.test);
|
|
const update = terminal.update !== null ? fn(terminal.update) : null;
|
|
const loop = fn(terminal.loop);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'for',
|
|
loc: terminal.loc,
|
|
init,
|
|
test,
|
|
update,
|
|
loop,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
};
|
|
}
|
|
case 'for-of': {
|
|
const init = fn(terminal.init);
|
|
const loop = fn(terminal.loop);
|
|
const test = fn(terminal.test);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'for-of',
|
|
loc: terminal.loc,
|
|
init,
|
|
test,
|
|
loop,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
};
|
|
}
|
|
case 'for-in': {
|
|
const init = fn(terminal.init);
|
|
const loop = fn(terminal.loop);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'for-in',
|
|
loc: terminal.loc,
|
|
init,
|
|
loop,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
};
|
|
}
|
|
case 'label': {
|
|
const block = fn(terminal.block);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'label',
|
|
block,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'sequence': {
|
|
const block = fn(terminal.block);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'sequence',
|
|
block,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'maybe-throw': {
|
|
const continuation = fn(terminal.continuation);
|
|
const handler = terminal.handler !== null ? fn(terminal.handler) : null;
|
|
return {
|
|
kind: 'maybe-throw',
|
|
continuation,
|
|
handler,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
effects: terminal.effects,
|
|
};
|
|
}
|
|
case 'try': {
|
|
const block = fn(terminal.block);
|
|
const handler = fn(terminal.handler);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: 'try',
|
|
block,
|
|
handlerBinding: terminal.handlerBinding,
|
|
handler,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'scope':
|
|
case 'pruned-scope': {
|
|
const block = fn(terminal.block);
|
|
const fallthrough = fn(terminal.fallthrough);
|
|
return {
|
|
kind: terminal.kind,
|
|
scope: terminal.scope,
|
|
block,
|
|
fallthrough,
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
case 'unreachable':
|
|
case 'unsupported': {
|
|
return terminal;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, `Unexpected terminal kind \`${terminal.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function terminalHasFallthrough(terminal) {
|
|
switch (terminal.kind) {
|
|
case 'maybe-throw':
|
|
case 'goto':
|
|
case 'return':
|
|
case 'throw':
|
|
case 'unreachable':
|
|
case 'unsupported': {
|
|
return false;
|
|
}
|
|
case 'branch':
|
|
case 'try':
|
|
case 'do-while':
|
|
case 'for-of':
|
|
case 'for-in':
|
|
case 'for':
|
|
case 'if':
|
|
case 'label':
|
|
case 'logical':
|
|
case 'optional':
|
|
case 'sequence':
|
|
case 'switch':
|
|
case 'ternary':
|
|
case 'while':
|
|
case 'scope':
|
|
case 'pruned-scope': {
|
|
return true;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, `Unexpected terminal kind \`${terminal.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function terminalFallthrough(terminal) {
|
|
if (terminalHasFallthrough(terminal)) {
|
|
return terminal.fallthrough;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
function* eachTerminalSuccessor(terminal) {
|
|
switch (terminal.kind) {
|
|
case 'goto': {
|
|
yield terminal.block;
|
|
break;
|
|
}
|
|
case 'if': {
|
|
yield terminal.consequent;
|
|
yield terminal.alternate;
|
|
break;
|
|
}
|
|
case 'branch': {
|
|
yield terminal.consequent;
|
|
yield terminal.alternate;
|
|
break;
|
|
}
|
|
case 'switch': {
|
|
for (const case_ of terminal.cases) {
|
|
yield case_.block;
|
|
}
|
|
break;
|
|
}
|
|
case 'optional':
|
|
case 'ternary':
|
|
case 'logical': {
|
|
yield terminal.test;
|
|
break;
|
|
}
|
|
case 'return': {
|
|
break;
|
|
}
|
|
case 'throw': {
|
|
break;
|
|
}
|
|
case 'do-while': {
|
|
yield terminal.loop;
|
|
break;
|
|
}
|
|
case 'while': {
|
|
yield terminal.test;
|
|
break;
|
|
}
|
|
case 'for': {
|
|
yield terminal.init;
|
|
break;
|
|
}
|
|
case 'for-of': {
|
|
yield terminal.init;
|
|
break;
|
|
}
|
|
case 'for-in': {
|
|
yield terminal.init;
|
|
break;
|
|
}
|
|
case 'label': {
|
|
yield terminal.block;
|
|
break;
|
|
}
|
|
case 'sequence': {
|
|
yield terminal.block;
|
|
break;
|
|
}
|
|
case 'maybe-throw': {
|
|
yield terminal.continuation;
|
|
if (terminal.handler !== null) {
|
|
yield terminal.handler;
|
|
}
|
|
break;
|
|
}
|
|
case 'try': {
|
|
yield terminal.block;
|
|
break;
|
|
}
|
|
case 'scope':
|
|
case 'pruned-scope': {
|
|
yield terminal.block;
|
|
break;
|
|
}
|
|
case 'unreachable':
|
|
case 'unsupported':
|
|
break;
|
|
default: {
|
|
assertExhaustive$1(terminal, `Unexpected terminal kind \`${terminal.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function mapTerminalOperands(terminal, fn) {
|
|
switch (terminal.kind) {
|
|
case 'if': {
|
|
terminal.test = fn(terminal.test);
|
|
break;
|
|
}
|
|
case 'branch': {
|
|
terminal.test = fn(terminal.test);
|
|
break;
|
|
}
|
|
case 'switch': {
|
|
terminal.test = fn(terminal.test);
|
|
for (const case_ of terminal.cases) {
|
|
if (case_.test === null) {
|
|
continue;
|
|
}
|
|
case_.test = fn(case_.test);
|
|
}
|
|
break;
|
|
}
|
|
case 'return':
|
|
case 'throw': {
|
|
terminal.value = fn(terminal.value);
|
|
break;
|
|
}
|
|
case 'try': {
|
|
if (terminal.handlerBinding !== null) {
|
|
terminal.handlerBinding = fn(terminal.handlerBinding);
|
|
}
|
|
else {
|
|
terminal.handlerBinding = null;
|
|
}
|
|
break;
|
|
}
|
|
case 'maybe-throw':
|
|
case 'sequence':
|
|
case 'label':
|
|
case 'optional':
|
|
case 'ternary':
|
|
case 'logical':
|
|
case 'do-while':
|
|
case 'while':
|
|
case 'for':
|
|
case 'for-of':
|
|
case 'for-in':
|
|
case 'goto':
|
|
case 'unreachable':
|
|
case 'unsupported':
|
|
case 'scope':
|
|
case 'pruned-scope': {
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, `Unexpected terminal kind \`${terminal.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function* eachTerminalOperand(terminal) {
|
|
switch (terminal.kind) {
|
|
case 'if': {
|
|
yield terminal.test;
|
|
break;
|
|
}
|
|
case 'branch': {
|
|
yield terminal.test;
|
|
break;
|
|
}
|
|
case 'switch': {
|
|
yield terminal.test;
|
|
for (const case_ of terminal.cases) {
|
|
if (case_.test === null) {
|
|
continue;
|
|
}
|
|
yield case_.test;
|
|
}
|
|
break;
|
|
}
|
|
case 'return':
|
|
case 'throw': {
|
|
yield terminal.value;
|
|
break;
|
|
}
|
|
case 'try': {
|
|
if (terminal.handlerBinding !== null) {
|
|
yield terminal.handlerBinding;
|
|
}
|
|
break;
|
|
}
|
|
case 'maybe-throw':
|
|
case 'sequence':
|
|
case 'label':
|
|
case 'optional':
|
|
case 'ternary':
|
|
case 'logical':
|
|
case 'do-while':
|
|
case 'while':
|
|
case 'for':
|
|
case 'for-of':
|
|
case 'for-in':
|
|
case 'goto':
|
|
case 'unreachable':
|
|
case 'unsupported':
|
|
case 'scope':
|
|
case 'pruned-scope': {
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, `Unexpected terminal kind \`${terminal.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
class ScopeBlockTraversal {
|
|
constructor() {
|
|
_ScopeBlockTraversal_activeScopes.set(this, []);
|
|
this.blockInfos = new Map();
|
|
}
|
|
recordScopes(block) {
|
|
var _a, _b;
|
|
const blockInfo = this.blockInfos.get(block.id);
|
|
if ((blockInfo === null || blockInfo === void 0 ? void 0 : blockInfo.kind) === 'begin') {
|
|
__classPrivateFieldGet(this, _ScopeBlockTraversal_activeScopes, "f").push(blockInfo.scope.id);
|
|
}
|
|
else if ((blockInfo === null || blockInfo === void 0 ? void 0 : blockInfo.kind) === 'end') {
|
|
const top = __classPrivateFieldGet(this, _ScopeBlockTraversal_activeScopes, "f").at(-1);
|
|
CompilerError.invariant(blockInfo.scope.id === top, {
|
|
reason: 'Expected traversed block fallthrough to match top-most active scope',
|
|
loc: (_b = (_a = block.instructions[0]) === null || _a === void 0 ? void 0 : _a.loc) !== null && _b !== void 0 ? _b : block.terminal.loc,
|
|
});
|
|
__classPrivateFieldGet(this, _ScopeBlockTraversal_activeScopes, "f").pop();
|
|
}
|
|
if (block.terminal.kind === 'scope' ||
|
|
block.terminal.kind === 'pruned-scope') {
|
|
CompilerError.invariant(!this.blockInfos.has(block.terminal.block) &&
|
|
!this.blockInfos.has(block.terminal.fallthrough), {
|
|
reason: 'Expected unique scope blocks and fallthroughs',
|
|
loc: block.terminal.loc,
|
|
});
|
|
this.blockInfos.set(block.terminal.block, {
|
|
kind: 'begin',
|
|
scope: block.terminal.scope,
|
|
pruned: block.terminal.kind === 'pruned-scope',
|
|
fallthrough: block.terminal.fallthrough,
|
|
});
|
|
this.blockInfos.set(block.terminal.fallthrough, {
|
|
kind: 'end',
|
|
scope: block.terminal.scope,
|
|
pruned: block.terminal.kind === 'pruned-scope',
|
|
});
|
|
}
|
|
}
|
|
isScopeActive(scopeId) {
|
|
return __classPrivateFieldGet(this, _ScopeBlockTraversal_activeScopes, "f").indexOf(scopeId) !== -1;
|
|
}
|
|
get currentScope() {
|
|
var _a;
|
|
return (_a = __classPrivateFieldGet(this, _ScopeBlockTraversal_activeScopes, "f").at(-1)) !== null && _a !== void 0 ? _a : null;
|
|
}
|
|
}
|
|
_ScopeBlockTraversal_activeScopes = new WeakMap();
|
|
|
|
function assertConsistentIdentifiers(fn) {
|
|
const identifiers = new Map();
|
|
const assignments = new Set();
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
validate(identifiers, phi.place.identifier);
|
|
for (const [, operand] of phi.operands) {
|
|
validate(identifiers, operand.identifier);
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
CompilerError.invariant(instr.lvalue.identifier.name === null, {
|
|
reason: `Expected all lvalues to be temporaries`,
|
|
description: `Found named lvalue \`${instr.lvalue.identifier.name}\``,
|
|
loc: instr.lvalue.loc,
|
|
});
|
|
CompilerError.invariant(!assignments.has(instr.lvalue.identifier.id), {
|
|
reason: `Expected lvalues to be assigned exactly once`,
|
|
description: `Found duplicate assignment of '${printPlace(instr.lvalue)}'`,
|
|
loc: instr.lvalue.loc,
|
|
});
|
|
assignments.add(instr.lvalue.identifier.id);
|
|
for (const operand of eachInstructionLValue(instr)) {
|
|
validate(identifiers, operand.identifier, operand.loc);
|
|
}
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
validate(identifiers, operand.identifier, operand.loc);
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
validate(identifiers, operand.identifier, operand.loc);
|
|
}
|
|
}
|
|
}
|
|
function validate(identifiers, identifier, loc = null) {
|
|
const previous = identifiers.get(identifier.id);
|
|
if (previous === undefined) {
|
|
identifiers.set(identifier.id, identifier);
|
|
}
|
|
else {
|
|
CompilerError.invariant(identifier === previous, {
|
|
reason: `Duplicate identifier object`,
|
|
description: `Found duplicate identifier object for id ${identifier.id}`,
|
|
loc: loc !== null && loc !== void 0 ? loc : GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
|
|
function assertTerminalSuccessorsExist(fn) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
mapTerminalSuccessors(block.terminal, successor => {
|
|
var _a;
|
|
CompilerError.invariant(fn.body.blocks.has(successor), {
|
|
reason: `Terminal successor references unknown block`,
|
|
description: `Block bb${successor} does not exist for terminal '${printTerminal(block.terminal)}'`,
|
|
loc: (_a = block.terminal.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
});
|
|
return successor;
|
|
});
|
|
}
|
|
}
|
|
function assertTerminalPredsExist(fn) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const pred of block.preds) {
|
|
const predBlock = fn.body.blocks.get(pred);
|
|
CompilerError.invariant(predBlock != null, {
|
|
reason: 'Expected predecessor block to exist',
|
|
description: `Block ${block.id} references non-existent ${pred}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
CompilerError.invariant([...eachTerminalSuccessor(predBlock.terminal)].includes(block.id), {
|
|
reason: 'Terminal successor does not reference correct predecessor',
|
|
description: `Block bb${block.id} has bb${predBlock.id} as a predecessor, but bb${predBlock.id}'s successors do not include bb${block.id}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function getScopes(fn) {
|
|
const scopes = new Set();
|
|
function visitPlace(place) {
|
|
const scope = place.identifier.scope;
|
|
if (scope != null) {
|
|
if (scope.range.start !== scope.range.end) {
|
|
scopes.add(scope);
|
|
}
|
|
}
|
|
}
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
for (const operand of eachInstructionLValue(instr)) {
|
|
visitPlace(operand);
|
|
}
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
visitPlace(operand);
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
visitPlace(operand);
|
|
}
|
|
}
|
|
return scopes;
|
|
}
|
|
function rangePreOrderComparator(a, b) {
|
|
const startDiff = a.start - b.start;
|
|
if (startDiff !== 0)
|
|
return startDiff;
|
|
return b.end - a.end;
|
|
}
|
|
function recursivelyTraverseItems(items, getRange, context, enter, exit) {
|
|
items.sort((a, b) => rangePreOrderComparator(getRange(a), getRange(b)));
|
|
let activeItems = [];
|
|
const ranges = items.map(getRange);
|
|
for (let i = 0; i < items.length; i++) {
|
|
const curr = items[i];
|
|
const currRange = ranges[i];
|
|
for (let i = activeItems.length - 1; i >= 0; i--) {
|
|
const maybeParent = activeItems[i];
|
|
const maybeParentRange = getRange(maybeParent);
|
|
const disjoint = currRange.start >= maybeParentRange.end;
|
|
const nested = currRange.end <= maybeParentRange.end;
|
|
CompilerError.invariant(disjoint || nested, {
|
|
reason: 'Invalid nesting in program blocks or scopes',
|
|
description: `Items overlap but are not nested: ${maybeParentRange.start}:${maybeParentRange.end}(${currRange.start}:${currRange.end})`,
|
|
loc: GeneratedSource,
|
|
});
|
|
if (disjoint) {
|
|
exit(maybeParent, context);
|
|
activeItems.length = i;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
enter(curr, context);
|
|
activeItems.push(curr);
|
|
}
|
|
let curr = activeItems.pop();
|
|
while (curr != null) {
|
|
exit(curr, context);
|
|
curr = activeItems.pop();
|
|
}
|
|
}
|
|
const no_op = () => { };
|
|
function assertValidBlockNesting(fn) {
|
|
var _a, _b;
|
|
const scopes = getScopes(fn);
|
|
const blocks = [...scopes].map(scope => (Object.assign({ kind: 'Scope', id: scope.id }, scope.range)));
|
|
for (const [, block] of fn.body.blocks) {
|
|
const fallthroughId = terminalFallthrough(block.terminal);
|
|
if (fallthroughId != null) {
|
|
const fallthrough = fn.body.blocks.get(fallthroughId);
|
|
const end = (_b = (_a = fallthrough.instructions[0]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : fallthrough.terminal.id;
|
|
blocks.push({
|
|
kind: 'ProgramBlockSubtree',
|
|
id: block.id,
|
|
start: block.terminal.id,
|
|
end,
|
|
});
|
|
}
|
|
}
|
|
recursivelyTraverseItems(blocks, block => block, null, no_op, no_op);
|
|
}
|
|
|
|
function assertValidMutableRanges(fn) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
visit$1(phi.place, `phi for block bb${block.id}`);
|
|
for (const [pred, operand] of phi.operands) {
|
|
visit$1(operand, `phi predecessor bb${pred} for block bb${block.id}`);
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
for (const operand of eachInstructionLValue(instr)) {
|
|
visit$1(operand, `instruction [${instr.id}]`);
|
|
}
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
visit$1(operand, `instruction [${instr.id}]`);
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
visit$1(operand, `terminal [${block.terminal.id}]`);
|
|
}
|
|
}
|
|
}
|
|
function visit$1(place, description) {
|
|
validateMutableRange(place, place.identifier.mutableRange, description);
|
|
if (place.identifier.scope !== null) {
|
|
validateMutableRange(place, place.identifier.scope.range, description);
|
|
}
|
|
}
|
|
function validateMutableRange(place, range, description) {
|
|
CompilerError.invariant((range.start === 0 && range.end === 0) || range.end > range.start, {
|
|
reason: `Invalid mutable range: [${range.start}:${range.end}]`,
|
|
description: `${printPlace(place)} in ${description}`,
|
|
loc: place.loc,
|
|
});
|
|
}
|
|
|
|
var _HIRBuilder_instances, _HIRBuilder_completed, _HIRBuilder_current, _HIRBuilder_entry, _HIRBuilder_scopes, _HIRBuilder_context, _HIRBuilder_bindings, _HIRBuilder_env, _HIRBuilder_exceptionHandlerStack, _HIRBuilder_resolveBabelBinding;
|
|
function newBlock(id, kind) {
|
|
return { id, kind, instructions: [] };
|
|
}
|
|
class HIRBuilder {
|
|
get nextIdentifierId() {
|
|
return __classPrivateFieldGet(this, _HIRBuilder_env, "f").nextIdentifierId;
|
|
}
|
|
get context() {
|
|
return __classPrivateFieldGet(this, _HIRBuilder_context, "f");
|
|
}
|
|
get bindings() {
|
|
return __classPrivateFieldGet(this, _HIRBuilder_bindings, "f");
|
|
}
|
|
get environment() {
|
|
return __classPrivateFieldGet(this, _HIRBuilder_env, "f");
|
|
}
|
|
constructor(env, options) {
|
|
var _a, _b, _c;
|
|
_HIRBuilder_instances.add(this);
|
|
_HIRBuilder_completed.set(this, new Map());
|
|
_HIRBuilder_current.set(this, void 0);
|
|
_HIRBuilder_entry.set(this, void 0);
|
|
_HIRBuilder_scopes.set(this, []);
|
|
_HIRBuilder_context.set(this, void 0);
|
|
_HIRBuilder_bindings.set(this, void 0);
|
|
_HIRBuilder_env.set(this, void 0);
|
|
_HIRBuilder_exceptionHandlerStack.set(this, []);
|
|
this.fbtDepth = 0;
|
|
__classPrivateFieldSet(this, _HIRBuilder_env, env, "f");
|
|
__classPrivateFieldSet(this, _HIRBuilder_bindings, (_a = options === null || options === void 0 ? void 0 : options.bindings) !== null && _a !== void 0 ? _a : new Map(), "f");
|
|
__classPrivateFieldSet(this, _HIRBuilder_context, (_b = options === null || options === void 0 ? void 0 : options.context) !== null && _b !== void 0 ? _b : new Map(), "f");
|
|
__classPrivateFieldSet(this, _HIRBuilder_entry, makeBlockId(env.nextBlockId), "f");
|
|
__classPrivateFieldSet(this, _HIRBuilder_current, newBlock(__classPrivateFieldGet(this, _HIRBuilder_entry, "f"), (_c = options === null || options === void 0 ? void 0 : options.entryBlockKind) !== null && _c !== void 0 ? _c : 'block'), "f");
|
|
}
|
|
recordError(error) {
|
|
__classPrivateFieldGet(this, _HIRBuilder_env, "f").recordError(error);
|
|
}
|
|
currentBlockKind() {
|
|
return __classPrivateFieldGet(this, _HIRBuilder_current, "f").kind;
|
|
}
|
|
push(instruction) {
|
|
__classPrivateFieldGet(this, _HIRBuilder_current, "f").instructions.push(instruction);
|
|
const exceptionHandler = __classPrivateFieldGet(this, _HIRBuilder_exceptionHandlerStack, "f").at(-1);
|
|
if (exceptionHandler !== undefined) {
|
|
const continuationBlock = this.reserve(this.currentBlockKind());
|
|
this.terminateWithContinuation({
|
|
kind: 'maybe-throw',
|
|
continuation: continuationBlock.id,
|
|
handler: exceptionHandler,
|
|
id: makeInstructionId(0),
|
|
loc: instruction.loc,
|
|
effects: null,
|
|
}, continuationBlock);
|
|
}
|
|
}
|
|
enterTryCatch(handler, fn) {
|
|
__classPrivateFieldGet(this, _HIRBuilder_exceptionHandlerStack, "f").push(handler);
|
|
fn();
|
|
__classPrivateFieldGet(this, _HIRBuilder_exceptionHandlerStack, "f").pop();
|
|
}
|
|
resolveThrowHandler() {
|
|
const handler = __classPrivateFieldGet(this, _HIRBuilder_exceptionHandlerStack, "f").at(-1);
|
|
return handler !== null && handler !== void 0 ? handler : null;
|
|
}
|
|
makeTemporary(loc) {
|
|
const id = this.nextIdentifierId;
|
|
return makeTemporaryIdentifier(id, loc);
|
|
}
|
|
resolveIdentifier(path) {
|
|
const originalName = path.node.name;
|
|
const babelBinding = __classPrivateFieldGet(this, _HIRBuilder_instances, "m", _HIRBuilder_resolveBabelBinding).call(this, path);
|
|
if (babelBinding == null) {
|
|
return { kind: 'Global', name: originalName };
|
|
}
|
|
const outerBinding = __classPrivateFieldGet(this, _HIRBuilder_env, "f").parentFunction.scope.parent.getBinding(originalName);
|
|
if (babelBinding === outerBinding) {
|
|
const path = babelBinding.path;
|
|
if (path.isImportDefaultSpecifier()) {
|
|
const importDeclaration = path.parentPath;
|
|
return {
|
|
kind: 'ImportDefault',
|
|
name: originalName,
|
|
module: importDeclaration.node.source.value,
|
|
};
|
|
}
|
|
else if (path.isImportSpecifier()) {
|
|
const importDeclaration = path.parentPath;
|
|
return {
|
|
kind: 'ImportSpecifier',
|
|
name: originalName,
|
|
module: importDeclaration.node.source.value,
|
|
imported: path.node.imported.type === 'Identifier'
|
|
? path.node.imported.name
|
|
: path.node.imported.value,
|
|
};
|
|
}
|
|
else if (path.isImportNamespaceSpecifier()) {
|
|
const importDeclaration = path.parentPath;
|
|
return {
|
|
kind: 'ImportNamespace',
|
|
name: originalName,
|
|
module: importDeclaration.node.source.value,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
kind: 'ModuleLocal',
|
|
name: originalName,
|
|
};
|
|
}
|
|
}
|
|
const resolvedBinding = this.resolveBinding(babelBinding.identifier);
|
|
if (resolvedBinding.name && resolvedBinding.name.value !== originalName) {
|
|
babelBinding.scope.rename(originalName, resolvedBinding.name.value);
|
|
}
|
|
return {
|
|
kind: 'Identifier',
|
|
identifier: resolvedBinding,
|
|
bindingKind: babelBinding.kind,
|
|
};
|
|
}
|
|
isContextIdentifier(path) {
|
|
const binding = __classPrivateFieldGet(this, _HIRBuilder_instances, "m", _HIRBuilder_resolveBabelBinding).call(this, path);
|
|
if (binding) {
|
|
const outerBinding = __classPrivateFieldGet(this, _HIRBuilder_env, "f").parentFunction.scope.parent.getBinding(path.node.name);
|
|
if (binding === outerBinding) {
|
|
return false;
|
|
}
|
|
return __classPrivateFieldGet(this, _HIRBuilder_env, "f").isContextIdentifier(binding.identifier);
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
resolveBinding(node) {
|
|
var _a, _b, _c;
|
|
if (node.name === 'fbt') {
|
|
this.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Support local variables named `fbt`',
|
|
description: 'Local variables named `fbt` may conflict with the fbt plugin and are not yet supported',
|
|
loc: (_a = node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
if (node.name === 'this') {
|
|
this.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.UnsupportedSyntax,
|
|
reason: '`this` is not supported syntax',
|
|
description: 'React Compiler does not support compiling functions that use `this`',
|
|
loc: (_b = node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
const originalName = node.name;
|
|
let name = originalName;
|
|
let index = 0;
|
|
while (true) {
|
|
const mapping = __classPrivateFieldGet(this, _HIRBuilder_bindings, "f").get(name);
|
|
if (mapping === undefined) {
|
|
const id = this.nextIdentifierId;
|
|
const identifier = {
|
|
id,
|
|
declarationId: makeDeclarationId(id),
|
|
name: makeIdentifierName(name),
|
|
mutableRange: {
|
|
start: makeInstructionId(0),
|
|
end: makeInstructionId(0),
|
|
},
|
|
scope: null,
|
|
type: makeType(),
|
|
loc: (_c = node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
};
|
|
__classPrivateFieldGet(this, _HIRBuilder_env, "f").programContext.addNewReference(name);
|
|
__classPrivateFieldGet(this, _HIRBuilder_bindings, "f").set(name, { node, identifier });
|
|
return identifier;
|
|
}
|
|
else if (mapping.node === node) {
|
|
return mapping.identifier;
|
|
}
|
|
else {
|
|
name = `${originalName}_${index++}`;
|
|
}
|
|
}
|
|
}
|
|
build() {
|
|
var _a, _b;
|
|
let ir = {
|
|
blocks: __classPrivateFieldGet(this, _HIRBuilder_completed, "f"),
|
|
entry: __classPrivateFieldGet(this, _HIRBuilder_entry, "f"),
|
|
};
|
|
const rpoBlocks = getReversePostorderedBlocks(ir);
|
|
for (const [id, block] of ir.blocks) {
|
|
if (!rpoBlocks.has(id) &&
|
|
block.instructions.some(instr => instr.value.kind === 'FunctionExpression')) {
|
|
this.recordError(new CompilerErrorDetail({
|
|
reason: `Support functions with unreachable code that may contain hoisted declarations`,
|
|
loc: (_b = (_a = block.instructions[0]) === null || _a === void 0 ? void 0 : _a.loc) !== null && _b !== void 0 ? _b : block.terminal.loc,
|
|
description: null,
|
|
suggestions: null,
|
|
category: ErrorCategory.Todo,
|
|
}));
|
|
}
|
|
}
|
|
ir.blocks = rpoBlocks;
|
|
removeUnreachableForUpdates(ir);
|
|
removeDeadDoWhileStatements(ir);
|
|
removeUnnecessaryTryCatch(ir);
|
|
markInstructionIds(ir);
|
|
markPredecessors(ir);
|
|
return ir;
|
|
}
|
|
terminate(terminal, nextBlockKind) {
|
|
const { id: blockId, kind, instructions } = __classPrivateFieldGet(this, _HIRBuilder_current, "f");
|
|
__classPrivateFieldGet(this, _HIRBuilder_completed, "f").set(blockId, {
|
|
kind,
|
|
id: blockId,
|
|
instructions,
|
|
terminal,
|
|
preds: new Set(),
|
|
phis: new Set(),
|
|
});
|
|
if (nextBlockKind) {
|
|
const nextId = __classPrivateFieldGet(this, _HIRBuilder_env, "f").nextBlockId;
|
|
__classPrivateFieldSet(this, _HIRBuilder_current, newBlock(nextId, nextBlockKind), "f");
|
|
}
|
|
return blockId;
|
|
}
|
|
terminateWithContinuation(terminal, continuation) {
|
|
const { id: blockId, kind, instructions } = __classPrivateFieldGet(this, _HIRBuilder_current, "f");
|
|
__classPrivateFieldGet(this, _HIRBuilder_completed, "f").set(blockId, {
|
|
kind: kind,
|
|
id: blockId,
|
|
instructions,
|
|
terminal: terminal,
|
|
preds: new Set(),
|
|
phis: new Set(),
|
|
});
|
|
__classPrivateFieldSet(this, _HIRBuilder_current, continuation, "f");
|
|
}
|
|
reserve(kind) {
|
|
return newBlock(makeBlockId(__classPrivateFieldGet(this, _HIRBuilder_env, "f").nextBlockId), kind);
|
|
}
|
|
complete(block, terminal) {
|
|
const { id: blockId, kind, instructions } = block;
|
|
__classPrivateFieldGet(this, _HIRBuilder_completed, "f").set(blockId, {
|
|
kind,
|
|
id: blockId,
|
|
instructions,
|
|
terminal,
|
|
preds: new Set(),
|
|
phis: new Set(),
|
|
});
|
|
}
|
|
enterReserved(wip, fn) {
|
|
const current = __classPrivateFieldGet(this, _HIRBuilder_current, "f");
|
|
__classPrivateFieldSet(this, _HIRBuilder_current, wip, "f");
|
|
const terminal = fn();
|
|
const { id: blockId, kind, instructions } = __classPrivateFieldGet(this, _HIRBuilder_current, "f");
|
|
__classPrivateFieldGet(this, _HIRBuilder_completed, "f").set(blockId, {
|
|
kind,
|
|
id: blockId,
|
|
instructions,
|
|
terminal,
|
|
preds: new Set(),
|
|
phis: new Set(),
|
|
});
|
|
__classPrivateFieldSet(this, _HIRBuilder_current, current, "f");
|
|
}
|
|
enter(nextBlockKind, fn) {
|
|
const wip = this.reserve(nextBlockKind);
|
|
this.enterReserved(wip, () => {
|
|
return fn(wip.id);
|
|
});
|
|
return wip.id;
|
|
}
|
|
label(label, breakBlock, fn) {
|
|
__classPrivateFieldGet(this, _HIRBuilder_scopes, "f").push({
|
|
kind: 'label',
|
|
breakBlock,
|
|
label,
|
|
});
|
|
const value = fn();
|
|
const last = __classPrivateFieldGet(this, _HIRBuilder_scopes, "f").pop();
|
|
CompilerError.invariant(last != null &&
|
|
last.kind === 'label' &&
|
|
last.label === label &&
|
|
last.breakBlock === breakBlock, {
|
|
reason: 'Mismatched label',
|
|
loc: GeneratedSource,
|
|
});
|
|
return value;
|
|
}
|
|
switch(label, breakBlock, fn) {
|
|
__classPrivateFieldGet(this, _HIRBuilder_scopes, "f").push({
|
|
kind: 'switch',
|
|
breakBlock,
|
|
label,
|
|
});
|
|
const value = fn();
|
|
const last = __classPrivateFieldGet(this, _HIRBuilder_scopes, "f").pop();
|
|
CompilerError.invariant(last != null &&
|
|
last.kind === 'switch' &&
|
|
last.label === label &&
|
|
last.breakBlock === breakBlock, {
|
|
reason: 'Mismatched label',
|
|
loc: GeneratedSource,
|
|
});
|
|
return value;
|
|
}
|
|
loop(label, continueBlock, breakBlock, fn) {
|
|
__classPrivateFieldGet(this, _HIRBuilder_scopes, "f").push({
|
|
kind: 'loop',
|
|
label,
|
|
continueBlock,
|
|
breakBlock,
|
|
});
|
|
const value = fn();
|
|
const last = __classPrivateFieldGet(this, _HIRBuilder_scopes, "f").pop();
|
|
CompilerError.invariant(last != null &&
|
|
last.kind === 'loop' &&
|
|
last.label === label &&
|
|
last.continueBlock === continueBlock &&
|
|
last.breakBlock === breakBlock, {
|
|
reason: 'Mismatched loops',
|
|
loc: GeneratedSource,
|
|
});
|
|
return value;
|
|
}
|
|
lookupBreak(label) {
|
|
for (let ii = __classPrivateFieldGet(this, _HIRBuilder_scopes, "f").length - 1; ii >= 0; ii--) {
|
|
const scope = __classPrivateFieldGet(this, _HIRBuilder_scopes, "f")[ii];
|
|
if ((label === null &&
|
|
(scope.kind === 'loop' || scope.kind === 'switch')) ||
|
|
label === scope.label) {
|
|
return scope.breakBlock;
|
|
}
|
|
}
|
|
CompilerError.invariant(false, {
|
|
reason: 'Expected a loop or switch to be in scope',
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
lookupContinue(label) {
|
|
for (let ii = __classPrivateFieldGet(this, _HIRBuilder_scopes, "f").length - 1; ii >= 0; ii--) {
|
|
const scope = __classPrivateFieldGet(this, _HIRBuilder_scopes, "f")[ii];
|
|
if (scope.kind === 'loop') {
|
|
if (label === null || label === scope.label) {
|
|
return scope.continueBlock;
|
|
}
|
|
}
|
|
else if (label !== null && scope.label === label) {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Continue may only refer to a labeled loop',
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
CompilerError.invariant(false, {
|
|
reason: 'Expected a loop to be in scope',
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
_HIRBuilder_completed = new WeakMap(), _HIRBuilder_current = new WeakMap(), _HIRBuilder_entry = new WeakMap(), _HIRBuilder_scopes = new WeakMap(), _HIRBuilder_context = new WeakMap(), _HIRBuilder_bindings = new WeakMap(), _HIRBuilder_env = new WeakMap(), _HIRBuilder_exceptionHandlerStack = new WeakMap(), _HIRBuilder_instances = new WeakSet(), _HIRBuilder_resolveBabelBinding = function _HIRBuilder_resolveBabelBinding(path) {
|
|
const originalName = path.node.name;
|
|
const binding = path.scope.getBinding(originalName);
|
|
if (binding == null) {
|
|
return null;
|
|
}
|
|
return binding;
|
|
};
|
|
function removeUnreachableForUpdates(fn) {
|
|
for (const [, block] of fn.blocks) {
|
|
if (block.terminal.kind === 'for' &&
|
|
block.terminal.update !== null &&
|
|
!fn.blocks.has(block.terminal.update)) {
|
|
block.terminal.update = null;
|
|
}
|
|
}
|
|
}
|
|
function removeDeadDoWhileStatements(func) {
|
|
const visited = new Set();
|
|
for (const [_, block] of func.blocks) {
|
|
visited.add(block.id);
|
|
}
|
|
for (const [_, block] of func.blocks) {
|
|
if (block.terminal.kind === 'do-while') {
|
|
if (!visited.has(block.terminal.test)) {
|
|
block.terminal = {
|
|
kind: 'goto',
|
|
block: block.terminal.loop,
|
|
variant: GotoVariant.Break,
|
|
id: block.terminal.id,
|
|
loc: block.terminal.loc,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function reversePostorderBlocks(func) {
|
|
const rpoBlocks = getReversePostorderedBlocks(func);
|
|
func.blocks = rpoBlocks;
|
|
}
|
|
function getReversePostorderedBlocks(func) {
|
|
const visited = new Set();
|
|
const used = new Set();
|
|
const usedFallthroughs = new Set();
|
|
const postorder = [];
|
|
function visit(blockId, isUsed) {
|
|
const wasUsed = used.has(blockId);
|
|
const wasVisited = visited.has(blockId);
|
|
visited.add(blockId);
|
|
if (isUsed) {
|
|
used.add(blockId);
|
|
}
|
|
if (wasVisited && (wasUsed || !isUsed)) {
|
|
return;
|
|
}
|
|
const block = func.blocks.get(blockId);
|
|
CompilerError.invariant(block != null, {
|
|
reason: '[HIRBuilder] Unexpected null block',
|
|
description: `expected block ${blockId} to exist`,
|
|
loc: GeneratedSource,
|
|
});
|
|
const successors = [...eachTerminalSuccessor(block.terminal)].reverse();
|
|
const fallthrough = terminalFallthrough(block.terminal);
|
|
if (fallthrough != null) {
|
|
if (isUsed) {
|
|
usedFallthroughs.add(fallthrough);
|
|
}
|
|
visit(fallthrough, false);
|
|
}
|
|
for (const successor of successors) {
|
|
visit(successor, isUsed);
|
|
}
|
|
if (!wasVisited) {
|
|
postorder.push(blockId);
|
|
}
|
|
}
|
|
visit(func.entry, true);
|
|
const blocks = new Map();
|
|
for (const blockId of postorder.reverse()) {
|
|
const block = func.blocks.get(blockId);
|
|
if (used.has(blockId)) {
|
|
blocks.set(blockId, func.blocks.get(blockId));
|
|
}
|
|
else if (usedFallthroughs.has(blockId)) {
|
|
blocks.set(blockId, Object.assign(Object.assign({}, block), { instructions: [], terminal: {
|
|
kind: 'unreachable',
|
|
id: block.terminal.id,
|
|
loc: block.terminal.loc,
|
|
} }));
|
|
}
|
|
}
|
|
return blocks;
|
|
}
|
|
function markInstructionIds(func) {
|
|
let id = 0;
|
|
const visited = new Set();
|
|
for (const [_, block] of func.blocks) {
|
|
for (const instr of block.instructions) {
|
|
CompilerError.invariant(!visited.has(instr), {
|
|
reason: `${printInstruction(instr)} already visited!`,
|
|
loc: instr.loc,
|
|
});
|
|
visited.add(instr);
|
|
instr.id = makeInstructionId(++id);
|
|
}
|
|
block.terminal.id = makeInstructionId(++id);
|
|
}
|
|
}
|
|
function markPredecessors(func) {
|
|
for (const [, block] of func.blocks) {
|
|
block.preds.clear();
|
|
}
|
|
const visited = new Set();
|
|
function visit(blockId, prevBlock) {
|
|
const block = func.blocks.get(blockId);
|
|
if (block == null) {
|
|
return;
|
|
}
|
|
CompilerError.invariant(block != null, {
|
|
reason: 'unexpected missing block',
|
|
description: `block ${blockId}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
if (prevBlock) {
|
|
block.preds.add(prevBlock.id);
|
|
}
|
|
if (visited.has(blockId)) {
|
|
return;
|
|
}
|
|
visited.add(blockId);
|
|
const { terminal } = block;
|
|
for (const successor of eachTerminalSuccessor(terminal)) {
|
|
visit(successor, block);
|
|
}
|
|
}
|
|
visit(func.entry, null);
|
|
}
|
|
function removeUnnecessaryTryCatch(fn) {
|
|
for (const [, block] of fn.blocks) {
|
|
if (block.terminal.kind === 'try' &&
|
|
!fn.blocks.has(block.terminal.handler)) {
|
|
const handlerId = block.terminal.handler;
|
|
const fallthroughId = block.terminal.fallthrough;
|
|
const fallthrough = fn.blocks.get(fallthroughId);
|
|
block.terminal = {
|
|
kind: 'goto',
|
|
block: block.terminal.block,
|
|
id: makeInstructionId(0),
|
|
loc: block.terminal.loc,
|
|
variant: GotoVariant.Break,
|
|
};
|
|
if (fallthrough != null) {
|
|
if (fallthrough.preds.size === 1 && fallthrough.preds.has(handlerId)) {
|
|
fn.blocks.delete(fallthroughId);
|
|
}
|
|
else {
|
|
fallthrough.preds.delete(handlerId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function createTemporaryPlace(env, loc) {
|
|
return {
|
|
kind: 'Identifier',
|
|
identifier: makeTemporaryIdentifier(env.nextIdentifierId, loc),
|
|
reactive: false,
|
|
effect: Effect.Unknown,
|
|
loc: GeneratedSource,
|
|
};
|
|
}
|
|
function clonePlaceToTemporary(env, place) {
|
|
const temp = createTemporaryPlace(env, place.loc);
|
|
temp.effect = place.effect;
|
|
temp.identifier.type = place.identifier.type;
|
|
temp.reactive = place.reactive;
|
|
return temp;
|
|
}
|
|
function fixScopeAndIdentifierRanges(func) {
|
|
var _a, _b;
|
|
for (const [, block] of func.blocks) {
|
|
const terminal = block.terminal;
|
|
if (terminal.kind === 'scope' || terminal.kind === 'pruned-scope') {
|
|
const fallthroughBlock = func.blocks.get(terminal.fallthrough);
|
|
const firstId = (_b = (_a = fallthroughBlock.instructions[0]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : fallthroughBlock.terminal.id;
|
|
terminal.scope.range.start = terminal.id;
|
|
terminal.scope.range.end = firstId;
|
|
}
|
|
}
|
|
}
|
|
|
|
const PRIMITIVE_TYPE = {
|
|
kind: 'Primitive',
|
|
};
|
|
let nextAnonId = 0;
|
|
function createAnonId() {
|
|
return `<generated_${nextAnonId++}>`;
|
|
}
|
|
function addFunction(registry, properties, fn, id = null, isConstructor = false) {
|
|
const shapeId = id !== null && id !== void 0 ? id : createAnonId();
|
|
const aliasing = fn.aliasing != null
|
|
? parseAliasingSignatureConfig(fn.aliasing, '<builtin>', GeneratedSource)
|
|
: null;
|
|
addShape(registry, shapeId, properties, Object.assign(Object.assign({}, fn), { aliasing, hookKind: null }));
|
|
return {
|
|
kind: 'Function',
|
|
return: fn.returnType,
|
|
shapeId,
|
|
isConstructor,
|
|
};
|
|
}
|
|
function addHook(registry, fn, id = null) {
|
|
const shapeId = id !== null && id !== void 0 ? id : createAnonId();
|
|
const aliasing = fn.aliasing != null
|
|
? parseAliasingSignatureConfig(fn.aliasing, '<builtin>', GeneratedSource)
|
|
: null;
|
|
addShape(registry, shapeId, [], Object.assign(Object.assign({}, fn), { aliasing }));
|
|
return {
|
|
kind: 'Function',
|
|
return: fn.returnType,
|
|
shapeId,
|
|
isConstructor: false,
|
|
};
|
|
}
|
|
function parseAliasingSignatureConfig(typeConfig, moduleName, loc) {
|
|
const lifetimes = new Map();
|
|
function define(temp) {
|
|
CompilerError.invariant(!lifetimes.has(temp), {
|
|
reason: `Invalid type configuration for module`,
|
|
description: `Expected aliasing signature to have unique names for receiver, params, rest, returns, and temporaries in module '${moduleName}'`,
|
|
loc,
|
|
});
|
|
const place = signatureArgument(lifetimes.size);
|
|
lifetimes.set(temp, place);
|
|
return place;
|
|
}
|
|
function lookup(temp) {
|
|
const place = lifetimes.get(temp);
|
|
CompilerError.invariant(place != null, {
|
|
reason: `Invalid type configuration for module`,
|
|
description: `Expected aliasing signature effects to reference known names from receiver/params/rest/returns/temporaries, but '${temp}' is not a known name in '${moduleName}'`,
|
|
loc,
|
|
});
|
|
return place;
|
|
}
|
|
const receiver = define(typeConfig.receiver);
|
|
const params = typeConfig.params.map(define);
|
|
const rest = typeConfig.rest != null ? define(typeConfig.rest) : null;
|
|
const returns = define(typeConfig.returns);
|
|
const temporaries = typeConfig.temporaries.map(define);
|
|
const effects = typeConfig.effects.map((effect) => {
|
|
switch (effect.kind) {
|
|
case 'ImmutableCapture':
|
|
case 'CreateFrom':
|
|
case 'Capture':
|
|
case 'Alias':
|
|
case 'Assign': {
|
|
const from = lookup(effect.from);
|
|
const into = lookup(effect.into);
|
|
return {
|
|
kind: effect.kind,
|
|
from,
|
|
into,
|
|
};
|
|
}
|
|
case 'Mutate':
|
|
case 'MutateTransitiveConditionally': {
|
|
const value = lookup(effect.value);
|
|
return { kind: effect.kind, value };
|
|
}
|
|
case 'Create': {
|
|
const into = lookup(effect.into);
|
|
return {
|
|
kind: 'Create',
|
|
into,
|
|
reason: effect.reason,
|
|
value: effect.value,
|
|
};
|
|
}
|
|
case 'Freeze': {
|
|
const value = lookup(effect.value);
|
|
return {
|
|
kind: 'Freeze',
|
|
value,
|
|
reason: effect.reason,
|
|
};
|
|
}
|
|
case 'Impure': {
|
|
const place = lookup(effect.place);
|
|
return {
|
|
kind: 'Impure',
|
|
place,
|
|
error: CompilerError.throwTodo({
|
|
reason: 'Support impure effect declarations',
|
|
loc: GeneratedSource,
|
|
}),
|
|
};
|
|
}
|
|
case 'Apply': {
|
|
const receiver = lookup(effect.receiver);
|
|
const fn = lookup(effect.function);
|
|
const args = effect.args.map(arg => {
|
|
if (typeof arg === 'string') {
|
|
return lookup(arg);
|
|
}
|
|
else if (arg.kind === 'Spread') {
|
|
return { kind: 'Spread', place: lookup(arg.place) };
|
|
}
|
|
else {
|
|
return arg;
|
|
}
|
|
});
|
|
const into = lookup(effect.into);
|
|
return {
|
|
kind: 'Apply',
|
|
receiver,
|
|
function: fn,
|
|
mutatesFunction: effect.mutatesFunction,
|
|
args,
|
|
into,
|
|
loc,
|
|
signature: null,
|
|
};
|
|
}
|
|
default: {
|
|
assertExhaustive$1(effect, `Unexpected effect kind '${effect.kind}'`);
|
|
}
|
|
}
|
|
});
|
|
return {
|
|
receiver: receiver.identifier.id,
|
|
params: params.map(p => p.identifier.id),
|
|
rest: rest != null ? rest.identifier.id : null,
|
|
returns: returns.identifier.id,
|
|
temporaries,
|
|
effects,
|
|
};
|
|
}
|
|
function addObject(registry, id, properties) {
|
|
const shapeId = id !== null && id !== void 0 ? id : createAnonId();
|
|
addShape(registry, shapeId, properties, null);
|
|
return {
|
|
kind: 'Object',
|
|
shapeId,
|
|
};
|
|
}
|
|
function addShape(registry, id, properties, functionType) {
|
|
const shape = {
|
|
properties: new Map(properties),
|
|
functionType,
|
|
};
|
|
CompilerError.invariant(!registry.has(id), {
|
|
reason: `[ObjectShape] Could not add shape to registry: name ${id} already exists.`,
|
|
loc: GeneratedSource,
|
|
});
|
|
registry.set(id, shape);
|
|
return shape;
|
|
}
|
|
const BuiltInPropsId = 'BuiltInProps';
|
|
const BuiltInArrayId = 'BuiltInArray';
|
|
const BuiltInSetId = 'BuiltInSet';
|
|
const BuiltInMapId = 'BuiltInMap';
|
|
const BuiltInWeakSetId = 'BuiltInWeakSet';
|
|
const BuiltInWeakMapId = 'BuiltInWeakMap';
|
|
const BuiltInFunctionId = 'BuiltInFunction';
|
|
const BuiltInJsxId = 'BuiltInJsx';
|
|
const BuiltInObjectId = 'BuiltInObject';
|
|
const BuiltInUseStateId = 'BuiltInUseState';
|
|
const BuiltInSetStateId = 'BuiltInSetState';
|
|
const BuiltInUseActionStateId = 'BuiltInUseActionState';
|
|
const BuiltInSetActionStateId = 'BuiltInSetActionState';
|
|
const BuiltInUseRefId = 'BuiltInUseRefId';
|
|
const BuiltInRefValueId = 'BuiltInRefValue';
|
|
const BuiltInMixedReadonlyId = 'BuiltInMixedReadonly';
|
|
const BuiltInUseEffectHookId = 'BuiltInUseEffectHook';
|
|
const BuiltInUseLayoutEffectHookId = 'BuiltInUseLayoutEffectHook';
|
|
const BuiltInUseInsertionEffectHookId = 'BuiltInUseInsertionEffectHook';
|
|
const BuiltInUseOperatorId = 'BuiltInUseOperator';
|
|
const BuiltInUseReducerId = 'BuiltInUseReducer';
|
|
const BuiltInDispatchId = 'BuiltInDispatch';
|
|
const BuiltInUseContextHookId = 'BuiltInUseContextHook';
|
|
const BuiltInUseTransitionId = 'BuiltInUseTransition';
|
|
const BuiltInUseOptimisticId = 'BuiltInUseOptimistic';
|
|
const BuiltInSetOptimisticId = 'BuiltInSetOptimistic';
|
|
const BuiltInStartTransitionId = 'BuiltInStartTransition';
|
|
const BuiltInUseEffectEventId = 'BuiltInUseEffectEvent';
|
|
const BuiltInEffectEventId = 'BuiltInEffectEventFunction';
|
|
const ReanimatedSharedValueId = 'ReanimatedSharedValueId';
|
|
const BUILTIN_SHAPES = new Map();
|
|
addObject(BUILTIN_SHAPES, BuiltInPropsId, [
|
|
['ref', { kind: 'Object', shapeId: BuiltInUseRefId }],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInArrayId, [
|
|
[
|
|
'indexOf',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'includes',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'pop',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'at',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'concat',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Capture,
|
|
returnType: {
|
|
kind: 'Object',
|
|
shapeId: BuiltInArrayId,
|
|
},
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
['length', PRIMITIVE_TYPE],
|
|
[
|
|
'push',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Capture,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Primitive,
|
|
aliasing: {
|
|
receiver: '@receiver',
|
|
params: [],
|
|
rest: '@rest',
|
|
returns: '@returns',
|
|
temporaries: [],
|
|
effects: [
|
|
{ kind: 'Mutate', value: '@receiver' },
|
|
{
|
|
kind: 'Capture',
|
|
from: '@rest',
|
|
into: '@receiver',
|
|
},
|
|
{
|
|
kind: 'Create',
|
|
into: '@returns',
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.KnownReturnSignature,
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
],
|
|
[
|
|
'slice',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: {
|
|
kind: 'Object',
|
|
shapeId: BuiltInArrayId,
|
|
},
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'map',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Mutable,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
aliasing: {
|
|
receiver: '@receiver',
|
|
params: ['@callback'],
|
|
rest: null,
|
|
returns: '@returns',
|
|
temporaries: [
|
|
'@item',
|
|
'@callbackReturn',
|
|
'@thisArg',
|
|
],
|
|
effects: [
|
|
{
|
|
kind: 'Create',
|
|
into: '@returns',
|
|
value: ValueKind.Mutable,
|
|
reason: ValueReason.KnownReturnSignature,
|
|
},
|
|
{
|
|
kind: 'CreateFrom',
|
|
from: '@receiver',
|
|
into: '@item',
|
|
},
|
|
{
|
|
kind: 'Create',
|
|
into: '@thisArg',
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.KnownReturnSignature,
|
|
},
|
|
{
|
|
kind: 'Apply',
|
|
receiver: '@thisArg',
|
|
args: ['@item', { kind: 'Hole' }, '@receiver'],
|
|
function: '@callback',
|
|
into: '@callbackReturn',
|
|
mutatesFunction: false,
|
|
},
|
|
{
|
|
kind: 'Capture',
|
|
from: '@callbackReturn',
|
|
into: '@returns',
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
],
|
|
[
|
|
'flatMap',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Mutable,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'filter',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Mutable,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'every',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Primitive,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'some',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Primitive,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'find',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Mutable,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'findIndex',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Primitive,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'join',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInObjectId, [
|
|
[
|
|
'toString',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInSetId, [
|
|
[
|
|
'add',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Capture],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInSetId },
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Mutable,
|
|
aliasing: {
|
|
receiver: '@receiver',
|
|
params: [],
|
|
rest: '@rest',
|
|
returns: '@returns',
|
|
temporaries: [],
|
|
effects: [
|
|
{
|
|
kind: 'Assign',
|
|
from: '@receiver',
|
|
into: '@returns',
|
|
},
|
|
{
|
|
kind: 'Mutate',
|
|
value: '@receiver',
|
|
},
|
|
{
|
|
kind: 'Capture',
|
|
from: '@rest',
|
|
into: '@receiver',
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
],
|
|
[
|
|
'clear',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'delete',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'has',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
['size', PRIMITIVE_TYPE],
|
|
[
|
|
'difference',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Capture],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInSetId },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'union',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Capture],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInSetId },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'symmetricalDifference',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Capture],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInSetId },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'isSubsetOf',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'isSupersetOf',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'forEach',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Primitive,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'entries',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'keys',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'values',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInMapId, [
|
|
[
|
|
'clear',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'delete',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'get',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'has',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'set',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Capture, Effect.Capture],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInMapId },
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
['size', PRIMITIVE_TYPE],
|
|
[
|
|
'forEach',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Primitive,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'entries',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'keys',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'values',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInWeakSetId, [
|
|
[
|
|
'add',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Capture],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInWeakSetId },
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'delete',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'has',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInWeakMapId, [
|
|
[
|
|
'delete',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'get',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'has',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'set',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Capture, Effect.Capture],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInWeakMapId },
|
|
calleeEffect: Effect.Store,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInUseStateId, [
|
|
['0', { kind: 'Poly' }],
|
|
[
|
|
'1',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}, BuiltInSetStateId),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInUseTransitionId, [
|
|
['0', { kind: 'Primitive' }],
|
|
[
|
|
'1',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}, BuiltInStartTransitionId),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInUseOptimisticId, [
|
|
['0', { kind: 'Poly' }],
|
|
[
|
|
'1',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}, BuiltInSetOptimisticId),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInUseActionStateId, [
|
|
['0', { kind: 'Poly' }],
|
|
[
|
|
'1',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}, BuiltInSetActionStateId),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInUseReducerId, [
|
|
['0', { kind: 'Poly' }],
|
|
[
|
|
'1',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}, BuiltInDispatchId),
|
|
],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInUseRefId, [
|
|
['current', { kind: 'Object', shapeId: BuiltInRefValueId }],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInRefValueId, [
|
|
['*', { kind: 'Object', shapeId: BuiltInRefValueId }],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, ReanimatedSharedValueId, []);
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}, BuiltInEffectEventId);
|
|
addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
|
|
[
|
|
'toString',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'indexOf',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'includes',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'at',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInMixedReadonlyId },
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Frozen,
|
|
}),
|
|
],
|
|
[
|
|
'map',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Mutable,
|
|
noAlias: true,
|
|
}),
|
|
],
|
|
[
|
|
'flatMap',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Mutable,
|
|
noAlias: true,
|
|
}),
|
|
],
|
|
[
|
|
'filter',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Mutable,
|
|
noAlias: true,
|
|
}),
|
|
],
|
|
[
|
|
'concat',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Capture,
|
|
returnType: {
|
|
kind: 'Object',
|
|
shapeId: BuiltInArrayId,
|
|
},
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'slice',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: {
|
|
kind: 'Object',
|
|
shapeId: BuiltInArrayId,
|
|
},
|
|
calleeEffect: Effect.Capture,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'every',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Primitive,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'some',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Primitive,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'find',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Object', shapeId: BuiltInMixedReadonlyId },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Frozen,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'findIndex',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.ConditionallyMutate,
|
|
returnValueKind: ValueKind.Primitive,
|
|
noAlias: true,
|
|
mutableOnlyIfOperandsAreMutable: true,
|
|
}),
|
|
],
|
|
[
|
|
'join',
|
|
addFunction(BUILTIN_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: PRIMITIVE_TYPE,
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
['*', { kind: 'Object', shapeId: BuiltInMixedReadonlyId }],
|
|
]);
|
|
addObject(BUILTIN_SHAPES, BuiltInJsxId, []);
|
|
addObject(BUILTIN_SHAPES, BuiltInFunctionId, []);
|
|
const DefaultMutatingHook = addHook(BUILTIN_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.ConditionallyMutate,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'Custom',
|
|
returnValueKind: ValueKind.Mutable,
|
|
}, 'DefaultMutatingHook');
|
|
const DefaultNonmutatingHook = addHook(BUILTIN_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'Custom',
|
|
returnValueKind: ValueKind.Frozen,
|
|
aliasing: {
|
|
receiver: '@receiver',
|
|
params: [],
|
|
rest: '@rest',
|
|
returns: '@returns',
|
|
temporaries: [],
|
|
effects: [
|
|
{
|
|
kind: 'Freeze',
|
|
value: '@rest',
|
|
reason: ValueReason.HookCaptured,
|
|
},
|
|
{
|
|
kind: 'Create',
|
|
into: '@returns',
|
|
value: ValueKind.Frozen,
|
|
reason: ValueReason.HookReturn,
|
|
},
|
|
{
|
|
kind: 'Alias',
|
|
from: '@rest',
|
|
into: '@returns',
|
|
},
|
|
],
|
|
},
|
|
}, 'DefaultNonmutatingHook');
|
|
function signatureArgument(id) {
|
|
const place = {
|
|
kind: 'Identifier',
|
|
effect: Effect.Unknown,
|
|
loc: GeneratedSource,
|
|
reactive: false,
|
|
identifier: {
|
|
declarationId: makeDeclarationId(id),
|
|
id: makeIdentifierId(id),
|
|
loc: GeneratedSource,
|
|
mutableRange: { start: makeInstructionId(0), end: makeInstructionId(0) },
|
|
name: null,
|
|
scope: null,
|
|
type: makeType(),
|
|
},
|
|
};
|
|
return place;
|
|
}
|
|
|
|
function lower(func, env, bindings = null, capturedRefs = new Map()) {
|
|
var _a, _b, _c;
|
|
const builder = new HIRBuilder(env, {
|
|
bindings,
|
|
context: capturedRefs,
|
|
});
|
|
const context = [];
|
|
for (const [ref, loc] of capturedRefs !== null && capturedRefs !== void 0 ? capturedRefs : []) {
|
|
context.push({
|
|
kind: 'Identifier',
|
|
identifier: builder.resolveBinding(ref),
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc,
|
|
});
|
|
}
|
|
let id = null;
|
|
if (func.isFunctionDeclaration() || func.isFunctionExpression()) {
|
|
const idNode = func.get('id');
|
|
if (hasNode(idNode)) {
|
|
id = idNode.node.name;
|
|
}
|
|
}
|
|
const params = [];
|
|
func.get('params').forEach(param => {
|
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
if (param.isIdentifier()) {
|
|
const binding = builder.resolveIdentifier(param);
|
|
if (binding.kind !== 'Identifier') {
|
|
builder.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Invariant,
|
|
reason: 'Could not find binding',
|
|
description: `[BuildHIR] Could not find binding for param \`${param.node.name}\``,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: (_a = param.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
message: 'Could not find binding',
|
|
}));
|
|
return;
|
|
}
|
|
const place = {
|
|
kind: 'Identifier',
|
|
identifier: binding.identifier,
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc: (_b = param.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
};
|
|
params.push(place);
|
|
}
|
|
else if (param.isObjectPattern() ||
|
|
param.isArrayPattern() ||
|
|
param.isAssignmentPattern()) {
|
|
const place = {
|
|
kind: 'Identifier',
|
|
identifier: builder.makeTemporary((_c = param.node.loc) !== null && _c !== void 0 ? _c : GeneratedSource),
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc: (_d = param.node.loc) !== null && _d !== void 0 ? _d : GeneratedSource,
|
|
};
|
|
promoteTemporary(place.identifier);
|
|
params.push(place);
|
|
lowerAssignment(builder, (_e = param.node.loc) !== null && _e !== void 0 ? _e : GeneratedSource, InstructionKind.Let, param, place, 'Assignment');
|
|
}
|
|
else if (param.isRestElement()) {
|
|
const place = {
|
|
kind: 'Identifier',
|
|
identifier: builder.makeTemporary((_f = param.node.loc) !== null && _f !== void 0 ? _f : GeneratedSource),
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc: (_g = param.node.loc) !== null && _g !== void 0 ? _g : GeneratedSource,
|
|
};
|
|
params.push({
|
|
kind: 'Spread',
|
|
place,
|
|
});
|
|
lowerAssignment(builder, (_h = param.node.loc) !== null && _h !== void 0 ? _h : GeneratedSource, InstructionKind.Let, param.get('argument'), place, 'Assignment');
|
|
}
|
|
else {
|
|
builder.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Todo,
|
|
reason: `Handle ${param.node.type} parameters`,
|
|
description: `[BuildHIR] Add support for ${param.node.type} parameters`,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: (_j = param.node.loc) !== null && _j !== void 0 ? _j : null,
|
|
message: 'Unsupported parameter type',
|
|
}));
|
|
}
|
|
});
|
|
let directives = [];
|
|
const body = func.get('body');
|
|
if (body.isExpression()) {
|
|
const fallthrough = builder.reserve('block');
|
|
const terminal = {
|
|
kind: 'return',
|
|
returnVariant: 'Implicit',
|
|
loc: GeneratedSource,
|
|
value: lowerExpressionToTemporary(builder, body),
|
|
id: makeInstructionId(0),
|
|
effects: null,
|
|
};
|
|
builder.terminateWithContinuation(terminal, fallthrough);
|
|
}
|
|
else if (body.isBlockStatement()) {
|
|
lowerStatement(builder, body);
|
|
directives = body.get('directives').map(d => d.node.value.value);
|
|
}
|
|
else {
|
|
builder.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Syntax,
|
|
reason: `Unexpected function body kind`,
|
|
description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: (_a = body.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
message: 'Expected a block statement or expression',
|
|
}));
|
|
}
|
|
let validatedId = null;
|
|
if (id != null) {
|
|
const idResult = validateIdentifierName(id);
|
|
if (idResult.isErr()) {
|
|
for (const detail of idResult.unwrapErr().details) {
|
|
builder.recordError(detail);
|
|
}
|
|
}
|
|
else {
|
|
validatedId = idResult.unwrap().value;
|
|
}
|
|
}
|
|
builder.terminate({
|
|
kind: 'return',
|
|
returnVariant: 'Void',
|
|
loc: GeneratedSource,
|
|
value: lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: GeneratedSource,
|
|
}),
|
|
id: makeInstructionId(0),
|
|
effects: null,
|
|
}, null);
|
|
const hirBody = builder.build();
|
|
return {
|
|
id: validatedId,
|
|
nameHint: null,
|
|
params,
|
|
fnType: bindings == null ? env.fnType : 'Other',
|
|
returnTypeAnnotation: null,
|
|
returns: createTemporaryPlace(env, (_b = func.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource),
|
|
body: hirBody,
|
|
context,
|
|
generator: func.node.generator === true,
|
|
async: func.node.async === true,
|
|
loc: (_c = func.node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
env,
|
|
aliasingEffects: null,
|
|
directives,
|
|
};
|
|
}
|
|
function lowerStatement(builder, stmtPath, label = null) {
|
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38;
|
|
const stmtNode = stmtPath.node;
|
|
switch (stmtNode.type) {
|
|
case 'ThrowStatement': {
|
|
const stmt = stmtPath;
|
|
const value = lowerExpressionToTemporary(builder, stmt.get('argument'));
|
|
const handler = builder.resolveThrowHandler();
|
|
if (handler != null) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: '(BuildHIR::lowerStatement) Support ThrowStatement inside of try/catch',
|
|
category: ErrorCategory.Todo,
|
|
loc: (_a = stmt.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
const terminal = {
|
|
kind: 'throw',
|
|
value,
|
|
id: makeInstructionId(0),
|
|
loc: (_b = stmt.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
};
|
|
builder.terminate(terminal, 'block');
|
|
return;
|
|
}
|
|
case 'ReturnStatement': {
|
|
const stmt = stmtPath;
|
|
const argument = stmt.get('argument');
|
|
let value;
|
|
if (argument.node === null) {
|
|
value = lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
else {
|
|
value = lowerExpressionToTemporary(builder, argument);
|
|
}
|
|
const terminal = {
|
|
kind: 'return',
|
|
returnVariant: 'Explicit',
|
|
loc: (_c = stmt.node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
value,
|
|
id: makeInstructionId(0),
|
|
effects: null,
|
|
};
|
|
builder.terminate(terminal, 'block');
|
|
return;
|
|
}
|
|
case 'IfStatement': {
|
|
const stmt = stmtPath;
|
|
const continuationBlock = builder.reserve('block');
|
|
const consequentBlock = builder.enter('block', _blockId => {
|
|
var _a;
|
|
const consequent = stmt.get('consequent');
|
|
lowerStatement(builder, consequent);
|
|
return {
|
|
kind: 'goto',
|
|
block: continuationBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = consequent.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
let alternateBlock;
|
|
const alternate = stmt.get('alternate');
|
|
if (hasNode(alternate)) {
|
|
alternateBlock = builder.enter('block', _blockId => {
|
|
var _a, _b;
|
|
lowerStatement(builder, alternate);
|
|
return {
|
|
kind: 'goto',
|
|
block: continuationBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_b = (_a = alternate.node) === null || _a === void 0 ? void 0 : _a.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
};
|
|
});
|
|
}
|
|
else {
|
|
alternateBlock = continuationBlock.id;
|
|
}
|
|
const test = lowerExpressionToTemporary(builder, stmt.get('test'));
|
|
const terminal = {
|
|
kind: 'if',
|
|
test,
|
|
consequent: consequentBlock,
|
|
alternate: alternateBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: (_d = stmt.node.loc) !== null && _d !== void 0 ? _d : GeneratedSource,
|
|
};
|
|
builder.terminateWithContinuation(terminal, continuationBlock);
|
|
return;
|
|
}
|
|
case 'BlockStatement': {
|
|
const stmt = stmtPath;
|
|
const statements = stmt.get('body');
|
|
const hoistableIdentifiers = new Set();
|
|
for (const [, binding] of Object.entries(stmt.scope.bindings)) {
|
|
if (binding.kind !== 'param') {
|
|
hoistableIdentifiers.add(binding.identifier);
|
|
}
|
|
}
|
|
for (const s of statements) {
|
|
const willHoist = new Set();
|
|
let fnDepth = s.isFunctionDeclaration() ? 1 : 0;
|
|
const withFunctionContext = {
|
|
enter: () => {
|
|
fnDepth++;
|
|
},
|
|
exit: () => {
|
|
fnDepth--;
|
|
},
|
|
};
|
|
s.traverse({
|
|
FunctionExpression: withFunctionContext,
|
|
FunctionDeclaration: withFunctionContext,
|
|
ArrowFunctionExpression: withFunctionContext,
|
|
ObjectMethod: withFunctionContext,
|
|
Identifier(id) {
|
|
const id2 = id;
|
|
if (!id2.isReferencedIdentifier() &&
|
|
id.parent.type !== 'AssignmentExpression') {
|
|
return;
|
|
}
|
|
const binding = id.scope.getBinding(id.node.name);
|
|
if (binding != null &&
|
|
hoistableIdentifiers.has(binding.identifier) &&
|
|
(fnDepth > 0 || binding.kind === 'hoisted')) {
|
|
willHoist.add(id);
|
|
}
|
|
},
|
|
});
|
|
s.traverse({
|
|
Identifier(path) {
|
|
if (hoistableIdentifiers.has(path.node)) {
|
|
hoistableIdentifiers.delete(path.node);
|
|
}
|
|
},
|
|
});
|
|
for (const id of willHoist) {
|
|
const binding = stmt.scope.getBinding(id.node.name);
|
|
CompilerError.invariant(binding != null, {
|
|
reason: 'Expected to find binding for hoisted identifier',
|
|
description: `Could not find a binding for ${id.node.name}`,
|
|
loc: (_e = id.node.loc) !== null && _e !== void 0 ? _e : GeneratedSource,
|
|
});
|
|
if (builder.environment.isHoistedIdentifier(binding.identifier)) {
|
|
continue;
|
|
}
|
|
let kind;
|
|
if (binding.kind === 'const' || binding.kind === 'var') {
|
|
kind = InstructionKind.HoistedConst;
|
|
}
|
|
else if (binding.kind === 'let') {
|
|
kind = InstructionKind.HoistedLet;
|
|
}
|
|
else if (binding.path.isFunctionDeclaration()) {
|
|
kind = InstructionKind.HoistedFunction;
|
|
}
|
|
else if (!binding.path.isVariableDeclarator()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Unsupported declaration type for hoisting',
|
|
description: `variable "${binding.identifier.name}" declared with ${binding.path.type}`,
|
|
suggestions: null,
|
|
loc: (_f = id.parentPath.node.loc) !== null && _f !== void 0 ? _f : GeneratedSource,
|
|
}));
|
|
continue;
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Handle non-const declarations for hoisting',
|
|
description: `variable "${binding.identifier.name}" declared with ${binding.kind}`,
|
|
suggestions: null,
|
|
loc: (_g = id.parentPath.node.loc) !== null && _g !== void 0 ? _g : GeneratedSource,
|
|
}));
|
|
continue;
|
|
}
|
|
const identifier = builder.resolveIdentifier(id);
|
|
CompilerError.invariant(identifier.kind === 'Identifier', {
|
|
reason: 'Expected hoisted binding to be a local identifier, not a global',
|
|
loc: (_h = id.node.loc) !== null && _h !== void 0 ? _h : GeneratedSource,
|
|
});
|
|
const place = {
|
|
effect: Effect.Unknown,
|
|
identifier: identifier.identifier,
|
|
kind: 'Identifier',
|
|
reactive: false,
|
|
loc: (_j = id.node.loc) !== null && _j !== void 0 ? _j : GeneratedSource,
|
|
};
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'DeclareContext',
|
|
lvalue: {
|
|
kind,
|
|
place,
|
|
},
|
|
loc: (_k = id.node.loc) !== null && _k !== void 0 ? _k : GeneratedSource,
|
|
});
|
|
builder.environment.addHoistedIdentifier(binding.identifier);
|
|
}
|
|
lowerStatement(builder, s);
|
|
}
|
|
return;
|
|
}
|
|
case 'BreakStatement': {
|
|
const stmt = stmtPath;
|
|
const block = builder.lookupBreak((_m = (_l = stmt.node.label) === null || _l === void 0 ? void 0 : _l.name) !== null && _m !== void 0 ? _m : null);
|
|
builder.terminate({
|
|
kind: 'goto',
|
|
block,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_o = stmt.node.loc) !== null && _o !== void 0 ? _o : GeneratedSource,
|
|
}, 'block');
|
|
return;
|
|
}
|
|
case 'ContinueStatement': {
|
|
const stmt = stmtPath;
|
|
const block = builder.lookupContinue((_q = (_p = stmt.node.label) === null || _p === void 0 ? void 0 : _p.name) !== null && _q !== void 0 ? _q : null);
|
|
builder.terminate({
|
|
kind: 'goto',
|
|
block,
|
|
variant: GotoVariant.Continue,
|
|
id: makeInstructionId(0),
|
|
loc: (_r = stmt.node.loc) !== null && _r !== void 0 ? _r : GeneratedSource,
|
|
}, 'block');
|
|
return;
|
|
}
|
|
case 'ForStatement': {
|
|
const stmt = stmtPath;
|
|
const testBlock = builder.reserve('loop');
|
|
const continuationBlock = builder.reserve('block');
|
|
const initBlock = builder.enter('loop', _blockId => {
|
|
var _a, _b, _c, _d, _e, _f;
|
|
const init = stmt.get('init');
|
|
if (init.node == null) {
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: (_a = stmt.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
block: testBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_b = stmt.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
};
|
|
}
|
|
if (!init.isVariableDeclaration()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: '(BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement',
|
|
category: ErrorCategory.Todo,
|
|
loc: (_c = stmt.node.loc) !== null && _c !== void 0 ? _c : null,
|
|
suggestions: null,
|
|
}));
|
|
if (init.isExpression()) {
|
|
lowerExpressionToTemporary(builder, init);
|
|
}
|
|
return {
|
|
kind: 'goto',
|
|
block: testBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_e = (_d = init.node) === null || _d === void 0 ? void 0 : _d.loc) !== null && _e !== void 0 ? _e : GeneratedSource,
|
|
};
|
|
}
|
|
lowerStatement(builder, init);
|
|
return {
|
|
kind: 'goto',
|
|
block: testBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_f = init.node.loc) !== null && _f !== void 0 ? _f : GeneratedSource,
|
|
};
|
|
});
|
|
let updateBlock = null;
|
|
const update = stmt.get('update');
|
|
if (hasNode(update)) {
|
|
updateBlock = builder.enter('loop', _blockId => {
|
|
var _a, _b;
|
|
lowerExpressionToTemporary(builder, update);
|
|
return {
|
|
kind: 'goto',
|
|
block: testBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_b = (_a = update.node) === null || _a === void 0 ? void 0 : _a.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
};
|
|
});
|
|
}
|
|
const bodyBlock = builder.enter('block', _blockId => {
|
|
return builder.loop(label, updateBlock !== null && updateBlock !== void 0 ? updateBlock : testBlock.id, continuationBlock.id, () => {
|
|
var _a;
|
|
const body = stmt.get('body');
|
|
lowerStatement(builder, body);
|
|
return {
|
|
kind: 'goto',
|
|
block: updateBlock !== null && updateBlock !== void 0 ? updateBlock : testBlock.id,
|
|
variant: GotoVariant.Continue,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = body.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'for',
|
|
loc: (_s = stmtNode.loc) !== null && _s !== void 0 ? _s : GeneratedSource,
|
|
init: initBlock,
|
|
test: testBlock.id,
|
|
update: updateBlock,
|
|
loop: bodyBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
}, testBlock);
|
|
const test = stmt.get('test');
|
|
if (test.node == null) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerStatement) Handle empty test in ForStatement`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_t = stmt.node.loc) !== null && _t !== void 0 ? _t : null,
|
|
suggestions: null,
|
|
}));
|
|
builder.terminateWithContinuation({
|
|
kind: 'branch',
|
|
test: lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: true,
|
|
loc: (_u = stmt.node.loc) !== null && _u !== void 0 ? _u : GeneratedSource,
|
|
}),
|
|
consequent: bodyBlock,
|
|
alternate: continuationBlock.id,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: (_v = stmt.node.loc) !== null && _v !== void 0 ? _v : GeneratedSource,
|
|
}, continuationBlock);
|
|
}
|
|
else {
|
|
builder.terminateWithContinuation({
|
|
kind: 'branch',
|
|
test: lowerExpressionToTemporary(builder, test),
|
|
consequent: bodyBlock,
|
|
alternate: continuationBlock.id,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: (_w = stmt.node.loc) !== null && _w !== void 0 ? _w : GeneratedSource,
|
|
}, continuationBlock);
|
|
}
|
|
return;
|
|
}
|
|
case 'WhileStatement': {
|
|
const stmt = stmtPath;
|
|
const conditionalBlock = builder.reserve('loop');
|
|
const continuationBlock = builder.reserve('block');
|
|
const loopBlock = builder.enter('block', _blockId => {
|
|
return builder.loop(label, conditionalBlock.id, continuationBlock.id, () => {
|
|
var _a;
|
|
const body = stmt.get('body');
|
|
lowerStatement(builder, body);
|
|
return {
|
|
kind: 'goto',
|
|
block: conditionalBlock.id,
|
|
variant: GotoVariant.Continue,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = body.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
});
|
|
const loc = (_x = stmt.node.loc) !== null && _x !== void 0 ? _x : GeneratedSource;
|
|
builder.terminateWithContinuation({
|
|
kind: 'while',
|
|
loc,
|
|
test: conditionalBlock.id,
|
|
loop: loopBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
}, conditionalBlock);
|
|
const test = lowerExpressionToTemporary(builder, stmt.get('test'));
|
|
const terminal = {
|
|
kind: 'branch',
|
|
test,
|
|
consequent: loopBlock,
|
|
alternate: continuationBlock.id,
|
|
fallthrough: conditionalBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: (_y = stmt.node.loc) !== null && _y !== void 0 ? _y : GeneratedSource,
|
|
};
|
|
builder.terminateWithContinuation(terminal, continuationBlock);
|
|
return;
|
|
}
|
|
case 'LabeledStatement': {
|
|
const stmt = stmtPath;
|
|
const label = stmt.node.label.name;
|
|
const body = stmt.get('body');
|
|
switch (body.node.type) {
|
|
case 'ForInStatement':
|
|
case 'ForOfStatement':
|
|
case 'ForStatement':
|
|
case 'WhileStatement':
|
|
case 'DoWhileStatement': {
|
|
lowerStatement(builder, stmt.get('body'), label);
|
|
break;
|
|
}
|
|
default: {
|
|
const continuationBlock = builder.reserve('block');
|
|
const block = builder.enter('block', () => {
|
|
var _a;
|
|
const body = stmt.get('body');
|
|
builder.label(label, continuationBlock.id, () => {
|
|
lowerStatement(builder, body);
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
block: continuationBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = body.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'label',
|
|
block,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: (_z = stmt.node.loc) !== null && _z !== void 0 ? _z : GeneratedSource,
|
|
}, continuationBlock);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
case 'SwitchStatement': {
|
|
const stmt = stmtPath;
|
|
const continuationBlock = builder.reserve('block');
|
|
let fallthrough = continuationBlock.id;
|
|
const cases = [];
|
|
let hasDefault = false;
|
|
for (let ii = stmt.get('cases').length - 1; ii >= 0; ii--) {
|
|
const case_ = stmt.get('cases')[ii];
|
|
const testExpr = case_.get('test');
|
|
if (testExpr.node == null) {
|
|
if (hasDefault) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Expected at most one \`default\` branch in a switch statement, this code should have failed to parse`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_0 = case_.node.loc) !== null && _0 !== void 0 ? _0 : null,
|
|
suggestions: null,
|
|
}));
|
|
break;
|
|
}
|
|
hasDefault = true;
|
|
}
|
|
const block = builder.enter('block', _blockId => {
|
|
return builder.switch(label, continuationBlock.id, () => {
|
|
var _a;
|
|
case_
|
|
.get('consequent')
|
|
.forEach(consequent => lowerStatement(builder, consequent));
|
|
return {
|
|
kind: 'goto',
|
|
block: fallthrough,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = case_.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
});
|
|
let test = null;
|
|
if (hasNode(testExpr)) {
|
|
test = lowerReorderableExpression(builder, testExpr);
|
|
}
|
|
cases.push({
|
|
test,
|
|
block,
|
|
});
|
|
fallthrough = block;
|
|
}
|
|
cases.reverse();
|
|
if (!hasDefault) {
|
|
cases.push({ test: null, block: continuationBlock.id });
|
|
}
|
|
const test = lowerExpressionToTemporary(builder, stmt.get('discriminant'));
|
|
builder.terminateWithContinuation({
|
|
kind: 'switch',
|
|
test,
|
|
cases,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: (_1 = stmt.node.loc) !== null && _1 !== void 0 ? _1 : GeneratedSource,
|
|
}, continuationBlock);
|
|
return;
|
|
}
|
|
case 'VariableDeclaration': {
|
|
const stmt = stmtPath;
|
|
const nodeKind = stmt.node.kind;
|
|
if (nodeKind === 'var') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerStatement) Handle ${nodeKind} kinds in VariableDeclaration`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_2 = stmt.node.loc) !== null && _2 !== void 0 ? _2 : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
const kind = nodeKind === 'let' || nodeKind === 'var'
|
|
? InstructionKind.Let
|
|
: InstructionKind.Const;
|
|
for (const declaration of stmt.get('declarations')) {
|
|
const id = declaration.get('id');
|
|
const init = declaration.get('init');
|
|
if (hasNode(init)) {
|
|
const value = lowerExpressionToTemporary(builder, init);
|
|
lowerAssignment(builder, (_3 = stmt.node.loc) !== null && _3 !== void 0 ? _3 : GeneratedSource, kind, id, value, id.isObjectPattern() || id.isArrayPattern()
|
|
? 'Destructure'
|
|
: 'Assignment');
|
|
}
|
|
else if (id.isIdentifier()) {
|
|
const binding = builder.resolveIdentifier(id);
|
|
if (binding.kind !== 'Identifier') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerAssignment) Could not find binding for declaration.`,
|
|
category: ErrorCategory.Invariant,
|
|
loc: (_4 = id.node.loc) !== null && _4 !== void 0 ? _4 : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
else {
|
|
const place = {
|
|
effect: Effect.Unknown,
|
|
identifier: binding.identifier,
|
|
kind: 'Identifier',
|
|
reactive: false,
|
|
loc: (_5 = id.node.loc) !== null && _5 !== void 0 ? _5 : GeneratedSource,
|
|
};
|
|
if (builder.isContextIdentifier(id)) {
|
|
if (kind === InstructionKind.Const) {
|
|
const declRangeStart = declaration.parentPath.node.start;
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Expect \`const\` declaration not to be reassigned`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_6 = id.node.loc) !== null && _6 !== void 0 ? _6 : null,
|
|
suggestions: [
|
|
{
|
|
description: 'Change to a `let` declaration',
|
|
op: CompilerSuggestionOperation.Replace,
|
|
range: [declRangeStart, declRangeStart + 5],
|
|
text: 'let',
|
|
},
|
|
],
|
|
}));
|
|
}
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'DeclareContext',
|
|
lvalue: {
|
|
kind: InstructionKind.Let,
|
|
place,
|
|
},
|
|
loc: (_7 = id.node.loc) !== null && _7 !== void 0 ? _7 : GeneratedSource,
|
|
});
|
|
}
|
|
else {
|
|
const typeAnnotation = id.get('typeAnnotation');
|
|
let type;
|
|
if (typeAnnotation.isTSTypeAnnotation()) {
|
|
const typePath = typeAnnotation.get('typeAnnotation');
|
|
type = typePath.node;
|
|
}
|
|
else if (typeAnnotation.isTypeAnnotation()) {
|
|
const typePath = typeAnnotation.get('typeAnnotation');
|
|
type = typePath.node;
|
|
}
|
|
else {
|
|
type = null;
|
|
}
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'DeclareLocal',
|
|
lvalue: {
|
|
kind,
|
|
place,
|
|
},
|
|
type,
|
|
loc: (_8 = id.node.loc) !== null && _8 !== void 0 ? _8 : GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Expected variable declaration to be an identifier if no initializer was provided`,
|
|
description: `Got a \`${id.type}\``,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_9 = stmt.node.loc) !== null && _9 !== void 0 ? _9 : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
case 'ExpressionStatement': {
|
|
const stmt = stmtPath;
|
|
const expression = stmt.get('expression');
|
|
lowerExpressionToTemporary(builder, expression);
|
|
return;
|
|
}
|
|
case 'DoWhileStatement': {
|
|
const stmt = stmtPath;
|
|
const conditionalBlock = builder.reserve('loop');
|
|
const continuationBlock = builder.reserve('block');
|
|
const loopBlock = builder.enter('block', _loopBlockId => {
|
|
return builder.loop(label, conditionalBlock.id, continuationBlock.id, () => {
|
|
var _a;
|
|
const body = stmt.get('body');
|
|
lowerStatement(builder, body);
|
|
return {
|
|
kind: 'goto',
|
|
block: conditionalBlock.id,
|
|
variant: GotoVariant.Continue,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = body.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
});
|
|
const loc = (_10 = stmt.node.loc) !== null && _10 !== void 0 ? _10 : GeneratedSource;
|
|
builder.terminateWithContinuation({
|
|
kind: 'do-while',
|
|
loc,
|
|
test: conditionalBlock.id,
|
|
loop: loopBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
}, conditionalBlock);
|
|
const test = lowerExpressionToTemporary(builder, stmt.get('test'));
|
|
const terminal = {
|
|
kind: 'branch',
|
|
test,
|
|
consequent: loopBlock,
|
|
alternate: continuationBlock.id,
|
|
fallthrough: conditionalBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
};
|
|
builder.terminateWithContinuation(terminal, continuationBlock);
|
|
return;
|
|
}
|
|
case 'FunctionDeclaration': {
|
|
const stmt = stmtPath;
|
|
stmt.skip();
|
|
CompilerError.invariant(stmt.get('id').type === 'Identifier', {
|
|
reason: 'function declarations must have a name',
|
|
loc: (_11 = stmt.node.loc) !== null && _11 !== void 0 ? _11 : GeneratedSource,
|
|
});
|
|
const id = stmt.get('id');
|
|
const fn = lowerValueToTemporary(builder, lowerFunctionToValue(builder, stmt));
|
|
lowerAssignment(builder, (_12 = stmt.node.loc) !== null && _12 !== void 0 ? _12 : GeneratedSource, InstructionKind.Function, id, fn, 'Assignment');
|
|
return;
|
|
}
|
|
case 'ForOfStatement': {
|
|
const stmt = stmtPath;
|
|
const continuationBlock = builder.reserve('block');
|
|
const initBlock = builder.reserve('loop');
|
|
const testBlock = builder.reserve('loop');
|
|
if (stmt.node.await) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerStatement) Handle for-await loops`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_13 = stmt.node.loc) !== null && _13 !== void 0 ? _13 : null,
|
|
suggestions: null,
|
|
}));
|
|
return;
|
|
}
|
|
const loopBlock = builder.enter('block', _blockId => {
|
|
return builder.loop(label, initBlock.id, continuationBlock.id, () => {
|
|
var _a;
|
|
const body = stmt.get('body');
|
|
lowerStatement(builder, body);
|
|
return {
|
|
kind: 'goto',
|
|
block: initBlock.id,
|
|
variant: GotoVariant.Continue,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = body.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
});
|
|
const loc = (_14 = stmt.node.loc) !== null && _14 !== void 0 ? _14 : GeneratedSource;
|
|
const value = lowerExpressionToTemporary(builder, stmt.get('right'));
|
|
builder.terminateWithContinuation({
|
|
kind: 'for-of',
|
|
loc,
|
|
init: initBlock.id,
|
|
test: testBlock.id,
|
|
loop: loopBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
}, initBlock);
|
|
const iterator = lowerValueToTemporary(builder, {
|
|
kind: 'GetIterator',
|
|
loc: value.loc,
|
|
collection: Object.assign({}, value),
|
|
});
|
|
builder.terminateWithContinuation({
|
|
id: makeInstructionId(0),
|
|
kind: 'goto',
|
|
block: testBlock.id,
|
|
variant: GotoVariant.Break,
|
|
loc: (_15 = stmt.node.loc) !== null && _15 !== void 0 ? _15 : GeneratedSource,
|
|
}, testBlock);
|
|
const left = stmt.get('left');
|
|
const leftLoc = (_16 = left.node.loc) !== null && _16 !== void 0 ? _16 : GeneratedSource;
|
|
let test;
|
|
const advanceIterator = lowerValueToTemporary(builder, {
|
|
kind: 'IteratorNext',
|
|
loc: leftLoc,
|
|
iterator: Object.assign({}, iterator),
|
|
collection: Object.assign({}, value),
|
|
});
|
|
if (left.isVariableDeclaration()) {
|
|
const declarations = left.get('declarations');
|
|
CompilerError.invariant(declarations.length === 1, {
|
|
reason: `Expected only one declaration in the init of a ForOfStatement, got ${declarations.length}`,
|
|
loc: (_17 = left.node.loc) !== null && _17 !== void 0 ? _17 : GeneratedSource,
|
|
});
|
|
const id = declarations[0].get('id');
|
|
const assign = lowerAssignment(builder, leftLoc, InstructionKind.Let, id, advanceIterator, 'Assignment');
|
|
test = lowerValueToTemporary(builder, assign);
|
|
}
|
|
else {
|
|
CompilerError.invariant(left.isLVal(), {
|
|
reason: 'Expected ForOf init to be a variable declaration or lval',
|
|
loc: leftLoc,
|
|
});
|
|
const assign = lowerAssignment(builder, leftLoc, InstructionKind.Reassign, left, advanceIterator, 'Assignment');
|
|
test = lowerValueToTemporary(builder, assign);
|
|
}
|
|
builder.terminateWithContinuation({
|
|
id: makeInstructionId(0),
|
|
kind: 'branch',
|
|
test,
|
|
consequent: loopBlock,
|
|
alternate: continuationBlock.id,
|
|
loc: (_18 = stmt.node.loc) !== null && _18 !== void 0 ? _18 : GeneratedSource,
|
|
fallthrough: continuationBlock.id,
|
|
}, continuationBlock);
|
|
return;
|
|
}
|
|
case 'ForInStatement': {
|
|
const stmt = stmtPath;
|
|
const continuationBlock = builder.reserve('block');
|
|
const initBlock = builder.reserve('loop');
|
|
const loopBlock = builder.enter('block', _blockId => {
|
|
return builder.loop(label, initBlock.id, continuationBlock.id, () => {
|
|
var _a;
|
|
const body = stmt.get('body');
|
|
lowerStatement(builder, body);
|
|
return {
|
|
kind: 'goto',
|
|
block: initBlock.id,
|
|
variant: GotoVariant.Continue,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = body.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
});
|
|
const loc = (_19 = stmt.node.loc) !== null && _19 !== void 0 ? _19 : GeneratedSource;
|
|
const value = lowerExpressionToTemporary(builder, stmt.get('right'));
|
|
builder.terminateWithContinuation({
|
|
kind: 'for-in',
|
|
loc,
|
|
init: initBlock.id,
|
|
loop: loopBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
}, initBlock);
|
|
const left = stmt.get('left');
|
|
const leftLoc = (_20 = left.node.loc) !== null && _20 !== void 0 ? _20 : GeneratedSource;
|
|
let test;
|
|
const nextPropertyTemp = lowerValueToTemporary(builder, {
|
|
kind: 'NextPropertyOf',
|
|
loc: leftLoc,
|
|
value,
|
|
});
|
|
if (left.isVariableDeclaration()) {
|
|
const declarations = left.get('declarations');
|
|
CompilerError.invariant(declarations.length === 1, {
|
|
reason: `Expected only one declaration in the init of a ForInStatement, got ${declarations.length}`,
|
|
loc: (_21 = left.node.loc) !== null && _21 !== void 0 ? _21 : GeneratedSource,
|
|
});
|
|
const id = declarations[0].get('id');
|
|
const assign = lowerAssignment(builder, leftLoc, InstructionKind.Let, id, nextPropertyTemp, 'Assignment');
|
|
test = lowerValueToTemporary(builder, assign);
|
|
}
|
|
else {
|
|
CompilerError.invariant(left.isLVal(), {
|
|
reason: 'Expected ForIn init to be a variable declaration or lval',
|
|
loc: leftLoc,
|
|
});
|
|
const assign = lowerAssignment(builder, leftLoc, InstructionKind.Reassign, left, nextPropertyTemp, 'Assignment');
|
|
test = lowerValueToTemporary(builder, assign);
|
|
}
|
|
builder.terminateWithContinuation({
|
|
id: makeInstructionId(0),
|
|
kind: 'branch',
|
|
test,
|
|
consequent: loopBlock,
|
|
alternate: continuationBlock.id,
|
|
fallthrough: continuationBlock.id,
|
|
loc: (_22 = stmt.node.loc) !== null && _22 !== void 0 ? _22 : GeneratedSource,
|
|
}, continuationBlock);
|
|
return;
|
|
}
|
|
case 'DebuggerStatement': {
|
|
const stmt = stmtPath;
|
|
const loc = (_23 = stmt.node.loc) !== null && _23 !== void 0 ? _23 : GeneratedSource;
|
|
builder.push({
|
|
id: makeInstructionId(0),
|
|
lvalue: buildTemporaryPlace(builder, loc),
|
|
value: {
|
|
kind: 'Debugger',
|
|
loc,
|
|
},
|
|
effects: null,
|
|
loc,
|
|
});
|
|
return;
|
|
}
|
|
case 'EmptyStatement': {
|
|
return;
|
|
}
|
|
case 'TryStatement': {
|
|
const stmt = stmtPath;
|
|
const continuationBlock = builder.reserve('block');
|
|
const handlerPath = stmt.get('handler');
|
|
if (!hasNode(handlerPath)) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerStatement) Handle TryStatement without a catch clause`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_24 = stmt.node.loc) !== null && _24 !== void 0 ? _24 : null,
|
|
suggestions: null,
|
|
}));
|
|
return;
|
|
}
|
|
if (hasNode(stmt.get('finalizer'))) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerStatement) Handle TryStatement with a finalizer ('finally') clause`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_25 = stmt.node.loc) !== null && _25 !== void 0 ? _25 : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
const handlerBindingPath = handlerPath.get('param');
|
|
let handlerBinding = null;
|
|
if (hasNode(handlerBindingPath)) {
|
|
const place = {
|
|
kind: 'Identifier',
|
|
identifier: builder.makeTemporary((_26 = handlerBindingPath.node.loc) !== null && _26 !== void 0 ? _26 : GeneratedSource),
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc: (_27 = handlerBindingPath.node.loc) !== null && _27 !== void 0 ? _27 : GeneratedSource,
|
|
};
|
|
promoteTemporary(place.identifier);
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'DeclareLocal',
|
|
lvalue: {
|
|
kind: InstructionKind.Catch,
|
|
place: Object.assign({}, place),
|
|
},
|
|
type: null,
|
|
loc: (_28 = handlerBindingPath.node.loc) !== null && _28 !== void 0 ? _28 : GeneratedSource,
|
|
});
|
|
handlerBinding = {
|
|
path: handlerBindingPath,
|
|
place,
|
|
};
|
|
}
|
|
const handler = builder.enter('catch', _blockId => {
|
|
var _a, _b;
|
|
if (handlerBinding !== null) {
|
|
lowerAssignment(builder, (_a = handlerBinding.path.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource, InstructionKind.Catch, handlerBinding.path, Object.assign({}, handlerBinding.place), 'Assignment');
|
|
}
|
|
lowerStatement(builder, handlerPath.get('body'));
|
|
return {
|
|
kind: 'goto',
|
|
block: continuationBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_b = handlerPath.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
};
|
|
});
|
|
const block = builder.enter('block', _blockId => {
|
|
var _a;
|
|
const block = stmt.get('block');
|
|
builder.enterTryCatch(handler, () => {
|
|
lowerStatement(builder, block);
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
block: continuationBlock.id,
|
|
variant: GotoVariant.Try,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = block.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'try',
|
|
block,
|
|
handlerBinding: handlerBinding !== null ? Object.assign({}, handlerBinding.place) : null,
|
|
handler,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: (_29 = stmt.node.loc) !== null && _29 !== void 0 ? _29 : GeneratedSource,
|
|
}, continuationBlock);
|
|
return;
|
|
}
|
|
case 'WithStatement': {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `JavaScript 'with' syntax is not supported`,
|
|
description: `'with' syntax is considered deprecated and removed from JavaScript standards, consider alternatives`,
|
|
category: ErrorCategory.UnsupportedSyntax,
|
|
loc: (_30 = stmtPath.node.loc) !== null && _30 !== void 0 ? _30 : null,
|
|
suggestions: null,
|
|
}));
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
loc: (_31 = stmtPath.node.loc) !== null && _31 !== void 0 ? _31 : GeneratedSource,
|
|
node: stmtPath.node,
|
|
});
|
|
return;
|
|
}
|
|
case 'ClassDeclaration': {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: 'Inline `class` declarations are not supported',
|
|
description: `Move class declarations outside of components/hooks`,
|
|
category: ErrorCategory.UnsupportedSyntax,
|
|
loc: (_32 = stmtPath.node.loc) !== null && _32 !== void 0 ? _32 : null,
|
|
suggestions: null,
|
|
}));
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
loc: (_33 = stmtPath.node.loc) !== null && _33 !== void 0 ? _33 : GeneratedSource,
|
|
node: stmtPath.node,
|
|
});
|
|
return;
|
|
}
|
|
case 'EnumDeclaration':
|
|
case 'TSEnumDeclaration': {
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
loc: (_34 = stmtPath.node.loc) !== null && _34 !== void 0 ? _34 : GeneratedSource,
|
|
node: stmtPath.node,
|
|
});
|
|
return;
|
|
}
|
|
case 'ExportAllDeclaration':
|
|
case 'ExportDefaultDeclaration':
|
|
case 'ExportNamedDeclaration':
|
|
case 'ImportDeclaration':
|
|
case 'TSExportAssignment':
|
|
case 'TSImportEqualsDeclaration': {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: 'JavaScript `import` and `export` statements may only appear at the top level of a module',
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_35 = stmtPath.node.loc) !== null && _35 !== void 0 ? _35 : null,
|
|
suggestions: null,
|
|
}));
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
loc: (_36 = stmtPath.node.loc) !== null && _36 !== void 0 ? _36 : GeneratedSource,
|
|
node: stmtPath.node,
|
|
});
|
|
return;
|
|
}
|
|
case 'TSNamespaceExportDeclaration': {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: 'TypeScript `namespace` statements may only appear at the top level of a module',
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_37 = stmtPath.node.loc) !== null && _37 !== void 0 ? _37 : null,
|
|
suggestions: null,
|
|
}));
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
loc: (_38 = stmtPath.node.loc) !== null && _38 !== void 0 ? _38 : GeneratedSource,
|
|
node: stmtPath.node,
|
|
});
|
|
return;
|
|
}
|
|
case 'DeclareClass':
|
|
case 'DeclareExportAllDeclaration':
|
|
case 'DeclareExportDeclaration':
|
|
case 'DeclareFunction':
|
|
case 'DeclareInterface':
|
|
case 'DeclareModule':
|
|
case 'DeclareModuleExports':
|
|
case 'DeclareOpaqueType':
|
|
case 'DeclareTypeAlias':
|
|
case 'DeclareVariable':
|
|
case 'InterfaceDeclaration':
|
|
case 'OpaqueType':
|
|
case 'TSDeclareFunction':
|
|
case 'TSInterfaceDeclaration':
|
|
case 'TSModuleDeclaration':
|
|
case 'TSTypeAliasDeclaration':
|
|
case 'TypeAlias': {
|
|
return;
|
|
}
|
|
default: {
|
|
return assertExhaustive$1(stmtNode, `Unsupported statement kind '${stmtNode.type}'`);
|
|
}
|
|
}
|
|
}
|
|
function lowerObjectMethod(builder, property) {
|
|
var _a;
|
|
const loc = (_a = property.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource;
|
|
const loweredFunc = lowerFunction(builder, property);
|
|
return {
|
|
kind: 'ObjectMethod',
|
|
loc,
|
|
loweredFunc,
|
|
};
|
|
}
|
|
function lowerObjectPropertyKey(builder, property) {
|
|
var _a;
|
|
const key = property.get('key');
|
|
if (key.isStringLiteral()) {
|
|
return {
|
|
kind: 'string',
|
|
name: key.node.value,
|
|
};
|
|
}
|
|
else if (property.node.computed && key.isExpression()) {
|
|
const place = lowerExpressionToTemporary(builder, key);
|
|
return {
|
|
kind: 'computed',
|
|
name: place,
|
|
};
|
|
}
|
|
else if (key.isIdentifier()) {
|
|
return {
|
|
kind: 'identifier',
|
|
name: key.node.name,
|
|
};
|
|
}
|
|
else if (key.isNumericLiteral()) {
|
|
return {
|
|
kind: 'identifier',
|
|
name: String(key.node.value),
|
|
};
|
|
}
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_a = key.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
suggestions: null,
|
|
}));
|
|
return null;
|
|
}
|
|
function lowerExpression(builder, exprPath) {
|
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23;
|
|
const exprNode = exprPath.node;
|
|
const exprLoc = (_a = exprNode.loc) !== null && _a !== void 0 ? _a : GeneratedSource;
|
|
switch (exprNode.type) {
|
|
case 'Identifier': {
|
|
const expr = exprPath;
|
|
const place = lowerIdentifier(builder, expr);
|
|
return {
|
|
kind: getLoadKind(builder, expr),
|
|
place,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'NullLiteral': {
|
|
return {
|
|
kind: 'Primitive',
|
|
value: null,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'BooleanLiteral':
|
|
case 'NumericLiteral':
|
|
case 'StringLiteral': {
|
|
const expr = exprPath;
|
|
const value = expr.node.value;
|
|
return {
|
|
kind: 'Primitive',
|
|
value,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'ObjectExpression': {
|
|
const expr = exprPath;
|
|
const propertyPaths = expr.get('properties');
|
|
const properties = [];
|
|
for (const propertyPath of propertyPaths) {
|
|
if (propertyPath.isObjectProperty()) {
|
|
const loweredKey = lowerObjectPropertyKey(builder, propertyPath);
|
|
if (!loweredKey) {
|
|
continue;
|
|
}
|
|
const valuePath = propertyPath.get('value');
|
|
if (!valuePath.isExpression()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle ${valuePath.type} values in ObjectExpression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_b = valuePath.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
const value = lowerExpressionToTemporary(builder, valuePath);
|
|
properties.push({
|
|
kind: 'ObjectProperty',
|
|
type: 'property',
|
|
place: value,
|
|
key: loweredKey,
|
|
});
|
|
}
|
|
else if (propertyPath.isSpreadElement()) {
|
|
const place = lowerExpressionToTemporary(builder, propertyPath.get('argument'));
|
|
properties.push({
|
|
kind: 'Spread',
|
|
place,
|
|
});
|
|
}
|
|
else if (propertyPath.isObjectMethod()) {
|
|
if (propertyPath.node.kind !== 'method') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle ${propertyPath.node.kind} functions in ObjectExpression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_c = propertyPath.node.loc) !== null && _c !== void 0 ? _c : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
const method = lowerObjectMethod(builder, propertyPath);
|
|
const place = lowerValueToTemporary(builder, method);
|
|
const loweredKey = lowerObjectPropertyKey(builder, propertyPath);
|
|
if (!loweredKey) {
|
|
continue;
|
|
}
|
|
properties.push({
|
|
kind: 'ObjectProperty',
|
|
type: 'method',
|
|
place,
|
|
key: loweredKey,
|
|
});
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle ${propertyPath.type} properties in ObjectExpression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_d = propertyPath.node.loc) !== null && _d !== void 0 ? _d : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
}
|
|
return {
|
|
kind: 'ObjectExpression',
|
|
properties,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'ArrayExpression': {
|
|
const expr = exprPath;
|
|
let elements = [];
|
|
for (const element of expr.get('elements')) {
|
|
if (element.node == null) {
|
|
elements.push({
|
|
kind: 'Hole',
|
|
});
|
|
continue;
|
|
}
|
|
else if (element.isExpression()) {
|
|
elements.push(lowerExpressionToTemporary(builder, element));
|
|
}
|
|
else if (element.isSpreadElement()) {
|
|
const place = lowerExpressionToTemporary(builder, element.get('argument'));
|
|
elements.push({ kind: 'Spread', place });
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle ${element.type} elements in ArrayExpression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_e = element.node.loc) !== null && _e !== void 0 ? _e : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
}
|
|
return {
|
|
kind: 'ArrayExpression',
|
|
elements,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'NewExpression': {
|
|
const expr = exprPath;
|
|
const calleePath = expr.get('callee');
|
|
if (!calleePath.isExpression()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Expected an expression as the \`new\` expression receiver (v8 intrinsics are not supported)`,
|
|
description: `Got a \`${calleePath.node.type}\``,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_f = calleePath.node.loc) !== null && _f !== void 0 ? _f : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
const callee = lowerExpressionToTemporary(builder, calleePath);
|
|
const args = lowerArguments(builder, expr.get('arguments'));
|
|
return {
|
|
kind: 'NewExpression',
|
|
callee,
|
|
args,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'OptionalCallExpression': {
|
|
const expr = exprPath;
|
|
return lowerOptionalCallExpression(builder, expr, null);
|
|
}
|
|
case 'CallExpression': {
|
|
const expr = exprPath;
|
|
const calleePath = expr.get('callee');
|
|
if (!calleePath.isExpression()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Expected Expression, got ${calleePath.type} in CallExpression (v8 intrinsics not supported). This error is likely caused by a bug in React Compiler. Please file an issue`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_g = calleePath.node.loc) !== null && _g !== void 0 ? _g : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
if (calleePath.isMemberExpression()) {
|
|
const memberExpr = lowerMemberExpression(builder, calleePath);
|
|
const propertyPlace = lowerValueToTemporary(builder, memberExpr.value);
|
|
const args = lowerArguments(builder, expr.get('arguments'));
|
|
return {
|
|
kind: 'MethodCall',
|
|
receiver: memberExpr.object,
|
|
property: Object.assign({}, propertyPlace),
|
|
args,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
else {
|
|
const callee = lowerExpressionToTemporary(builder, calleePath);
|
|
const args = lowerArguments(builder, expr.get('arguments'));
|
|
return {
|
|
kind: 'CallExpression',
|
|
callee,
|
|
args,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
}
|
|
case 'BinaryExpression': {
|
|
const expr = exprPath;
|
|
const leftPath = expr.get('left');
|
|
if (!leftPath.isExpression()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Expected Expression, got ${leftPath.type} lval in BinaryExpression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_h = leftPath.node.loc) !== null && _h !== void 0 ? _h : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
const left = lowerExpressionToTemporary(builder, leftPath);
|
|
const right = lowerExpressionToTemporary(builder, expr.get('right'));
|
|
const operator = expr.node.operator;
|
|
if (operator === '|>') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Pipe operator not supported`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_j = leftPath.node.loc) !== null && _j !== void 0 ? _j : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
return {
|
|
kind: 'BinaryExpression',
|
|
operator,
|
|
left,
|
|
right,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'SequenceExpression': {
|
|
const expr = exprPath;
|
|
const exprLoc = (_k = expr.node.loc) !== null && _k !== void 0 ? _k : GeneratedSource;
|
|
const continuationBlock = builder.reserve(builder.currentBlockKind());
|
|
const place = buildTemporaryPlace(builder, exprLoc);
|
|
const sequenceBlock = builder.enter('sequence', _ => {
|
|
var _a;
|
|
let last = null;
|
|
for (const item of expr.get('expressions')) {
|
|
last = lowerExpressionToTemporary(builder, item);
|
|
}
|
|
if (last === null) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Expected sequence expression to have at least one expression`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_a = expr.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
else {
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, place) },
|
|
value: last,
|
|
type: null,
|
|
loc: exprLoc,
|
|
});
|
|
}
|
|
return {
|
|
kind: 'goto',
|
|
id: makeInstructionId(0),
|
|
block: continuationBlock.id,
|
|
loc: exprLoc,
|
|
variant: GotoVariant.Break,
|
|
};
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'sequence',
|
|
block: sequenceBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: exprLoc,
|
|
}, continuationBlock);
|
|
return { kind: 'LoadLocal', place, loc: place.loc };
|
|
}
|
|
case 'ConditionalExpression': {
|
|
const expr = exprPath;
|
|
const exprLoc = (_l = expr.node.loc) !== null && _l !== void 0 ? _l : GeneratedSource;
|
|
const continuationBlock = builder.reserve(builder.currentBlockKind());
|
|
const testBlock = builder.reserve('value');
|
|
const place = buildTemporaryPlace(builder, exprLoc);
|
|
const consequentBlock = builder.enter('value', _blockId => {
|
|
var _a;
|
|
const consequentPath = expr.get('consequent');
|
|
const consequent = lowerExpressionToTemporary(builder, consequentPath);
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, place) },
|
|
value: consequent,
|
|
type: null,
|
|
loc: exprLoc,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
block: continuationBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = consequentPath.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
const alternateBlock = builder.enter('value', _blockId => {
|
|
var _a;
|
|
const alternatePath = expr.get('alternate');
|
|
const alternate = lowerExpressionToTemporary(builder, alternatePath);
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, place) },
|
|
value: alternate,
|
|
type: null,
|
|
loc: exprLoc,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
block: continuationBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_a = alternatePath.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
};
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'ternary',
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
test: testBlock.id,
|
|
loc: exprLoc,
|
|
}, testBlock);
|
|
const testPlace = lowerExpressionToTemporary(builder, expr.get('test'));
|
|
builder.terminateWithContinuation({
|
|
kind: 'branch',
|
|
test: Object.assign({}, testPlace),
|
|
consequent: consequentBlock,
|
|
alternate: alternateBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: exprLoc,
|
|
}, continuationBlock);
|
|
return { kind: 'LoadLocal', place, loc: place.loc };
|
|
}
|
|
case 'LogicalExpression': {
|
|
const expr = exprPath;
|
|
const exprLoc = (_m = expr.node.loc) !== null && _m !== void 0 ? _m : GeneratedSource;
|
|
const continuationBlock = builder.reserve(builder.currentBlockKind());
|
|
const testBlock = builder.reserve('value');
|
|
const place = buildTemporaryPlace(builder, exprLoc);
|
|
const leftPlace = buildTemporaryPlace(builder, (_o = expr.get('left').node.loc) !== null && _o !== void 0 ? _o : GeneratedSource);
|
|
const consequent = builder.enter('value', () => {
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, place) },
|
|
value: Object.assign({}, leftPlace),
|
|
type: null,
|
|
loc: leftPlace.loc,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
block: continuationBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: leftPlace.loc,
|
|
};
|
|
});
|
|
const alternate = builder.enter('value', () => {
|
|
const right = lowerExpressionToTemporary(builder, expr.get('right'));
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, place) },
|
|
value: Object.assign({}, right),
|
|
type: null,
|
|
loc: right.loc,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
block: continuationBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: right.loc,
|
|
};
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'logical',
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
test: testBlock.id,
|
|
operator: expr.node.operator,
|
|
loc: exprLoc,
|
|
}, testBlock);
|
|
const leftValue = lowerExpressionToTemporary(builder, expr.get('left'));
|
|
builder.push({
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign({}, leftPlace),
|
|
value: {
|
|
kind: 'LoadLocal',
|
|
place: leftValue,
|
|
loc: exprLoc,
|
|
},
|
|
effects: null,
|
|
loc: exprLoc,
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'branch',
|
|
test: Object.assign({}, leftPlace),
|
|
consequent,
|
|
alternate,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: exprLoc,
|
|
}, continuationBlock);
|
|
return { kind: 'LoadLocal', place, loc: place.loc };
|
|
}
|
|
case 'AssignmentExpression': {
|
|
const expr = exprPath;
|
|
const operator = expr.node.operator;
|
|
if (operator === '=') {
|
|
const left = expr.get('left');
|
|
if (left.isLVal()) {
|
|
return lowerAssignment(builder, (_p = left.node.loc) !== null && _p !== void 0 ? _p : GeneratedSource, InstructionKind.Reassign, left, lowerExpressionToTemporary(builder, expr.get('right')), left.isArrayPattern() || left.isObjectPattern()
|
|
? 'Destructure'
|
|
: 'Assignment');
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Unsupported syntax on the left side of an AssignmentExpression`,
|
|
description: `Expected an LVal, got: ${left.type}`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_q = left.node.loc) !== null && _q !== void 0 ? _q : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
}
|
|
const operators = {
|
|
'+=': '+',
|
|
'-=': '-',
|
|
'/=': '/',
|
|
'%=': '%',
|
|
'*=': '*',
|
|
'**=': '**',
|
|
'&=': '&',
|
|
'|=': '|',
|
|
'>>=': '>>',
|
|
'>>>=': '>>>',
|
|
'<<=': '<<',
|
|
'^=': '^',
|
|
};
|
|
const binaryOperator = operators[operator];
|
|
if (binaryOperator == null) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle ${operator} operators in AssignmentExpression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_r = expr.node.loc) !== null && _r !== void 0 ? _r : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
const left = expr.get('left');
|
|
const leftNode = left.node;
|
|
switch (leftNode.type) {
|
|
case 'Identifier': {
|
|
const leftExpr = left;
|
|
const leftPlace = lowerExpressionToTemporary(builder, leftExpr);
|
|
const right = lowerExpressionToTemporary(builder, expr.get('right'));
|
|
const binaryPlace = lowerValueToTemporary(builder, {
|
|
kind: 'BinaryExpression',
|
|
operator: binaryOperator,
|
|
left: leftPlace,
|
|
right,
|
|
loc: exprLoc,
|
|
});
|
|
const binding = builder.resolveIdentifier(leftExpr);
|
|
if (binding.kind === 'Identifier') {
|
|
const identifier = lowerIdentifier(builder, leftExpr);
|
|
const kind = getStoreKind(builder, leftExpr);
|
|
if (kind === 'StoreLocal') {
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: {
|
|
place: Object.assign({}, identifier),
|
|
kind: InstructionKind.Reassign,
|
|
},
|
|
value: Object.assign({}, binaryPlace),
|
|
type: null,
|
|
loc: exprLoc,
|
|
});
|
|
return { kind: 'LoadLocal', place: identifier, loc: exprLoc };
|
|
}
|
|
else {
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreContext',
|
|
lvalue: {
|
|
place: Object.assign({}, identifier),
|
|
kind: InstructionKind.Reassign,
|
|
},
|
|
value: Object.assign({}, binaryPlace),
|
|
loc: exprLoc,
|
|
});
|
|
return { kind: 'LoadContext', place: identifier, loc: exprLoc };
|
|
}
|
|
}
|
|
else {
|
|
const temporary = lowerValueToTemporary(builder, {
|
|
kind: 'StoreGlobal',
|
|
name: leftExpr.node.name,
|
|
value: Object.assign({}, binaryPlace),
|
|
loc: exprLoc,
|
|
});
|
|
return { kind: 'LoadLocal', place: temporary, loc: temporary.loc };
|
|
}
|
|
}
|
|
case 'MemberExpression': {
|
|
const leftExpr = left;
|
|
const { object, property, value } = lowerMemberExpression(builder, leftExpr);
|
|
const previousValuePlace = lowerValueToTemporary(builder, value);
|
|
const newValuePlace = lowerValueToTemporary(builder, {
|
|
kind: 'BinaryExpression',
|
|
operator: binaryOperator,
|
|
left: Object.assign({}, previousValuePlace),
|
|
right: lowerExpressionToTemporary(builder, expr.get('right')),
|
|
loc: (_s = leftExpr.node.loc) !== null && _s !== void 0 ? _s : GeneratedSource,
|
|
});
|
|
if (typeof property === 'string' || typeof property === 'number') {
|
|
return {
|
|
kind: 'PropertyStore',
|
|
object: Object.assign({}, object),
|
|
property: makePropertyLiteral(property),
|
|
value: Object.assign({}, newValuePlace),
|
|
loc: (_t = leftExpr.node.loc) !== null && _t !== void 0 ? _t : GeneratedSource,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
kind: 'ComputedStore',
|
|
object: Object.assign({}, object),
|
|
property: Object.assign({}, property),
|
|
value: Object.assign({}, newValuePlace),
|
|
loc: (_u = leftExpr.node.loc) !== null && _u !== void 0 ? _u : GeneratedSource,
|
|
};
|
|
}
|
|
}
|
|
default: {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Expected Identifier or MemberExpression, got ${expr.type} lval in AssignmentExpression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_v = expr.node.loc) !== null && _v !== void 0 ? _v : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
}
|
|
}
|
|
case 'OptionalMemberExpression': {
|
|
const expr = exprPath;
|
|
const { value } = lowerOptionalMemberExpression(builder, expr, null);
|
|
return { kind: 'LoadLocal', place: value, loc: value.loc };
|
|
}
|
|
case 'MemberExpression': {
|
|
const expr = exprPath;
|
|
const { value } = lowerMemberExpression(builder, expr);
|
|
const place = lowerValueToTemporary(builder, value);
|
|
return { kind: 'LoadLocal', place, loc: place.loc };
|
|
}
|
|
case 'JSXElement': {
|
|
const expr = exprPath;
|
|
const opening = expr.get('openingElement');
|
|
const openingLoc = (_w = opening.node.loc) !== null && _w !== void 0 ? _w : GeneratedSource;
|
|
const tag = lowerJsxElementName(builder, opening.get('name'));
|
|
const props = [];
|
|
for (const attribute of opening.get('attributes')) {
|
|
if (attribute.isJSXSpreadAttribute()) {
|
|
const argument = lowerExpressionToTemporary(builder, attribute.get('argument'));
|
|
props.push({ kind: 'JsxSpreadAttribute', argument });
|
|
continue;
|
|
}
|
|
if (!attribute.isJSXAttribute()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle ${attribute.type} attributes in JSXElement`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_x = attribute.node.loc) !== null && _x !== void 0 ? _x : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
const namePath = attribute.get('name');
|
|
let propName;
|
|
if (namePath.isJSXIdentifier()) {
|
|
propName = namePath.node.name;
|
|
if (propName.indexOf(':') !== -1) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Unexpected colon in attribute name \`${propName}\``,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_y = namePath.node.loc) !== null && _y !== void 0 ? _y : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
}
|
|
else {
|
|
CompilerError.invariant(namePath.isJSXNamespacedName(), {
|
|
reason: 'Refinement',
|
|
loc: (_z = namePath.node.loc) !== null && _z !== void 0 ? _z : GeneratedSource,
|
|
});
|
|
const namespace = namePath.node.namespace.name;
|
|
const name = namePath.node.name.name;
|
|
propName = `${namespace}:${name}`;
|
|
}
|
|
const valueExpr = attribute.get('value');
|
|
let value;
|
|
if (valueExpr.isJSXElement() || valueExpr.isStringLiteral()) {
|
|
value = lowerExpressionToTemporary(builder, valueExpr);
|
|
}
|
|
else if (valueExpr.type == null) {
|
|
value = lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: true,
|
|
loc: (_0 = attribute.node.loc) !== null && _0 !== void 0 ? _0 : GeneratedSource,
|
|
});
|
|
}
|
|
else {
|
|
if (!valueExpr.isJSXExpressionContainer()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle ${valueExpr.type} attribute values in JSXElement`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_2 = (_1 = valueExpr.node) === null || _1 === void 0 ? void 0 : _1.loc) !== null && _2 !== void 0 ? _2 : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
const expression = valueExpr.get('expression');
|
|
if (!expression.isExpression()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle ${expression.type} expressions in JSXExpressionContainer within JSXElement`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_3 = valueExpr.node.loc) !== null && _3 !== void 0 ? _3 : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
value = lowerExpressionToTemporary(builder, expression);
|
|
}
|
|
props.push({ kind: 'JsxAttribute', name: propName, place: value });
|
|
}
|
|
const isFbt = tag.kind === 'BuiltinTag' && (tag.name === 'fbt' || tag.name === 'fbs');
|
|
if (isFbt) {
|
|
const tagName = tag.name;
|
|
const openingIdentifier = opening.get('name');
|
|
const tagIdentifier = openingIdentifier.isJSXIdentifier()
|
|
? builder.resolveIdentifier(openingIdentifier)
|
|
: null;
|
|
if (tagIdentifier != null) {
|
|
CompilerError.invariant(tagIdentifier.kind !== 'Identifier', {
|
|
reason: `<${tagName}> tags should be module-level imports`,
|
|
loc: (_4 = openingIdentifier.node.loc) !== null && _4 !== void 0 ? _4 : GeneratedSource,
|
|
});
|
|
}
|
|
const fbtLocations = {
|
|
enum: new Array(),
|
|
plural: new Array(),
|
|
pronoun: new Array(),
|
|
};
|
|
expr.traverse({
|
|
JSXClosingElement(path) {
|
|
path.skip();
|
|
},
|
|
JSXNamespacedName(path) {
|
|
var _a, _b, _c;
|
|
if (path.node.namespace.name === tagName) {
|
|
switch (path.node.name.name) {
|
|
case 'enum':
|
|
fbtLocations.enum.push((_a = path.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource);
|
|
break;
|
|
case 'plural':
|
|
fbtLocations.plural.push((_b = path.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource);
|
|
break;
|
|
case 'pronoun':
|
|
fbtLocations.pronoun.push((_c = path.node.loc) !== null && _c !== void 0 ? _c : GeneratedSource);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
});
|
|
for (const [name, locations] of Object.entries(fbtLocations)) {
|
|
if (locations.length > 1) {
|
|
builder.recordError(new CompilerDiagnostic({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Support duplicate fbt tags',
|
|
description: `Support \`<${tagName}>\` tags with multiple \`<${tagName}:${name}>\` values`,
|
|
details: locations.map(loc => {
|
|
return {
|
|
kind: 'error',
|
|
message: `Multiple \`<${tagName}:${name}>\` tags found`,
|
|
loc,
|
|
};
|
|
}),
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
isFbt && builder.fbtDepth++;
|
|
const children = expr
|
|
.get('children')
|
|
.map(child => lowerJsxElement(builder, child))
|
|
.filter(notNull);
|
|
isFbt && builder.fbtDepth--;
|
|
return {
|
|
kind: 'JsxExpression',
|
|
tag,
|
|
props,
|
|
children: children.length === 0 ? null : children,
|
|
loc: exprLoc,
|
|
openingLoc: openingLoc,
|
|
closingLoc: (_6 = (_5 = expr.get('closingElement').node) === null || _5 === void 0 ? void 0 : _5.loc) !== null && _6 !== void 0 ? _6 : GeneratedSource,
|
|
};
|
|
}
|
|
case 'JSXFragment': {
|
|
const expr = exprPath;
|
|
const children = expr
|
|
.get('children')
|
|
.map(child => lowerJsxElement(builder, child))
|
|
.filter(notNull);
|
|
return {
|
|
kind: 'JsxFragment',
|
|
children,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'ArrowFunctionExpression':
|
|
case 'FunctionExpression': {
|
|
const expr = exprPath;
|
|
return lowerFunctionToValue(builder, expr);
|
|
}
|
|
case 'TaggedTemplateExpression': {
|
|
const expr = exprPath;
|
|
if (expr.get('quasi').get('expressions').length !== 0) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: '(BuildHIR::lowerExpression) Handle tagged template with interpolations',
|
|
category: ErrorCategory.Todo,
|
|
loc: (_7 = exprPath.node.loc) !== null && _7 !== void 0 ? _7 : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
CompilerError.invariant(expr.get('quasi').get('quasis').length == 1, {
|
|
reason: "there should be only one quasi as we don't support interpolations yet",
|
|
loc: (_8 = expr.node.loc) !== null && _8 !== void 0 ? _8 : GeneratedSource,
|
|
});
|
|
const value = expr.get('quasi').get('quasis').at(0).node.value;
|
|
if (value.raw !== value.cooked) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: '(BuildHIR::lowerExpression) Handle tagged template where cooked value is different from raw value',
|
|
category: ErrorCategory.Todo,
|
|
loc: (_9 = exprPath.node.loc) !== null && _9 !== void 0 ? _9 : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
return {
|
|
kind: 'TaggedTemplateExpression',
|
|
tag: lowerExpressionToTemporary(builder, expr.get('tag')),
|
|
value,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'TemplateLiteral': {
|
|
const expr = exprPath;
|
|
const subexprs = expr.get('expressions');
|
|
const quasis = expr.get('quasis');
|
|
if (subexprs.length !== quasis.length - 1) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Unexpected quasi and subexpression lengths in template literal`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_10 = exprPath.node.loc) !== null && _10 !== void 0 ? _10 : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
if (subexprs.some(e => !e.isExpression())) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerAssignment) Handle TSType in TemplateLiteral.`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_11 = exprPath.node.loc) !== null && _11 !== void 0 ? _11 : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
const subexprPlaces = subexprs.map(e => lowerExpressionToTemporary(builder, e));
|
|
return {
|
|
kind: 'TemplateLiteral',
|
|
subexprs: subexprPlaces,
|
|
quasis: expr.get('quasis').map(q => q.node.value),
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'UnaryExpression': {
|
|
let expr = exprPath;
|
|
if (expr.node.operator === 'delete') {
|
|
const argument = expr.get('argument');
|
|
if (argument.isMemberExpression()) {
|
|
const { object, property } = lowerMemberExpression(builder, argument);
|
|
if (typeof property === 'string' || typeof property === 'number') {
|
|
return {
|
|
kind: 'PropertyDelete',
|
|
object,
|
|
property: makePropertyLiteral(property),
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
kind: 'ComputedDelete',
|
|
object,
|
|
property,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Only object properties can be deleted`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_12 = expr.node.loc) !== null && _12 !== void 0 ? _12 : null,
|
|
suggestions: [
|
|
{
|
|
description: 'Remove this line',
|
|
range: [expr.node.start, expr.node.end],
|
|
op: CompilerSuggestionOperation.Remove,
|
|
},
|
|
],
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: expr.node, loc: exprLoc };
|
|
}
|
|
}
|
|
else if (expr.node.operator === 'throw') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Throw expressions are not supported`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_13 = expr.node.loc) !== null && _13 !== void 0 ? _13 : null,
|
|
suggestions: [
|
|
{
|
|
description: 'Remove this line',
|
|
range: [expr.node.start, expr.node.end],
|
|
op: CompilerSuggestionOperation.Remove,
|
|
},
|
|
],
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: expr.node, loc: exprLoc };
|
|
}
|
|
else {
|
|
return {
|
|
kind: 'UnaryExpression',
|
|
operator: expr.node.operator,
|
|
value: lowerExpressionToTemporary(builder, expr.get('argument')),
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
}
|
|
case 'AwaitExpression': {
|
|
let expr = exprPath;
|
|
return {
|
|
kind: 'Await',
|
|
value: lowerExpressionToTemporary(builder, expr.get('argument')),
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'TypeCastExpression': {
|
|
let expr = exprPath;
|
|
const typeAnnotation = expr.get('typeAnnotation').get('typeAnnotation');
|
|
return {
|
|
kind: 'TypeCastExpression',
|
|
value: lowerExpressionToTemporary(builder, expr.get('expression')),
|
|
typeAnnotation: typeAnnotation.node,
|
|
typeAnnotationKind: 'cast',
|
|
type: lowerType(typeAnnotation.node),
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'TSSatisfiesExpression': {
|
|
let expr = exprPath;
|
|
const typeAnnotation = expr.get('typeAnnotation');
|
|
return {
|
|
kind: 'TypeCastExpression',
|
|
value: lowerExpressionToTemporary(builder, expr.get('expression')),
|
|
typeAnnotation: typeAnnotation.node,
|
|
typeAnnotationKind: 'satisfies',
|
|
type: lowerType(typeAnnotation.node),
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'TSAsExpression': {
|
|
let expr = exprPath;
|
|
const typeAnnotation = expr.get('typeAnnotation');
|
|
return {
|
|
kind: 'TypeCastExpression',
|
|
value: lowerExpressionToTemporary(builder, expr.get('expression')),
|
|
typeAnnotation: typeAnnotation.node,
|
|
typeAnnotationKind: 'as',
|
|
type: lowerType(typeAnnotation.node),
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
case 'UpdateExpression': {
|
|
let expr = exprPath;
|
|
const argument = expr.get('argument');
|
|
if (argument.isMemberExpression()) {
|
|
const binaryOperator = expr.node.operator === '++' ? '+' : '-';
|
|
const leftExpr = argument;
|
|
const { object, property, value } = lowerMemberExpression(builder, leftExpr);
|
|
const previousValuePlace = lowerValueToTemporary(builder, value);
|
|
const updatedValue = lowerValueToTemporary(builder, {
|
|
kind: 'BinaryExpression',
|
|
operator: binaryOperator,
|
|
left: Object.assign({}, previousValuePlace),
|
|
right: lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: 1,
|
|
loc: GeneratedSource,
|
|
}),
|
|
loc: (_14 = leftExpr.node.loc) !== null && _14 !== void 0 ? _14 : GeneratedSource,
|
|
});
|
|
let newValuePlace;
|
|
if (typeof property === 'string' || typeof property === 'number') {
|
|
newValuePlace = lowerValueToTemporary(builder, {
|
|
kind: 'PropertyStore',
|
|
object: Object.assign({}, object),
|
|
property: makePropertyLiteral(property),
|
|
value: Object.assign({}, updatedValue),
|
|
loc: (_15 = leftExpr.node.loc) !== null && _15 !== void 0 ? _15 : GeneratedSource,
|
|
});
|
|
}
|
|
else {
|
|
newValuePlace = lowerValueToTemporary(builder, {
|
|
kind: 'ComputedStore',
|
|
object: Object.assign({}, object),
|
|
property: Object.assign({}, property),
|
|
value: Object.assign({}, updatedValue),
|
|
loc: (_16 = leftExpr.node.loc) !== null && _16 !== void 0 ? _16 : GeneratedSource,
|
|
});
|
|
}
|
|
return {
|
|
kind: 'LoadLocal',
|
|
place: expr.node.prefix
|
|
? Object.assign({}, newValuePlace) : Object.assign({}, previousValuePlace),
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
if (!argument.isIdentifier()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle UpdateExpression with ${argument.type} argument`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_17 = exprPath.node.loc) !== null && _17 !== void 0 ? _17 : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
else if (builder.isContextIdentifier(argument)) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle UpdateExpression to variables captured within lambdas.`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_18 = exprPath.node.loc) !== null && _18 !== void 0 ? _18 : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
const lvalue = lowerIdentifierForAssignment(builder, (_19 = argument.node.loc) !== null && _19 !== void 0 ? _19 : GeneratedSource, InstructionKind.Reassign, argument);
|
|
if (lvalue === null) {
|
|
if (!builder.environment.hasErrors()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Found an invalid UpdateExpression without a previously reported error`,
|
|
category: ErrorCategory.Invariant,
|
|
loc: exprLoc,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
else if (lvalue.kind === 'Global') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Support UpdateExpression where argument is a global`,
|
|
category: ErrorCategory.Todo,
|
|
loc: exprLoc,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
const value = lowerIdentifier(builder, argument);
|
|
if (expr.node.prefix) {
|
|
return {
|
|
kind: 'PrefixUpdate',
|
|
lvalue,
|
|
operation: expr.node.operator,
|
|
value,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
kind: 'PostfixUpdate',
|
|
lvalue,
|
|
operation: expr.node.operator,
|
|
value,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
}
|
|
case 'RegExpLiteral': {
|
|
let expr = exprPath;
|
|
return {
|
|
kind: 'RegExpLiteral',
|
|
pattern: expr.node.pattern,
|
|
flags: expr.node.flags,
|
|
loc: (_20 = expr.node.loc) !== null && _20 !== void 0 ? _20 : GeneratedSource,
|
|
};
|
|
}
|
|
case 'TSInstantiationExpression':
|
|
case 'TSNonNullExpression': {
|
|
let expr = exprPath;
|
|
return lowerExpression(builder, expr.get('expression'));
|
|
}
|
|
case 'MetaProperty': {
|
|
let expr = exprPath;
|
|
if (expr.node.meta.name === 'import' &&
|
|
expr.node.property.name === 'meta') {
|
|
return {
|
|
kind: 'MetaProperty',
|
|
meta: expr.node.meta.name,
|
|
property: expr.node.property.name,
|
|
loc: (_21 = expr.node.loc) !== null && _21 !== void 0 ? _21 : GeneratedSource,
|
|
};
|
|
}
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle MetaProperty expressions other than import.meta`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_22 = exprPath.node.loc) !== null && _22 !== void 0 ? _22 : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
default: {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle ${exprPath.type} expressions`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_23 = exprPath.node.loc) !== null && _23 !== void 0 ? _23 : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
}
|
|
}
|
|
function lowerOptionalMemberExpression(builder, expr, parentAlternate) {
|
|
var _a;
|
|
const optional = expr.node.optional;
|
|
const loc = (_a = expr.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource;
|
|
const place = buildTemporaryPlace(builder, loc);
|
|
const continuationBlock = builder.reserve(builder.currentBlockKind());
|
|
const consequent = builder.reserve('value');
|
|
const alternate = parentAlternate !== null
|
|
? parentAlternate
|
|
: builder.enter('value', () => {
|
|
const temp = lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc,
|
|
});
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, place) },
|
|
value: Object.assign({}, temp),
|
|
type: null,
|
|
loc,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
variant: GotoVariant.Break,
|
|
block: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
};
|
|
});
|
|
let object = null;
|
|
const testBlock = builder.enter('value', () => {
|
|
const objectPath = expr.get('object');
|
|
if (objectPath.isOptionalMemberExpression()) {
|
|
const { value } = lowerOptionalMemberExpression(builder, objectPath, alternate);
|
|
object = value;
|
|
}
|
|
else if (objectPath.isOptionalCallExpression()) {
|
|
const value = lowerOptionalCallExpression(builder, objectPath, alternate);
|
|
object = lowerValueToTemporary(builder, value);
|
|
}
|
|
else {
|
|
object = lowerExpressionToTemporary(builder, objectPath);
|
|
}
|
|
return {
|
|
kind: 'branch',
|
|
test: Object.assign({}, object),
|
|
consequent: consequent.id,
|
|
alternate,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
};
|
|
});
|
|
CompilerError.invariant(object !== null, {
|
|
reason: 'Satisfy type checker',
|
|
loc: GeneratedSource,
|
|
});
|
|
builder.enterReserved(consequent, () => {
|
|
const { value } = lowerMemberExpression(builder, expr, object);
|
|
const temp = lowerValueToTemporary(builder, value);
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, place) },
|
|
value: Object.assign({}, temp),
|
|
type: null,
|
|
loc,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
variant: GotoVariant.Break,
|
|
block: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
};
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'optional',
|
|
optional,
|
|
test: testBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
}, continuationBlock);
|
|
return { object, value: place };
|
|
}
|
|
function lowerOptionalCallExpression(builder, expr, parentAlternate) {
|
|
var _a;
|
|
const optional = expr.node.optional;
|
|
const calleePath = expr.get('callee');
|
|
const loc = (_a = expr.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource;
|
|
const place = buildTemporaryPlace(builder, loc);
|
|
const continuationBlock = builder.reserve(builder.currentBlockKind());
|
|
const consequent = builder.reserve('value');
|
|
const alternate = parentAlternate !== null
|
|
? parentAlternate
|
|
: builder.enter('value', () => {
|
|
const temp = lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc,
|
|
});
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, place) },
|
|
value: Object.assign({}, temp),
|
|
type: null,
|
|
loc,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
variant: GotoVariant.Break,
|
|
block: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
};
|
|
});
|
|
let callee;
|
|
const testBlock = builder.enter('value', () => {
|
|
if (calleePath.isOptionalCallExpression()) {
|
|
const value = lowerOptionalCallExpression(builder, calleePath, alternate);
|
|
const valuePlace = lowerValueToTemporary(builder, value);
|
|
callee = {
|
|
kind: 'CallExpression',
|
|
callee: valuePlace,
|
|
};
|
|
}
|
|
else if (calleePath.isOptionalMemberExpression()) {
|
|
const { object, value } = lowerOptionalMemberExpression(builder, calleePath, alternate);
|
|
callee = {
|
|
kind: 'MethodCall',
|
|
receiver: object,
|
|
property: value,
|
|
};
|
|
}
|
|
else if (calleePath.isMemberExpression()) {
|
|
const memberExpr = lowerMemberExpression(builder, calleePath);
|
|
const propertyPlace = lowerValueToTemporary(builder, memberExpr.value);
|
|
callee = {
|
|
kind: 'MethodCall',
|
|
receiver: memberExpr.object,
|
|
property: propertyPlace,
|
|
};
|
|
}
|
|
else {
|
|
callee = {
|
|
kind: 'CallExpression',
|
|
callee: lowerExpressionToTemporary(builder, calleePath),
|
|
};
|
|
}
|
|
const testPlace = callee.kind === 'CallExpression' ? callee.callee : callee.property;
|
|
return {
|
|
kind: 'branch',
|
|
test: Object.assign({}, testPlace),
|
|
consequent: consequent.id,
|
|
alternate,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
};
|
|
});
|
|
builder.enterReserved(consequent, () => {
|
|
const args = lowerArguments(builder, expr.get('arguments'));
|
|
const temp = buildTemporaryPlace(builder, loc);
|
|
if (callee.kind === 'CallExpression') {
|
|
builder.push({
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign({}, temp),
|
|
value: {
|
|
kind: 'CallExpression',
|
|
callee: Object.assign({}, callee.callee),
|
|
args,
|
|
loc,
|
|
},
|
|
effects: null,
|
|
loc,
|
|
});
|
|
}
|
|
else {
|
|
builder.push({
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign({}, temp),
|
|
value: {
|
|
kind: 'MethodCall',
|
|
receiver: Object.assign({}, callee.receiver),
|
|
property: Object.assign({}, callee.property),
|
|
args,
|
|
loc,
|
|
},
|
|
effects: null,
|
|
loc,
|
|
});
|
|
}
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, place) },
|
|
value: Object.assign({}, temp),
|
|
type: null,
|
|
loc,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
variant: GotoVariant.Break,
|
|
block: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
};
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'optional',
|
|
optional,
|
|
test: testBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
}, continuationBlock);
|
|
return { kind: 'LoadLocal', place, loc: place.loc };
|
|
}
|
|
function lowerReorderableExpression(builder, expr) {
|
|
var _a;
|
|
if (!isReorderableExpression(builder, expr, true)) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::node.lowerReorderableExpression) Expression type \`${expr.type}\` cannot be safely reordered`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_a = expr.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
return lowerExpressionToTemporary(builder, expr);
|
|
}
|
|
function isReorderableExpression(builder, expr, allowLocalIdentifiers) {
|
|
switch (expr.node.type) {
|
|
case 'Identifier': {
|
|
const binding = builder.resolveIdentifier(expr);
|
|
if (binding.kind === 'Identifier') {
|
|
return allowLocalIdentifiers;
|
|
}
|
|
else {
|
|
return true;
|
|
}
|
|
}
|
|
case 'TSInstantiationExpression': {
|
|
const innerExpr = expr.get('expression');
|
|
return isReorderableExpression(builder, innerExpr, allowLocalIdentifiers);
|
|
}
|
|
case 'RegExpLiteral':
|
|
case 'StringLiteral':
|
|
case 'NumericLiteral':
|
|
case 'NullLiteral':
|
|
case 'BooleanLiteral':
|
|
case 'BigIntLiteral': {
|
|
return true;
|
|
}
|
|
case 'UnaryExpression': {
|
|
const unary = expr;
|
|
switch (expr.node.operator) {
|
|
case '!':
|
|
case '+':
|
|
case '-': {
|
|
return isReorderableExpression(builder, unary.get('argument'), allowLocalIdentifiers);
|
|
}
|
|
default: {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
case 'TSAsExpression':
|
|
case 'TSNonNullExpression':
|
|
case 'TypeCastExpression': {
|
|
return isReorderableExpression(builder, expr.get('expression'), allowLocalIdentifiers);
|
|
}
|
|
case 'LogicalExpression': {
|
|
const logical = expr;
|
|
return (isReorderableExpression(builder, logical.get('left'), allowLocalIdentifiers) &&
|
|
isReorderableExpression(builder, logical.get('right'), allowLocalIdentifiers));
|
|
}
|
|
case 'ConditionalExpression': {
|
|
const conditional = expr;
|
|
return (isReorderableExpression(builder, conditional.get('test'), allowLocalIdentifiers) &&
|
|
isReorderableExpression(builder, conditional.get('consequent'), allowLocalIdentifiers) &&
|
|
isReorderableExpression(builder, conditional.get('alternate'), allowLocalIdentifiers));
|
|
}
|
|
case 'ArrayExpression': {
|
|
return expr
|
|
.get('elements')
|
|
.every(element => element.isExpression() &&
|
|
isReorderableExpression(builder, element, allowLocalIdentifiers));
|
|
}
|
|
case 'ObjectExpression': {
|
|
return expr
|
|
.get('properties')
|
|
.every(property => {
|
|
if (!property.isObjectProperty() || property.node.computed) {
|
|
return false;
|
|
}
|
|
const value = property.get('value');
|
|
return (value.isExpression() &&
|
|
isReorderableExpression(builder, value, allowLocalIdentifiers));
|
|
});
|
|
}
|
|
case 'MemberExpression': {
|
|
const test = expr;
|
|
let innerObject = test;
|
|
while (innerObject.isMemberExpression()) {
|
|
innerObject = innerObject.get('object');
|
|
}
|
|
if (innerObject.isIdentifier() &&
|
|
builder.resolveIdentifier(innerObject).kind !== 'Identifier') {
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
case 'ArrowFunctionExpression': {
|
|
const fn = expr;
|
|
const body = fn.get('body');
|
|
if (body.node.type === 'BlockStatement') {
|
|
return body.node.body.length === 0;
|
|
}
|
|
else {
|
|
invariant(body.isExpression(), 'Expected an expression');
|
|
return isReorderableExpression(builder, body, false);
|
|
}
|
|
}
|
|
case 'CallExpression': {
|
|
const call = expr;
|
|
const callee = call.get('callee');
|
|
return (callee.isExpression() &&
|
|
isReorderableExpression(builder, callee, allowLocalIdentifiers) &&
|
|
call
|
|
.get('arguments')
|
|
.every(arg => arg.isExpression() &&
|
|
isReorderableExpression(builder, arg, allowLocalIdentifiers)));
|
|
}
|
|
case 'NewExpression': {
|
|
const newExpr = expr;
|
|
const callee = newExpr.get('callee');
|
|
return (callee.isExpression() &&
|
|
isReorderableExpression(builder, callee, allowLocalIdentifiers) &&
|
|
newExpr
|
|
.get('arguments')
|
|
.every(arg => arg.isExpression() &&
|
|
isReorderableExpression(builder, arg, allowLocalIdentifiers)));
|
|
}
|
|
default: {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
function lowerArguments(builder, expr) {
|
|
var _a;
|
|
let args = [];
|
|
for (const argPath of expr) {
|
|
if (argPath.isSpreadElement()) {
|
|
args.push({
|
|
kind: 'Spread',
|
|
place: lowerExpressionToTemporary(builder, argPath.get('argument')),
|
|
});
|
|
}
|
|
else if (argPath.isExpression()) {
|
|
args.push(lowerExpressionToTemporary(builder, argPath));
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in CallExpression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_a = argPath.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
}
|
|
return args;
|
|
}
|
|
function lowerMemberExpression(builder, expr, loweredObject = null) {
|
|
var _a, _b, _c;
|
|
const exprNode = expr.node;
|
|
const exprLoc = (_a = exprNode.loc) !== null && _a !== void 0 ? _a : GeneratedSource;
|
|
const objectNode = expr.get('object');
|
|
const propertyNode = expr.get('property');
|
|
const object = loweredObject !== null && loweredObject !== void 0 ? loweredObject : lowerExpressionToTemporary(builder, objectNode);
|
|
if (!expr.node.computed || expr.node.property.type === 'NumericLiteral') {
|
|
let property;
|
|
if (propertyNode.isIdentifier()) {
|
|
property = makePropertyLiteral(propertyNode.node.name);
|
|
}
|
|
else if (propertyNode.isNumericLiteral()) {
|
|
property = makePropertyLiteral(propertyNode.node.value);
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerMemberExpression) Handle ${propertyNode.type} property`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_b = propertyNode.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
suggestions: null,
|
|
}));
|
|
return {
|
|
object,
|
|
property: propertyNode.toString(),
|
|
value: { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc },
|
|
};
|
|
}
|
|
const value = {
|
|
kind: 'PropertyLoad',
|
|
object: Object.assign({}, object),
|
|
property,
|
|
loc: exprLoc,
|
|
};
|
|
return { object, property, value };
|
|
}
|
|
else {
|
|
if (!propertyNode.isExpression()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerMemberExpression) Expected Expression, got ${propertyNode.type} property`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_c = propertyNode.node.loc) !== null && _c !== void 0 ? _c : null,
|
|
suggestions: null,
|
|
}));
|
|
return {
|
|
object,
|
|
property: propertyNode.toString(),
|
|
value: {
|
|
kind: 'UnsupportedNode',
|
|
node: exprNode,
|
|
loc: exprLoc,
|
|
},
|
|
};
|
|
}
|
|
const property = lowerExpressionToTemporary(builder, propertyNode);
|
|
const value = {
|
|
kind: 'ComputedLoad',
|
|
object: Object.assign({}, object),
|
|
property: Object.assign({}, property),
|
|
loc: exprLoc,
|
|
};
|
|
return { object, property, value };
|
|
}
|
|
}
|
|
function lowerJsxElementName(builder, exprPath) {
|
|
var _a, _b, _c;
|
|
const exprNode = exprPath.node;
|
|
const exprLoc = (_a = exprNode.loc) !== null && _a !== void 0 ? _a : GeneratedSource;
|
|
if (exprPath.isJSXIdentifier()) {
|
|
const tag = exprPath.node.name;
|
|
if (tag.match(/^[A-Z]/)) {
|
|
const kind = getLoadKind(builder, exprPath);
|
|
return lowerValueToTemporary(builder, {
|
|
kind: kind,
|
|
place: lowerIdentifier(builder, exprPath),
|
|
loc: exprLoc,
|
|
});
|
|
}
|
|
else {
|
|
return {
|
|
kind: 'BuiltinTag',
|
|
name: tag,
|
|
loc: exprLoc,
|
|
};
|
|
}
|
|
}
|
|
else if (exprPath.isJSXMemberExpression()) {
|
|
return lowerJsxMemberExpression(builder, exprPath);
|
|
}
|
|
else if (exprPath.isJSXNamespacedName()) {
|
|
const namespace = exprPath.node.namespace.name;
|
|
const name = exprPath.node.name.name;
|
|
const tag = `${namespace}:${name}`;
|
|
if (namespace.indexOf(':') !== -1 || name.indexOf(':') !== -1) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Expected JSXNamespacedName to have no colons in the namespace or name`,
|
|
description: `Got \`${namespace}\` : \`${name}\``,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_b = exprPath.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
const place = lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: tag,
|
|
loc: exprLoc,
|
|
});
|
|
return place;
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerJsxElementName) Handle ${exprPath.type} tags`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_c = exprPath.node.loc) !== null && _c !== void 0 ? _c : null,
|
|
suggestions: null,
|
|
}));
|
|
return lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
node: exprNode,
|
|
loc: exprLoc,
|
|
});
|
|
}
|
|
}
|
|
function lowerJsxMemberExpression(builder, exprPath) {
|
|
var _a, _b, _c;
|
|
const loc = (_a = exprPath.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource;
|
|
const object = exprPath.get('object');
|
|
let objectPlace;
|
|
if (object.isJSXMemberExpression()) {
|
|
objectPlace = lowerJsxMemberExpression(builder, object);
|
|
}
|
|
else {
|
|
CompilerError.invariant(object.isJSXIdentifier(), {
|
|
reason: `TypeScript refinement fail: expected 'JsxIdentifier', got \`${object.node.type}\``,
|
|
loc: (_b = object.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
});
|
|
const kind = getLoadKind(builder, object);
|
|
objectPlace = lowerValueToTemporary(builder, {
|
|
kind: kind,
|
|
place: lowerIdentifier(builder, object),
|
|
loc: (_c = exprPath.node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
});
|
|
}
|
|
const property = exprPath.get('property').node.name;
|
|
return lowerValueToTemporary(builder, {
|
|
kind: 'PropertyLoad',
|
|
object: objectPlace,
|
|
property: makePropertyLiteral(property),
|
|
loc,
|
|
});
|
|
}
|
|
function lowerJsxElement(builder, exprPath) {
|
|
var _a, _b, _c;
|
|
const exprNode = exprPath.node;
|
|
const exprLoc = (_a = exprNode.loc) !== null && _a !== void 0 ? _a : GeneratedSource;
|
|
if (exprPath.isJSXElement() || exprPath.isJSXFragment()) {
|
|
return lowerExpressionToTemporary(builder, exprPath);
|
|
}
|
|
else if (exprPath.isJSXExpressionContainer()) {
|
|
const expression = exprPath.get('expression');
|
|
if (expression.isJSXEmptyExpression()) {
|
|
return null;
|
|
}
|
|
else {
|
|
CompilerError.invariant(expression.isExpression(), {
|
|
reason: `(BuildHIR::lowerJsxElement) Expected Expression but found ${expression.type}!`,
|
|
loc: (_b = expression.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
});
|
|
return lowerExpressionToTemporary(builder, expression);
|
|
}
|
|
}
|
|
else if (exprPath.isJSXText()) {
|
|
let text;
|
|
if (builder.fbtDepth > 0) {
|
|
text = exprPath.node.value;
|
|
}
|
|
else {
|
|
text = trimJsxText(exprPath.node.value);
|
|
}
|
|
if (text === null) {
|
|
return null;
|
|
}
|
|
const place = lowerValueToTemporary(builder, {
|
|
kind: 'JSXText',
|
|
value: text,
|
|
loc: exprLoc,
|
|
});
|
|
return place;
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerJsxElement) Unhandled JsxElement, got: ${exprPath.type}`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_c = exprPath.node.loc) !== null && _c !== void 0 ? _c : null,
|
|
suggestions: null,
|
|
}));
|
|
const place = lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
node: exprNode,
|
|
loc: exprLoc,
|
|
});
|
|
return place;
|
|
}
|
|
}
|
|
function trimJsxText(original) {
|
|
const lines = original.split(/\r\n|\n|\r/);
|
|
let lastNonEmptyLine = 0;
|
|
for (let i = 0; i < lines.length; i++) {
|
|
if (lines[i].match(/[^ \t]/)) {
|
|
lastNonEmptyLine = i;
|
|
}
|
|
}
|
|
let str = '';
|
|
for (let i = 0; i < lines.length; i++) {
|
|
const line = lines[i];
|
|
const isFirstLine = i === 0;
|
|
const isLastLine = i === lines.length - 1;
|
|
const isLastNonEmptyLine = i === lastNonEmptyLine;
|
|
let trimmedLine = line.replace(/\t/g, ' ');
|
|
if (!isFirstLine) {
|
|
trimmedLine = trimmedLine.replace(/^[ ]+/, '');
|
|
}
|
|
if (!isLastLine) {
|
|
trimmedLine = trimmedLine.replace(/[ ]+$/, '');
|
|
}
|
|
if (trimmedLine) {
|
|
if (!isLastNonEmptyLine) {
|
|
trimmedLine += ' ';
|
|
}
|
|
str += trimmedLine;
|
|
}
|
|
}
|
|
if (str.length !== 0) {
|
|
return str;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
function lowerFunctionToValue(builder, expr) {
|
|
var _a;
|
|
const exprNode = expr.node;
|
|
const exprLoc = (_a = exprNode.loc) !== null && _a !== void 0 ? _a : GeneratedSource;
|
|
const loweredFunc = lowerFunction(builder, expr);
|
|
return {
|
|
kind: 'FunctionExpression',
|
|
name: loweredFunc.func.id,
|
|
nameHint: null,
|
|
type: expr.node.type,
|
|
loc: exprLoc,
|
|
loweredFunc,
|
|
};
|
|
}
|
|
function lowerFunction(builder, expr) {
|
|
const componentScope = builder.environment.parentFunction.scope;
|
|
const capturedContext = gatherCapturedContext(expr, componentScope);
|
|
const loweredFunc = lower(expr, builder.environment, builder.bindings, new Map([...builder.context, ...capturedContext]));
|
|
return {
|
|
func: loweredFunc,
|
|
};
|
|
}
|
|
function lowerExpressionToTemporary(builder, exprPath) {
|
|
const value = lowerExpression(builder, exprPath);
|
|
return lowerValueToTemporary(builder, value);
|
|
}
|
|
function lowerValueToTemporary(builder, value) {
|
|
if (value.kind === 'LoadLocal' && value.place.identifier.name === null) {
|
|
return value.place;
|
|
}
|
|
const place = buildTemporaryPlace(builder, value.loc);
|
|
builder.push({
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign({}, place),
|
|
value: value,
|
|
effects: null,
|
|
loc: value.loc,
|
|
});
|
|
return place;
|
|
}
|
|
function lowerIdentifier(builder, exprPath) {
|
|
var _a, _b;
|
|
const exprNode = exprPath.node;
|
|
const exprLoc = (_a = exprNode.loc) !== null && _a !== void 0 ? _a : GeneratedSource;
|
|
const binding = builder.resolveIdentifier(exprPath);
|
|
switch (binding.kind) {
|
|
case 'Identifier': {
|
|
const place = {
|
|
kind: 'Identifier',
|
|
identifier: binding.identifier,
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc: exprLoc,
|
|
};
|
|
return place;
|
|
}
|
|
default: {
|
|
if (binding.kind === 'Global' && binding.name === 'eval') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `The 'eval' function is not supported`,
|
|
description: 'Eval is an anti-pattern in JavaScript, and the code executed cannot be evaluated by React Compiler',
|
|
category: ErrorCategory.UnsupportedSyntax,
|
|
loc: (_b = exprPath.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
return lowerValueToTemporary(builder, {
|
|
kind: 'LoadGlobal',
|
|
binding,
|
|
loc: exprLoc,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
function buildTemporaryPlace(builder, loc) {
|
|
const place = {
|
|
kind: 'Identifier',
|
|
identifier: builder.makeTemporary(loc),
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc,
|
|
};
|
|
return place;
|
|
}
|
|
function getStoreKind(builder, identifier) {
|
|
const isContext = builder.isContextIdentifier(identifier);
|
|
return isContext ? 'StoreContext' : 'StoreLocal';
|
|
}
|
|
function getLoadKind(builder, identifier) {
|
|
const isContext = builder.isContextIdentifier(identifier);
|
|
return isContext ? 'LoadContext' : 'LoadLocal';
|
|
}
|
|
function lowerIdentifierForAssignment(builder, loc, kind, path) {
|
|
var _a, _b;
|
|
const binding = builder.resolveIdentifier(path);
|
|
if (binding.kind !== 'Identifier') {
|
|
if (kind === InstructionKind.Reassign) {
|
|
return { kind: 'Global', name: path.node.name };
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerAssignment) Could not find binding for declaration.`,
|
|
category: ErrorCategory.Invariant,
|
|
loc: (_a = path.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
suggestions: null,
|
|
}));
|
|
return null;
|
|
}
|
|
}
|
|
else if (binding.bindingKind === 'const' &&
|
|
kind === InstructionKind.Reassign) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Cannot reassign a \`const\` variable`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_b = path.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
description: binding.identifier.name != null
|
|
? `\`${binding.identifier.name.value}\` is declared as const`
|
|
: null,
|
|
}));
|
|
return null;
|
|
}
|
|
const place = {
|
|
kind: 'Identifier',
|
|
identifier: binding.identifier,
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc,
|
|
};
|
|
return place;
|
|
}
|
|
function lowerAssignment(builder, loc, kind, lvaluePath, value, assignmentKind) {
|
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4;
|
|
const lvalueNode = lvaluePath.node;
|
|
switch (lvalueNode.type) {
|
|
case 'Identifier': {
|
|
const lvalue = lvaluePath;
|
|
const place = lowerIdentifierForAssignment(builder, loc, kind, lvalue);
|
|
if (place === null) {
|
|
return {
|
|
kind: 'UnsupportedNode',
|
|
loc: (_a = lvalue.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
node: lvalue.node,
|
|
};
|
|
}
|
|
else if (place.kind === 'Global') {
|
|
const temporary = lowerValueToTemporary(builder, {
|
|
kind: 'StoreGlobal',
|
|
name: place.name,
|
|
value,
|
|
loc,
|
|
});
|
|
return { kind: 'LoadLocal', place: temporary, loc: temporary.loc };
|
|
}
|
|
const isHoistedIdentifier = builder.environment.isHoistedIdentifier(lvalue.node);
|
|
let temporary;
|
|
if (builder.isContextIdentifier(lvalue)) {
|
|
if (kind === InstructionKind.Const && !isHoistedIdentifier) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Expected \`const\` declaration not to be reassigned`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_b = lvalue.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
if (kind !== InstructionKind.Const &&
|
|
kind !== InstructionKind.Reassign &&
|
|
kind !== InstructionKind.Let &&
|
|
kind !== InstructionKind.Function) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `Unexpected context variable kind`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_c = lvalue.node.loc) !== null && _c !== void 0 ? _c : null,
|
|
suggestions: null,
|
|
}));
|
|
temporary = lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
node: lvalueNode,
|
|
loc: (_d = lvalueNode.loc) !== null && _d !== void 0 ? _d : GeneratedSource,
|
|
});
|
|
}
|
|
else {
|
|
temporary = lowerValueToTemporary(builder, {
|
|
kind: 'StoreContext',
|
|
lvalue: { place: Object.assign({}, place), kind },
|
|
value,
|
|
loc,
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
const typeAnnotation = lvalue.get('typeAnnotation');
|
|
let type;
|
|
if (typeAnnotation.isTSTypeAnnotation()) {
|
|
const typePath = typeAnnotation.get('typeAnnotation');
|
|
type = typePath.node;
|
|
}
|
|
else if (typeAnnotation.isTypeAnnotation()) {
|
|
const typePath = typeAnnotation.get('typeAnnotation');
|
|
type = typePath.node;
|
|
}
|
|
else {
|
|
type = null;
|
|
}
|
|
temporary = lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { place: Object.assign({}, place), kind },
|
|
value,
|
|
type,
|
|
loc,
|
|
});
|
|
}
|
|
return { kind: 'LoadLocal', place: temporary, loc: temporary.loc };
|
|
}
|
|
case 'MemberExpression': {
|
|
CompilerError.invariant(kind === InstructionKind.Reassign, {
|
|
reason: 'MemberExpression may only appear in an assignment expression',
|
|
loc: (_e = lvaluePath.node.loc) !== null && _e !== void 0 ? _e : GeneratedSource,
|
|
});
|
|
const lvalue = lvaluePath;
|
|
const property = lvalue.get('property');
|
|
const object = lowerExpressionToTemporary(builder, lvalue.get('object'));
|
|
if (!lvalue.node.computed || lvalue.get('property').isNumericLiteral()) {
|
|
let temporary;
|
|
if (property.isIdentifier()) {
|
|
temporary = lowerValueToTemporary(builder, {
|
|
kind: 'PropertyStore',
|
|
object,
|
|
property: makePropertyLiteral(property.node.name),
|
|
value,
|
|
loc,
|
|
});
|
|
}
|
|
else if (property.isNumericLiteral()) {
|
|
temporary = lowerValueToTemporary(builder, {
|
|
kind: 'PropertyStore',
|
|
object,
|
|
property: makePropertyLiteral(property.node.value),
|
|
value,
|
|
loc,
|
|
});
|
|
}
|
|
else {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in MemberExpression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_f = property.node.loc) !== null && _f !== void 0 ? _f : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: lvalueNode, loc };
|
|
}
|
|
return { kind: 'LoadLocal', place: temporary, loc: temporary.loc };
|
|
}
|
|
else {
|
|
if (!property.isExpression()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: '(BuildHIR::lowerAssignment) Expected private name to appear as a non-computed property',
|
|
category: ErrorCategory.Todo,
|
|
loc: (_g = property.node.loc) !== null && _g !== void 0 ? _g : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: lvalueNode, loc };
|
|
}
|
|
const propertyPlace = lowerExpressionToTemporary(builder, property);
|
|
const temporary = lowerValueToTemporary(builder, {
|
|
kind: 'ComputedStore',
|
|
object,
|
|
property: propertyPlace,
|
|
value,
|
|
loc,
|
|
});
|
|
return { kind: 'LoadLocal', place: temporary, loc: temporary.loc };
|
|
}
|
|
}
|
|
case 'ArrayPattern': {
|
|
const lvalue = lvaluePath;
|
|
const elements = lvalue.get('elements');
|
|
const items = [];
|
|
const followups = [];
|
|
const forceTemporaries = kind === InstructionKind.Reassign &&
|
|
(elements.some(element => !element.isIdentifier()) ||
|
|
elements.some(element => element.isIdentifier() &&
|
|
(getStoreKind(builder, element) !== 'StoreLocal' ||
|
|
builder.resolveIdentifier(element).kind !== 'Identifier')));
|
|
for (let i = 0; i < elements.length; i++) {
|
|
const element = elements[i];
|
|
if (element.node == null) {
|
|
items.push({
|
|
kind: 'Hole',
|
|
});
|
|
continue;
|
|
}
|
|
if (element.isRestElement()) {
|
|
const argument = element.get('argument');
|
|
if (argument.isIdentifier() &&
|
|
!forceTemporaries &&
|
|
(assignmentKind === 'Assignment' ||
|
|
getStoreKind(builder, argument) === 'StoreLocal')) {
|
|
const identifier = lowerIdentifierForAssignment(builder, (_h = element.node.loc) !== null && _h !== void 0 ? _h : GeneratedSource, kind, argument);
|
|
if (identifier === null) {
|
|
continue;
|
|
}
|
|
else if (identifier.kind === 'Global') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Expected reassignment of globals to enable forceTemporaries',
|
|
loc: (_j = element.node.loc) !== null && _j !== void 0 ? _j : GeneratedSource,
|
|
}));
|
|
continue;
|
|
}
|
|
items.push({
|
|
kind: 'Spread',
|
|
place: identifier,
|
|
});
|
|
}
|
|
else {
|
|
const temp = buildTemporaryPlace(builder, (_k = element.node.loc) !== null && _k !== void 0 ? _k : GeneratedSource);
|
|
promoteTemporary(temp.identifier);
|
|
items.push({
|
|
kind: 'Spread',
|
|
place: Object.assign({}, temp),
|
|
});
|
|
followups.push({ place: temp, path: argument });
|
|
}
|
|
}
|
|
else if (element.isIdentifier() &&
|
|
!forceTemporaries &&
|
|
(assignmentKind === 'Assignment' ||
|
|
getStoreKind(builder, element) === 'StoreLocal')) {
|
|
const identifier = lowerIdentifierForAssignment(builder, (_l = element.node.loc) !== null && _l !== void 0 ? _l : GeneratedSource, kind, element);
|
|
if (identifier === null) {
|
|
continue;
|
|
}
|
|
else if (identifier.kind === 'Global') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Expected reassignment of globals to enable forceTemporaries',
|
|
loc: (_m = element.node.loc) !== null && _m !== void 0 ? _m : GeneratedSource,
|
|
}));
|
|
continue;
|
|
}
|
|
items.push(identifier);
|
|
}
|
|
else {
|
|
const temp = buildTemporaryPlace(builder, (_o = element.node.loc) !== null && _o !== void 0 ? _o : GeneratedSource);
|
|
promoteTemporary(temp.identifier);
|
|
items.push(Object.assign({}, temp));
|
|
followups.push({ place: temp, path: element });
|
|
}
|
|
}
|
|
const temporary = lowerValueToTemporary(builder, {
|
|
kind: 'Destructure',
|
|
lvalue: {
|
|
kind,
|
|
pattern: {
|
|
kind: 'ArrayPattern',
|
|
items,
|
|
loc: (_p = lvalue.node.loc) !== null && _p !== void 0 ? _p : GeneratedSource,
|
|
},
|
|
},
|
|
value,
|
|
loc,
|
|
});
|
|
for (const { place, path } of followups) {
|
|
lowerAssignment(builder, (_q = path.node.loc) !== null && _q !== void 0 ? _q : loc, kind, path, place, assignmentKind);
|
|
}
|
|
return { kind: 'LoadLocal', place: temporary, loc: value.loc };
|
|
}
|
|
case 'ObjectPattern': {
|
|
const lvalue = lvaluePath;
|
|
const propertiesPaths = lvalue.get('properties');
|
|
const properties = [];
|
|
const followups = [];
|
|
const forceTemporaries = kind === InstructionKind.Reassign &&
|
|
propertiesPaths.some(property => property.isRestElement() ||
|
|
(property.isObjectProperty() &&
|
|
(!property.get('value').isIdentifier() ||
|
|
builder.resolveIdentifier(property.get('value')).kind !== 'Identifier')));
|
|
for (let i = 0; i < propertiesPaths.length; i++) {
|
|
const property = propertiesPaths[i];
|
|
if (property.isRestElement()) {
|
|
const argument = property.get('argument');
|
|
if (!argument.isIdentifier()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerAssignment) Handle ${argument.node.type} rest element in ObjectPattern`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_r = argument.node.loc) !== null && _r !== void 0 ? _r : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
if (forceTemporaries ||
|
|
getStoreKind(builder, argument) === 'StoreContext') {
|
|
const temp = buildTemporaryPlace(builder, (_s = property.node.loc) !== null && _s !== void 0 ? _s : GeneratedSource);
|
|
promoteTemporary(temp.identifier);
|
|
properties.push({
|
|
kind: 'Spread',
|
|
place: Object.assign({}, temp),
|
|
});
|
|
followups.push({ place: temp, path: argument });
|
|
}
|
|
else {
|
|
const identifier = lowerIdentifierForAssignment(builder, (_t = property.node.loc) !== null && _t !== void 0 ? _t : GeneratedSource, kind, argument);
|
|
if (identifier === null) {
|
|
continue;
|
|
}
|
|
else if (identifier.kind === 'Global') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Expected reassignment of globals to enable forceTemporaries',
|
|
loc: (_u = property.node.loc) !== null && _u !== void 0 ? _u : GeneratedSource,
|
|
}));
|
|
continue;
|
|
}
|
|
properties.push({
|
|
kind: 'Spread',
|
|
place: identifier,
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
if (!property.isObjectProperty()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in ObjectPattern`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_v = property.node.loc) !== null && _v !== void 0 ? _v : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
if (property.node.computed) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_w = property.node.loc) !== null && _w !== void 0 ? _w : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
const loweredKey = lowerObjectPropertyKey(builder, property);
|
|
if (!loweredKey) {
|
|
continue;
|
|
}
|
|
const element = property.get('value');
|
|
if (!element.isLVal()) {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerAssignment) Expected object property value to be an LVal, got: ${element.type}`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_x = element.node.loc) !== null && _x !== void 0 ? _x : null,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
if (element.isIdentifier() &&
|
|
!forceTemporaries &&
|
|
(assignmentKind === 'Assignment' ||
|
|
getStoreKind(builder, element) === 'StoreLocal')) {
|
|
const identifier = lowerIdentifierForAssignment(builder, (_y = element.node.loc) !== null && _y !== void 0 ? _y : GeneratedSource, kind, element);
|
|
if (identifier === null) {
|
|
continue;
|
|
}
|
|
else if (identifier.kind === 'Global') {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Expected reassignment of globals to enable forceTemporaries',
|
|
loc: (_z = element.node.loc) !== null && _z !== void 0 ? _z : GeneratedSource,
|
|
}));
|
|
continue;
|
|
}
|
|
properties.push({
|
|
kind: 'ObjectProperty',
|
|
type: 'property',
|
|
place: identifier,
|
|
key: loweredKey,
|
|
});
|
|
}
|
|
else {
|
|
const temp = buildTemporaryPlace(builder, (_0 = element.node.loc) !== null && _0 !== void 0 ? _0 : GeneratedSource);
|
|
promoteTemporary(temp.identifier);
|
|
properties.push({
|
|
kind: 'ObjectProperty',
|
|
type: 'property',
|
|
place: Object.assign({}, temp),
|
|
key: loweredKey,
|
|
});
|
|
followups.push({ place: temp, path: element });
|
|
}
|
|
}
|
|
}
|
|
const temporary = lowerValueToTemporary(builder, {
|
|
kind: 'Destructure',
|
|
lvalue: {
|
|
kind,
|
|
pattern: {
|
|
kind: 'ObjectPattern',
|
|
properties,
|
|
loc: (_1 = lvalue.node.loc) !== null && _1 !== void 0 ? _1 : GeneratedSource,
|
|
},
|
|
},
|
|
value,
|
|
loc,
|
|
});
|
|
for (const { place, path } of followups) {
|
|
lowerAssignment(builder, (_2 = path.node.loc) !== null && _2 !== void 0 ? _2 : loc, kind, path, place, assignmentKind);
|
|
}
|
|
return { kind: 'LoadLocal', place: temporary, loc: value.loc };
|
|
}
|
|
case 'AssignmentPattern': {
|
|
const lvalue = lvaluePath;
|
|
const loc = (_3 = lvalue.node.loc) !== null && _3 !== void 0 ? _3 : GeneratedSource;
|
|
const temp = buildTemporaryPlace(builder, loc);
|
|
const testBlock = builder.reserve('value');
|
|
const continuationBlock = builder.reserve(builder.currentBlockKind());
|
|
const consequent = builder.enter('value', () => {
|
|
const defaultValue = lowerReorderableExpression(builder, lvalue.get('right'));
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, temp) },
|
|
value: Object.assign({}, defaultValue),
|
|
type: null,
|
|
loc,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
variant: GotoVariant.Break,
|
|
block: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
};
|
|
});
|
|
const alternate = builder.enter('value', () => {
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, temp) },
|
|
value: Object.assign({}, value),
|
|
type: null,
|
|
loc,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
variant: GotoVariant.Break,
|
|
block: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
};
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'ternary',
|
|
test: testBlock.id,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
}, testBlock);
|
|
const undef = lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc,
|
|
});
|
|
const test = lowerValueToTemporary(builder, {
|
|
kind: 'BinaryExpression',
|
|
left: Object.assign({}, value),
|
|
operator: '===',
|
|
right: Object.assign({}, undef),
|
|
loc,
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'branch',
|
|
test: Object.assign({}, test),
|
|
consequent,
|
|
alternate,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
}, continuationBlock);
|
|
return lowerAssignment(builder, loc, kind, lvalue.get('left'), temp, assignmentKind);
|
|
}
|
|
default: {
|
|
builder.recordError(new CompilerErrorDetail({
|
|
reason: `(BuildHIR::lowerAssignment) Handle ${lvaluePath.type} assignments`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_4 = lvaluePath.node.loc) !== null && _4 !== void 0 ? _4 : null,
|
|
suggestions: null,
|
|
}));
|
|
return { kind: 'UnsupportedNode', node: lvalueNode, loc };
|
|
}
|
|
}
|
|
}
|
|
function captureScopes({ from, to }) {
|
|
let scopes = new Set();
|
|
while (from) {
|
|
scopes.add(from);
|
|
if (from === to) {
|
|
break;
|
|
}
|
|
from = from.parent;
|
|
}
|
|
return scopes;
|
|
}
|
|
function gatherCapturedContext(fn, componentScope) {
|
|
const capturedIds = new Map();
|
|
const pureScopes = captureScopes({
|
|
from: fn.scope.parent,
|
|
to: componentScope,
|
|
});
|
|
function handleMaybeDependency(path) {
|
|
var _a, _b;
|
|
let baseIdentifier;
|
|
if (path.isJSXOpeningElement()) {
|
|
const name = path.get('name');
|
|
if (!(name.isJSXMemberExpression() || name.isJSXIdentifier())) {
|
|
return;
|
|
}
|
|
let current = name;
|
|
while (current.isJSXMemberExpression()) {
|
|
current = current.get('object');
|
|
}
|
|
invariant(current.isJSXIdentifier(), 'Invalid logic in gatherCapturedDeps');
|
|
baseIdentifier = current;
|
|
}
|
|
else {
|
|
baseIdentifier = path;
|
|
}
|
|
path.skip();
|
|
const binding = baseIdentifier.scope.getBinding(baseIdentifier.node.name);
|
|
if (binding !== undefined &&
|
|
pureScopes.has(binding.scope) &&
|
|
!capturedIds.has(binding.identifier)) {
|
|
capturedIds.set(binding.identifier, (_b = (_a = path.node.loc) !== null && _a !== void 0 ? _a : binding.identifier.loc) !== null && _b !== void 0 ? _b : GeneratedSource);
|
|
}
|
|
}
|
|
fn.traverse({
|
|
TypeAnnotation(path) {
|
|
path.skip();
|
|
},
|
|
TSTypeAnnotation(path) {
|
|
path.skip();
|
|
},
|
|
TypeAlias(path) {
|
|
path.skip();
|
|
},
|
|
TSTypeAliasDeclaration(path) {
|
|
path.skip();
|
|
},
|
|
Expression(path) {
|
|
if (path.isAssignmentExpression()) {
|
|
const left = path.get('left');
|
|
if (left.isIdentifier()) {
|
|
handleMaybeDependency(left);
|
|
}
|
|
return;
|
|
}
|
|
else if (path.isJSXElement()) {
|
|
handleMaybeDependency(path.get('openingElement'));
|
|
}
|
|
else if (path.isIdentifier()) {
|
|
handleMaybeDependency(path);
|
|
}
|
|
},
|
|
});
|
|
return capturedIds;
|
|
}
|
|
function notNull(value) {
|
|
return value !== null;
|
|
}
|
|
function lowerType(node) {
|
|
switch (node.type) {
|
|
case 'GenericTypeAnnotation': {
|
|
const id = node.id;
|
|
if (id.type === 'Identifier' && id.name === 'Array') {
|
|
return { kind: 'Object', shapeId: BuiltInArrayId };
|
|
}
|
|
return makeType();
|
|
}
|
|
case 'TSTypeReference': {
|
|
const typeName = node.typeName;
|
|
if (typeName.type === 'Identifier' && typeName.name === 'Array') {
|
|
return { kind: 'Object', shapeId: BuiltInArrayId };
|
|
}
|
|
return makeType();
|
|
}
|
|
case 'ArrayTypeAnnotation':
|
|
case 'TSArrayType': {
|
|
return { kind: 'Object', shapeId: BuiltInArrayId };
|
|
}
|
|
case 'BooleanLiteralTypeAnnotation':
|
|
case 'BooleanTypeAnnotation':
|
|
case 'NullLiteralTypeAnnotation':
|
|
case 'NumberLiteralTypeAnnotation':
|
|
case 'NumberTypeAnnotation':
|
|
case 'StringLiteralTypeAnnotation':
|
|
case 'StringTypeAnnotation':
|
|
case 'TSBooleanKeyword':
|
|
case 'TSNullKeyword':
|
|
case 'TSNumberKeyword':
|
|
case 'TSStringKeyword':
|
|
case 'TSSymbolKeyword':
|
|
case 'TSUndefinedKeyword':
|
|
case 'TSVoidKeyword':
|
|
case 'VoidTypeAnnotation': {
|
|
return { kind: 'Primitive' };
|
|
}
|
|
default: {
|
|
return makeType();
|
|
}
|
|
}
|
|
}
|
|
|
|
function buildReactiveScopeTerminalsHIR(fn) {
|
|
const queuedRewrites = [];
|
|
recursivelyTraverseItems([...getScopes(fn)], scope => scope.range, {
|
|
fallthroughs: new Map(),
|
|
rewrites: queuedRewrites,
|
|
env: fn.env,
|
|
}, pushStartScopeTerminal, pushEndScopeTerminal);
|
|
const rewrittenFinalBlocks = new Map();
|
|
const nextBlocks = new Map();
|
|
queuedRewrites.reverse();
|
|
for (const [, block] of fn.body.blocks) {
|
|
const context = {
|
|
nextBlockId: block.id,
|
|
rewrites: [],
|
|
nextPreds: block.preds,
|
|
instrSliceIdx: 0,
|
|
source: block,
|
|
};
|
|
for (let i = 0; i < block.instructions.length + 1; i++) {
|
|
const instrId = i < block.instructions.length
|
|
? block.instructions[i].id
|
|
: block.terminal.id;
|
|
let rewrite = queuedRewrites.at(-1);
|
|
while (rewrite != null && rewrite.instrId <= instrId) {
|
|
handleRewrite(rewrite, i, context);
|
|
queuedRewrites.pop();
|
|
rewrite = queuedRewrites.at(-1);
|
|
}
|
|
}
|
|
if (context.rewrites.length > 0) {
|
|
const finalBlock = {
|
|
id: context.nextBlockId,
|
|
kind: block.kind,
|
|
preds: context.nextPreds,
|
|
terminal: block.terminal,
|
|
instructions: block.instructions.slice(context.instrSliceIdx),
|
|
phis: new Set(),
|
|
};
|
|
context.rewrites.push(finalBlock);
|
|
for (const b of context.rewrites) {
|
|
nextBlocks.set(b.id, b);
|
|
}
|
|
rewrittenFinalBlocks.set(block.id, finalBlock.id);
|
|
}
|
|
else {
|
|
nextBlocks.set(block.id, block);
|
|
}
|
|
}
|
|
const originalBlocks = fn.body.blocks;
|
|
fn.body.blocks = nextBlocks;
|
|
for (const [, block] of originalBlocks) {
|
|
for (const phi of block.phis) {
|
|
for (const [originalId, value] of phi.operands) {
|
|
const newId = rewrittenFinalBlocks.get(originalId);
|
|
if (newId != null) {
|
|
phi.operands.delete(originalId);
|
|
phi.operands.set(newId, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
reversePostorderBlocks(fn.body);
|
|
markPredecessors(fn.body);
|
|
markInstructionIds(fn.body);
|
|
fixScopeAndIdentifierRanges(fn.body);
|
|
}
|
|
function pushStartScopeTerminal(scope, context) {
|
|
const blockId = context.env.nextBlockId;
|
|
const fallthroughId = context.env.nextBlockId;
|
|
context.rewrites.push({
|
|
kind: 'StartScope',
|
|
blockId,
|
|
fallthroughId,
|
|
instrId: scope.range.start,
|
|
scope,
|
|
});
|
|
context.fallthroughs.set(scope.id, fallthroughId);
|
|
}
|
|
function pushEndScopeTerminal(scope, context) {
|
|
const fallthroughId = context.fallthroughs.get(scope.id);
|
|
CompilerError.invariant(fallthroughId != null, {
|
|
reason: 'Expected scope to exist',
|
|
loc: GeneratedSource,
|
|
});
|
|
context.rewrites.push({
|
|
kind: 'EndScope',
|
|
fallthroughId,
|
|
instrId: scope.range.end,
|
|
});
|
|
}
|
|
function handleRewrite(terminalInfo, idx, context) {
|
|
const terminal = terminalInfo.kind === 'StartScope'
|
|
? {
|
|
kind: 'scope',
|
|
fallthrough: terminalInfo.fallthroughId,
|
|
block: terminalInfo.blockId,
|
|
scope: terminalInfo.scope,
|
|
id: terminalInfo.instrId,
|
|
loc: GeneratedSource,
|
|
}
|
|
: {
|
|
kind: 'goto',
|
|
variant: GotoVariant.Break,
|
|
block: terminalInfo.fallthroughId,
|
|
id: terminalInfo.instrId,
|
|
loc: GeneratedSource,
|
|
};
|
|
const currBlockId = context.nextBlockId;
|
|
context.rewrites.push({
|
|
kind: context.source.kind,
|
|
id: currBlockId,
|
|
instructions: context.source.instructions.slice(context.instrSliceIdx, idx),
|
|
preds: context.nextPreds,
|
|
phis: context.rewrites.length === 0 ? context.source.phis : new Set(),
|
|
terminal,
|
|
});
|
|
context.nextPreds = new Set([currBlockId]);
|
|
context.nextBlockId =
|
|
terminalInfo.kind === 'StartScope'
|
|
? terminalInfo.blockId
|
|
: terminalInfo.fallthroughId;
|
|
context.instrSliceIdx = idx;
|
|
}
|
|
|
|
var ansiStylesExports = {};
|
|
var ansiStyles = {
|
|
get exports(){ return ansiStylesExports; },
|
|
set exports(v){ ansiStylesExports = v; },
|
|
};
|
|
|
|
var conversionsExports = {};
|
|
var conversions = {
|
|
get exports(){ return conversionsExports; },
|
|
set exports(v){ conversionsExports = v; },
|
|
};
|
|
|
|
var colorName;
|
|
var hasRequiredColorName;
|
|
|
|
function requireColorName () {
|
|
if (hasRequiredColorName) return colorName;
|
|
hasRequiredColorName = 1;
|
|
|
|
colorName = {
|
|
"aliceblue": [240, 248, 255],
|
|
"antiquewhite": [250, 235, 215],
|
|
"aqua": [0, 255, 255],
|
|
"aquamarine": [127, 255, 212],
|
|
"azure": [240, 255, 255],
|
|
"beige": [245, 245, 220],
|
|
"bisque": [255, 228, 196],
|
|
"black": [0, 0, 0],
|
|
"blanchedalmond": [255, 235, 205],
|
|
"blue": [0, 0, 255],
|
|
"blueviolet": [138, 43, 226],
|
|
"brown": [165, 42, 42],
|
|
"burlywood": [222, 184, 135],
|
|
"cadetblue": [95, 158, 160],
|
|
"chartreuse": [127, 255, 0],
|
|
"chocolate": [210, 105, 30],
|
|
"coral": [255, 127, 80],
|
|
"cornflowerblue": [100, 149, 237],
|
|
"cornsilk": [255, 248, 220],
|
|
"crimson": [220, 20, 60],
|
|
"cyan": [0, 255, 255],
|
|
"darkblue": [0, 0, 139],
|
|
"darkcyan": [0, 139, 139],
|
|
"darkgoldenrod": [184, 134, 11],
|
|
"darkgray": [169, 169, 169],
|
|
"darkgreen": [0, 100, 0],
|
|
"darkgrey": [169, 169, 169],
|
|
"darkkhaki": [189, 183, 107],
|
|
"darkmagenta": [139, 0, 139],
|
|
"darkolivegreen": [85, 107, 47],
|
|
"darkorange": [255, 140, 0],
|
|
"darkorchid": [153, 50, 204],
|
|
"darkred": [139, 0, 0],
|
|
"darksalmon": [233, 150, 122],
|
|
"darkseagreen": [143, 188, 143],
|
|
"darkslateblue": [72, 61, 139],
|
|
"darkslategray": [47, 79, 79],
|
|
"darkslategrey": [47, 79, 79],
|
|
"darkturquoise": [0, 206, 209],
|
|
"darkviolet": [148, 0, 211],
|
|
"deeppink": [255, 20, 147],
|
|
"deepskyblue": [0, 191, 255],
|
|
"dimgray": [105, 105, 105],
|
|
"dimgrey": [105, 105, 105],
|
|
"dodgerblue": [30, 144, 255],
|
|
"firebrick": [178, 34, 34],
|
|
"floralwhite": [255, 250, 240],
|
|
"forestgreen": [34, 139, 34],
|
|
"fuchsia": [255, 0, 255],
|
|
"gainsboro": [220, 220, 220],
|
|
"ghostwhite": [248, 248, 255],
|
|
"gold": [255, 215, 0],
|
|
"goldenrod": [218, 165, 32],
|
|
"gray": [128, 128, 128],
|
|
"green": [0, 128, 0],
|
|
"greenyellow": [173, 255, 47],
|
|
"grey": [128, 128, 128],
|
|
"honeydew": [240, 255, 240],
|
|
"hotpink": [255, 105, 180],
|
|
"indianred": [205, 92, 92],
|
|
"indigo": [75, 0, 130],
|
|
"ivory": [255, 255, 240],
|
|
"khaki": [240, 230, 140],
|
|
"lavender": [230, 230, 250],
|
|
"lavenderblush": [255, 240, 245],
|
|
"lawngreen": [124, 252, 0],
|
|
"lemonchiffon": [255, 250, 205],
|
|
"lightblue": [173, 216, 230],
|
|
"lightcoral": [240, 128, 128],
|
|
"lightcyan": [224, 255, 255],
|
|
"lightgoldenrodyellow": [250, 250, 210],
|
|
"lightgray": [211, 211, 211],
|
|
"lightgreen": [144, 238, 144],
|
|
"lightgrey": [211, 211, 211],
|
|
"lightpink": [255, 182, 193],
|
|
"lightsalmon": [255, 160, 122],
|
|
"lightseagreen": [32, 178, 170],
|
|
"lightskyblue": [135, 206, 250],
|
|
"lightslategray": [119, 136, 153],
|
|
"lightslategrey": [119, 136, 153],
|
|
"lightsteelblue": [176, 196, 222],
|
|
"lightyellow": [255, 255, 224],
|
|
"lime": [0, 255, 0],
|
|
"limegreen": [50, 205, 50],
|
|
"linen": [250, 240, 230],
|
|
"magenta": [255, 0, 255],
|
|
"maroon": [128, 0, 0],
|
|
"mediumaquamarine": [102, 205, 170],
|
|
"mediumblue": [0, 0, 205],
|
|
"mediumorchid": [186, 85, 211],
|
|
"mediumpurple": [147, 112, 219],
|
|
"mediumseagreen": [60, 179, 113],
|
|
"mediumslateblue": [123, 104, 238],
|
|
"mediumspringgreen": [0, 250, 154],
|
|
"mediumturquoise": [72, 209, 204],
|
|
"mediumvioletred": [199, 21, 133],
|
|
"midnightblue": [25, 25, 112],
|
|
"mintcream": [245, 255, 250],
|
|
"mistyrose": [255, 228, 225],
|
|
"moccasin": [255, 228, 181],
|
|
"navajowhite": [255, 222, 173],
|
|
"navy": [0, 0, 128],
|
|
"oldlace": [253, 245, 230],
|
|
"olive": [128, 128, 0],
|
|
"olivedrab": [107, 142, 35],
|
|
"orange": [255, 165, 0],
|
|
"orangered": [255, 69, 0],
|
|
"orchid": [218, 112, 214],
|
|
"palegoldenrod": [238, 232, 170],
|
|
"palegreen": [152, 251, 152],
|
|
"paleturquoise": [175, 238, 238],
|
|
"palevioletred": [219, 112, 147],
|
|
"papayawhip": [255, 239, 213],
|
|
"peachpuff": [255, 218, 185],
|
|
"peru": [205, 133, 63],
|
|
"pink": [255, 192, 203],
|
|
"plum": [221, 160, 221],
|
|
"powderblue": [176, 224, 230],
|
|
"purple": [128, 0, 128],
|
|
"rebeccapurple": [102, 51, 153],
|
|
"red": [255, 0, 0],
|
|
"rosybrown": [188, 143, 143],
|
|
"royalblue": [65, 105, 225],
|
|
"saddlebrown": [139, 69, 19],
|
|
"salmon": [250, 128, 114],
|
|
"sandybrown": [244, 164, 96],
|
|
"seagreen": [46, 139, 87],
|
|
"seashell": [255, 245, 238],
|
|
"sienna": [160, 82, 45],
|
|
"silver": [192, 192, 192],
|
|
"skyblue": [135, 206, 235],
|
|
"slateblue": [106, 90, 205],
|
|
"slategray": [112, 128, 144],
|
|
"slategrey": [112, 128, 144],
|
|
"snow": [255, 250, 250],
|
|
"springgreen": [0, 255, 127],
|
|
"steelblue": [70, 130, 180],
|
|
"tan": [210, 180, 140],
|
|
"teal": [0, 128, 128],
|
|
"thistle": [216, 191, 216],
|
|
"tomato": [255, 99, 71],
|
|
"turquoise": [64, 224, 208],
|
|
"violet": [238, 130, 238],
|
|
"wheat": [245, 222, 179],
|
|
"white": [255, 255, 255],
|
|
"whitesmoke": [245, 245, 245],
|
|
"yellow": [255, 255, 0],
|
|
"yellowgreen": [154, 205, 50]
|
|
};
|
|
return colorName;
|
|
}
|
|
|
|
var hasRequiredConversions;
|
|
|
|
function requireConversions () {
|
|
if (hasRequiredConversions) return conversionsExports;
|
|
hasRequiredConversions = 1;
|
|
var cssKeywords = requireColorName();
|
|
|
|
// NOTE: conversions should only return primitive values (i.e. arrays, or
|
|
// values that give correct `typeof` results).
|
|
// do not use box values types (i.e. Number(), String(), etc.)
|
|
|
|
var reverseKeywords = {};
|
|
for (var key in cssKeywords) {
|
|
if (cssKeywords.hasOwnProperty(key)) {
|
|
reverseKeywords[cssKeywords[key]] = key;
|
|
}
|
|
}
|
|
|
|
var convert = conversions.exports = {
|
|
rgb: {channels: 3, labels: 'rgb'},
|
|
hsl: {channels: 3, labels: 'hsl'},
|
|
hsv: {channels: 3, labels: 'hsv'},
|
|
hwb: {channels: 3, labels: 'hwb'},
|
|
cmyk: {channels: 4, labels: 'cmyk'},
|
|
xyz: {channels: 3, labels: 'xyz'},
|
|
lab: {channels: 3, labels: 'lab'},
|
|
lch: {channels: 3, labels: 'lch'},
|
|
hex: {channels: 1, labels: ['hex']},
|
|
keyword: {channels: 1, labels: ['keyword']},
|
|
ansi16: {channels: 1, labels: ['ansi16']},
|
|
ansi256: {channels: 1, labels: ['ansi256']},
|
|
hcg: {channels: 3, labels: ['h', 'c', 'g']},
|
|
apple: {channels: 3, labels: ['r16', 'g16', 'b16']},
|
|
gray: {channels: 1, labels: ['gray']}
|
|
};
|
|
|
|
// hide .channels and .labels properties
|
|
for (var model in convert) {
|
|
if (convert.hasOwnProperty(model)) {
|
|
if (!('channels' in convert[model])) {
|
|
throw new Error('missing channels property: ' + model);
|
|
}
|
|
|
|
if (!('labels' in convert[model])) {
|
|
throw new Error('missing channel labels property: ' + model);
|
|
}
|
|
|
|
if (convert[model].labels.length !== convert[model].channels) {
|
|
throw new Error('channel and label counts mismatch: ' + model);
|
|
}
|
|
|
|
var channels = convert[model].channels;
|
|
var labels = convert[model].labels;
|
|
delete convert[model].channels;
|
|
delete convert[model].labels;
|
|
Object.defineProperty(convert[model], 'channels', {value: channels});
|
|
Object.defineProperty(convert[model], 'labels', {value: labels});
|
|
}
|
|
}
|
|
|
|
convert.rgb.hsl = function (rgb) {
|
|
var r = rgb[0] / 255;
|
|
var g = rgb[1] / 255;
|
|
var b = rgb[2] / 255;
|
|
var min = Math.min(r, g, b);
|
|
var max = Math.max(r, g, b);
|
|
var delta = max - min;
|
|
var h;
|
|
var s;
|
|
var l;
|
|
|
|
if (max === min) {
|
|
h = 0;
|
|
} else if (r === max) {
|
|
h = (g - b) / delta;
|
|
} else if (g === max) {
|
|
h = 2 + (b - r) / delta;
|
|
} else if (b === max) {
|
|
h = 4 + (r - g) / delta;
|
|
}
|
|
|
|
h = Math.min(h * 60, 360);
|
|
|
|
if (h < 0) {
|
|
h += 360;
|
|
}
|
|
|
|
l = (min + max) / 2;
|
|
|
|
if (max === min) {
|
|
s = 0;
|
|
} else if (l <= 0.5) {
|
|
s = delta / (max + min);
|
|
} else {
|
|
s = delta / (2 - max - min);
|
|
}
|
|
|
|
return [h, s * 100, l * 100];
|
|
};
|
|
|
|
convert.rgb.hsv = function (rgb) {
|
|
var rdif;
|
|
var gdif;
|
|
var bdif;
|
|
var h;
|
|
var s;
|
|
|
|
var r = rgb[0] / 255;
|
|
var g = rgb[1] / 255;
|
|
var b = rgb[2] / 255;
|
|
var v = Math.max(r, g, b);
|
|
var diff = v - Math.min(r, g, b);
|
|
var diffc = function (c) {
|
|
return (v - c) / 6 / diff + 1 / 2;
|
|
};
|
|
|
|
if (diff === 0) {
|
|
h = s = 0;
|
|
} else {
|
|
s = diff / v;
|
|
rdif = diffc(r);
|
|
gdif = diffc(g);
|
|
bdif = diffc(b);
|
|
|
|
if (r === v) {
|
|
h = bdif - gdif;
|
|
} else if (g === v) {
|
|
h = (1 / 3) + rdif - bdif;
|
|
} else if (b === v) {
|
|
h = (2 / 3) + gdif - rdif;
|
|
}
|
|
if (h < 0) {
|
|
h += 1;
|
|
} else if (h > 1) {
|
|
h -= 1;
|
|
}
|
|
}
|
|
|
|
return [
|
|
h * 360,
|
|
s * 100,
|
|
v * 100
|
|
];
|
|
};
|
|
|
|
convert.rgb.hwb = function (rgb) {
|
|
var r = rgb[0];
|
|
var g = rgb[1];
|
|
var b = rgb[2];
|
|
var h = convert.rgb.hsl(rgb)[0];
|
|
var w = 1 / 255 * Math.min(r, Math.min(g, b));
|
|
|
|
b = 1 - 1 / 255 * Math.max(r, Math.max(g, b));
|
|
|
|
return [h, w * 100, b * 100];
|
|
};
|
|
|
|
convert.rgb.cmyk = function (rgb) {
|
|
var r = rgb[0] / 255;
|
|
var g = rgb[1] / 255;
|
|
var b = rgb[2] / 255;
|
|
var c;
|
|
var m;
|
|
var y;
|
|
var k;
|
|
|
|
k = Math.min(1 - r, 1 - g, 1 - b);
|
|
c = (1 - r - k) / (1 - k) || 0;
|
|
m = (1 - g - k) / (1 - k) || 0;
|
|
y = (1 - b - k) / (1 - k) || 0;
|
|
|
|
return [c * 100, m * 100, y * 100, k * 100];
|
|
};
|
|
|
|
/**
|
|
* See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance
|
|
* */
|
|
function comparativeDistance(x, y) {
|
|
return (
|
|
Math.pow(x[0] - y[0], 2) +
|
|
Math.pow(x[1] - y[1], 2) +
|
|
Math.pow(x[2] - y[2], 2)
|
|
);
|
|
}
|
|
|
|
convert.rgb.keyword = function (rgb) {
|
|
var reversed = reverseKeywords[rgb];
|
|
if (reversed) {
|
|
return reversed;
|
|
}
|
|
|
|
var currentClosestDistance = Infinity;
|
|
var currentClosestKeyword;
|
|
|
|
for (var keyword in cssKeywords) {
|
|
if (cssKeywords.hasOwnProperty(keyword)) {
|
|
var value = cssKeywords[keyword];
|
|
|
|
// Compute comparative distance
|
|
var distance = comparativeDistance(rgb, value);
|
|
|
|
// Check if its less, if so set as closest
|
|
if (distance < currentClosestDistance) {
|
|
currentClosestDistance = distance;
|
|
currentClosestKeyword = keyword;
|
|
}
|
|
}
|
|
}
|
|
|
|
return currentClosestKeyword;
|
|
};
|
|
|
|
convert.keyword.rgb = function (keyword) {
|
|
return cssKeywords[keyword];
|
|
};
|
|
|
|
convert.rgb.xyz = function (rgb) {
|
|
var r = rgb[0] / 255;
|
|
var g = rgb[1] / 255;
|
|
var b = rgb[2] / 255;
|
|
|
|
// assume sRGB
|
|
r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
|
|
g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
|
|
b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
|
|
|
|
var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
|
|
var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
|
|
var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
|
|
|
|
return [x * 100, y * 100, z * 100];
|
|
};
|
|
|
|
convert.rgb.lab = function (rgb) {
|
|
var xyz = convert.rgb.xyz(rgb);
|
|
var x = xyz[0];
|
|
var y = xyz[1];
|
|
var z = xyz[2];
|
|
var l;
|
|
var a;
|
|
var b;
|
|
|
|
x /= 95.047;
|
|
y /= 100;
|
|
z /= 108.883;
|
|
|
|
x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
|
|
y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
|
|
z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
|
|
|
|
l = (116 * y) - 16;
|
|
a = 500 * (x - y);
|
|
b = 200 * (y - z);
|
|
|
|
return [l, a, b];
|
|
};
|
|
|
|
convert.hsl.rgb = function (hsl) {
|
|
var h = hsl[0] / 360;
|
|
var s = hsl[1] / 100;
|
|
var l = hsl[2] / 100;
|
|
var t1;
|
|
var t2;
|
|
var t3;
|
|
var rgb;
|
|
var val;
|
|
|
|
if (s === 0) {
|
|
val = l * 255;
|
|
return [val, val, val];
|
|
}
|
|
|
|
if (l < 0.5) {
|
|
t2 = l * (1 + s);
|
|
} else {
|
|
t2 = l + s - l * s;
|
|
}
|
|
|
|
t1 = 2 * l - t2;
|
|
|
|
rgb = [0, 0, 0];
|
|
for (var i = 0; i < 3; i++) {
|
|
t3 = h + 1 / 3 * -(i - 1);
|
|
if (t3 < 0) {
|
|
t3++;
|
|
}
|
|
if (t3 > 1) {
|
|
t3--;
|
|
}
|
|
|
|
if (6 * t3 < 1) {
|
|
val = t1 + (t2 - t1) * 6 * t3;
|
|
} else if (2 * t3 < 1) {
|
|
val = t2;
|
|
} else if (3 * t3 < 2) {
|
|
val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
|
|
} else {
|
|
val = t1;
|
|
}
|
|
|
|
rgb[i] = val * 255;
|
|
}
|
|
|
|
return rgb;
|
|
};
|
|
|
|
convert.hsl.hsv = function (hsl) {
|
|
var h = hsl[0];
|
|
var s = hsl[1] / 100;
|
|
var l = hsl[2] / 100;
|
|
var smin = s;
|
|
var lmin = Math.max(l, 0.01);
|
|
var sv;
|
|
var v;
|
|
|
|
l *= 2;
|
|
s *= (l <= 1) ? l : 2 - l;
|
|
smin *= lmin <= 1 ? lmin : 2 - lmin;
|
|
v = (l + s) / 2;
|
|
sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);
|
|
|
|
return [h, sv * 100, v * 100];
|
|
};
|
|
|
|
convert.hsv.rgb = function (hsv) {
|
|
var h = hsv[0] / 60;
|
|
var s = hsv[1] / 100;
|
|
var v = hsv[2] / 100;
|
|
var hi = Math.floor(h) % 6;
|
|
|
|
var f = h - Math.floor(h);
|
|
var p = 255 * v * (1 - s);
|
|
var q = 255 * v * (1 - (s * f));
|
|
var t = 255 * v * (1 - (s * (1 - f)));
|
|
v *= 255;
|
|
|
|
switch (hi) {
|
|
case 0:
|
|
return [v, t, p];
|
|
case 1:
|
|
return [q, v, p];
|
|
case 2:
|
|
return [p, v, t];
|
|
case 3:
|
|
return [p, q, v];
|
|
case 4:
|
|
return [t, p, v];
|
|
case 5:
|
|
return [v, p, q];
|
|
}
|
|
};
|
|
|
|
convert.hsv.hsl = function (hsv) {
|
|
var h = hsv[0];
|
|
var s = hsv[1] / 100;
|
|
var v = hsv[2] / 100;
|
|
var vmin = Math.max(v, 0.01);
|
|
var lmin;
|
|
var sl;
|
|
var l;
|
|
|
|
l = (2 - s) * v;
|
|
lmin = (2 - s) * vmin;
|
|
sl = s * vmin;
|
|
sl /= (lmin <= 1) ? lmin : 2 - lmin;
|
|
sl = sl || 0;
|
|
l /= 2;
|
|
|
|
return [h, sl * 100, l * 100];
|
|
};
|
|
|
|
// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
|
|
convert.hwb.rgb = function (hwb) {
|
|
var h = hwb[0] / 360;
|
|
var wh = hwb[1] / 100;
|
|
var bl = hwb[2] / 100;
|
|
var ratio = wh + bl;
|
|
var i;
|
|
var v;
|
|
var f;
|
|
var n;
|
|
|
|
// wh + bl cant be > 1
|
|
if (ratio > 1) {
|
|
wh /= ratio;
|
|
bl /= ratio;
|
|
}
|
|
|
|
i = Math.floor(6 * h);
|
|
v = 1 - bl;
|
|
f = 6 * h - i;
|
|
|
|
if ((i & 0x01) !== 0) {
|
|
f = 1 - f;
|
|
}
|
|
|
|
n = wh + f * (v - wh); // linear interpolation
|
|
|
|
var r;
|
|
var g;
|
|
var b;
|
|
switch (i) {
|
|
default:
|
|
case 6:
|
|
case 0: r = v; g = n; b = wh; break;
|
|
case 1: r = n; g = v; b = wh; break;
|
|
case 2: r = wh; g = v; b = n; break;
|
|
case 3: r = wh; g = n; b = v; break;
|
|
case 4: r = n; g = wh; b = v; break;
|
|
case 5: r = v; g = wh; b = n; break;
|
|
}
|
|
|
|
return [r * 255, g * 255, b * 255];
|
|
};
|
|
|
|
convert.cmyk.rgb = function (cmyk) {
|
|
var c = cmyk[0] / 100;
|
|
var m = cmyk[1] / 100;
|
|
var y = cmyk[2] / 100;
|
|
var k = cmyk[3] / 100;
|
|
var r;
|
|
var g;
|
|
var b;
|
|
|
|
r = 1 - Math.min(1, c * (1 - k) + k);
|
|
g = 1 - Math.min(1, m * (1 - k) + k);
|
|
b = 1 - Math.min(1, y * (1 - k) + k);
|
|
|
|
return [r * 255, g * 255, b * 255];
|
|
};
|
|
|
|
convert.xyz.rgb = function (xyz) {
|
|
var x = xyz[0] / 100;
|
|
var y = xyz[1] / 100;
|
|
var z = xyz[2] / 100;
|
|
var r;
|
|
var g;
|
|
var b;
|
|
|
|
r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
|
|
g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
|
|
b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
|
|
|
|
// assume sRGB
|
|
r = r > 0.0031308
|
|
? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
|
|
: r * 12.92;
|
|
|
|
g = g > 0.0031308
|
|
? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
|
|
: g * 12.92;
|
|
|
|
b = b > 0.0031308
|
|
? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
|
|
: b * 12.92;
|
|
|
|
r = Math.min(Math.max(0, r), 1);
|
|
g = Math.min(Math.max(0, g), 1);
|
|
b = Math.min(Math.max(0, b), 1);
|
|
|
|
return [r * 255, g * 255, b * 255];
|
|
};
|
|
|
|
convert.xyz.lab = function (xyz) {
|
|
var x = xyz[0];
|
|
var y = xyz[1];
|
|
var z = xyz[2];
|
|
var l;
|
|
var a;
|
|
var b;
|
|
|
|
x /= 95.047;
|
|
y /= 100;
|
|
z /= 108.883;
|
|
|
|
x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
|
|
y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
|
|
z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
|
|
|
|
l = (116 * y) - 16;
|
|
a = 500 * (x - y);
|
|
b = 200 * (y - z);
|
|
|
|
return [l, a, b];
|
|
};
|
|
|
|
convert.lab.xyz = function (lab) {
|
|
var l = lab[0];
|
|
var a = lab[1];
|
|
var b = lab[2];
|
|
var x;
|
|
var y;
|
|
var z;
|
|
|
|
y = (l + 16) / 116;
|
|
x = a / 500 + y;
|
|
z = y - b / 200;
|
|
|
|
var y2 = Math.pow(y, 3);
|
|
var x2 = Math.pow(x, 3);
|
|
var z2 = Math.pow(z, 3);
|
|
y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;
|
|
x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;
|
|
z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;
|
|
|
|
x *= 95.047;
|
|
y *= 100;
|
|
z *= 108.883;
|
|
|
|
return [x, y, z];
|
|
};
|
|
|
|
convert.lab.lch = function (lab) {
|
|
var l = lab[0];
|
|
var a = lab[1];
|
|
var b = lab[2];
|
|
var hr;
|
|
var h;
|
|
var c;
|
|
|
|
hr = Math.atan2(b, a);
|
|
h = hr * 360 / 2 / Math.PI;
|
|
|
|
if (h < 0) {
|
|
h += 360;
|
|
}
|
|
|
|
c = Math.sqrt(a * a + b * b);
|
|
|
|
return [l, c, h];
|
|
};
|
|
|
|
convert.lch.lab = function (lch) {
|
|
var l = lch[0];
|
|
var c = lch[1];
|
|
var h = lch[2];
|
|
var a;
|
|
var b;
|
|
var hr;
|
|
|
|
hr = h / 360 * 2 * Math.PI;
|
|
a = c * Math.cos(hr);
|
|
b = c * Math.sin(hr);
|
|
|
|
return [l, a, b];
|
|
};
|
|
|
|
convert.rgb.ansi16 = function (args) {
|
|
var r = args[0];
|
|
var g = args[1];
|
|
var b = args[2];
|
|
var value = 1 in arguments ? arguments[1] : convert.rgb.hsv(args)[2]; // hsv -> ansi16 optimization
|
|
|
|
value = Math.round(value / 50);
|
|
|
|
if (value === 0) {
|
|
return 30;
|
|
}
|
|
|
|
var ansi = 30
|
|
+ ((Math.round(b / 255) << 2)
|
|
| (Math.round(g / 255) << 1)
|
|
| Math.round(r / 255));
|
|
|
|
if (value === 2) {
|
|
ansi += 60;
|
|
}
|
|
|
|
return ansi;
|
|
};
|
|
|
|
convert.hsv.ansi16 = function (args) {
|
|
// optimization here; we already know the value and don't need to get
|
|
// it converted for us.
|
|
return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);
|
|
};
|
|
|
|
convert.rgb.ansi256 = function (args) {
|
|
var r = args[0];
|
|
var g = args[1];
|
|
var b = args[2];
|
|
|
|
// we use the extended greyscale palette here, with the exception of
|
|
// black and white. normal palette only has 4 greyscale shades.
|
|
if (r === g && g === b) {
|
|
if (r < 8) {
|
|
return 16;
|
|
}
|
|
|
|
if (r > 248) {
|
|
return 231;
|
|
}
|
|
|
|
return Math.round(((r - 8) / 247) * 24) + 232;
|
|
}
|
|
|
|
var ansi = 16
|
|
+ (36 * Math.round(r / 255 * 5))
|
|
+ (6 * Math.round(g / 255 * 5))
|
|
+ Math.round(b / 255 * 5);
|
|
|
|
return ansi;
|
|
};
|
|
|
|
convert.ansi16.rgb = function (args) {
|
|
var color = args % 10;
|
|
|
|
// handle greyscale
|
|
if (color === 0 || color === 7) {
|
|
if (args > 50) {
|
|
color += 3.5;
|
|
}
|
|
|
|
color = color / 10.5 * 255;
|
|
|
|
return [color, color, color];
|
|
}
|
|
|
|
var mult = (~~(args > 50) + 1) * 0.5;
|
|
var r = ((color & 1) * mult) * 255;
|
|
var g = (((color >> 1) & 1) * mult) * 255;
|
|
var b = (((color >> 2) & 1) * mult) * 255;
|
|
|
|
return [r, g, b];
|
|
};
|
|
|
|
convert.ansi256.rgb = function (args) {
|
|
// handle greyscale
|
|
if (args >= 232) {
|
|
var c = (args - 232) * 10 + 8;
|
|
return [c, c, c];
|
|
}
|
|
|
|
args -= 16;
|
|
|
|
var rem;
|
|
var r = Math.floor(args / 36) / 5 * 255;
|
|
var g = Math.floor((rem = args % 36) / 6) / 5 * 255;
|
|
var b = (rem % 6) / 5 * 255;
|
|
|
|
return [r, g, b];
|
|
};
|
|
|
|
convert.rgb.hex = function (args) {
|
|
var integer = ((Math.round(args[0]) & 0xFF) << 16)
|
|
+ ((Math.round(args[1]) & 0xFF) << 8)
|
|
+ (Math.round(args[2]) & 0xFF);
|
|
|
|
var string = integer.toString(16).toUpperCase();
|
|
return '000000'.substring(string.length) + string;
|
|
};
|
|
|
|
convert.hex.rgb = function (args) {
|
|
var match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
|
|
if (!match) {
|
|
return [0, 0, 0];
|
|
}
|
|
|
|
var colorString = match[0];
|
|
|
|
if (match[0].length === 3) {
|
|
colorString = colorString.split('').map(function (char) {
|
|
return char + char;
|
|
}).join('');
|
|
}
|
|
|
|
var integer = parseInt(colorString, 16);
|
|
var r = (integer >> 16) & 0xFF;
|
|
var g = (integer >> 8) & 0xFF;
|
|
var b = integer & 0xFF;
|
|
|
|
return [r, g, b];
|
|
};
|
|
|
|
convert.rgb.hcg = function (rgb) {
|
|
var r = rgb[0] / 255;
|
|
var g = rgb[1] / 255;
|
|
var b = rgb[2] / 255;
|
|
var max = Math.max(Math.max(r, g), b);
|
|
var min = Math.min(Math.min(r, g), b);
|
|
var chroma = (max - min);
|
|
var grayscale;
|
|
var hue;
|
|
|
|
if (chroma < 1) {
|
|
grayscale = min / (1 - chroma);
|
|
} else {
|
|
grayscale = 0;
|
|
}
|
|
|
|
if (chroma <= 0) {
|
|
hue = 0;
|
|
} else
|
|
if (max === r) {
|
|
hue = ((g - b) / chroma) % 6;
|
|
} else
|
|
if (max === g) {
|
|
hue = 2 + (b - r) / chroma;
|
|
} else {
|
|
hue = 4 + (r - g) / chroma + 4;
|
|
}
|
|
|
|
hue /= 6;
|
|
hue %= 1;
|
|
|
|
return [hue * 360, chroma * 100, grayscale * 100];
|
|
};
|
|
|
|
convert.hsl.hcg = function (hsl) {
|
|
var s = hsl[1] / 100;
|
|
var l = hsl[2] / 100;
|
|
var c = 1;
|
|
var f = 0;
|
|
|
|
if (l < 0.5) {
|
|
c = 2.0 * s * l;
|
|
} else {
|
|
c = 2.0 * s * (1.0 - l);
|
|
}
|
|
|
|
if (c < 1.0) {
|
|
f = (l - 0.5 * c) / (1.0 - c);
|
|
}
|
|
|
|
return [hsl[0], c * 100, f * 100];
|
|
};
|
|
|
|
convert.hsv.hcg = function (hsv) {
|
|
var s = hsv[1] / 100;
|
|
var v = hsv[2] / 100;
|
|
|
|
var c = s * v;
|
|
var f = 0;
|
|
|
|
if (c < 1.0) {
|
|
f = (v - c) / (1 - c);
|
|
}
|
|
|
|
return [hsv[0], c * 100, f * 100];
|
|
};
|
|
|
|
convert.hcg.rgb = function (hcg) {
|
|
var h = hcg[0] / 360;
|
|
var c = hcg[1] / 100;
|
|
var g = hcg[2] / 100;
|
|
|
|
if (c === 0.0) {
|
|
return [g * 255, g * 255, g * 255];
|
|
}
|
|
|
|
var pure = [0, 0, 0];
|
|
var hi = (h % 1) * 6;
|
|
var v = hi % 1;
|
|
var w = 1 - v;
|
|
var mg = 0;
|
|
|
|
switch (Math.floor(hi)) {
|
|
case 0:
|
|
pure[0] = 1; pure[1] = v; pure[2] = 0; break;
|
|
case 1:
|
|
pure[0] = w; pure[1] = 1; pure[2] = 0; break;
|
|
case 2:
|
|
pure[0] = 0; pure[1] = 1; pure[2] = v; break;
|
|
case 3:
|
|
pure[0] = 0; pure[1] = w; pure[2] = 1; break;
|
|
case 4:
|
|
pure[0] = v; pure[1] = 0; pure[2] = 1; break;
|
|
default:
|
|
pure[0] = 1; pure[1] = 0; pure[2] = w;
|
|
}
|
|
|
|
mg = (1.0 - c) * g;
|
|
|
|
return [
|
|
(c * pure[0] + mg) * 255,
|
|
(c * pure[1] + mg) * 255,
|
|
(c * pure[2] + mg) * 255
|
|
];
|
|
};
|
|
|
|
convert.hcg.hsv = function (hcg) {
|
|
var c = hcg[1] / 100;
|
|
var g = hcg[2] / 100;
|
|
|
|
var v = c + g * (1.0 - c);
|
|
var f = 0;
|
|
|
|
if (v > 0.0) {
|
|
f = c / v;
|
|
}
|
|
|
|
return [hcg[0], f * 100, v * 100];
|
|
};
|
|
|
|
convert.hcg.hsl = function (hcg) {
|
|
var c = hcg[1] / 100;
|
|
var g = hcg[2] / 100;
|
|
|
|
var l = g * (1.0 - c) + 0.5 * c;
|
|
var s = 0;
|
|
|
|
if (l > 0.0 && l < 0.5) {
|
|
s = c / (2 * l);
|
|
} else
|
|
if (l >= 0.5 && l < 1.0) {
|
|
s = c / (2 * (1 - l));
|
|
}
|
|
|
|
return [hcg[0], s * 100, l * 100];
|
|
};
|
|
|
|
convert.hcg.hwb = function (hcg) {
|
|
var c = hcg[1] / 100;
|
|
var g = hcg[2] / 100;
|
|
var v = c + g * (1.0 - c);
|
|
return [hcg[0], (v - c) * 100, (1 - v) * 100];
|
|
};
|
|
|
|
convert.hwb.hcg = function (hwb) {
|
|
var w = hwb[1] / 100;
|
|
var b = hwb[2] / 100;
|
|
var v = 1 - b;
|
|
var c = v - w;
|
|
var g = 0;
|
|
|
|
if (c < 1) {
|
|
g = (v - c) / (1 - c);
|
|
}
|
|
|
|
return [hwb[0], c * 100, g * 100];
|
|
};
|
|
|
|
convert.apple.rgb = function (apple) {
|
|
return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];
|
|
};
|
|
|
|
convert.rgb.apple = function (rgb) {
|
|
return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];
|
|
};
|
|
|
|
convert.gray.rgb = function (args) {
|
|
return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];
|
|
};
|
|
|
|
convert.gray.hsl = convert.gray.hsv = function (args) {
|
|
return [0, 0, args[0]];
|
|
};
|
|
|
|
convert.gray.hwb = function (gray) {
|
|
return [0, 100, gray[0]];
|
|
};
|
|
|
|
convert.gray.cmyk = function (gray) {
|
|
return [0, 0, 0, gray[0]];
|
|
};
|
|
|
|
convert.gray.lab = function (gray) {
|
|
return [gray[0], 0, 0];
|
|
};
|
|
|
|
convert.gray.hex = function (gray) {
|
|
var val = Math.round(gray[0] / 100 * 255) & 0xFF;
|
|
var integer = (val << 16) + (val << 8) + val;
|
|
|
|
var string = integer.toString(16).toUpperCase();
|
|
return '000000'.substring(string.length) + string;
|
|
};
|
|
|
|
convert.rgb.gray = function (rgb) {
|
|
var val = (rgb[0] + rgb[1] + rgb[2]) / 3;
|
|
return [val / 255 * 100];
|
|
};
|
|
return conversionsExports;
|
|
}
|
|
|
|
var route;
|
|
var hasRequiredRoute;
|
|
|
|
function requireRoute () {
|
|
if (hasRequiredRoute) return route;
|
|
hasRequiredRoute = 1;
|
|
var conversions = requireConversions();
|
|
|
|
/*
|
|
this function routes a model to all other models.
|
|
|
|
all functions that are routed have a property `.conversion` attached
|
|
to the returned synthetic function. This property is an array
|
|
of strings, each with the steps in between the 'from' and 'to'
|
|
color models (inclusive).
|
|
|
|
conversions that are not possible simply are not included.
|
|
*/
|
|
|
|
function buildGraph() {
|
|
var graph = {};
|
|
// https://jsperf.com/object-keys-vs-for-in-with-closure/3
|
|
var models = Object.keys(conversions);
|
|
|
|
for (var len = models.length, i = 0; i < len; i++) {
|
|
graph[models[i]] = {
|
|
// http://jsperf.com/1-vs-infinity
|
|
// micro-opt, but this is simple.
|
|
distance: -1,
|
|
parent: null
|
|
};
|
|
}
|
|
|
|
return graph;
|
|
}
|
|
|
|
// https://en.wikipedia.org/wiki/Breadth-first_search
|
|
function deriveBFS(fromModel) {
|
|
var graph = buildGraph();
|
|
var queue = [fromModel]; // unshift -> queue -> pop
|
|
|
|
graph[fromModel].distance = 0;
|
|
|
|
while (queue.length) {
|
|
var current = queue.pop();
|
|
var adjacents = Object.keys(conversions[current]);
|
|
|
|
for (var len = adjacents.length, i = 0; i < len; i++) {
|
|
var adjacent = adjacents[i];
|
|
var node = graph[adjacent];
|
|
|
|
if (node.distance === -1) {
|
|
node.distance = graph[current].distance + 1;
|
|
node.parent = current;
|
|
queue.unshift(adjacent);
|
|
}
|
|
}
|
|
}
|
|
|
|
return graph;
|
|
}
|
|
|
|
function link(from, to) {
|
|
return function (args) {
|
|
return to(from(args));
|
|
};
|
|
}
|
|
|
|
function wrapConversion(toModel, graph) {
|
|
var path = [graph[toModel].parent, toModel];
|
|
var fn = conversions[graph[toModel].parent][toModel];
|
|
|
|
var cur = graph[toModel].parent;
|
|
while (graph[cur].parent) {
|
|
path.unshift(graph[cur].parent);
|
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
cur = graph[cur].parent;
|
|
}
|
|
|
|
fn.conversion = path;
|
|
return fn;
|
|
}
|
|
|
|
route = function (fromModel) {
|
|
var graph = deriveBFS(fromModel);
|
|
var conversion = {};
|
|
|
|
var models = Object.keys(graph);
|
|
for (var len = models.length, i = 0; i < len; i++) {
|
|
var toModel = models[i];
|
|
var node = graph[toModel];
|
|
|
|
if (node.parent === null) {
|
|
// no possible conversion, or this node is the source model.
|
|
continue;
|
|
}
|
|
|
|
conversion[toModel] = wrapConversion(toModel, graph);
|
|
}
|
|
|
|
return conversion;
|
|
};
|
|
return route;
|
|
}
|
|
|
|
var colorConvert;
|
|
var hasRequiredColorConvert;
|
|
|
|
function requireColorConvert () {
|
|
if (hasRequiredColorConvert) return colorConvert;
|
|
hasRequiredColorConvert = 1;
|
|
var conversions = requireConversions();
|
|
var route = requireRoute();
|
|
|
|
var convert = {};
|
|
|
|
var models = Object.keys(conversions);
|
|
|
|
function wrapRaw(fn) {
|
|
var wrappedFn = function (args) {
|
|
if (args === undefined || args === null) {
|
|
return args;
|
|
}
|
|
|
|
if (arguments.length > 1) {
|
|
args = Array.prototype.slice.call(arguments);
|
|
}
|
|
|
|
return fn(args);
|
|
};
|
|
|
|
// preserve .conversion property if there is one
|
|
if ('conversion' in fn) {
|
|
wrappedFn.conversion = fn.conversion;
|
|
}
|
|
|
|
return wrappedFn;
|
|
}
|
|
|
|
function wrapRounded(fn) {
|
|
var wrappedFn = function (args) {
|
|
if (args === undefined || args === null) {
|
|
return args;
|
|
}
|
|
|
|
if (arguments.length > 1) {
|
|
args = Array.prototype.slice.call(arguments);
|
|
}
|
|
|
|
var result = fn(args);
|
|
|
|
// we're assuming the result is an array here.
|
|
// see notice in conversions.js; don't use box types
|
|
// in conversion functions.
|
|
if (typeof result === 'object') {
|
|
for (var len = result.length, i = 0; i < len; i++) {
|
|
result[i] = Math.round(result[i]);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
// preserve .conversion property if there is one
|
|
if ('conversion' in fn) {
|
|
wrappedFn.conversion = fn.conversion;
|
|
}
|
|
|
|
return wrappedFn;
|
|
}
|
|
|
|
models.forEach(function (fromModel) {
|
|
convert[fromModel] = {};
|
|
|
|
Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels});
|
|
Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels});
|
|
|
|
var routes = route(fromModel);
|
|
var routeModels = Object.keys(routes);
|
|
|
|
routeModels.forEach(function (toModel) {
|
|
var fn = routes[toModel];
|
|
|
|
convert[fromModel][toModel] = wrapRounded(fn);
|
|
convert[fromModel][toModel].raw = wrapRaw(fn);
|
|
});
|
|
});
|
|
|
|
colorConvert = convert;
|
|
return colorConvert;
|
|
}
|
|
|
|
var hasRequiredAnsiStyles;
|
|
|
|
function requireAnsiStyles () {
|
|
if (hasRequiredAnsiStyles) return ansiStylesExports;
|
|
hasRequiredAnsiStyles = 1;
|
|
(function (module) {
|
|
const colorConvert = requireColorConvert();
|
|
|
|
const wrapAnsi16 = (fn, offset) => function () {
|
|
const code = fn.apply(colorConvert, arguments);
|
|
return `\u001B[${code + offset}m`;
|
|
};
|
|
|
|
const wrapAnsi256 = (fn, offset) => function () {
|
|
const code = fn.apply(colorConvert, arguments);
|
|
return `\u001B[${38 + offset};5;${code}m`;
|
|
};
|
|
|
|
const wrapAnsi16m = (fn, offset) => function () {
|
|
const rgb = fn.apply(colorConvert, arguments);
|
|
return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`;
|
|
};
|
|
|
|
function assembleStyles() {
|
|
const codes = new Map();
|
|
const styles = {
|
|
modifier: {
|
|
reset: [0, 0],
|
|
// 21 isn't widely supported and 22 does the same thing
|
|
bold: [1, 22],
|
|
dim: [2, 22],
|
|
italic: [3, 23],
|
|
underline: [4, 24],
|
|
inverse: [7, 27],
|
|
hidden: [8, 28],
|
|
strikethrough: [9, 29]
|
|
},
|
|
color: {
|
|
black: [30, 39],
|
|
red: [31, 39],
|
|
green: [32, 39],
|
|
yellow: [33, 39],
|
|
blue: [34, 39],
|
|
magenta: [35, 39],
|
|
cyan: [36, 39],
|
|
white: [37, 39],
|
|
gray: [90, 39],
|
|
|
|
// Bright color
|
|
redBright: [91, 39],
|
|
greenBright: [92, 39],
|
|
yellowBright: [93, 39],
|
|
blueBright: [94, 39],
|
|
magentaBright: [95, 39],
|
|
cyanBright: [96, 39],
|
|
whiteBright: [97, 39]
|
|
},
|
|
bgColor: {
|
|
bgBlack: [40, 49],
|
|
bgRed: [41, 49],
|
|
bgGreen: [42, 49],
|
|
bgYellow: [43, 49],
|
|
bgBlue: [44, 49],
|
|
bgMagenta: [45, 49],
|
|
bgCyan: [46, 49],
|
|
bgWhite: [47, 49],
|
|
|
|
// Bright color
|
|
bgBlackBright: [100, 49],
|
|
bgRedBright: [101, 49],
|
|
bgGreenBright: [102, 49],
|
|
bgYellowBright: [103, 49],
|
|
bgBlueBright: [104, 49],
|
|
bgMagentaBright: [105, 49],
|
|
bgCyanBright: [106, 49],
|
|
bgWhiteBright: [107, 49]
|
|
}
|
|
};
|
|
|
|
// Fix humans
|
|
styles.color.grey = styles.color.gray;
|
|
|
|
for (const groupName of Object.keys(styles)) {
|
|
const group = styles[groupName];
|
|
|
|
for (const styleName of Object.keys(group)) {
|
|
const style = group[styleName];
|
|
|
|
styles[styleName] = {
|
|
open: `\u001B[${style[0]}m`,
|
|
close: `\u001B[${style[1]}m`
|
|
};
|
|
|
|
group[styleName] = styles[styleName];
|
|
|
|
codes.set(style[0], style[1]);
|
|
}
|
|
|
|
Object.defineProperty(styles, groupName, {
|
|
value: group,
|
|
enumerable: false
|
|
});
|
|
|
|
Object.defineProperty(styles, 'codes', {
|
|
value: codes,
|
|
enumerable: false
|
|
});
|
|
}
|
|
|
|
const ansi2ansi = n => n;
|
|
const rgb2rgb = (r, g, b) => [r, g, b];
|
|
|
|
styles.color.close = '\u001B[39m';
|
|
styles.bgColor.close = '\u001B[49m';
|
|
|
|
styles.color.ansi = {
|
|
ansi: wrapAnsi16(ansi2ansi, 0)
|
|
};
|
|
styles.color.ansi256 = {
|
|
ansi256: wrapAnsi256(ansi2ansi, 0)
|
|
};
|
|
styles.color.ansi16m = {
|
|
rgb: wrapAnsi16m(rgb2rgb, 0)
|
|
};
|
|
|
|
styles.bgColor.ansi = {
|
|
ansi: wrapAnsi16(ansi2ansi, 10)
|
|
};
|
|
styles.bgColor.ansi256 = {
|
|
ansi256: wrapAnsi256(ansi2ansi, 10)
|
|
};
|
|
styles.bgColor.ansi16m = {
|
|
rgb: wrapAnsi16m(rgb2rgb, 10)
|
|
};
|
|
|
|
for (let key of Object.keys(colorConvert)) {
|
|
if (typeof colorConvert[key] !== 'object') {
|
|
continue;
|
|
}
|
|
|
|
const suite = colorConvert[key];
|
|
|
|
if (key === 'ansi16') {
|
|
key = 'ansi';
|
|
}
|
|
|
|
if ('ansi16' in suite) {
|
|
styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0);
|
|
styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10);
|
|
}
|
|
|
|
if ('ansi256' in suite) {
|
|
styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0);
|
|
styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10);
|
|
}
|
|
|
|
if ('rgb' in suite) {
|
|
styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0);
|
|
styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10);
|
|
}
|
|
}
|
|
|
|
return styles;
|
|
}
|
|
|
|
// Make the export immutable
|
|
Object.defineProperty(module, 'exports', {
|
|
enumerable: true,
|
|
get: assembleStyles
|
|
});
|
|
} (ansiStyles));
|
|
return ansiStylesExports;
|
|
}
|
|
|
|
var collections = {};
|
|
|
|
var hasRequiredCollections;
|
|
|
|
function requireCollections () {
|
|
if (hasRequiredCollections) return collections;
|
|
hasRequiredCollections = 1;
|
|
|
|
Object.defineProperty(collections, '__esModule', {
|
|
value: true
|
|
});
|
|
collections.printIteratorEntries = printIteratorEntries;
|
|
collections.printIteratorValues = printIteratorValues;
|
|
collections.printListItems = printListItems;
|
|
collections.printObjectProperties = printObjectProperties;
|
|
|
|
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
*/
|
|
const getKeysOfEnumerableProperties = object => {
|
|
const keys = Object.keys(object).sort();
|
|
|
|
if (Object.getOwnPropertySymbols) {
|
|
Object.getOwnPropertySymbols(object).forEach(symbol => {
|
|
if (Object.getOwnPropertyDescriptor(object, symbol).enumerable) {
|
|
keys.push(symbol);
|
|
}
|
|
});
|
|
}
|
|
|
|
return keys;
|
|
};
|
|
/**
|
|
* Return entries (for example, of a map)
|
|
* with spacing, indentation, and comma
|
|
* without surrounding punctuation (for example, braces)
|
|
*/
|
|
|
|
function printIteratorEntries( // Flow 0.51.0: property `@@iterator` of $Iterator not found in Object
|
|
// To allow simplistic getRecordIterator in immutable.js
|
|
iterator,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer, // Too bad, so sad that separator for ECMAScript Map has been ' => '
|
|
// What a distracting diff if you change a data structure to/from
|
|
separator = ': '
|
|
) {
|
|
let result = '';
|
|
let current = iterator.next();
|
|
|
|
if (!current.done) {
|
|
result += config.spacingOuter;
|
|
const indentationNext = indentation + config.indent;
|
|
|
|
while (!current.done) {
|
|
const name = printer(
|
|
current.value[0],
|
|
config,
|
|
indentationNext,
|
|
depth,
|
|
refs
|
|
);
|
|
const value = printer(
|
|
current.value[1],
|
|
config,
|
|
indentationNext,
|
|
depth,
|
|
refs
|
|
);
|
|
result += indentationNext + name + separator + value;
|
|
current = iterator.next();
|
|
|
|
if (!current.done) {
|
|
result += ',' + config.spacingInner;
|
|
} else if (!config.min) {
|
|
result += ',';
|
|
}
|
|
}
|
|
|
|
result += config.spacingOuter + indentation;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
/**
|
|
* Return values (for example, of a set)
|
|
* with spacing, indentation, and comma
|
|
* without surrounding punctuation (braces or brackets)
|
|
*/
|
|
|
|
function printIteratorValues(
|
|
iterator,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) {
|
|
let result = '';
|
|
let current = iterator.next();
|
|
|
|
if (!current.done) {
|
|
result += config.spacingOuter;
|
|
const indentationNext = indentation + config.indent;
|
|
|
|
while (!current.done) {
|
|
result +=
|
|
indentationNext +
|
|
printer(current.value, config, indentationNext, depth, refs);
|
|
current = iterator.next();
|
|
|
|
if (!current.done) {
|
|
result += ',' + config.spacingInner;
|
|
} else if (!config.min) {
|
|
result += ',';
|
|
}
|
|
}
|
|
|
|
result += config.spacingOuter + indentation;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
/**
|
|
* Return items (for example, of an array)
|
|
* with spacing, indentation, and comma
|
|
* without surrounding punctuation (for example, brackets)
|
|
**/
|
|
|
|
function printListItems(list, config, indentation, depth, refs, printer) {
|
|
let result = '';
|
|
|
|
if (list.length) {
|
|
result += config.spacingOuter;
|
|
const indentationNext = indentation + config.indent;
|
|
|
|
for (let i = 0; i < list.length; i++) {
|
|
result +=
|
|
indentationNext +
|
|
printer(list[i], config, indentationNext, depth, refs);
|
|
|
|
if (i < list.length - 1) {
|
|
result += ',' + config.spacingInner;
|
|
} else if (!config.min) {
|
|
result += ',';
|
|
}
|
|
}
|
|
|
|
result += config.spacingOuter + indentation;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
/**
|
|
* Return properties of an object
|
|
* with spacing, indentation, and comma
|
|
* without surrounding punctuation (for example, braces)
|
|
*/
|
|
|
|
function printObjectProperties(val, config, indentation, depth, refs, printer) {
|
|
let result = '';
|
|
const keys = getKeysOfEnumerableProperties(val);
|
|
|
|
if (keys.length) {
|
|
result += config.spacingOuter;
|
|
const indentationNext = indentation + config.indent;
|
|
|
|
for (let i = 0; i < keys.length; i++) {
|
|
const key = keys[i];
|
|
const name = printer(key, config, indentationNext, depth, refs);
|
|
const value = printer(val[key], config, indentationNext, depth, refs);
|
|
result += indentationNext + name + ': ' + value;
|
|
|
|
if (i < keys.length - 1) {
|
|
result += ',' + config.spacingInner;
|
|
} else if (!config.min) {
|
|
result += ',';
|
|
}
|
|
}
|
|
|
|
result += config.spacingOuter + indentation;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
return collections;
|
|
}
|
|
|
|
var AsymmetricMatcher = {};
|
|
|
|
var hasRequiredAsymmetricMatcher;
|
|
|
|
function requireAsymmetricMatcher () {
|
|
if (hasRequiredAsymmetricMatcher) return AsymmetricMatcher;
|
|
hasRequiredAsymmetricMatcher = 1;
|
|
|
|
Object.defineProperty(AsymmetricMatcher, '__esModule', {
|
|
value: true
|
|
});
|
|
AsymmetricMatcher.default = AsymmetricMatcher.test = AsymmetricMatcher.serialize = void 0;
|
|
|
|
var _collections = requireCollections();
|
|
|
|
var Symbol = commonjsGlobal['jest-symbol-do-not-touch'] || commonjsGlobal.Symbol;
|
|
const asymmetricMatcher = Symbol.for('jest.asymmetricMatcher');
|
|
const SPACE = ' ';
|
|
|
|
const serialize = (val, config, indentation, depth, refs, printer) => {
|
|
const stringedValue = val.toString();
|
|
|
|
if (
|
|
stringedValue === 'ArrayContaining' ||
|
|
stringedValue === 'ArrayNotContaining'
|
|
) {
|
|
if (++depth > config.maxDepth) {
|
|
return '[' + stringedValue + ']';
|
|
}
|
|
|
|
return (
|
|
stringedValue +
|
|
SPACE +
|
|
'[' +
|
|
(0, _collections.printListItems)(
|
|
val.sample,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
']'
|
|
);
|
|
}
|
|
|
|
if (
|
|
stringedValue === 'ObjectContaining' ||
|
|
stringedValue === 'ObjectNotContaining'
|
|
) {
|
|
if (++depth > config.maxDepth) {
|
|
return '[' + stringedValue + ']';
|
|
}
|
|
|
|
return (
|
|
stringedValue +
|
|
SPACE +
|
|
'{' +
|
|
(0, _collections.printObjectProperties)(
|
|
val.sample,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
'}'
|
|
);
|
|
}
|
|
|
|
if (
|
|
stringedValue === 'StringMatching' ||
|
|
stringedValue === 'StringNotMatching'
|
|
) {
|
|
return (
|
|
stringedValue +
|
|
SPACE +
|
|
printer(val.sample, config, indentation, depth, refs)
|
|
);
|
|
}
|
|
|
|
if (
|
|
stringedValue === 'StringContaining' ||
|
|
stringedValue === 'StringNotContaining'
|
|
) {
|
|
return (
|
|
stringedValue +
|
|
SPACE +
|
|
printer(val.sample, config, indentation, depth, refs)
|
|
);
|
|
}
|
|
|
|
return val.toAsymmetricMatcher();
|
|
};
|
|
|
|
AsymmetricMatcher.serialize = serialize;
|
|
|
|
const test = val => val && val.$$typeof === asymmetricMatcher;
|
|
|
|
AsymmetricMatcher.test = test;
|
|
const plugin = {
|
|
serialize,
|
|
test
|
|
};
|
|
var _default = plugin;
|
|
AsymmetricMatcher.default = _default;
|
|
return AsymmetricMatcher;
|
|
}
|
|
|
|
var ConvertAnsi = {};
|
|
|
|
var ansiRegex;
|
|
var hasRequiredAnsiRegex;
|
|
|
|
function requireAnsiRegex () {
|
|
if (hasRequiredAnsiRegex) return ansiRegex;
|
|
hasRequiredAnsiRegex = 1;
|
|
|
|
ansiRegex = options => {
|
|
options = Object.assign({
|
|
onlyFirst: false
|
|
}, options);
|
|
|
|
const pattern = [
|
|
'[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
|
|
'(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'
|
|
].join('|');
|
|
|
|
return new RegExp(pattern, options.onlyFirst ? undefined : 'g');
|
|
};
|
|
return ansiRegex;
|
|
}
|
|
|
|
var hasRequiredConvertAnsi;
|
|
|
|
function requireConvertAnsi () {
|
|
if (hasRequiredConvertAnsi) return ConvertAnsi;
|
|
hasRequiredConvertAnsi = 1;
|
|
|
|
Object.defineProperty(ConvertAnsi, '__esModule', {
|
|
value: true
|
|
});
|
|
ConvertAnsi.default = ConvertAnsi.serialize = ConvertAnsi.test = void 0;
|
|
|
|
var _ansiRegex = _interopRequireDefault(requireAnsiRegex());
|
|
|
|
var _ansiStyles = _interopRequireDefault(requireAnsiStyles());
|
|
|
|
function _interopRequireDefault(obj) {
|
|
return obj && obj.__esModule ? obj : {default: obj};
|
|
}
|
|
|
|
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
const toHumanReadableAnsi = text =>
|
|
text.replace((0, _ansiRegex.default)(), match => {
|
|
switch (match) {
|
|
case _ansiStyles.default.red.close:
|
|
case _ansiStyles.default.green.close:
|
|
case _ansiStyles.default.cyan.close:
|
|
case _ansiStyles.default.gray.close:
|
|
case _ansiStyles.default.white.close:
|
|
case _ansiStyles.default.yellow.close:
|
|
case _ansiStyles.default.bgRed.close:
|
|
case _ansiStyles.default.bgGreen.close:
|
|
case _ansiStyles.default.bgYellow.close:
|
|
case _ansiStyles.default.inverse.close:
|
|
case _ansiStyles.default.dim.close:
|
|
case _ansiStyles.default.bold.close:
|
|
case _ansiStyles.default.reset.open:
|
|
case _ansiStyles.default.reset.close:
|
|
return '</>';
|
|
|
|
case _ansiStyles.default.red.open:
|
|
return '<red>';
|
|
|
|
case _ansiStyles.default.green.open:
|
|
return '<green>';
|
|
|
|
case _ansiStyles.default.cyan.open:
|
|
return '<cyan>';
|
|
|
|
case _ansiStyles.default.gray.open:
|
|
return '<gray>';
|
|
|
|
case _ansiStyles.default.white.open:
|
|
return '<white>';
|
|
|
|
case _ansiStyles.default.yellow.open:
|
|
return '<yellow>';
|
|
|
|
case _ansiStyles.default.bgRed.open:
|
|
return '<bgRed>';
|
|
|
|
case _ansiStyles.default.bgGreen.open:
|
|
return '<bgGreen>';
|
|
|
|
case _ansiStyles.default.bgYellow.open:
|
|
return '<bgYellow>';
|
|
|
|
case _ansiStyles.default.inverse.open:
|
|
return '<inverse>';
|
|
|
|
case _ansiStyles.default.dim.open:
|
|
return '<dim>';
|
|
|
|
case _ansiStyles.default.bold.open:
|
|
return '<bold>';
|
|
|
|
default:
|
|
return '';
|
|
}
|
|
});
|
|
|
|
const test = val =>
|
|
typeof val === 'string' && !!val.match((0, _ansiRegex.default)());
|
|
|
|
ConvertAnsi.test = test;
|
|
|
|
const serialize = (val, config, indentation, depth, refs, printer) =>
|
|
printer(toHumanReadableAnsi(val), config, indentation, depth, refs);
|
|
|
|
ConvertAnsi.serialize = serialize;
|
|
const plugin = {
|
|
serialize,
|
|
test
|
|
};
|
|
var _default = plugin;
|
|
ConvertAnsi.default = _default;
|
|
return ConvertAnsi;
|
|
}
|
|
|
|
var DOMCollection = {};
|
|
|
|
var hasRequiredDOMCollection;
|
|
|
|
function requireDOMCollection () {
|
|
if (hasRequiredDOMCollection) return DOMCollection;
|
|
hasRequiredDOMCollection = 1;
|
|
|
|
Object.defineProperty(DOMCollection, '__esModule', {
|
|
value: true
|
|
});
|
|
DOMCollection.default = DOMCollection.serialize = DOMCollection.test = void 0;
|
|
|
|
var _collections = requireCollections();
|
|
|
|
function _objectSpread(target) {
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
var source = arguments[i] != null ? arguments[i] : {};
|
|
var ownKeys = Object.keys(source);
|
|
if (typeof Object.getOwnPropertySymbols === 'function') {
|
|
ownKeys = ownKeys.concat(
|
|
Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
})
|
|
);
|
|
}
|
|
ownKeys.forEach(function(key) {
|
|
_defineProperty(target, key, source[key]);
|
|
});
|
|
}
|
|
return target;
|
|
}
|
|
|
|
function _defineProperty(obj, key, value) {
|
|
if (key in obj) {
|
|
Object.defineProperty(obj, key, {
|
|
value: value,
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true
|
|
});
|
|
} else {
|
|
obj[key] = value;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
const SPACE = ' ';
|
|
const OBJECT_NAMES = ['DOMStringMap', 'NamedNodeMap'];
|
|
const ARRAY_REGEXP = /^(HTML\w*Collection|NodeList)$/;
|
|
|
|
const testName = name =>
|
|
OBJECT_NAMES.indexOf(name) !== -1 || ARRAY_REGEXP.test(name);
|
|
|
|
const test = val =>
|
|
val &&
|
|
val.constructor &&
|
|
val.constructor.name &&
|
|
testName(val.constructor.name); // Convert array of attribute objects to props object.
|
|
|
|
DOMCollection.test = test;
|
|
|
|
const propsReducer = (props, attribute) => {
|
|
props[attribute.name] = attribute.value;
|
|
return props;
|
|
};
|
|
|
|
const serialize = (collection, config, indentation, depth, refs, printer) => {
|
|
const name = collection.constructor.name;
|
|
|
|
if (++depth > config.maxDepth) {
|
|
return '[' + name + ']';
|
|
}
|
|
|
|
return (
|
|
(config.min ? '' : name + SPACE) +
|
|
(OBJECT_NAMES.indexOf(name) !== -1
|
|
? '{' +
|
|
(0, _collections.printObjectProperties)(
|
|
name === 'NamedNodeMap'
|
|
? Array.prototype.reduce.call(collection, propsReducer, {})
|
|
: _objectSpread({}, collection),
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
'}'
|
|
: '[' +
|
|
(0, _collections.printListItems)(
|
|
Array.from(collection),
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
']')
|
|
);
|
|
};
|
|
|
|
DOMCollection.serialize = serialize;
|
|
const plugin = {
|
|
serialize,
|
|
test
|
|
};
|
|
var _default = plugin;
|
|
DOMCollection.default = _default;
|
|
return DOMCollection;
|
|
}
|
|
|
|
var DOMElement = {};
|
|
|
|
var markup = {};
|
|
|
|
var escapeHTML = {};
|
|
|
|
var hasRequiredEscapeHTML;
|
|
|
|
function requireEscapeHTML () {
|
|
if (hasRequiredEscapeHTML) return escapeHTML;
|
|
hasRequiredEscapeHTML = 1;
|
|
|
|
Object.defineProperty(escapeHTML, '__esModule', {
|
|
value: true
|
|
});
|
|
escapeHTML.default = escapeHTML$1;
|
|
|
|
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
function escapeHTML$1(str) {
|
|
return str.replace(/</g, '<').replace(/>/g, '>');
|
|
}
|
|
return escapeHTML;
|
|
}
|
|
|
|
var hasRequiredMarkup;
|
|
|
|
function requireMarkup () {
|
|
if (hasRequiredMarkup) return markup;
|
|
hasRequiredMarkup = 1;
|
|
|
|
Object.defineProperty(markup, '__esModule', {
|
|
value: true
|
|
});
|
|
markup.printElementAsLeaf = markup.printElement = markup.printComment = markup.printText = markup.printChildren = markup.printProps = void 0;
|
|
|
|
var _escapeHTML = _interopRequireDefault(requireEscapeHTML());
|
|
|
|
function _interopRequireDefault(obj) {
|
|
return obj && obj.__esModule ? obj : {default: obj};
|
|
}
|
|
|
|
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
// Return empty string if keys is empty.
|
|
const printProps = (keys, props, config, indentation, depth, refs, printer) => {
|
|
const indentationNext = indentation + config.indent;
|
|
const colors = config.colors;
|
|
return keys
|
|
.map(key => {
|
|
const value = props[key];
|
|
let printed = printer(value, config, indentationNext, depth, refs);
|
|
|
|
if (typeof value !== 'string') {
|
|
if (printed.indexOf('\n') !== -1) {
|
|
printed =
|
|
config.spacingOuter +
|
|
indentationNext +
|
|
printed +
|
|
config.spacingOuter +
|
|
indentation;
|
|
}
|
|
|
|
printed = '{' + printed + '}';
|
|
}
|
|
|
|
return (
|
|
config.spacingInner +
|
|
indentation +
|
|
colors.prop.open +
|
|
key +
|
|
colors.prop.close +
|
|
'=' +
|
|
colors.value.open +
|
|
printed +
|
|
colors.value.close
|
|
);
|
|
})
|
|
.join('');
|
|
}; // Return empty string if children is empty.
|
|
|
|
markup.printProps = printProps;
|
|
|
|
const printChildren = (children, config, indentation, depth, refs, printer) =>
|
|
children
|
|
.map(
|
|
child =>
|
|
config.spacingOuter +
|
|
indentation +
|
|
(typeof child === 'string'
|
|
? printText(child, config)
|
|
: printer(child, config, indentation, depth, refs))
|
|
)
|
|
.join('');
|
|
|
|
markup.printChildren = printChildren;
|
|
|
|
const printText = (text, config) => {
|
|
const contentColor = config.colors.content;
|
|
return (
|
|
contentColor.open + (0, _escapeHTML.default)(text) + contentColor.close
|
|
);
|
|
};
|
|
|
|
markup.printText = printText;
|
|
|
|
const printComment = (comment, config) => {
|
|
const commentColor = config.colors.comment;
|
|
return (
|
|
commentColor.open +
|
|
'<!--' +
|
|
(0, _escapeHTML.default)(comment) +
|
|
'-->' +
|
|
commentColor.close
|
|
);
|
|
}; // Separate the functions to format props, children, and element,
|
|
// so a plugin could override a particular function, if needed.
|
|
// Too bad, so sad: the traditional (but unnecessary) space
|
|
// in a self-closing tagColor requires a second test of printedProps.
|
|
|
|
markup.printComment = printComment;
|
|
|
|
const printElement = (
|
|
type,
|
|
printedProps,
|
|
printedChildren,
|
|
config,
|
|
indentation
|
|
) => {
|
|
const tagColor = config.colors.tag;
|
|
return (
|
|
tagColor.open +
|
|
'<' +
|
|
type +
|
|
(printedProps &&
|
|
tagColor.close +
|
|
printedProps +
|
|
config.spacingOuter +
|
|
indentation +
|
|
tagColor.open) +
|
|
(printedChildren
|
|
? '>' +
|
|
tagColor.close +
|
|
printedChildren +
|
|
config.spacingOuter +
|
|
indentation +
|
|
tagColor.open +
|
|
'</' +
|
|
type
|
|
: (printedProps && !config.min ? '' : ' ') + '/') +
|
|
'>' +
|
|
tagColor.close
|
|
);
|
|
};
|
|
|
|
markup.printElement = printElement;
|
|
|
|
const printElementAsLeaf = (type, config) => {
|
|
const tagColor = config.colors.tag;
|
|
return (
|
|
tagColor.open +
|
|
'<' +
|
|
type +
|
|
tagColor.close +
|
|
' …' +
|
|
tagColor.open +
|
|
' />' +
|
|
tagColor.close
|
|
);
|
|
};
|
|
|
|
markup.printElementAsLeaf = printElementAsLeaf;
|
|
return markup;
|
|
}
|
|
|
|
var hasRequiredDOMElement;
|
|
|
|
function requireDOMElement () {
|
|
if (hasRequiredDOMElement) return DOMElement;
|
|
hasRequiredDOMElement = 1;
|
|
|
|
Object.defineProperty(DOMElement, '__esModule', {
|
|
value: true
|
|
});
|
|
DOMElement.default = DOMElement.serialize = DOMElement.test = void 0;
|
|
|
|
var _markup = requireMarkup();
|
|
|
|
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
const ELEMENT_NODE = 1;
|
|
const TEXT_NODE = 3;
|
|
const COMMENT_NODE = 8;
|
|
const FRAGMENT_NODE = 11;
|
|
const ELEMENT_REGEXP = /^((HTML|SVG)\w*)?Element$/;
|
|
|
|
const testNode = (nodeType, name) =>
|
|
(nodeType === ELEMENT_NODE && ELEMENT_REGEXP.test(name)) ||
|
|
(nodeType === TEXT_NODE && name === 'Text') ||
|
|
(nodeType === COMMENT_NODE && name === 'Comment') ||
|
|
(nodeType === FRAGMENT_NODE && name === 'DocumentFragment');
|
|
|
|
const test = val =>
|
|
val &&
|
|
val.constructor &&
|
|
val.constructor.name &&
|
|
testNode(val.nodeType, val.constructor.name);
|
|
|
|
DOMElement.test = test;
|
|
|
|
function nodeIsText(node) {
|
|
return node.nodeType === TEXT_NODE;
|
|
}
|
|
|
|
function nodeIsComment(node) {
|
|
return node.nodeType === COMMENT_NODE;
|
|
}
|
|
|
|
function nodeIsFragment(node) {
|
|
return node.nodeType === FRAGMENT_NODE;
|
|
}
|
|
|
|
const serialize = (node, config, indentation, depth, refs, printer) => {
|
|
if (nodeIsText(node)) {
|
|
return (0, _markup.printText)(node.data, config);
|
|
}
|
|
|
|
if (nodeIsComment(node)) {
|
|
return (0, _markup.printComment)(node.data, config);
|
|
}
|
|
|
|
const type = nodeIsFragment(node)
|
|
? `DocumentFragment`
|
|
: node.tagName.toLowerCase();
|
|
|
|
if (++depth > config.maxDepth) {
|
|
return (0, _markup.printElementAsLeaf)(type, config);
|
|
}
|
|
|
|
return (0, _markup.printElement)(
|
|
type,
|
|
(0, _markup.printProps)(
|
|
nodeIsFragment(node)
|
|
? []
|
|
: Array.from(node.attributes)
|
|
.map(attr => attr.name)
|
|
.sort(),
|
|
nodeIsFragment(node)
|
|
? []
|
|
: Array.from(node.attributes).reduce((props, attribute) => {
|
|
props[attribute.name] = attribute.value;
|
|
return props;
|
|
}, {}),
|
|
config,
|
|
indentation + config.indent,
|
|
depth,
|
|
refs,
|
|
printer
|
|
),
|
|
(0, _markup.printChildren)(
|
|
Array.prototype.slice.call(node.childNodes || node.children),
|
|
config,
|
|
indentation + config.indent,
|
|
depth,
|
|
refs,
|
|
printer
|
|
),
|
|
config,
|
|
indentation
|
|
);
|
|
};
|
|
|
|
DOMElement.serialize = serialize;
|
|
const plugin = {
|
|
serialize,
|
|
test
|
|
};
|
|
var _default = plugin;
|
|
DOMElement.default = _default;
|
|
return DOMElement;
|
|
}
|
|
|
|
var Immutable = {};
|
|
|
|
var hasRequiredImmutable;
|
|
|
|
function requireImmutable () {
|
|
if (hasRequiredImmutable) return Immutable;
|
|
hasRequiredImmutable = 1;
|
|
|
|
Object.defineProperty(Immutable, '__esModule', {
|
|
value: true
|
|
});
|
|
Immutable.default = Immutable.test = Immutable.serialize = void 0;
|
|
|
|
var _collections = requireCollections();
|
|
|
|
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
// SENTINEL constants are from https://github.com/facebook/immutable-js
|
|
const IS_ITERABLE_SENTINEL = '@@__IMMUTABLE_ITERABLE__@@';
|
|
const IS_LIST_SENTINEL = '@@__IMMUTABLE_LIST__@@';
|
|
const IS_KEYED_SENTINEL = '@@__IMMUTABLE_KEYED__@@';
|
|
const IS_MAP_SENTINEL = '@@__IMMUTABLE_MAP__@@';
|
|
const IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@';
|
|
const IS_RECORD_SENTINEL = '@@__IMMUTABLE_RECORD__@@'; // immutable v4
|
|
|
|
const IS_SEQ_SENTINEL = '@@__IMMUTABLE_SEQ__@@';
|
|
const IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@';
|
|
const IS_STACK_SENTINEL = '@@__IMMUTABLE_STACK__@@';
|
|
|
|
const getImmutableName = name => 'Immutable.' + name;
|
|
|
|
const printAsLeaf = name => '[' + name + ']';
|
|
|
|
const SPACE = ' ';
|
|
const LAZY = '…'; // Seq is lazy if it calls a method like filter
|
|
|
|
const printImmutableEntries = (
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer,
|
|
type
|
|
) =>
|
|
++depth > config.maxDepth
|
|
? printAsLeaf(getImmutableName(type))
|
|
: getImmutableName(type) +
|
|
SPACE +
|
|
'{' +
|
|
(0, _collections.printIteratorEntries)(
|
|
val.entries(),
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
'}'; // Record has an entries method because it is a collection in immutable v3.
|
|
// Return an iterator for Immutable Record from version v3 or v4.
|
|
|
|
const getRecordEntries = val => {
|
|
let i = 0;
|
|
return {
|
|
next() {
|
|
if (i < val._keys.length) {
|
|
const key = val._keys[i++];
|
|
return {
|
|
done: false,
|
|
value: [key, val.get(key)]
|
|
};
|
|
}
|
|
|
|
return {
|
|
done: true
|
|
};
|
|
}
|
|
};
|
|
};
|
|
|
|
const printImmutableRecord = (
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) => {
|
|
// _name property is defined only for an Immutable Record instance
|
|
// which was constructed with a second optional descriptive name arg
|
|
const name = getImmutableName(val._name || 'Record');
|
|
return ++depth > config.maxDepth
|
|
? printAsLeaf(name)
|
|
: name +
|
|
SPACE +
|
|
'{' +
|
|
(0, _collections.printIteratorEntries)(
|
|
getRecordEntries(val),
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
'}';
|
|
};
|
|
|
|
const printImmutableSeq = (val, config, indentation, depth, refs, printer) => {
|
|
const name = getImmutableName('Seq');
|
|
|
|
if (++depth > config.maxDepth) {
|
|
return printAsLeaf(name);
|
|
}
|
|
|
|
if (val[IS_KEYED_SENTINEL]) {
|
|
return (
|
|
name +
|
|
SPACE +
|
|
'{' + // from Immutable collection of entries or from ECMAScript object
|
|
(val._iter || val._object
|
|
? (0, _collections.printIteratorEntries)(
|
|
val.entries(),
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
)
|
|
: LAZY) +
|
|
'}'
|
|
);
|
|
}
|
|
|
|
return (
|
|
name +
|
|
SPACE +
|
|
'[' +
|
|
(val._iter || // from Immutable collection of values
|
|
val._array || // from ECMAScript array
|
|
val._collection || // from ECMAScript collection in immutable v4
|
|
val._iterable // from ECMAScript collection in immutable v3
|
|
? (0, _collections.printIteratorValues)(
|
|
val.values(),
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
)
|
|
: LAZY) +
|
|
']'
|
|
);
|
|
};
|
|
|
|
const printImmutableValues = (
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer,
|
|
type
|
|
) =>
|
|
++depth > config.maxDepth
|
|
? printAsLeaf(getImmutableName(type))
|
|
: getImmutableName(type) +
|
|
SPACE +
|
|
'[' +
|
|
(0, _collections.printIteratorValues)(
|
|
val.values(),
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
']';
|
|
|
|
const serialize = (val, config, indentation, depth, refs, printer) => {
|
|
if (val[IS_MAP_SENTINEL]) {
|
|
return printImmutableEntries(
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer,
|
|
val[IS_ORDERED_SENTINEL] ? 'OrderedMap' : 'Map'
|
|
);
|
|
}
|
|
|
|
if (val[IS_LIST_SENTINEL]) {
|
|
return printImmutableValues(
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer,
|
|
'List'
|
|
);
|
|
}
|
|
|
|
if (val[IS_SET_SENTINEL]) {
|
|
return printImmutableValues(
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer,
|
|
val[IS_ORDERED_SENTINEL] ? 'OrderedSet' : 'Set'
|
|
);
|
|
}
|
|
|
|
if (val[IS_STACK_SENTINEL]) {
|
|
return printImmutableValues(
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer,
|
|
'Stack'
|
|
);
|
|
}
|
|
|
|
if (val[IS_SEQ_SENTINEL]) {
|
|
return printImmutableSeq(val, config, indentation, depth, refs, printer);
|
|
} // For compatibility with immutable v3 and v4, let record be the default.
|
|
|
|
return printImmutableRecord(val, config, indentation, depth, refs, printer);
|
|
}; // Explicitly comparing sentinel properties to true avoids false positive
|
|
// when mock identity-obj-proxy returns the key as the value for any key.
|
|
|
|
Immutable.serialize = serialize;
|
|
|
|
const test = val =>
|
|
val &&
|
|
(val[IS_ITERABLE_SENTINEL] === true || val[IS_RECORD_SENTINEL] === true);
|
|
|
|
Immutable.test = test;
|
|
const plugin = {
|
|
serialize,
|
|
test
|
|
};
|
|
var _default = plugin;
|
|
Immutable.default = _default;
|
|
return Immutable;
|
|
}
|
|
|
|
var ReactElement = {};
|
|
|
|
var reactIsExports = {};
|
|
var reactIs = {
|
|
get exports(){ return reactIsExports; },
|
|
set exports(v){ reactIsExports = v; },
|
|
};
|
|
|
|
var reactIs_development = {};
|
|
|
|
var hasRequiredReactIs_development;
|
|
|
|
function requireReactIs_development () {
|
|
if (hasRequiredReactIs_development) return reactIs_development;
|
|
hasRequiredReactIs_development = 1;
|
|
|
|
|
|
|
|
{
|
|
(function() {
|
|
|
|
// The Symbol used to tag the ReactElement-like types. If there is no native Symbol
|
|
// nor polyfill, then a plain number is used for performance.
|
|
var hasSymbol = typeof Symbol === 'function' && Symbol.for;
|
|
var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7;
|
|
var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca;
|
|
var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb;
|
|
var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc;
|
|
var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2;
|
|
var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd;
|
|
var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary
|
|
// (unstable) APIs that have been removed. Can we remove the symbols?
|
|
|
|
var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for('react.async_mode') : 0xeacf;
|
|
var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf;
|
|
var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
|
|
var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1;
|
|
var REACT_SUSPENSE_LIST_TYPE = hasSymbol ? Symbol.for('react.suspense_list') : 0xead8;
|
|
var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
|
|
var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4;
|
|
var REACT_BLOCK_TYPE = hasSymbol ? Symbol.for('react.block') : 0xead9;
|
|
var REACT_FUNDAMENTAL_TYPE = hasSymbol ? Symbol.for('react.fundamental') : 0xead5;
|
|
var REACT_RESPONDER_TYPE = hasSymbol ? Symbol.for('react.responder') : 0xead6;
|
|
var REACT_SCOPE_TYPE = hasSymbol ? Symbol.for('react.scope') : 0xead7;
|
|
|
|
function isValidElementType(type) {
|
|
return typeof type === 'string' || typeof type === 'function' || // Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill.
|
|
type === REACT_FRAGMENT_TYPE || type === REACT_CONCURRENT_MODE_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || typeof type === 'object' && type !== null && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_RESPONDER_TYPE || type.$$typeof === REACT_SCOPE_TYPE || type.$$typeof === REACT_BLOCK_TYPE);
|
|
}
|
|
|
|
function typeOf(object) {
|
|
if (typeof object === 'object' && object !== null) {
|
|
var $$typeof = object.$$typeof;
|
|
|
|
switch ($$typeof) {
|
|
case REACT_ELEMENT_TYPE:
|
|
var type = object.type;
|
|
|
|
switch (type) {
|
|
case REACT_ASYNC_MODE_TYPE:
|
|
case REACT_CONCURRENT_MODE_TYPE:
|
|
case REACT_FRAGMENT_TYPE:
|
|
case REACT_PROFILER_TYPE:
|
|
case REACT_STRICT_MODE_TYPE:
|
|
case REACT_SUSPENSE_TYPE:
|
|
return type;
|
|
|
|
default:
|
|
var $$typeofType = type && type.$$typeof;
|
|
|
|
switch ($$typeofType) {
|
|
case REACT_CONTEXT_TYPE:
|
|
case REACT_FORWARD_REF_TYPE:
|
|
case REACT_LAZY_TYPE:
|
|
case REACT_MEMO_TYPE:
|
|
case REACT_PROVIDER_TYPE:
|
|
return $$typeofType;
|
|
|
|
default:
|
|
return $$typeof;
|
|
}
|
|
|
|
}
|
|
|
|
case REACT_PORTAL_TYPE:
|
|
return $$typeof;
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
} // AsyncMode is deprecated along with isAsyncMode
|
|
|
|
var AsyncMode = REACT_ASYNC_MODE_TYPE;
|
|
var ConcurrentMode = REACT_CONCURRENT_MODE_TYPE;
|
|
var ContextConsumer = REACT_CONTEXT_TYPE;
|
|
var ContextProvider = REACT_PROVIDER_TYPE;
|
|
var Element = REACT_ELEMENT_TYPE;
|
|
var ForwardRef = REACT_FORWARD_REF_TYPE;
|
|
var Fragment = REACT_FRAGMENT_TYPE;
|
|
var Lazy = REACT_LAZY_TYPE;
|
|
var Memo = REACT_MEMO_TYPE;
|
|
var Portal = REACT_PORTAL_TYPE;
|
|
var Profiler = REACT_PROFILER_TYPE;
|
|
var StrictMode = REACT_STRICT_MODE_TYPE;
|
|
var Suspense = REACT_SUSPENSE_TYPE;
|
|
var hasWarnedAboutDeprecatedIsAsyncMode = false; // AsyncMode should be deprecated
|
|
|
|
function isAsyncMode(object) {
|
|
{
|
|
if (!hasWarnedAboutDeprecatedIsAsyncMode) {
|
|
hasWarnedAboutDeprecatedIsAsyncMode = true; // Using console['warn'] to evade Babel and ESLint
|
|
|
|
console['warn']('The ReactIs.isAsyncMode() alias has been deprecated, ' + 'and will be removed in React 17+. Update your code to use ' + 'ReactIs.isConcurrentMode() instead. It has the exact same API.');
|
|
}
|
|
}
|
|
|
|
return isConcurrentMode(object) || typeOf(object) === REACT_ASYNC_MODE_TYPE;
|
|
}
|
|
function isConcurrentMode(object) {
|
|
return typeOf(object) === REACT_CONCURRENT_MODE_TYPE;
|
|
}
|
|
function isContextConsumer(object) {
|
|
return typeOf(object) === REACT_CONTEXT_TYPE;
|
|
}
|
|
function isContextProvider(object) {
|
|
return typeOf(object) === REACT_PROVIDER_TYPE;
|
|
}
|
|
function isElement(object) {
|
|
return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
|
|
}
|
|
function isForwardRef(object) {
|
|
return typeOf(object) === REACT_FORWARD_REF_TYPE;
|
|
}
|
|
function isFragment(object) {
|
|
return typeOf(object) === REACT_FRAGMENT_TYPE;
|
|
}
|
|
function isLazy(object) {
|
|
return typeOf(object) === REACT_LAZY_TYPE;
|
|
}
|
|
function isMemo(object) {
|
|
return typeOf(object) === REACT_MEMO_TYPE;
|
|
}
|
|
function isPortal(object) {
|
|
return typeOf(object) === REACT_PORTAL_TYPE;
|
|
}
|
|
function isProfiler(object) {
|
|
return typeOf(object) === REACT_PROFILER_TYPE;
|
|
}
|
|
function isStrictMode(object) {
|
|
return typeOf(object) === REACT_STRICT_MODE_TYPE;
|
|
}
|
|
function isSuspense(object) {
|
|
return typeOf(object) === REACT_SUSPENSE_TYPE;
|
|
}
|
|
|
|
reactIs_development.AsyncMode = AsyncMode;
|
|
reactIs_development.ConcurrentMode = ConcurrentMode;
|
|
reactIs_development.ContextConsumer = ContextConsumer;
|
|
reactIs_development.ContextProvider = ContextProvider;
|
|
reactIs_development.Element = Element;
|
|
reactIs_development.ForwardRef = ForwardRef;
|
|
reactIs_development.Fragment = Fragment;
|
|
reactIs_development.Lazy = Lazy;
|
|
reactIs_development.Memo = Memo;
|
|
reactIs_development.Portal = Portal;
|
|
reactIs_development.Profiler = Profiler;
|
|
reactIs_development.StrictMode = StrictMode;
|
|
reactIs_development.Suspense = Suspense;
|
|
reactIs_development.isAsyncMode = isAsyncMode;
|
|
reactIs_development.isConcurrentMode = isConcurrentMode;
|
|
reactIs_development.isContextConsumer = isContextConsumer;
|
|
reactIs_development.isContextProvider = isContextProvider;
|
|
reactIs_development.isElement = isElement;
|
|
reactIs_development.isForwardRef = isForwardRef;
|
|
reactIs_development.isFragment = isFragment;
|
|
reactIs_development.isLazy = isLazy;
|
|
reactIs_development.isMemo = isMemo;
|
|
reactIs_development.isPortal = isPortal;
|
|
reactIs_development.isProfiler = isProfiler;
|
|
reactIs_development.isStrictMode = isStrictMode;
|
|
reactIs_development.isSuspense = isSuspense;
|
|
reactIs_development.isValidElementType = isValidElementType;
|
|
reactIs_development.typeOf = typeOf;
|
|
})();
|
|
}
|
|
return reactIs_development;
|
|
}
|
|
|
|
var hasRequiredReactIs;
|
|
|
|
function requireReactIs () {
|
|
if (hasRequiredReactIs) return reactIsExports;
|
|
hasRequiredReactIs = 1;
|
|
(function (module) {
|
|
|
|
{
|
|
module.exports = requireReactIs_development();
|
|
}
|
|
} (reactIs));
|
|
return reactIsExports;
|
|
}
|
|
|
|
var hasRequiredReactElement;
|
|
|
|
function requireReactElement () {
|
|
if (hasRequiredReactElement) return ReactElement;
|
|
hasRequiredReactElement = 1;
|
|
|
|
Object.defineProperty(ReactElement, '__esModule', {
|
|
value: true
|
|
});
|
|
ReactElement.default = ReactElement.test = ReactElement.serialize = void 0;
|
|
|
|
var ReactIs = _interopRequireWildcard(requireReactIs());
|
|
|
|
var _markup = requireMarkup();
|
|
|
|
function _interopRequireWildcard(obj) {
|
|
if (obj && obj.__esModule) {
|
|
return obj;
|
|
} else {
|
|
var newObj = {};
|
|
if (obj != null) {
|
|
for (var key in obj) {
|
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
var desc =
|
|
Object.defineProperty && Object.getOwnPropertyDescriptor
|
|
? Object.getOwnPropertyDescriptor(obj, key)
|
|
: {};
|
|
if (desc.get || desc.set) {
|
|
Object.defineProperty(newObj, key, desc);
|
|
} else {
|
|
newObj[key] = obj[key];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
newObj.default = obj;
|
|
return newObj;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
// Given element.props.children, or subtree during recursive traversal,
|
|
// return flattened array of children.
|
|
const getChildren = (arg, children = []) => {
|
|
if (Array.isArray(arg)) {
|
|
arg.forEach(item => {
|
|
getChildren(item, children);
|
|
});
|
|
} else if (arg != null && arg !== false) {
|
|
children.push(arg);
|
|
}
|
|
|
|
return children;
|
|
};
|
|
|
|
const getType = element => {
|
|
const type = element.type;
|
|
|
|
if (typeof type === 'string') {
|
|
return type;
|
|
}
|
|
|
|
if (typeof type === 'function') {
|
|
return type.displayName || type.name || 'Unknown';
|
|
}
|
|
|
|
if (ReactIs.isFragment(element)) {
|
|
return 'React.Fragment';
|
|
}
|
|
|
|
if (ReactIs.isSuspense(element)) {
|
|
return 'React.Suspense';
|
|
}
|
|
|
|
if (typeof type === 'object' && type !== null) {
|
|
if (ReactIs.isContextProvider(element)) {
|
|
return 'Context.Provider';
|
|
}
|
|
|
|
if (ReactIs.isContextConsumer(element)) {
|
|
return 'Context.Consumer';
|
|
}
|
|
|
|
if (ReactIs.isForwardRef(element)) {
|
|
const functionName = type.render.displayName || type.render.name || '';
|
|
return functionName !== ''
|
|
? 'ForwardRef(' + functionName + ')'
|
|
: 'ForwardRef';
|
|
}
|
|
|
|
if (ReactIs.isMemo(type)) {
|
|
const functionName =
|
|
type.displayName || type.type.displayName || type.type.name || '';
|
|
return functionName !== '' ? 'Memo(' + functionName + ')' : 'Memo';
|
|
}
|
|
}
|
|
|
|
return 'UNDEFINED';
|
|
};
|
|
|
|
const getPropKeys = element => {
|
|
const props = element.props;
|
|
return Object.keys(props)
|
|
.filter(key => key !== 'children' && props[key] !== undefined)
|
|
.sort();
|
|
};
|
|
|
|
const serialize = (element, config, indentation, depth, refs, printer) =>
|
|
++depth > config.maxDepth
|
|
? (0, _markup.printElementAsLeaf)(getType(element), config)
|
|
: (0, _markup.printElement)(
|
|
getType(element),
|
|
(0, _markup.printProps)(
|
|
getPropKeys(element),
|
|
element.props,
|
|
config,
|
|
indentation + config.indent,
|
|
depth,
|
|
refs,
|
|
printer
|
|
),
|
|
(0, _markup.printChildren)(
|
|
getChildren(element.props.children),
|
|
config,
|
|
indentation + config.indent,
|
|
depth,
|
|
refs,
|
|
printer
|
|
),
|
|
config,
|
|
indentation
|
|
);
|
|
|
|
ReactElement.serialize = serialize;
|
|
|
|
const test = val => val && ReactIs.isElement(val);
|
|
|
|
ReactElement.test = test;
|
|
const plugin = {
|
|
serialize,
|
|
test
|
|
};
|
|
var _default = plugin;
|
|
ReactElement.default = _default;
|
|
return ReactElement;
|
|
}
|
|
|
|
var ReactTestComponent = {};
|
|
|
|
var hasRequiredReactTestComponent;
|
|
|
|
function requireReactTestComponent () {
|
|
if (hasRequiredReactTestComponent) return ReactTestComponent;
|
|
hasRequiredReactTestComponent = 1;
|
|
|
|
Object.defineProperty(ReactTestComponent, '__esModule', {
|
|
value: true
|
|
});
|
|
ReactTestComponent.default = ReactTestComponent.test = ReactTestComponent.serialize = void 0;
|
|
|
|
var _markup = requireMarkup();
|
|
|
|
var Symbol = commonjsGlobal['jest-symbol-do-not-touch'] || commonjsGlobal.Symbol;
|
|
const testSymbol = Symbol.for('react.test.json');
|
|
|
|
const getPropKeys = object => {
|
|
const props = object.props;
|
|
return props
|
|
? Object.keys(props)
|
|
.filter(key => props[key] !== undefined)
|
|
.sort()
|
|
: [];
|
|
};
|
|
|
|
const serialize = (object, config, indentation, depth, refs, printer) =>
|
|
++depth > config.maxDepth
|
|
? (0, _markup.printElementAsLeaf)(object.type, config)
|
|
: (0, _markup.printElement)(
|
|
object.type,
|
|
object.props
|
|
? (0, _markup.printProps)(
|
|
getPropKeys(object),
|
|
object.props,
|
|
config,
|
|
indentation + config.indent,
|
|
depth,
|
|
refs,
|
|
printer
|
|
)
|
|
: '',
|
|
object.children
|
|
? (0, _markup.printChildren)(
|
|
object.children,
|
|
config,
|
|
indentation + config.indent,
|
|
depth,
|
|
refs,
|
|
printer
|
|
)
|
|
: '',
|
|
config,
|
|
indentation
|
|
);
|
|
|
|
ReactTestComponent.serialize = serialize;
|
|
|
|
const test = val => val && val.$$typeof === testSymbol;
|
|
|
|
ReactTestComponent.test = test;
|
|
const plugin = {
|
|
serialize,
|
|
test
|
|
};
|
|
var _default = plugin;
|
|
ReactTestComponent.default = _default;
|
|
return ReactTestComponent;
|
|
}
|
|
|
|
var build;
|
|
var hasRequiredBuild;
|
|
|
|
function requireBuild () {
|
|
if (hasRequiredBuild) return build;
|
|
hasRequiredBuild = 1;
|
|
|
|
var _ansiStyles = _interopRequireDefault(requireAnsiStyles());
|
|
|
|
var _collections = requireCollections();
|
|
|
|
var _AsymmetricMatcher = _interopRequireDefault(
|
|
requireAsymmetricMatcher()
|
|
);
|
|
|
|
var _ConvertAnsi = _interopRequireDefault(requireConvertAnsi());
|
|
|
|
var _DOMCollection = _interopRequireDefault(requireDOMCollection());
|
|
|
|
var _DOMElement = _interopRequireDefault(requireDOMElement());
|
|
|
|
var _Immutable = _interopRequireDefault(requireImmutable());
|
|
|
|
var _ReactElement = _interopRequireDefault(requireReactElement());
|
|
|
|
var _ReactTestComponent = _interopRequireDefault(
|
|
requireReactTestComponent()
|
|
);
|
|
|
|
function _interopRequireDefault(obj) {
|
|
return obj && obj.__esModule ? obj : {default: obj};
|
|
}
|
|
|
|
var Symbol = commonjsGlobal['jest-symbol-do-not-touch'] || commonjsGlobal.Symbol;
|
|
const toString = Object.prototype.toString;
|
|
const toISOString = Date.prototype.toISOString;
|
|
const errorToString = Error.prototype.toString;
|
|
const regExpToString = RegExp.prototype.toString;
|
|
const symbolToString = Symbol.prototype.toString;
|
|
/**
|
|
* Explicitly comparing typeof constructor to function avoids undefined as name
|
|
* when mock identity-obj-proxy returns the key as the value for any key.
|
|
*/
|
|
|
|
const getConstructorName = val =>
|
|
(typeof val.constructor === 'function' && val.constructor.name) || 'Object';
|
|
/* global window */
|
|
|
|
/** Is val is equal to global window object? Works even if it does not exist :) */
|
|
|
|
const isWindow = val => typeof window !== 'undefined' && val === window;
|
|
|
|
const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/;
|
|
const NEWLINE_REGEXP = /\n/gi;
|
|
|
|
class PrettyFormatPluginError extends Error {
|
|
constructor(message, stack) {
|
|
super(message);
|
|
this.stack = stack;
|
|
this.name = this.constructor.name;
|
|
}
|
|
}
|
|
|
|
function isToStringedArrayType(toStringed) {
|
|
return (
|
|
toStringed === '[object Array]' ||
|
|
toStringed === '[object ArrayBuffer]' ||
|
|
toStringed === '[object DataView]' ||
|
|
toStringed === '[object Float32Array]' ||
|
|
toStringed === '[object Float64Array]' ||
|
|
toStringed === '[object Int8Array]' ||
|
|
toStringed === '[object Int16Array]' ||
|
|
toStringed === '[object Int32Array]' ||
|
|
toStringed === '[object Uint8Array]' ||
|
|
toStringed === '[object Uint8ClampedArray]' ||
|
|
toStringed === '[object Uint16Array]' ||
|
|
toStringed === '[object Uint32Array]'
|
|
);
|
|
}
|
|
|
|
function printNumber(val) {
|
|
return Object.is(val, -0) ? '-0' : String(val);
|
|
}
|
|
|
|
function printBigInt(val) {
|
|
return String(`${val}n`);
|
|
}
|
|
|
|
function printFunction(val, printFunctionName) {
|
|
if (!printFunctionName) {
|
|
return '[Function]';
|
|
}
|
|
|
|
return '[Function ' + (val.name || 'anonymous') + ']';
|
|
}
|
|
|
|
function printSymbol(val) {
|
|
return symbolToString.call(val).replace(SYMBOL_REGEXP, 'Symbol($1)');
|
|
}
|
|
|
|
function printError(val) {
|
|
return '[' + errorToString.call(val) + ']';
|
|
}
|
|
/**
|
|
* The first port of call for printing an object, handles most of the
|
|
* data-types in JS.
|
|
*/
|
|
|
|
function printBasicValue(val, printFunctionName, escapeRegex, escapeString) {
|
|
if (val === true || val === false) {
|
|
return '' + val;
|
|
}
|
|
|
|
if (val === undefined) {
|
|
return 'undefined';
|
|
}
|
|
|
|
if (val === null) {
|
|
return 'null';
|
|
}
|
|
|
|
const typeOf = typeof val;
|
|
|
|
if (typeOf === 'number') {
|
|
return printNumber(val);
|
|
}
|
|
|
|
if (typeOf === 'bigint') {
|
|
return printBigInt(val);
|
|
}
|
|
|
|
if (typeOf === 'string') {
|
|
if (escapeString) {
|
|
return '"' + val.replace(/"|\\/g, '\\$&') + '"';
|
|
}
|
|
|
|
return '"' + val + '"';
|
|
}
|
|
|
|
if (typeOf === 'function') {
|
|
return printFunction(val, printFunctionName);
|
|
}
|
|
|
|
if (typeOf === 'symbol') {
|
|
return printSymbol(val);
|
|
}
|
|
|
|
const toStringed = toString.call(val);
|
|
|
|
if (toStringed === '[object WeakMap]') {
|
|
return 'WeakMap {}';
|
|
}
|
|
|
|
if (toStringed === '[object WeakSet]') {
|
|
return 'WeakSet {}';
|
|
}
|
|
|
|
if (
|
|
toStringed === '[object Function]' ||
|
|
toStringed === '[object GeneratorFunction]'
|
|
) {
|
|
return printFunction(val, printFunctionName);
|
|
}
|
|
|
|
if (toStringed === '[object Symbol]') {
|
|
return printSymbol(val);
|
|
}
|
|
|
|
if (toStringed === '[object Date]') {
|
|
return isNaN(+val) ? 'Date { NaN }' : toISOString.call(val);
|
|
}
|
|
|
|
if (toStringed === '[object Error]') {
|
|
return printError(val);
|
|
}
|
|
|
|
if (toStringed === '[object RegExp]') {
|
|
if (escapeRegex) {
|
|
// https://github.com/benjamingr/RegExp.escape/blob/master/polyfill.js
|
|
return regExpToString.call(val).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
}
|
|
|
|
return regExpToString.call(val);
|
|
}
|
|
|
|
if (val instanceof Error) {
|
|
return printError(val);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
/**
|
|
* Handles more complex objects ( such as objects with circular references.
|
|
* maps and sets etc )
|
|
*/
|
|
|
|
function printComplexValue(
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
hasCalledToJSON
|
|
) {
|
|
if (refs.indexOf(val) !== -1) {
|
|
return '[Circular]';
|
|
}
|
|
|
|
refs = refs.slice();
|
|
refs.push(val);
|
|
const hitMaxDepth = ++depth > config.maxDepth;
|
|
const min = config.min;
|
|
|
|
if (
|
|
config.callToJSON &&
|
|
!hitMaxDepth &&
|
|
val.toJSON &&
|
|
typeof val.toJSON === 'function' &&
|
|
!hasCalledToJSON
|
|
) {
|
|
return printer(val.toJSON(), config, indentation, depth, refs, true);
|
|
}
|
|
|
|
const toStringed = toString.call(val);
|
|
|
|
if (toStringed === '[object Arguments]') {
|
|
return hitMaxDepth
|
|
? '[Arguments]'
|
|
: (min ? '' : 'Arguments ') +
|
|
'[' +
|
|
(0, _collections.printListItems)(
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
']';
|
|
}
|
|
|
|
if (isToStringedArrayType(toStringed)) {
|
|
return hitMaxDepth
|
|
? '[' + val.constructor.name + ']'
|
|
: (min ? '' : val.constructor.name + ' ') +
|
|
'[' +
|
|
(0, _collections.printListItems)(
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
']';
|
|
}
|
|
|
|
if (toStringed === '[object Map]') {
|
|
return hitMaxDepth
|
|
? '[Map]'
|
|
: 'Map {' +
|
|
(0, _collections.printIteratorEntries)(
|
|
val.entries(),
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer,
|
|
' => '
|
|
) +
|
|
'}';
|
|
}
|
|
|
|
if (toStringed === '[object Set]') {
|
|
return hitMaxDepth
|
|
? '[Set]'
|
|
: 'Set {' +
|
|
(0, _collections.printIteratorValues)(
|
|
val.values(),
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
'}';
|
|
} // Avoid failure to serialize global window object in jsdom test environment.
|
|
// For example, not even relevant if window is prop of React element.
|
|
|
|
return hitMaxDepth || isWindow(val)
|
|
? '[' + getConstructorName(val) + ']'
|
|
: (min ? '' : getConstructorName(val) + ' ') +
|
|
'{' +
|
|
(0, _collections.printObjectProperties)(
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
printer
|
|
) +
|
|
'}';
|
|
}
|
|
|
|
function isNewPlugin(plugin) {
|
|
return plugin.serialize != null;
|
|
}
|
|
|
|
function printPlugin(plugin, val, config, indentation, depth, refs) {
|
|
let printed;
|
|
|
|
try {
|
|
printed = isNewPlugin(plugin)
|
|
? plugin.serialize(val, config, indentation, depth, refs, printer)
|
|
: plugin.print(
|
|
val,
|
|
valChild => printer(valChild, config, indentation, depth, refs),
|
|
str => {
|
|
const indentationNext = indentation + config.indent;
|
|
return (
|
|
indentationNext +
|
|
str.replace(NEWLINE_REGEXP, '\n' + indentationNext)
|
|
);
|
|
},
|
|
{
|
|
edgeSpacing: config.spacingOuter,
|
|
min: config.min,
|
|
spacing: config.spacingInner
|
|
},
|
|
config.colors
|
|
);
|
|
} catch (error) {
|
|
throw new PrettyFormatPluginError(error.message, error.stack);
|
|
}
|
|
|
|
if (typeof printed !== 'string') {
|
|
throw new Error(
|
|
`pretty-format: Plugin must return type "string" but instead returned "${typeof printed}".`
|
|
);
|
|
}
|
|
|
|
return printed;
|
|
}
|
|
|
|
function findPlugin(plugins, val) {
|
|
for (let p = 0; p < plugins.length; p++) {
|
|
try {
|
|
if (plugins[p].test(val)) {
|
|
return plugins[p];
|
|
}
|
|
} catch (error) {
|
|
throw new PrettyFormatPluginError(error.message, error.stack);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function printer(val, config, indentation, depth, refs, hasCalledToJSON) {
|
|
const plugin = findPlugin(config.plugins, val);
|
|
|
|
if (plugin !== null) {
|
|
return printPlugin(plugin, val, config, indentation, depth, refs);
|
|
}
|
|
|
|
const basicResult = printBasicValue(
|
|
val,
|
|
config.printFunctionName,
|
|
config.escapeRegex,
|
|
config.escapeString
|
|
);
|
|
|
|
if (basicResult !== null) {
|
|
return basicResult;
|
|
}
|
|
|
|
return printComplexValue(
|
|
val,
|
|
config,
|
|
indentation,
|
|
depth,
|
|
refs,
|
|
hasCalledToJSON
|
|
);
|
|
}
|
|
|
|
const DEFAULT_THEME = {
|
|
comment: 'gray',
|
|
content: 'reset',
|
|
prop: 'yellow',
|
|
tag: 'cyan',
|
|
value: 'green'
|
|
};
|
|
const DEFAULT_THEME_KEYS = Object.keys(DEFAULT_THEME);
|
|
const DEFAULT_OPTIONS = {
|
|
callToJSON: true,
|
|
escapeRegex: false,
|
|
escapeString: true,
|
|
highlight: false,
|
|
indent: 2,
|
|
maxDepth: Infinity,
|
|
min: false,
|
|
plugins: [],
|
|
printFunctionName: true,
|
|
theme: DEFAULT_THEME
|
|
};
|
|
|
|
function validateOptions(options) {
|
|
Object.keys(options).forEach(key => {
|
|
if (!DEFAULT_OPTIONS.hasOwnProperty(key)) {
|
|
throw new Error(`pretty-format: Unknown option "${key}".`);
|
|
}
|
|
});
|
|
|
|
if (options.min && options.indent !== undefined && options.indent !== 0) {
|
|
throw new Error(
|
|
'pretty-format: Options "min" and "indent" cannot be used together.'
|
|
);
|
|
}
|
|
|
|
if (options.theme !== undefined) {
|
|
if (options.theme === null) {
|
|
throw new Error(`pretty-format: Option "theme" must not be null.`);
|
|
}
|
|
|
|
if (typeof options.theme !== 'object') {
|
|
throw new Error(
|
|
`pretty-format: Option "theme" must be of type "object" but instead received "${typeof options.theme}".`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
const getColorsHighlight = options =>
|
|
DEFAULT_THEME_KEYS.reduce((colors, key) => {
|
|
const value =
|
|
options.theme && options.theme[key] !== undefined
|
|
? options.theme[key]
|
|
: DEFAULT_THEME[key];
|
|
const color = value && _ansiStyles.default[value];
|
|
|
|
if (
|
|
color &&
|
|
typeof color.close === 'string' &&
|
|
typeof color.open === 'string'
|
|
) {
|
|
colors[key] = color;
|
|
} else {
|
|
throw new Error(
|
|
`pretty-format: Option "theme" has a key "${key}" whose value "${value}" is undefined in ansi-styles.`
|
|
);
|
|
}
|
|
|
|
return colors;
|
|
}, Object.create(null));
|
|
|
|
const getColorsEmpty = () =>
|
|
DEFAULT_THEME_KEYS.reduce((colors, key) => {
|
|
colors[key] = {
|
|
close: '',
|
|
open: ''
|
|
};
|
|
return colors;
|
|
}, Object.create(null));
|
|
|
|
const getPrintFunctionName = options =>
|
|
options && options.printFunctionName !== undefined
|
|
? options.printFunctionName
|
|
: DEFAULT_OPTIONS.printFunctionName;
|
|
|
|
const getEscapeRegex = options =>
|
|
options && options.escapeRegex !== undefined
|
|
? options.escapeRegex
|
|
: DEFAULT_OPTIONS.escapeRegex;
|
|
|
|
const getEscapeString = options =>
|
|
options && options.escapeString !== undefined
|
|
? options.escapeString
|
|
: DEFAULT_OPTIONS.escapeString;
|
|
|
|
const getConfig = options => ({
|
|
callToJSON:
|
|
options && options.callToJSON !== undefined
|
|
? options.callToJSON
|
|
: DEFAULT_OPTIONS.callToJSON,
|
|
colors:
|
|
options && options.highlight
|
|
? getColorsHighlight(options)
|
|
: getColorsEmpty(),
|
|
escapeRegex: getEscapeRegex(options),
|
|
escapeString: getEscapeString(options),
|
|
indent:
|
|
options && options.min
|
|
? ''
|
|
: createIndent(
|
|
options && options.indent !== undefined
|
|
? options.indent
|
|
: DEFAULT_OPTIONS.indent
|
|
),
|
|
maxDepth:
|
|
options && options.maxDepth !== undefined
|
|
? options.maxDepth
|
|
: DEFAULT_OPTIONS.maxDepth,
|
|
min: options && options.min !== undefined ? options.min : DEFAULT_OPTIONS.min,
|
|
plugins:
|
|
options && options.plugins !== undefined
|
|
? options.plugins
|
|
: DEFAULT_OPTIONS.plugins,
|
|
printFunctionName: getPrintFunctionName(options),
|
|
spacingInner: options && options.min ? ' ' : '\n',
|
|
spacingOuter: options && options.min ? '' : '\n'
|
|
});
|
|
|
|
function createIndent(indent) {
|
|
return new Array(indent + 1).join(' ');
|
|
}
|
|
/**
|
|
* Returns a presentation string of your `val` object
|
|
* @param val any potential JavaScript object
|
|
* @param options Custom settings
|
|
*/
|
|
|
|
function prettyFormat(val, options) {
|
|
if (options) {
|
|
validateOptions(options);
|
|
|
|
if (options.plugins) {
|
|
const plugin = findPlugin(options.plugins, val);
|
|
|
|
if (plugin !== null) {
|
|
return printPlugin(plugin, val, getConfig(options), '', 0, []);
|
|
}
|
|
}
|
|
}
|
|
|
|
const basicResult = printBasicValue(
|
|
val,
|
|
getPrintFunctionName(options),
|
|
getEscapeRegex(options),
|
|
getEscapeString(options)
|
|
);
|
|
|
|
if (basicResult !== null) {
|
|
return basicResult;
|
|
}
|
|
|
|
return printComplexValue(val, getConfig(options), '', 0, []);
|
|
}
|
|
|
|
prettyFormat.plugins = {
|
|
AsymmetricMatcher: _AsymmetricMatcher.default,
|
|
ConvertAnsi: _ConvertAnsi.default,
|
|
DOMCollection: _DOMCollection.default,
|
|
DOMElement: _DOMElement.default,
|
|
Immutable: _Immutable.default,
|
|
ReactElement: _ReactElement.default,
|
|
ReactTestComponent: _ReactTestComponent.default
|
|
};
|
|
/* eslint-disable-next-line no-redeclare */
|
|
|
|
build = prettyFormat;
|
|
return build;
|
|
}
|
|
|
|
var buildExports = requireBuild();
|
|
var prettyFormat = /*@__PURE__*/getDefaultExportFromCjs(buildExports);
|
|
|
|
var _PostDominator_exit, _PostDominator_nodes;
|
|
function computePostDominatorTree(fn, options) {
|
|
const graph = buildReverseGraph(fn, options.includeThrowsAsExitNode);
|
|
const nodes = computeImmediateDominators(graph);
|
|
if (!options.includeThrowsAsExitNode) {
|
|
for (const [id] of fn.body.blocks) {
|
|
if (!nodes.has(id)) {
|
|
nodes.set(id, id);
|
|
}
|
|
}
|
|
}
|
|
return new PostDominator(graph.entry, nodes);
|
|
}
|
|
class PostDominator {
|
|
constructor(exit, nodes) {
|
|
_PostDominator_exit.set(this, void 0);
|
|
_PostDominator_nodes.set(this, void 0);
|
|
__classPrivateFieldSet(this, _PostDominator_exit, exit, "f");
|
|
__classPrivateFieldSet(this, _PostDominator_nodes, nodes, "f");
|
|
}
|
|
get exit() {
|
|
return __classPrivateFieldGet(this, _PostDominator_exit, "f");
|
|
}
|
|
get(id) {
|
|
const dominator = __classPrivateFieldGet(this, _PostDominator_nodes, "f").get(id);
|
|
CompilerError.invariant(dominator !== undefined, {
|
|
reason: 'Unknown node',
|
|
loc: GeneratedSource,
|
|
});
|
|
return dominator === id ? null : dominator;
|
|
}
|
|
debug() {
|
|
const postDominators = new Map();
|
|
for (const [key, value] of __classPrivateFieldGet(this, _PostDominator_nodes, "f")) {
|
|
postDominators.set(`bb${key}`, `bb${value}`);
|
|
}
|
|
return prettyFormat({
|
|
exit: `bb${this.exit}`,
|
|
postDominators,
|
|
});
|
|
}
|
|
}
|
|
_PostDominator_exit = new WeakMap(), _PostDominator_nodes = new WeakMap();
|
|
function computeImmediateDominators(graph) {
|
|
const nodes = new Map();
|
|
nodes.set(graph.entry, graph.entry);
|
|
let changed = true;
|
|
while (changed) {
|
|
changed = false;
|
|
for (const [id, node] of graph.nodes) {
|
|
if (node.id === graph.entry) {
|
|
continue;
|
|
}
|
|
let newIdom = null;
|
|
for (const pred of node.preds) {
|
|
if (nodes.has(pred)) {
|
|
newIdom = pred;
|
|
break;
|
|
}
|
|
}
|
|
CompilerError.invariant(newIdom !== null, {
|
|
reason: `At least one predecessor must have been visited for block ${id}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
for (const pred of node.preds) {
|
|
if (pred === newIdom) {
|
|
continue;
|
|
}
|
|
const predDom = nodes.get(pred);
|
|
if (predDom !== undefined) {
|
|
newIdom = intersect(pred, newIdom, graph, nodes);
|
|
}
|
|
}
|
|
if (nodes.get(id) !== newIdom) {
|
|
nodes.set(id, newIdom);
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
return nodes;
|
|
}
|
|
function intersect(a, b, graph, nodes) {
|
|
let block1 = graph.nodes.get(a);
|
|
let block2 = graph.nodes.get(b);
|
|
while (block1 !== block2) {
|
|
while (block1.index > block2.index) {
|
|
const dom = nodes.get(block1.id);
|
|
block1 = graph.nodes.get(dom);
|
|
}
|
|
while (block2.index > block1.index) {
|
|
const dom = nodes.get(block2.id);
|
|
block2 = graph.nodes.get(dom);
|
|
}
|
|
}
|
|
return block1.id;
|
|
}
|
|
function buildReverseGraph(fn, includeThrowsAsExitNode) {
|
|
const nodes = new Map();
|
|
const exitId = fn.env.nextBlockId;
|
|
const exit = {
|
|
id: exitId,
|
|
index: 0,
|
|
preds: new Set(),
|
|
succs: new Set(),
|
|
};
|
|
nodes.set(exitId, exit);
|
|
for (const [id, block] of fn.body.blocks) {
|
|
const node = {
|
|
id,
|
|
index: 0,
|
|
preds: new Set(eachTerminalSuccessor(block.terminal)),
|
|
succs: new Set(block.preds),
|
|
};
|
|
if (block.terminal.kind === 'return') {
|
|
node.preds.add(exitId);
|
|
exit.succs.add(id);
|
|
}
|
|
else if (block.terminal.kind === 'throw' && includeThrowsAsExitNode) {
|
|
node.preds.add(exitId);
|
|
exit.succs.add(id);
|
|
}
|
|
nodes.set(id, node);
|
|
}
|
|
const visited = new Set();
|
|
const postorder = [];
|
|
function visit(id) {
|
|
if (visited.has(id)) {
|
|
return;
|
|
}
|
|
visited.add(id);
|
|
const node = nodes.get(id);
|
|
for (const successor of node.succs) {
|
|
visit(successor);
|
|
}
|
|
postorder.push(id);
|
|
}
|
|
visit(exitId);
|
|
const rpo = { entry: exitId, nodes: new Map() };
|
|
let index = 0;
|
|
for (const id of postorder.reverse()) {
|
|
const node = nodes.get(id);
|
|
node.index = index++;
|
|
rpo.nodes.set(id, node);
|
|
}
|
|
return rpo;
|
|
}
|
|
|
|
const DEFAULT_SHAPES = new Map(BUILTIN_SHAPES);
|
|
const UNTYPED_GLOBALS = new Set([
|
|
'Object',
|
|
'Function',
|
|
'RegExp',
|
|
'Date',
|
|
'Error',
|
|
'TypeError',
|
|
'RangeError',
|
|
'ReferenceError',
|
|
'SyntaxError',
|
|
'URIError',
|
|
'EvalError',
|
|
'DataView',
|
|
'Float32Array',
|
|
'Float64Array',
|
|
'Int8Array',
|
|
'Int16Array',
|
|
'Int32Array',
|
|
'WeakMap',
|
|
'Uint8Array',
|
|
'Uint8ClampedArray',
|
|
'Uint16Array',
|
|
'Uint32Array',
|
|
'ArrayBuffer',
|
|
'JSON',
|
|
'console',
|
|
'eval',
|
|
]);
|
|
const TYPED_GLOBALS = [
|
|
[
|
|
'Object',
|
|
addObject(DEFAULT_SHAPES, 'Object', [
|
|
[
|
|
'keys',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'fromEntries',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [Effect.ConditionallyMutate],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInObjectId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'entries',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [Effect.Capture],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
aliasing: {
|
|
receiver: '@receiver',
|
|
params: ['@object'],
|
|
rest: null,
|
|
returns: '@returns',
|
|
temporaries: [],
|
|
effects: [
|
|
{
|
|
kind: 'Create',
|
|
into: '@returns',
|
|
reason: ValueReason.KnownReturnSignature,
|
|
value: ValueKind.Mutable,
|
|
},
|
|
{
|
|
kind: 'Capture',
|
|
from: '@object',
|
|
into: '@returns',
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
],
|
|
[
|
|
'keys',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
aliasing: {
|
|
receiver: '@receiver',
|
|
params: ['@object'],
|
|
rest: null,
|
|
returns: '@returns',
|
|
temporaries: [],
|
|
effects: [
|
|
{
|
|
kind: 'Create',
|
|
into: '@returns',
|
|
reason: ValueReason.KnownReturnSignature,
|
|
value: ValueKind.Mutable,
|
|
},
|
|
{
|
|
kind: 'ImmutableCapture',
|
|
from: '@object',
|
|
into: '@returns',
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
],
|
|
[
|
|
'values',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [Effect.Capture],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
aliasing: {
|
|
receiver: '@receiver',
|
|
params: ['@object'],
|
|
rest: null,
|
|
returns: '@returns',
|
|
temporaries: [],
|
|
effects: [
|
|
{
|
|
kind: 'Create',
|
|
into: '@returns',
|
|
reason: ValueReason.KnownReturnSignature,
|
|
value: ValueKind.Mutable,
|
|
},
|
|
{
|
|
kind: 'Capture',
|
|
from: '@object',
|
|
into: '@returns',
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
],
|
|
]),
|
|
],
|
|
[
|
|
'Array',
|
|
addObject(DEFAULT_SHAPES, 'Array', [
|
|
[
|
|
'isArray',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [Effect.Read],
|
|
restParam: null,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'from',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [
|
|
Effect.ConditionallyMutateIterator,
|
|
Effect.ConditionallyMutate,
|
|
Effect.ConditionallyMutate,
|
|
],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'of',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Object', shapeId: BuiltInArrayId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
]),
|
|
],
|
|
[
|
|
'performance',
|
|
addObject(DEFAULT_SHAPES, 'performance', [
|
|
[
|
|
'now',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
impure: true,
|
|
canonicalName: 'performance.now',
|
|
}),
|
|
],
|
|
]),
|
|
],
|
|
[
|
|
'Date',
|
|
addObject(DEFAULT_SHAPES, 'Date', [
|
|
[
|
|
'now',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
impure: true,
|
|
canonicalName: 'Date.now',
|
|
}),
|
|
],
|
|
]),
|
|
],
|
|
[
|
|
'Math',
|
|
addObject(DEFAULT_SHAPES, 'Math', [
|
|
['PI', { kind: 'Primitive' }],
|
|
[
|
|
'max',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'min',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'trunc',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'ceil',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'floor',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'pow',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'random',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
impure: true,
|
|
canonicalName: 'Math.random',
|
|
}),
|
|
],
|
|
]),
|
|
],
|
|
['Infinity', { kind: 'Primitive' }],
|
|
['NaN', { kind: 'Primitive' }],
|
|
[
|
|
'console',
|
|
addObject(DEFAULT_SHAPES, 'console', [
|
|
[
|
|
'error',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'info',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'log',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'table',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'trace',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'warn',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
]),
|
|
],
|
|
[
|
|
'Boolean',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'Number',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'String',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'parseInt',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'parseFloat',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'isNaN',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'isFinite',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'encodeURI',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'encodeURIComponent',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'decodeURI',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'decodeURIComponent',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Primitive,
|
|
}),
|
|
],
|
|
[
|
|
'Map',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [Effect.ConditionallyMutateIterator],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInMapId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}, null, true),
|
|
],
|
|
[
|
|
'Set',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [Effect.ConditionallyMutateIterator],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInSetId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}, null, true),
|
|
],
|
|
[
|
|
'WeakMap',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [Effect.ConditionallyMutateIterator],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInWeakMapId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}, null, true),
|
|
],
|
|
[
|
|
'WeakSet',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [Effect.ConditionallyMutateIterator],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInWeakSetId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}, null, true),
|
|
],
|
|
];
|
|
const REACT_APIS = [
|
|
[
|
|
'useContext',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useContext',
|
|
returnValueKind: ValueKind.Frozen,
|
|
returnValueReason: ValueReason.Context,
|
|
}, BuiltInUseContextHookId),
|
|
],
|
|
[
|
|
'useState',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Object', shapeId: BuiltInUseStateId },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useState',
|
|
returnValueKind: ValueKind.Frozen,
|
|
returnValueReason: ValueReason.State,
|
|
}),
|
|
],
|
|
[
|
|
'useActionState',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Object', shapeId: BuiltInUseActionStateId },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useActionState',
|
|
returnValueKind: ValueKind.Frozen,
|
|
returnValueReason: ValueReason.State,
|
|
}),
|
|
],
|
|
[
|
|
'useReducer',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Object', shapeId: BuiltInUseReducerId },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useReducer',
|
|
returnValueKind: ValueKind.Frozen,
|
|
returnValueReason: ValueReason.ReducerState,
|
|
}),
|
|
],
|
|
[
|
|
'useRef',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Capture,
|
|
returnType: { kind: 'Object', shapeId: BuiltInUseRefId },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useRef',
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
[
|
|
'useImperativeHandle',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useImperativeHandle',
|
|
returnValueKind: ValueKind.Frozen,
|
|
}),
|
|
],
|
|
[
|
|
'useMemo',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useMemo',
|
|
returnValueKind: ValueKind.Frozen,
|
|
}),
|
|
],
|
|
[
|
|
'useCallback',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useCallback',
|
|
returnValueKind: ValueKind.Frozen,
|
|
}),
|
|
],
|
|
[
|
|
'useEffect',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Primitive' },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useEffect',
|
|
returnValueKind: ValueKind.Frozen,
|
|
aliasing: {
|
|
receiver: '@receiver',
|
|
params: [],
|
|
rest: '@rest',
|
|
returns: '@returns',
|
|
temporaries: ['@effect'],
|
|
effects: [
|
|
{
|
|
kind: 'Freeze',
|
|
value: '@rest',
|
|
reason: ValueReason.Effect,
|
|
},
|
|
{
|
|
kind: 'Create',
|
|
into: '@effect',
|
|
value: ValueKind.Frozen,
|
|
reason: ValueReason.KnownReturnSignature,
|
|
},
|
|
{
|
|
kind: 'Capture',
|
|
from: '@rest',
|
|
into: '@effect',
|
|
},
|
|
{
|
|
kind: 'Create',
|
|
into: '@returns',
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.KnownReturnSignature,
|
|
},
|
|
],
|
|
},
|
|
}, BuiltInUseEffectHookId),
|
|
],
|
|
[
|
|
'useLayoutEffect',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useLayoutEffect',
|
|
returnValueKind: ValueKind.Frozen,
|
|
}, BuiltInUseLayoutEffectHookId),
|
|
],
|
|
[
|
|
'useInsertionEffect',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useInsertionEffect',
|
|
returnValueKind: ValueKind.Frozen,
|
|
}, BuiltInUseInsertionEffectHookId),
|
|
],
|
|
[
|
|
'useTransition',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: { kind: 'Object', shapeId: BuiltInUseTransitionId },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useTransition',
|
|
returnValueKind: ValueKind.Frozen,
|
|
}),
|
|
],
|
|
[
|
|
'useOptimistic',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Object', shapeId: BuiltInUseOptimisticId },
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useOptimistic',
|
|
returnValueKind: ValueKind.Frozen,
|
|
returnValueReason: ValueReason.State,
|
|
}),
|
|
],
|
|
[
|
|
'use',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Frozen,
|
|
}, BuiltInUseOperatorId),
|
|
],
|
|
[
|
|
'useEffectEvent',
|
|
addHook(DEFAULT_SHAPES, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: {
|
|
kind: 'Function',
|
|
return: { kind: 'Poly' },
|
|
shapeId: BuiltInEffectEventId,
|
|
isConstructor: false,
|
|
},
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'useEffectEvent',
|
|
returnValueKind: ValueKind.Frozen,
|
|
}, BuiltInUseEffectEventId),
|
|
],
|
|
];
|
|
TYPED_GLOBALS.push([
|
|
'React',
|
|
addObject(DEFAULT_SHAPES, null, [
|
|
...REACT_APIS,
|
|
[
|
|
'createElement',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Frozen,
|
|
}),
|
|
],
|
|
[
|
|
'cloneElement',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Frozen,
|
|
}),
|
|
],
|
|
[
|
|
'createRef',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Capture,
|
|
returnType: { kind: 'Object', shapeId: BuiltInUseRefId },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
}),
|
|
],
|
|
]),
|
|
], [
|
|
'_jsx',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Frozen,
|
|
}),
|
|
]);
|
|
const DEFAULT_GLOBALS = new Map(REACT_APIS);
|
|
for (const name of UNTYPED_GLOBALS) {
|
|
DEFAULT_GLOBALS.set(name, {
|
|
kind: 'Poly',
|
|
});
|
|
}
|
|
for (const [name, type_] of TYPED_GLOBALS) {
|
|
DEFAULT_GLOBALS.set(name, type_);
|
|
}
|
|
DEFAULT_GLOBALS.set('globalThis', addObject(DEFAULT_SHAPES, 'globalThis', TYPED_GLOBALS));
|
|
DEFAULT_GLOBALS.set('global', addObject(DEFAULT_SHAPES, 'global', TYPED_GLOBALS));
|
|
function installTypeConfig(globals, shapes, typeConfig, moduleName, loc) {
|
|
var _a, _b, _c, _d, _e, _f;
|
|
switch (typeConfig.kind) {
|
|
case 'type': {
|
|
switch (typeConfig.name) {
|
|
case 'Array': {
|
|
return { kind: 'Object', shapeId: BuiltInArrayId };
|
|
}
|
|
case 'MixedReadonly': {
|
|
return { kind: 'Object', shapeId: BuiltInMixedReadonlyId };
|
|
}
|
|
case 'Primitive': {
|
|
return { kind: 'Primitive' };
|
|
}
|
|
case 'Ref': {
|
|
return { kind: 'Object', shapeId: BuiltInUseRefId };
|
|
}
|
|
case 'Any': {
|
|
return { kind: 'Poly' };
|
|
}
|
|
default: {
|
|
assertExhaustive$1(typeConfig.name, `Unexpected type '${typeConfig.name}'`);
|
|
}
|
|
}
|
|
}
|
|
case 'function': {
|
|
return addFunction(shapes, [], {
|
|
positionalParams: typeConfig.positionalParams,
|
|
restParam: typeConfig.restParam,
|
|
calleeEffect: typeConfig.calleeEffect,
|
|
returnType: installTypeConfig(globals, shapes, typeConfig.returnType, moduleName, loc),
|
|
returnValueKind: typeConfig.returnValueKind,
|
|
noAlias: typeConfig.noAlias === true,
|
|
mutableOnlyIfOperandsAreMutable: typeConfig.mutableOnlyIfOperandsAreMutable === true,
|
|
aliasing: typeConfig.aliasing,
|
|
knownIncompatible: (_a = typeConfig.knownIncompatible) !== null && _a !== void 0 ? _a : null,
|
|
});
|
|
}
|
|
case 'hook': {
|
|
return addHook(shapes, {
|
|
hookKind: 'Custom',
|
|
positionalParams: (_b = typeConfig.positionalParams) !== null && _b !== void 0 ? _b : [],
|
|
restParam: (_c = typeConfig.restParam) !== null && _c !== void 0 ? _c : Effect.Freeze,
|
|
calleeEffect: Effect.Read,
|
|
returnType: installTypeConfig(globals, shapes, typeConfig.returnType, moduleName, loc),
|
|
returnValueKind: (_d = typeConfig.returnValueKind) !== null && _d !== void 0 ? _d : ValueKind.Frozen,
|
|
noAlias: typeConfig.noAlias === true,
|
|
aliasing: typeConfig.aliasing,
|
|
knownIncompatible: (_e = typeConfig.knownIncompatible) !== null && _e !== void 0 ? _e : null,
|
|
});
|
|
}
|
|
case 'object': {
|
|
return addObject(shapes, null, Object.entries((_f = typeConfig.properties) !== null && _f !== void 0 ? _f : {}).map(([key, value]) => {
|
|
var _a;
|
|
const type = installTypeConfig(globals, shapes, value, moduleName, loc);
|
|
const expectHook = isHookName$2(key);
|
|
let isHook = false;
|
|
if (type.kind === 'Function' && type.shapeId !== null) {
|
|
const functionType = shapes.get(type.shapeId);
|
|
if (((_a = functionType === null || functionType === void 0 ? void 0 : functionType.functionType) === null || _a === void 0 ? void 0 : _a.hookKind) !== null) {
|
|
isHook = true;
|
|
}
|
|
}
|
|
if (expectHook !== isHook) {
|
|
CompilerError.throwInvalidConfig({
|
|
reason: `Invalid type configuration for module`,
|
|
description: `Expected type for object property '${key}' from module '${moduleName}' ${expectHook ? 'to be a hook' : 'not to be a hook'} based on the property name`,
|
|
loc,
|
|
});
|
|
}
|
|
return [key, type];
|
|
}));
|
|
}
|
|
default: {
|
|
assertExhaustive$1(typeConfig, `Unexpected type kind '${typeConfig.kind}'`);
|
|
}
|
|
}
|
|
}
|
|
function getReanimatedModuleType(registry) {
|
|
const frozenHooks = [
|
|
'useFrameCallback',
|
|
'useAnimatedStyle',
|
|
'useAnimatedProps',
|
|
'useAnimatedScrollHandler',
|
|
'useAnimatedReaction',
|
|
'useWorkletCallback',
|
|
];
|
|
const reanimatedType = [];
|
|
for (const hook of frozenHooks) {
|
|
reanimatedType.push([
|
|
hook,
|
|
addHook(registry, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
returnValueKind: ValueKind.Frozen,
|
|
noAlias: true,
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'Custom',
|
|
}),
|
|
]);
|
|
}
|
|
const mutableHooks = ['useSharedValue', 'useDerivedValue'];
|
|
for (const hook of mutableHooks) {
|
|
reanimatedType.push([
|
|
hook,
|
|
addHook(registry, {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Object', shapeId: ReanimatedSharedValueId },
|
|
returnValueKind: ValueKind.Mutable,
|
|
noAlias: true,
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'Custom',
|
|
}),
|
|
]);
|
|
}
|
|
const funcs = [
|
|
'withTiming',
|
|
'withSpring',
|
|
'createAnimatedPropAdapter',
|
|
'withDecay',
|
|
'withRepeat',
|
|
'runOnUI',
|
|
'executeOnUIRuntimeSync',
|
|
];
|
|
for (const fn of funcs) {
|
|
reanimatedType.push([
|
|
fn,
|
|
addFunction(registry, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Mutable,
|
|
noAlias: true,
|
|
}),
|
|
]);
|
|
}
|
|
return addObject(registry, null, reanimatedType);
|
|
}
|
|
|
|
const ObjectPropertiesSchema = v4.z
|
|
.record(v4.z.string(), v4.z.lazy(() => TypeSchema))
|
|
.refine(record => {
|
|
return Object.keys(record).every(key => key === '*' || key === 'default' || libExports$1.isValidIdentifier(key));
|
|
}, 'Expected all "object" property names to be valid identifier, `*` to match any property, of `default` to define a module default export');
|
|
const ObjectTypeSchema = v4.z.object({
|
|
kind: v4.z.literal('object'),
|
|
properties: ObjectPropertiesSchema.nullable(),
|
|
});
|
|
const LifetimeIdSchema = v4.z.string().refine(id => id.startsWith('@'), {
|
|
message: "Placeholder names must start with '@'",
|
|
});
|
|
const FreezeEffectSchema = v4.z.object({
|
|
kind: v4.z.literal('Freeze'),
|
|
value: LifetimeIdSchema,
|
|
reason: ValueReasonSchema,
|
|
});
|
|
const MutateEffectSchema = v4.z.object({
|
|
kind: v4.z.literal('Mutate'),
|
|
value: LifetimeIdSchema,
|
|
});
|
|
const MutateTransitiveConditionallySchema = v4.z.object({
|
|
kind: v4.z.literal('MutateTransitiveConditionally'),
|
|
value: LifetimeIdSchema,
|
|
});
|
|
const CreateEffectSchema = v4.z.object({
|
|
kind: v4.z.literal('Create'),
|
|
into: LifetimeIdSchema,
|
|
value: ValueKindSchema,
|
|
reason: ValueReasonSchema,
|
|
});
|
|
const AssignEffectSchema = v4.z.object({
|
|
kind: v4.z.literal('Assign'),
|
|
from: LifetimeIdSchema,
|
|
into: LifetimeIdSchema,
|
|
});
|
|
const AliasEffectSchema = v4.z.object({
|
|
kind: v4.z.literal('Alias'),
|
|
from: LifetimeIdSchema,
|
|
into: LifetimeIdSchema,
|
|
});
|
|
const ImmutableCaptureEffectSchema = v4.z.object({
|
|
kind: v4.z.literal('ImmutableCapture'),
|
|
from: LifetimeIdSchema,
|
|
into: LifetimeIdSchema,
|
|
});
|
|
const CaptureEffectSchema = v4.z.object({
|
|
kind: v4.z.literal('Capture'),
|
|
from: LifetimeIdSchema,
|
|
into: LifetimeIdSchema,
|
|
});
|
|
const CreateFromEffectSchema = v4.z.object({
|
|
kind: v4.z.literal('CreateFrom'),
|
|
from: LifetimeIdSchema,
|
|
into: LifetimeIdSchema,
|
|
});
|
|
const ApplyArgSchema = v4.z.union([
|
|
LifetimeIdSchema,
|
|
v4.z.object({
|
|
kind: v4.z.literal('Spread'),
|
|
place: LifetimeIdSchema,
|
|
}),
|
|
v4.z.object({
|
|
kind: v4.z.literal('Hole'),
|
|
}),
|
|
]);
|
|
const ApplyEffectSchema = v4.z.object({
|
|
kind: v4.z.literal('Apply'),
|
|
receiver: LifetimeIdSchema,
|
|
function: LifetimeIdSchema,
|
|
mutatesFunction: v4.z.boolean(),
|
|
args: v4.z.array(ApplyArgSchema),
|
|
into: LifetimeIdSchema,
|
|
});
|
|
const ImpureEffectSchema = v4.z.object({
|
|
kind: v4.z.literal('Impure'),
|
|
place: LifetimeIdSchema,
|
|
});
|
|
const AliasingEffectSchema = v4.z.union([
|
|
FreezeEffectSchema,
|
|
CreateEffectSchema,
|
|
CreateFromEffectSchema,
|
|
AssignEffectSchema,
|
|
AliasEffectSchema,
|
|
CaptureEffectSchema,
|
|
ImmutableCaptureEffectSchema,
|
|
ImpureEffectSchema,
|
|
MutateEffectSchema,
|
|
MutateTransitiveConditionallySchema,
|
|
ApplyEffectSchema,
|
|
]);
|
|
const AliasingSignatureSchema = v4.z.object({
|
|
receiver: LifetimeIdSchema,
|
|
params: v4.z.array(LifetimeIdSchema),
|
|
rest: LifetimeIdSchema.nullable(),
|
|
returns: LifetimeIdSchema,
|
|
effects: v4.z.array(AliasingEffectSchema),
|
|
temporaries: v4.z.array(LifetimeIdSchema),
|
|
});
|
|
const FunctionTypeSchema = v4.z.object({
|
|
kind: v4.z.literal('function'),
|
|
positionalParams: v4.z.array(EffectSchema),
|
|
restParam: EffectSchema.nullable(),
|
|
calleeEffect: EffectSchema,
|
|
returnType: v4.z.lazy(() => TypeSchema),
|
|
returnValueKind: ValueKindSchema,
|
|
noAlias: v4.z.boolean().nullable().optional(),
|
|
mutableOnlyIfOperandsAreMutable: v4.z.boolean().nullable().optional(),
|
|
impure: v4.z.boolean().nullable().optional(),
|
|
canonicalName: v4.z.string().nullable().optional(),
|
|
aliasing: AliasingSignatureSchema.nullable().optional(),
|
|
knownIncompatible: v4.z.string().nullable().optional(),
|
|
});
|
|
const HookTypeSchema = v4.z.object({
|
|
kind: v4.z.literal('hook'),
|
|
positionalParams: v4.z.array(EffectSchema).nullable().optional(),
|
|
restParam: EffectSchema.nullable().optional(),
|
|
returnType: v4.z.lazy(() => TypeSchema),
|
|
returnValueKind: ValueKindSchema.nullable().optional(),
|
|
noAlias: v4.z.boolean().nullable().optional(),
|
|
aliasing: AliasingSignatureSchema.nullable().optional(),
|
|
knownIncompatible: v4.z.string().nullable().optional(),
|
|
});
|
|
const BuiltInTypeSchema = v4.z.union([
|
|
v4.z.literal('Any'),
|
|
v4.z.literal('Ref'),
|
|
v4.z.literal('Array'),
|
|
v4.z.literal('Primitive'),
|
|
v4.z.literal('MixedReadonly'),
|
|
]);
|
|
const TypeReferenceSchema = v4.z.object({
|
|
kind: v4.z.literal('type'),
|
|
name: BuiltInTypeSchema,
|
|
});
|
|
const TypeSchema = v4.z.union([
|
|
ObjectTypeSchema,
|
|
FunctionTypeSchema,
|
|
HookTypeSchema,
|
|
TypeReferenceSchema,
|
|
]);
|
|
|
|
function unsupportedTypeAnnotation(desc, loc) {
|
|
CompilerError.throwInvalidJS({
|
|
reason: `Typedchecker does not currently support type annotation: ${desc}`,
|
|
loc,
|
|
});
|
|
}
|
|
|
|
var _FlowTypeEnv_nextNominalId, _FlowTypeEnv_nextTypeParameterId, _FlowTypeEnv_types, _FlowTypeEnv_bindings, _FlowTypeEnv_generics, _FlowTypeEnv_flowTypes;
|
|
function makeTypeParameterId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected TypeParameterId to be a non-negative integer',
|
|
loc: GeneratedSource,
|
|
});
|
|
return id;
|
|
}
|
|
function makeNominalId(id) {
|
|
return id;
|
|
}
|
|
const DUMMY_NOMINAL = makeNominalId(0);
|
|
function convertFlowType(flowType, loc) {
|
|
let nextGenericId = 0;
|
|
function convertFlowTypeImpl(flowType, loc, genericEnv, platform, poly = null) {
|
|
var _a, _b, _c;
|
|
switch (flowType.kind) {
|
|
case 'TypeApp': {
|
|
if (flowType.type.kind === 'Def' &&
|
|
flowType.type.def.kind === 'Poly' &&
|
|
flowType.type.def.t_out.kind === 'Def' &&
|
|
flowType.type.def.t_out.def.kind === 'Type' &&
|
|
flowType.type.def.t_out.def.type.kind === 'Opaque' &&
|
|
flowType.type.def.t_out.def.type.opaquetype.opaque_name ===
|
|
'Client' &&
|
|
flowType.targs.length === 1) {
|
|
return convertFlowTypeImpl(flowType.targs[0], loc, genericEnv, 'client');
|
|
}
|
|
else if (flowType.type.kind === 'Def' &&
|
|
flowType.type.def.kind === 'Poly' &&
|
|
flowType.type.def.t_out.kind === 'Def' &&
|
|
flowType.type.def.t_out.def.kind === 'Type' &&
|
|
flowType.type.def.t_out.def.type.kind === 'Opaque' &&
|
|
flowType.type.def.t_out.def.type.opaquetype.opaque_name ===
|
|
'Server' &&
|
|
flowType.targs.length === 1) {
|
|
return convertFlowTypeImpl(flowType.targs[0], loc, genericEnv, 'server');
|
|
}
|
|
return Resolved.todo(platform);
|
|
}
|
|
case 'Open':
|
|
return Resolved.mixed(platform);
|
|
case 'Any':
|
|
return Resolved.todo(platform);
|
|
case 'Annot':
|
|
return convertFlowTypeImpl(flowType.type, loc, genericEnv, platform, poly);
|
|
case 'Opaque': {
|
|
if (flowType.opaquetype.opaque_name === 'Client' &&
|
|
flowType.opaquetype.super_t != null) {
|
|
return convertFlowTypeImpl(flowType.opaquetype.super_t, loc, genericEnv, 'client');
|
|
}
|
|
if (flowType.opaquetype.opaque_name === 'Server' &&
|
|
flowType.opaquetype.super_t != null) {
|
|
return convertFlowTypeImpl(flowType.opaquetype.super_t, loc, genericEnv, 'server');
|
|
}
|
|
const t = (_a = flowType.opaquetype.underlying_t) !== null && _a !== void 0 ? _a : flowType.opaquetype.super_t;
|
|
if (t != null) {
|
|
return convertFlowTypeImpl(t, loc, genericEnv, platform, poly);
|
|
}
|
|
else {
|
|
return Resolved.todo(platform);
|
|
}
|
|
}
|
|
case 'Def': {
|
|
switch (flowType.def.kind) {
|
|
case 'EnumValue':
|
|
return convertFlowTypeImpl(flowType.def.enum_info.representation_t, loc, genericEnv, platform, poly);
|
|
case 'EnumObject':
|
|
return Resolved.enum(platform);
|
|
case 'Empty':
|
|
return Resolved.todo(platform);
|
|
case 'Instance': {
|
|
const members = new Map();
|
|
for (const key in flowType.def.instance.inst.own_props) {
|
|
const prop = flowType.def.instance.inst.own_props[key];
|
|
if (prop.kind === 'Field') {
|
|
members.set(key, convertFlowTypeImpl(prop.type, loc, genericEnv, platform));
|
|
}
|
|
else {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unsupported property kind ${prop.kind}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
return Resolved.class((_b = flowType.def.instance.inst.class_name) !== null && _b !== void 0 ? _b : '[anonymous class]', members, platform);
|
|
}
|
|
case 'Type':
|
|
return convertFlowTypeImpl(flowType.def.type, loc, genericEnv, platform, poly);
|
|
case 'NumGeneral':
|
|
case 'SingletonNum':
|
|
return Resolved.number(platform);
|
|
case 'StrGeneral':
|
|
case 'SingletonStr':
|
|
return Resolved.string(platform);
|
|
case 'BoolGeneral':
|
|
case 'SingletonBool':
|
|
return Resolved.boolean(platform);
|
|
case 'Void':
|
|
return Resolved.void(platform);
|
|
case 'Null':
|
|
return Resolved.void(platform);
|
|
case 'Mixed':
|
|
return Resolved.mixed(platform);
|
|
case 'Arr': {
|
|
if (flowType.def.arrtype.kind === 'ArrayAT' ||
|
|
flowType.def.arrtype.kind === 'ROArrayAT') {
|
|
return Resolved.array(convertFlowTypeImpl(flowType.def.arrtype.elem_t, loc, genericEnv, platform), platform);
|
|
}
|
|
else {
|
|
return Resolved.tuple(DUMMY_NOMINAL, flowType.def.arrtype.elements.map(t => convertFlowTypeImpl(t.t, loc, genericEnv, platform)), platform);
|
|
}
|
|
}
|
|
case 'Obj': {
|
|
const members = new Map();
|
|
for (const key in flowType.def.objtype.props) {
|
|
const prop = flowType.def.objtype.props[key];
|
|
if (prop.kind === 'Field') {
|
|
members.set(key, convertFlowTypeImpl(prop.type, loc, genericEnv, platform));
|
|
}
|
|
else {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unsupported property kind ${prop.kind}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
return Resolved.object(DUMMY_NOMINAL, members, platform);
|
|
}
|
|
case 'Class': {
|
|
if (flowType.def.type.kind === 'ThisInstance') {
|
|
const members = new Map();
|
|
for (const key in flowType.def.type.instance.inst.own_props) {
|
|
const prop = flowType.def.type.instance.inst.own_props[key];
|
|
if (prop.kind === 'Field') {
|
|
members.set(key, convertFlowTypeImpl(prop.type, loc, genericEnv, platform));
|
|
}
|
|
else {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unsupported property kind ${prop.kind}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
return Resolved.class((_c = flowType.def.type.instance.inst.class_name) !== null && _c !== void 0 ? _c : '[anonymous class]', members, platform);
|
|
}
|
|
CompilerError.invariant(false, {
|
|
reason: `Unsupported class instance type ${flowType.def.type.kind}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
case 'Fun':
|
|
return Resolved.function(poly, flowType.def.funtype.params.map(p => convertFlowTypeImpl(p.type, loc, genericEnv, platform)), convertFlowTypeImpl(flowType.def.funtype.return_t, loc, genericEnv, platform), platform);
|
|
case 'Poly': {
|
|
let newEnv = genericEnv;
|
|
const poly = flowType.def.tparams.map(p => {
|
|
const id = makeTypeParameterId(nextGenericId++);
|
|
const bound = convertFlowTypeImpl(p.bound, loc, newEnv, platform);
|
|
newEnv = new Map(newEnv);
|
|
newEnv.set(p.name, id);
|
|
return {
|
|
name: p.name,
|
|
id,
|
|
bound,
|
|
};
|
|
});
|
|
return convertFlowTypeImpl(flowType.def.t_out, loc, newEnv, platform, poly);
|
|
}
|
|
case 'ReactAbstractComponent': {
|
|
const props = new Map();
|
|
let children = null;
|
|
const propsType = convertFlowTypeImpl(flowType.def.config, loc, genericEnv, platform);
|
|
if (propsType.type.kind === 'Object') {
|
|
propsType.type.members.forEach((v, k) => {
|
|
if (k === 'children') {
|
|
children = v;
|
|
}
|
|
else {
|
|
props.set(k, v);
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unsupported component props type ${propsType.type.kind}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
return Resolved.component(props, children, platform);
|
|
}
|
|
case 'Renders':
|
|
return Resolved.todo(platform);
|
|
default:
|
|
unsupportedTypeAnnotation('Renders', GeneratedSource);
|
|
}
|
|
}
|
|
case 'Generic': {
|
|
const id = genericEnv.get(flowType.name);
|
|
if (id == null) {
|
|
unsupportedTypeAnnotation(flowType.name, GeneratedSource);
|
|
}
|
|
return Resolved.generic(id, platform, convertFlowTypeImpl(flowType.bound, loc, genericEnv, platform));
|
|
}
|
|
case 'Union': {
|
|
const members = flowType.members.map(t => convertFlowTypeImpl(t, loc, genericEnv, platform));
|
|
if (members.length === 1) {
|
|
return members[0];
|
|
}
|
|
if (members[0].type.kind === 'Number' ||
|
|
members[0].type.kind === 'String' ||
|
|
members[0].type.kind === 'Boolean') {
|
|
const dupes = members.filter(t => t.type.kind === members[0].type.kind);
|
|
if (dupes.length === members.length) {
|
|
return members[0];
|
|
}
|
|
}
|
|
if (members[0].type.kind === 'Array' &&
|
|
(members[0].type.element.type.kind === 'Number' ||
|
|
members[0].type.element.type.kind === 'String' ||
|
|
members[0].type.element.type.kind === 'Boolean')) {
|
|
const first = members[0].type.element;
|
|
const dupes = members.filter(t => t.type.kind === 'Array' &&
|
|
t.type.element.type.kind === first.type.kind);
|
|
if (dupes.length === members.length) {
|
|
return members[0];
|
|
}
|
|
}
|
|
return Resolved.union(members, platform);
|
|
}
|
|
case 'Eval': {
|
|
if (flowType.destructor.kind === 'ReactDRO' ||
|
|
flowType.destructor.kind === 'ReactCheckComponentConfig') {
|
|
return convertFlowTypeImpl(flowType.type, loc, genericEnv, platform, poly);
|
|
}
|
|
unsupportedTypeAnnotation(`EvalT(${flowType.destructor.kind})`, GeneratedSource);
|
|
}
|
|
case 'Optional': {
|
|
return Resolved.union([
|
|
convertFlowTypeImpl(flowType.type, loc, genericEnv, platform),
|
|
Resolved.void(platform),
|
|
], platform);
|
|
}
|
|
default:
|
|
unsupportedTypeAnnotation(flowType.kind, GeneratedSource);
|
|
}
|
|
}
|
|
return convertFlowTypeImpl(flowType, loc, new Map(), 'shared');
|
|
}
|
|
function serializeLoc(location) {
|
|
return `${location.start.line}:${location.start.column}-${location.end.line}:${location.end.column}`;
|
|
}
|
|
function buildTypeEnvironment(flowOutput) {
|
|
const result = new Map();
|
|
for (const item of flowOutput) {
|
|
const loc = {
|
|
start: {
|
|
line: item.loc.start.line,
|
|
column: item.loc.start.column - 1,
|
|
index: item.loc.start.index,
|
|
},
|
|
end: item.loc.end,
|
|
filename: item.loc.filename,
|
|
identifierName: item.loc.identifierName,
|
|
};
|
|
result.set(serializeLoc(loc), item.type);
|
|
}
|
|
return result;
|
|
}
|
|
let lastFlowSource = null;
|
|
let lastFlowResult = null;
|
|
class FlowTypeEnv {
|
|
constructor() {
|
|
this.moduleEnv = new Map();
|
|
_FlowTypeEnv_nextNominalId.set(this, 0);
|
|
_FlowTypeEnv_nextTypeParameterId.set(this, 0);
|
|
_FlowTypeEnv_types.set(this, new Map());
|
|
_FlowTypeEnv_bindings.set(this, new Map());
|
|
_FlowTypeEnv_generics.set(this, []);
|
|
_FlowTypeEnv_flowTypes.set(this, new Map());
|
|
}
|
|
init(env, source) {
|
|
CompilerError.invariant(env.config.flowTypeProvider != null, {
|
|
reason: 'Expected flowDumpTypes to be defined in environment config',
|
|
loc: GeneratedSource,
|
|
});
|
|
let stdout;
|
|
if (source === lastFlowSource) {
|
|
stdout = lastFlowResult;
|
|
}
|
|
else {
|
|
lastFlowSource = source;
|
|
lastFlowResult = env.config.flowTypeProvider(source);
|
|
stdout = lastFlowResult;
|
|
}
|
|
const flowTypes = buildTypeEnvironment(stdout);
|
|
const resolvedFlowTypes = new Map();
|
|
for (const [loc, type] of flowTypes) {
|
|
if (typeof loc === 'symbol')
|
|
continue;
|
|
resolvedFlowTypes.set(loc, convertFlowType(JSON.parse(type), loc));
|
|
}
|
|
__classPrivateFieldSet(this, _FlowTypeEnv_flowTypes, resolvedFlowTypes, "f");
|
|
}
|
|
setType(identifier, type) {
|
|
if (typeof identifier.loc !== 'symbol' &&
|
|
__classPrivateFieldGet(this, _FlowTypeEnv_flowTypes, "f").has(serializeLoc(identifier.loc))) {
|
|
return;
|
|
}
|
|
__classPrivateFieldGet(this, _FlowTypeEnv_types, "f").set(identifier.id, type);
|
|
}
|
|
getType(identifier) {
|
|
const result = this.getTypeOrNull(identifier);
|
|
if (result == null) {
|
|
throw new Error(`Type not found for ${identifier.id}, ${typeof identifier.loc === 'symbol' ? 'generated loc' : serializeLoc(identifier.loc)}`);
|
|
}
|
|
return result;
|
|
}
|
|
getTypeOrNull(identifier) {
|
|
var _a;
|
|
const result = (_a = __classPrivateFieldGet(this, _FlowTypeEnv_types, "f").get(identifier.id)) !== null && _a !== void 0 ? _a : null;
|
|
if (result == null && typeof identifier.loc !== 'symbol') {
|
|
const flowType = __classPrivateFieldGet(this, _FlowTypeEnv_flowTypes, "f").get(serializeLoc(identifier.loc));
|
|
return flowType !== null && flowType !== void 0 ? flowType : null;
|
|
}
|
|
return result;
|
|
}
|
|
getTypeByLoc(loc) {
|
|
if (typeof loc === 'symbol') {
|
|
return null;
|
|
}
|
|
const flowType = __classPrivateFieldGet(this, _FlowTypeEnv_flowTypes, "f").get(serializeLoc(loc));
|
|
return flowType !== null && flowType !== void 0 ? flowType : null;
|
|
}
|
|
nextNominalId() {
|
|
var _a, _b;
|
|
return makeNominalId((__classPrivateFieldSet(this, _FlowTypeEnv_nextNominalId, (_b = __classPrivateFieldGet(this, _FlowTypeEnv_nextNominalId, "f"), _a = _b++, _b), "f"), _a));
|
|
}
|
|
nextTypeParameterId() {
|
|
var _a, _b;
|
|
return makeTypeParameterId((__classPrivateFieldSet(this, _FlowTypeEnv_nextTypeParameterId, (_b = __classPrivateFieldGet(this, _FlowTypeEnv_nextTypeParameterId, "f"), _a = _b++, _b), "f"), _a));
|
|
}
|
|
addBinding(bindingIdentifier, type) {
|
|
__classPrivateFieldGet(this, _FlowTypeEnv_bindings, "f").set(bindingIdentifier, type);
|
|
}
|
|
resolveBinding(bindingIdentifier) {
|
|
var _a;
|
|
return (_a = __classPrivateFieldGet(this, _FlowTypeEnv_bindings, "f").get(bindingIdentifier)) !== null && _a !== void 0 ? _a : null;
|
|
}
|
|
pushGeneric(name, generic) {
|
|
__classPrivateFieldGet(this, _FlowTypeEnv_generics, "f").unshift([name, generic]);
|
|
}
|
|
popGeneric(name) {
|
|
for (let i = 0; i < __classPrivateFieldGet(this, _FlowTypeEnv_generics, "f").length; i++) {
|
|
if (__classPrivateFieldGet(this, _FlowTypeEnv_generics, "f")[i][0] === name) {
|
|
__classPrivateFieldGet(this, _FlowTypeEnv_generics, "f").splice(i, 1);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
getGeneric(name) {
|
|
for (const [eltName, param] of __classPrivateFieldGet(this, _FlowTypeEnv_generics, "f")) {
|
|
if (name === eltName) {
|
|
return param;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
_FlowTypeEnv_nextNominalId = new WeakMap(), _FlowTypeEnv_nextTypeParameterId = new WeakMap(), _FlowTypeEnv_types = new WeakMap(), _FlowTypeEnv_bindings = new WeakMap(), _FlowTypeEnv_generics = new WeakMap(), _FlowTypeEnv_flowTypes = new WeakMap();
|
|
const Primitives = {
|
|
number(platform) {
|
|
return { kind: 'Concrete', type: { kind: 'Number' }, platform };
|
|
},
|
|
string(platform) {
|
|
return { kind: 'Concrete', type: { kind: 'String' }, platform };
|
|
},
|
|
boolean(platform) {
|
|
return { kind: 'Concrete', type: { kind: 'Boolean' }, platform };
|
|
},
|
|
void(platform) {
|
|
return { kind: 'Concrete', type: { kind: 'Void' }, platform };
|
|
},
|
|
mixed(platform) {
|
|
return { kind: 'Concrete', type: { kind: 'Mixed' }, platform };
|
|
},
|
|
enum(platform) {
|
|
return { kind: 'Concrete', type: { kind: 'Enum' }, platform };
|
|
},
|
|
todo(platform) {
|
|
return { kind: 'Concrete', type: { kind: 'Mixed' }, platform };
|
|
},
|
|
};
|
|
const Resolved = Object.assign(Object.assign({}, Primitives), { nullable(type, platform) {
|
|
return { kind: 'Concrete', type: { kind: 'Nullable', type }, platform };
|
|
},
|
|
array(element, platform) {
|
|
return { kind: 'Concrete', type: { kind: 'Array', element }, platform };
|
|
},
|
|
set(element, platform) {
|
|
return { kind: 'Concrete', type: { kind: 'Set', element }, platform };
|
|
},
|
|
map(key, value, platform) {
|
|
return { kind: 'Concrete', type: { kind: 'Map', key, value }, platform };
|
|
},
|
|
function(typeParameters, params, returnType, platform) {
|
|
return {
|
|
kind: 'Concrete',
|
|
type: { kind: 'Function', typeParameters, params, returnType },
|
|
platform,
|
|
};
|
|
},
|
|
component(props, children, platform) {
|
|
return {
|
|
kind: 'Concrete',
|
|
type: { kind: 'Component', props, children },
|
|
platform,
|
|
};
|
|
},
|
|
object(id, members, platform) {
|
|
return {
|
|
kind: 'Concrete',
|
|
type: {
|
|
kind: 'Object',
|
|
id,
|
|
members,
|
|
},
|
|
platform,
|
|
};
|
|
},
|
|
class(name, members, platform) {
|
|
return {
|
|
kind: 'Concrete',
|
|
type: {
|
|
kind: 'Instance',
|
|
name,
|
|
members,
|
|
},
|
|
platform,
|
|
};
|
|
},
|
|
tuple(id, members, platform) {
|
|
return {
|
|
kind: 'Concrete',
|
|
type: {
|
|
kind: 'Tuple',
|
|
id,
|
|
members,
|
|
},
|
|
platform,
|
|
};
|
|
},
|
|
generic(id, platform, bound = Primitives.mixed(platform)) {
|
|
return {
|
|
kind: 'Concrete',
|
|
type: {
|
|
kind: 'Generic',
|
|
id,
|
|
bound,
|
|
},
|
|
platform,
|
|
};
|
|
},
|
|
union(members, platform) {
|
|
return {
|
|
kind: 'Concrete',
|
|
type: {
|
|
kind: 'Union',
|
|
members,
|
|
},
|
|
platform,
|
|
};
|
|
} });
|
|
|
|
function defaultModuleTypeProvider(moduleName) {
|
|
switch (moduleName) {
|
|
case 'react-hook-form': {
|
|
return {
|
|
kind: 'object',
|
|
properties: {
|
|
useForm: {
|
|
kind: 'hook',
|
|
returnType: {
|
|
kind: 'object',
|
|
properties: {
|
|
watch: {
|
|
kind: 'function',
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
calleeEffect: Effect.Read,
|
|
returnType: { kind: 'type', name: 'Any' },
|
|
returnValueKind: ValueKind.Mutable,
|
|
knownIncompatible: `React Hook Form's \`useForm()\` API returns a \`watch()\` function which cannot be memoized safely.`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
case '@tanstack/react-table': {
|
|
return {
|
|
kind: 'object',
|
|
properties: {
|
|
useReactTable: {
|
|
kind: 'hook',
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'type', name: 'Any' },
|
|
knownIncompatible: `TanStack Table's \`useReactTable()\` API returns functions that cannot be memoized safely`,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
case '@tanstack/react-virtual': {
|
|
return {
|
|
kind: 'object',
|
|
properties: {
|
|
useVirtualizer: {
|
|
kind: 'hook',
|
|
positionalParams: [],
|
|
restParam: Effect.Read,
|
|
returnType: { kind: 'type', name: 'Any' },
|
|
knownIncompatible: `TanStack Virtual's \`useVirtualizer()\` API returns functions that cannot be memoized safely`,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
var _Environment_instances, _Environment_globals, _Environment_shapes, _Environment_moduleTypes, _Environment_nextIdentifer, _Environment_nextBlock, _Environment_nextScope, _Environment_scope, _Environment_outlinedFunctions, _Environment_contextIdentifiers, _Environment_hoistedIdentifiers, _Environment_flowTypeEnvironment, _Environment_errors, _Environment_resolveModuleType, _Environment_isKnownReactModule, _Environment_getCustomHookType;
|
|
const ExternalFunctionSchema = v4.z.object({
|
|
source: v4.z.string(),
|
|
importSpecifierName: v4.z.string(),
|
|
});
|
|
const InstrumentationSchema = v4.z
|
|
.object({
|
|
fn: ExternalFunctionSchema,
|
|
gating: ExternalFunctionSchema.nullable(),
|
|
globalGating: v4.z.string().nullable(),
|
|
})
|
|
.refine(opts => opts.gating != null || opts.globalGating != null, 'Expected at least one of gating or globalGating');
|
|
const MacroSchema = v4.z.string();
|
|
const HookSchema = v4.z.object({
|
|
effectKind: v4.z.nativeEnum(Effect),
|
|
valueKind: v4.z.nativeEnum(ValueKind),
|
|
noAlias: v4.z.boolean().default(false),
|
|
transitiveMixedData: v4.z.boolean().default(false),
|
|
});
|
|
const EnvironmentConfigSchema = v4.z.object({
|
|
customHooks: v4.z.map(v4.z.string(), HookSchema).default(new Map()),
|
|
moduleTypeProvider: v4.z.nullable(v4.z.any()).default(null),
|
|
customMacros: v4.z.nullable(v4.z.array(MacroSchema)).default(null),
|
|
enableResetCacheOnSourceFileChanges: v4.z.nullable(v4.z.boolean()).default(null),
|
|
enablePreserveExistingMemoizationGuarantees: v4.z.boolean().default(true),
|
|
validatePreserveExistingMemoizationGuarantees: v4.z.boolean().default(true),
|
|
validateExhaustiveMemoizationDependencies: v4.z.boolean().default(true),
|
|
validateExhaustiveEffectDependencies: v4.z
|
|
.enum(['off', 'all', 'missing-only', 'extra-only'])
|
|
.default('off'),
|
|
enableForest: v4.z.boolean().default(false),
|
|
flowTypeProvider: v4.z.nullable(v4.z.any()).default(null),
|
|
enableOptionalDependencies: v4.z.boolean().default(true),
|
|
enableNameAnonymousFunctions: v4.z.boolean().default(false),
|
|
validateHooksUsage: v4.z.boolean().default(true),
|
|
validateRefAccessDuringRender: v4.z.boolean().default(true),
|
|
validateNoSetStateInRender: v4.z.boolean().default(true),
|
|
enableUseKeyedState: v4.z.boolean().default(false),
|
|
validateNoSetStateInEffects: v4.z.boolean().default(false),
|
|
validateNoDerivedComputationsInEffects: v4.z.boolean().default(false),
|
|
validateNoDerivedComputationsInEffects_exp: v4.z.boolean().default(false),
|
|
validateNoJSXInTryStatements: v4.z.boolean().default(false),
|
|
validateStaticComponents: v4.z.boolean().default(false),
|
|
validateNoCapitalizedCalls: v4.z.nullable(v4.z.array(v4.z.string())).default(null),
|
|
validateBlocklistedImports: v4.z.nullable(v4.z.array(v4.z.string())).default(null),
|
|
validateSourceLocations: v4.z.boolean().default(false),
|
|
validateNoImpureFunctionsInRender: v4.z.boolean().default(false),
|
|
validateNoFreezingKnownMutableFunctions: v4.z.boolean().default(false),
|
|
enableAssumeHooksFollowRulesOfReact: v4.z.boolean().default(true),
|
|
enableTransitivelyFreezeFunctionExpressions: v4.z.boolean().default(true),
|
|
enableEmitHookGuards: ExternalFunctionSchema.nullable().default(null),
|
|
enableFunctionOutlining: v4.z.boolean().default(true),
|
|
enableJsxOutlining: v4.z.boolean().default(false),
|
|
enableEmitInstrumentForget: InstrumentationSchema.nullable().default(null),
|
|
assertValidMutableRanges: v4.z.boolean().default(false),
|
|
throwUnknownException__testonly: v4.z.boolean().default(false),
|
|
enableCustomTypeDefinitionForReanimated: v4.z.boolean().default(false),
|
|
enableTreatRefLikeIdentifiersAsRefs: v4.z.boolean().default(true),
|
|
enableTreatSetIdentifiersAsStateSetters: v4.z.boolean().default(false),
|
|
validateNoVoidUseMemo: v4.z.boolean().default(true),
|
|
enableAllowSetStateFromRefsInEffects: v4.z.boolean().default(true),
|
|
enableVerboseNoSetStateInEffect: v4.z.boolean().default(false),
|
|
});
|
|
class Environment {
|
|
constructor(scope, fnType, outputMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
|
|
_Environment_instances.add(this);
|
|
_Environment_globals.set(this, void 0);
|
|
_Environment_shapes.set(this, void 0);
|
|
_Environment_moduleTypes.set(this, new Map());
|
|
_Environment_nextIdentifer.set(this, 0);
|
|
_Environment_nextBlock.set(this, 0);
|
|
_Environment_nextScope.set(this, 0);
|
|
_Environment_scope.set(this, void 0);
|
|
_Environment_outlinedFunctions.set(this, []);
|
|
_Environment_contextIdentifiers.set(this, void 0);
|
|
_Environment_hoistedIdentifiers.set(this, void 0);
|
|
_Environment_flowTypeEnvironment.set(this, void 0);
|
|
_Environment_errors.set(this, new CompilerError());
|
|
__classPrivateFieldSet(this, _Environment_scope, scope, "f");
|
|
this.fnType = fnType;
|
|
this.outputMode = outputMode;
|
|
this.config = config;
|
|
this.filename = filename;
|
|
this.code = code;
|
|
this.logger = logger;
|
|
this.programContext = programContext;
|
|
__classPrivateFieldSet(this, _Environment_shapes, new Map(DEFAULT_SHAPES), "f");
|
|
__classPrivateFieldSet(this, _Environment_globals, new Map(DEFAULT_GLOBALS), "f");
|
|
for (const [hookName, hook] of this.config.customHooks) {
|
|
CompilerError.invariant(!__classPrivateFieldGet(this, _Environment_globals, "f").has(hookName), {
|
|
reason: `[Globals] Found existing definition in global registry for custom hook ${hookName}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
__classPrivateFieldGet(this, _Environment_globals, "f").set(hookName, addHook(__classPrivateFieldGet(this, _Environment_shapes, "f"), {
|
|
positionalParams: [],
|
|
restParam: hook.effectKind,
|
|
returnType: hook.transitiveMixedData
|
|
? { kind: 'Object', shapeId: BuiltInMixedReadonlyId }
|
|
: { kind: 'Poly' },
|
|
returnValueKind: hook.valueKind,
|
|
calleeEffect: Effect.Read,
|
|
hookKind: 'Custom',
|
|
noAlias: hook.noAlias,
|
|
}));
|
|
}
|
|
if (config.enableCustomTypeDefinitionForReanimated) {
|
|
const reanimatedModuleType = getReanimatedModuleType(__classPrivateFieldGet(this, _Environment_shapes, "f"));
|
|
__classPrivateFieldGet(this, _Environment_moduleTypes, "f").set(REANIMATED_MODULE_NAME, reanimatedModuleType);
|
|
}
|
|
this.parentFunction = parentFunction;
|
|
__classPrivateFieldSet(this, _Environment_contextIdentifiers, contextIdentifiers, "f");
|
|
__classPrivateFieldSet(this, _Environment_hoistedIdentifiers, new Set(), "f");
|
|
if (config.flowTypeProvider != null) {
|
|
__classPrivateFieldSet(this, _Environment_flowTypeEnvironment, new FlowTypeEnv(), "f");
|
|
CompilerError.invariant(code != null, {
|
|
reason: 'Expected Environment to be initialized with source code when a Flow type provider is specified',
|
|
loc: GeneratedSource,
|
|
});
|
|
__classPrivateFieldGet(this, _Environment_flowTypeEnvironment, "f").init(this, code);
|
|
}
|
|
else {
|
|
__classPrivateFieldSet(this, _Environment_flowTypeEnvironment, null, "f");
|
|
}
|
|
}
|
|
get typeContext() {
|
|
CompilerError.invariant(__classPrivateFieldGet(this, _Environment_flowTypeEnvironment, "f") != null, {
|
|
reason: 'Flow type environment not initialized',
|
|
loc: GeneratedSource,
|
|
});
|
|
return __classPrivateFieldGet(this, _Environment_flowTypeEnvironment, "f");
|
|
}
|
|
get enableDropManualMemoization() {
|
|
switch (this.outputMode) {
|
|
case 'lint': {
|
|
return true;
|
|
}
|
|
case 'client':
|
|
case 'ssr': {
|
|
return true;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(this.outputMode, `Unexpected output mode '${this.outputMode}'`);
|
|
}
|
|
}
|
|
}
|
|
get enableMemoization() {
|
|
switch (this.outputMode) {
|
|
case 'client':
|
|
case 'lint': {
|
|
return true;
|
|
}
|
|
case 'ssr': {
|
|
return false;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(this.outputMode, `Unexpected output mode '${this.outputMode}'`);
|
|
}
|
|
}
|
|
}
|
|
get enableValidations() {
|
|
switch (this.outputMode) {
|
|
case 'client':
|
|
case 'lint':
|
|
case 'ssr': {
|
|
return true;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(this.outputMode, `Unexpected output mode '${this.outputMode}'`);
|
|
}
|
|
}
|
|
}
|
|
get nextIdentifierId() {
|
|
var _a, _b;
|
|
return makeIdentifierId((__classPrivateFieldSet(this, _Environment_nextIdentifer, (_b = __classPrivateFieldGet(this, _Environment_nextIdentifer, "f"), _a = _b++, _b), "f"), _a));
|
|
}
|
|
get nextBlockId() {
|
|
var _a, _b;
|
|
return makeBlockId((__classPrivateFieldSet(this, _Environment_nextBlock, (_b = __classPrivateFieldGet(this, _Environment_nextBlock, "f"), _a = _b++, _b), "f"), _a));
|
|
}
|
|
get nextScopeId() {
|
|
var _a, _b;
|
|
return makeScopeId((__classPrivateFieldSet(this, _Environment_nextScope, (_b = __classPrivateFieldGet(this, _Environment_nextScope, "f"), _a = _b++, _b), "f"), _a));
|
|
}
|
|
get scope() {
|
|
return __classPrivateFieldGet(this, _Environment_scope, "f");
|
|
}
|
|
logErrors(errors) {
|
|
if (errors.isOk() || this.logger == null) {
|
|
return;
|
|
}
|
|
for (const error of errors.unwrapErr().details) {
|
|
this.logger.logEvent(this.filename, {
|
|
kind: 'CompileError',
|
|
detail: error,
|
|
fnLoc: null,
|
|
});
|
|
}
|
|
}
|
|
recordError(error) {
|
|
if (error.category === ErrorCategory.Invariant) {
|
|
const compilerError = new CompilerError();
|
|
if (error instanceof CompilerDiagnostic) {
|
|
compilerError.pushDiagnostic(error);
|
|
}
|
|
else {
|
|
compilerError.pushErrorDetail(error);
|
|
}
|
|
throw compilerError;
|
|
}
|
|
if (error instanceof CompilerDiagnostic) {
|
|
__classPrivateFieldGet(this, _Environment_errors, "f").pushDiagnostic(error);
|
|
}
|
|
else {
|
|
__classPrivateFieldGet(this, _Environment_errors, "f").pushErrorDetail(error);
|
|
}
|
|
}
|
|
recordErrors(error) {
|
|
for (const detail of error.details) {
|
|
this.recordError(detail);
|
|
}
|
|
}
|
|
hasErrors() {
|
|
return __classPrivateFieldGet(this, _Environment_errors, "f").hasAnyErrors();
|
|
}
|
|
aggregateErrors() {
|
|
return __classPrivateFieldGet(this, _Environment_errors, "f");
|
|
}
|
|
isContextIdentifier(node) {
|
|
return __classPrivateFieldGet(this, _Environment_contextIdentifiers, "f").has(node);
|
|
}
|
|
isHoistedIdentifier(node) {
|
|
return __classPrivateFieldGet(this, _Environment_hoistedIdentifiers, "f").has(node);
|
|
}
|
|
generateGloballyUniqueIdentifierName(name) {
|
|
const identifierNode = __classPrivateFieldGet(this, _Environment_scope, "f").generateUidIdentifier(name !== null && name !== void 0 ? name : undefined);
|
|
return makeIdentifierName(identifierNode.name);
|
|
}
|
|
outlineFunction(fn, type) {
|
|
__classPrivateFieldGet(this, _Environment_outlinedFunctions, "f").push({ fn, type });
|
|
}
|
|
getOutlinedFunctions() {
|
|
return __classPrivateFieldGet(this, _Environment_outlinedFunctions, "f");
|
|
}
|
|
getGlobalDeclaration(binding, loc) {
|
|
var _a, _b, _c;
|
|
switch (binding.kind) {
|
|
case 'ModuleLocal': {
|
|
return isHookName$2(binding.name) ? __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_getCustomHookType).call(this) : null;
|
|
}
|
|
case 'Global': {
|
|
return ((_a = __classPrivateFieldGet(this, _Environment_globals, "f").get(binding.name)) !== null && _a !== void 0 ? _a : (isHookName$2(binding.name) ? __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_getCustomHookType).call(this) : null));
|
|
}
|
|
case 'ImportSpecifier': {
|
|
if (__classPrivateFieldGet(this, _Environment_instances, "m", _Environment_isKnownReactModule).call(this, binding.module)) {
|
|
return ((_b = __classPrivateFieldGet(this, _Environment_globals, "f").get(binding.imported)) !== null && _b !== void 0 ? _b : (isHookName$2(binding.imported) || isHookName$2(binding.name)
|
|
? __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_getCustomHookType).call(this)
|
|
: null));
|
|
}
|
|
else {
|
|
const moduleType = __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_resolveModuleType).call(this, binding.module, loc);
|
|
if (moduleType !== null) {
|
|
const importedType = this.getPropertyType(moduleType, binding.imported);
|
|
if (importedType != null) {
|
|
const expectHook = isHookName$2(binding.imported);
|
|
const isHook = getHookKindForType(this, importedType) != null;
|
|
if (expectHook !== isHook) {
|
|
CompilerError.throwInvalidConfig({
|
|
reason: `Invalid type configuration for module`,
|
|
description: `Expected type for \`import {${binding.imported}} from '${binding.module}'\` ${expectHook ? 'to be a hook' : 'not to be a hook'} based on the exported name`,
|
|
loc,
|
|
});
|
|
}
|
|
return importedType;
|
|
}
|
|
}
|
|
return isHookName$2(binding.imported) || isHookName$2(binding.name)
|
|
? __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_getCustomHookType).call(this)
|
|
: null;
|
|
}
|
|
}
|
|
case 'ImportDefault':
|
|
case 'ImportNamespace': {
|
|
if (__classPrivateFieldGet(this, _Environment_instances, "m", _Environment_isKnownReactModule).call(this, binding.module)) {
|
|
return ((_c = __classPrivateFieldGet(this, _Environment_globals, "f").get(binding.name)) !== null && _c !== void 0 ? _c : (isHookName$2(binding.name) ? __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_getCustomHookType).call(this) : null));
|
|
}
|
|
else {
|
|
const moduleType = __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_resolveModuleType).call(this, binding.module, loc);
|
|
if (moduleType !== null) {
|
|
let importedType = null;
|
|
if (binding.kind === 'ImportDefault') {
|
|
const defaultType = this.getPropertyType(moduleType, 'default');
|
|
if (defaultType !== null) {
|
|
importedType = defaultType;
|
|
}
|
|
}
|
|
else {
|
|
importedType = moduleType;
|
|
}
|
|
if (importedType !== null) {
|
|
const expectHook = isHookName$2(binding.module);
|
|
const isHook = getHookKindForType(this, importedType) != null;
|
|
if (expectHook !== isHook) {
|
|
CompilerError.throwInvalidConfig({
|
|
reason: `Invalid type configuration for module`,
|
|
description: `Expected type for \`import ... from '${binding.module}'\` ${expectHook ? 'to be a hook' : 'not to be a hook'} based on the module name`,
|
|
loc,
|
|
});
|
|
}
|
|
return importedType;
|
|
}
|
|
}
|
|
return isHookName$2(binding.name) ? __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_getCustomHookType).call(this) : null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
getFallthroughPropertyType(receiver, _property) {
|
|
var _a;
|
|
let shapeId = null;
|
|
if (receiver.kind === 'Object' || receiver.kind === 'Function') {
|
|
shapeId = receiver.shapeId;
|
|
}
|
|
if (shapeId !== null) {
|
|
const shape = __classPrivateFieldGet(this, _Environment_shapes, "f").get(shapeId);
|
|
CompilerError.invariant(shape !== undefined, {
|
|
reason: `[HIR] Forget internal error: cannot resolve shape ${shapeId}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
return (_a = shape.properties.get('*')) !== null && _a !== void 0 ? _a : null;
|
|
}
|
|
return null;
|
|
}
|
|
getPropertyType(receiver, property) {
|
|
var _a, _b, _c;
|
|
let shapeId = null;
|
|
if (receiver.kind === 'Object' || receiver.kind === 'Function') {
|
|
shapeId = receiver.shapeId;
|
|
}
|
|
if (shapeId !== null) {
|
|
const shape = __classPrivateFieldGet(this, _Environment_shapes, "f").get(shapeId);
|
|
CompilerError.invariant(shape !== undefined, {
|
|
reason: `[HIR] Forget internal error: cannot resolve shape ${shapeId}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
if (typeof property === 'string') {
|
|
return ((_b = (_a = shape.properties.get(property)) !== null && _a !== void 0 ? _a : shape.properties.get('*')) !== null && _b !== void 0 ? _b : (isHookName$2(property) ? __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_getCustomHookType).call(this) : null));
|
|
}
|
|
else {
|
|
return (_c = shape.properties.get('*')) !== null && _c !== void 0 ? _c : null;
|
|
}
|
|
}
|
|
else if (typeof property === 'string' && isHookName$2(property)) {
|
|
return __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_getCustomHookType).call(this);
|
|
}
|
|
return null;
|
|
}
|
|
getFunctionSignature(type) {
|
|
const { shapeId } = type;
|
|
if (shapeId !== null) {
|
|
const shape = __classPrivateFieldGet(this, _Environment_shapes, "f").get(shapeId);
|
|
CompilerError.invariant(shape !== undefined, {
|
|
reason: `[HIR] Forget internal error: cannot resolve shape ${shapeId}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
return shape.functionType;
|
|
}
|
|
return null;
|
|
}
|
|
addHoistedIdentifier(node) {
|
|
__classPrivateFieldGet(this, _Environment_contextIdentifiers, "f").add(node);
|
|
__classPrivateFieldGet(this, _Environment_hoistedIdentifiers, "f").add(node);
|
|
}
|
|
}
|
|
_Environment_globals = new WeakMap(), _Environment_shapes = new WeakMap(), _Environment_moduleTypes = new WeakMap(), _Environment_nextIdentifer = new WeakMap(), _Environment_nextBlock = new WeakMap(), _Environment_nextScope = new WeakMap(), _Environment_scope = new WeakMap(), _Environment_outlinedFunctions = new WeakMap(), _Environment_contextIdentifiers = new WeakMap(), _Environment_hoistedIdentifiers = new WeakMap(), _Environment_flowTypeEnvironment = new WeakMap(), _Environment_errors = new WeakMap(), _Environment_instances = new WeakSet(), _Environment_resolveModuleType = function _Environment_resolveModuleType(moduleName, loc) {
|
|
var _a;
|
|
let moduleType = __classPrivateFieldGet(this, _Environment_moduleTypes, "f").get(moduleName);
|
|
if (moduleType === undefined) {
|
|
const moduleTypeProvider = (_a = this.config.moduleTypeProvider) !== null && _a !== void 0 ? _a : defaultModuleTypeProvider;
|
|
if (moduleTypeProvider == null) {
|
|
return null;
|
|
}
|
|
if (typeof moduleTypeProvider !== 'function') {
|
|
CompilerError.throwInvalidConfig({
|
|
reason: `Expected a function for \`moduleTypeProvider\``,
|
|
loc,
|
|
});
|
|
}
|
|
const unparsedModuleConfig = moduleTypeProvider(moduleName);
|
|
if (unparsedModuleConfig != null) {
|
|
const parsedModuleConfig = TypeSchema.safeParse(unparsedModuleConfig);
|
|
if (!parsedModuleConfig.success) {
|
|
CompilerError.throwInvalidConfig({
|
|
reason: `Could not parse module type, the configured \`moduleTypeProvider\` function returned an invalid module description`,
|
|
description: parsedModuleConfig.error.toString(),
|
|
loc,
|
|
});
|
|
}
|
|
const moduleConfig = parsedModuleConfig.data;
|
|
moduleType = installTypeConfig(__classPrivateFieldGet(this, _Environment_globals, "f"), __classPrivateFieldGet(this, _Environment_shapes, "f"), moduleConfig, moduleName, loc);
|
|
}
|
|
else {
|
|
moduleType = null;
|
|
}
|
|
__classPrivateFieldGet(this, _Environment_moduleTypes, "f").set(moduleName, moduleType);
|
|
}
|
|
return moduleType;
|
|
}, _Environment_isKnownReactModule = function _Environment_isKnownReactModule(moduleName) {
|
|
return (moduleName.toLowerCase() === 'react' ||
|
|
moduleName.toLowerCase() === 'react-dom');
|
|
}, _Environment_getCustomHookType = function _Environment_getCustomHookType() {
|
|
if (this.config.enableAssumeHooksFollowRulesOfReact) {
|
|
return DefaultNonmutatingHook;
|
|
}
|
|
else {
|
|
return DefaultMutatingHook;
|
|
}
|
|
};
|
|
Environment.knownReactModules = ['react', 'react-dom'];
|
|
const REANIMATED_MODULE_NAME = 'react-native-reanimated';
|
|
function isHookName$2(name) {
|
|
return /^use[A-Z0-9]/.test(name);
|
|
}
|
|
function parseEnvironmentConfig(partialConfig) {
|
|
const config = EnvironmentConfigSchema.safeParse(partialConfig);
|
|
if (config.success) {
|
|
return Ok(config.data);
|
|
}
|
|
else {
|
|
return Err(config.error);
|
|
}
|
|
}
|
|
function validateEnvironmentConfig(partialConfig) {
|
|
const config = EnvironmentConfigSchema.safeParse(partialConfig);
|
|
if (config.success) {
|
|
return config.data;
|
|
}
|
|
CompilerError.throwInvalidConfig({
|
|
reason: 'Could not validate environment config. Update React Compiler config to fix the error',
|
|
description: `${v4$1.fromZodError(config.error)}`,
|
|
loc: null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
function tryParseExternalFunction(maybeExternalFunction) {
|
|
const externalFunction = ExternalFunctionSchema.safeParse(maybeExternalFunction);
|
|
if (externalFunction.success) {
|
|
return externalFunction.data;
|
|
}
|
|
CompilerError.throwInvalidConfig({
|
|
reason: 'Could not parse external function. Update React Compiler config to fix the error',
|
|
description: `${v4$1.fromZodError(externalFunction.error)}`,
|
|
loc: null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
|
|
var _MergedBlocks_map;
|
|
function mergeConsecutiveBlocks(fn) {
|
|
const merged = new MergedBlocks();
|
|
const fallthroughBlocks = new Set();
|
|
for (const [, block] of fn.body.blocks) {
|
|
const fallthrough = terminalFallthrough(block.terminal);
|
|
if (fallthrough !== null) {
|
|
fallthroughBlocks.add(fallthrough);
|
|
}
|
|
for (const instr of block.instructions) {
|
|
if (instr.value.kind === 'FunctionExpression' ||
|
|
instr.value.kind === 'ObjectMethod') {
|
|
mergeConsecutiveBlocks(instr.value.loweredFunc.func);
|
|
}
|
|
}
|
|
if (block.preds.size !== 1 ||
|
|
block.kind !== 'block' ||
|
|
fallthroughBlocks.has(block.id)) {
|
|
continue;
|
|
}
|
|
const originalPredecessorId = Array.from(block.preds)[0];
|
|
const predecessorId = merged.get(originalPredecessorId);
|
|
const predecessor = fn.body.blocks.get(predecessorId);
|
|
CompilerError.invariant(predecessor !== undefined, {
|
|
reason: `Expected predecessor ${predecessorId} to exist`,
|
|
loc: GeneratedSource,
|
|
});
|
|
if (predecessor.terminal.kind !== 'goto' || predecessor.kind !== 'block') {
|
|
continue;
|
|
}
|
|
for (const phi of block.phis) {
|
|
CompilerError.invariant(phi.operands.size === 1, {
|
|
reason: `Found a block with a single predecessor but where a phi has multiple (${phi.operands.size}) operands`,
|
|
loc: GeneratedSource,
|
|
});
|
|
const operand = Array.from(phi.operands.values())[0];
|
|
const lvalue = {
|
|
kind: 'Identifier',
|
|
identifier: phi.place.identifier,
|
|
effect: Effect.ConditionallyMutate,
|
|
reactive: false,
|
|
loc: GeneratedSource,
|
|
};
|
|
const instr = {
|
|
id: predecessor.terminal.id,
|
|
lvalue: Object.assign({}, lvalue),
|
|
value: {
|
|
kind: 'LoadLocal',
|
|
place: Object.assign({}, operand),
|
|
loc: GeneratedSource,
|
|
},
|
|
effects: [{ kind: 'Alias', from: Object.assign({}, operand), into: Object.assign({}, lvalue) }],
|
|
loc: GeneratedSource,
|
|
};
|
|
predecessor.instructions.push(instr);
|
|
}
|
|
predecessor.instructions.push(...block.instructions);
|
|
predecessor.terminal = block.terminal;
|
|
merged.merge(block.id, predecessorId);
|
|
fn.body.blocks.delete(block.id);
|
|
}
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
for (const [predecessorId, operand] of phi.operands) {
|
|
const mapped = merged.get(predecessorId);
|
|
if (mapped !== predecessorId) {
|
|
phi.operands.delete(predecessorId);
|
|
phi.operands.set(mapped, operand);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
markPredecessors(fn.body);
|
|
for (const [, { terminal }] of fn.body.blocks) {
|
|
if (terminalHasFallthrough(terminal)) {
|
|
terminal.fallthrough = merged.get(terminal.fallthrough);
|
|
}
|
|
}
|
|
}
|
|
class MergedBlocks {
|
|
constructor() {
|
|
_MergedBlocks_map.set(this, new Map());
|
|
}
|
|
merge(block, into) {
|
|
const target = this.get(into);
|
|
__classPrivateFieldGet(this, _MergedBlocks_map, "f").set(block, target);
|
|
}
|
|
get(block) {
|
|
var _a;
|
|
let current = block;
|
|
while (__classPrivateFieldGet(this, _MergedBlocks_map, "f").has(current)) {
|
|
current = (_a = __classPrivateFieldGet(this, _MergedBlocks_map, "f").get(current)) !== null && _a !== void 0 ? _a : current;
|
|
}
|
|
return current;
|
|
}
|
|
}
|
|
_MergedBlocks_map = new WeakMap();
|
|
|
|
var _DisjointSet_entries;
|
|
class DisjointSet {
|
|
constructor() {
|
|
_DisjointSet_entries.set(this, new Map());
|
|
}
|
|
union(items) {
|
|
const first = items.shift();
|
|
CompilerError.invariant(first != null, {
|
|
reason: 'Expected set to be non-empty',
|
|
loc: GeneratedSource,
|
|
});
|
|
let root = this.find(first);
|
|
if (root == null) {
|
|
root = first;
|
|
__classPrivateFieldGet(this, _DisjointSet_entries, "f").set(first, first);
|
|
}
|
|
for (const item of items) {
|
|
let itemParent = __classPrivateFieldGet(this, _DisjointSet_entries, "f").get(item);
|
|
if (itemParent == null) {
|
|
__classPrivateFieldGet(this, _DisjointSet_entries, "f").set(item, root);
|
|
continue;
|
|
}
|
|
else if (itemParent === root) {
|
|
continue;
|
|
}
|
|
else {
|
|
let current = item;
|
|
while (itemParent !== root) {
|
|
__classPrivateFieldGet(this, _DisjointSet_entries, "f").set(current, root);
|
|
current = itemParent;
|
|
itemParent = __classPrivateFieldGet(this, _DisjointSet_entries, "f").get(current);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
find(item) {
|
|
if (!__classPrivateFieldGet(this, _DisjointSet_entries, "f").has(item)) {
|
|
return null;
|
|
}
|
|
const parent = __classPrivateFieldGet(this, _DisjointSet_entries, "f").get(item);
|
|
if (parent === item) {
|
|
return item;
|
|
}
|
|
const root = this.find(parent);
|
|
__classPrivateFieldGet(this, _DisjointSet_entries, "f").set(item, root);
|
|
return root;
|
|
}
|
|
has(item) {
|
|
return __classPrivateFieldGet(this, _DisjointSet_entries, "f").has(item);
|
|
}
|
|
canonicalize() {
|
|
const entries = new Map();
|
|
for (const item of __classPrivateFieldGet(this, _DisjointSet_entries, "f").keys()) {
|
|
const root = this.find(item);
|
|
entries.set(item, root);
|
|
}
|
|
return entries;
|
|
}
|
|
forEach(fn) {
|
|
for (const item of __classPrivateFieldGet(this, _DisjointSet_entries, "f").keys()) {
|
|
const group = this.find(item);
|
|
fn(item, group);
|
|
}
|
|
}
|
|
buildSets() {
|
|
const ids = new Map();
|
|
const sets = new Map();
|
|
this.forEach((identifier, groupIdentifier) => {
|
|
let id = ids.get(groupIdentifier);
|
|
if (id == null) {
|
|
id = ids.size;
|
|
ids.set(groupIdentifier, id);
|
|
}
|
|
let set = sets.get(id);
|
|
if (set === undefined) {
|
|
set = new Set();
|
|
sets.set(id, set);
|
|
}
|
|
set.add(identifier);
|
|
});
|
|
return [...sets.values()];
|
|
}
|
|
get size() {
|
|
return __classPrivateFieldGet(this, _DisjointSet_entries, "f").size;
|
|
}
|
|
}
|
|
_DisjointSet_entries = new WeakMap();
|
|
|
|
function inferReactiveScopeVariables(fn) {
|
|
var _a, _b;
|
|
const scopeIdentifiers = findDisjointMutableValues(fn);
|
|
const scopes = new Map();
|
|
scopeIdentifiers.forEach((identifier, groupIdentifier) => {
|
|
let scope = scopes.get(groupIdentifier);
|
|
if (scope === undefined) {
|
|
scope = {
|
|
id: fn.env.nextScopeId,
|
|
range: identifier.mutableRange,
|
|
dependencies: new Set(),
|
|
declarations: new Map(),
|
|
reassignments: new Set(),
|
|
earlyReturnValue: null,
|
|
merged: new Set(),
|
|
loc: identifier.loc,
|
|
};
|
|
scopes.set(groupIdentifier, scope);
|
|
}
|
|
else {
|
|
if (scope.range.start === 0) {
|
|
scope.range.start = identifier.mutableRange.start;
|
|
}
|
|
else if (identifier.mutableRange.start !== 0) {
|
|
scope.range.start = makeInstructionId(Math.min(scope.range.start, identifier.mutableRange.start));
|
|
}
|
|
scope.range.end = makeInstructionId(Math.max(scope.range.end, identifier.mutableRange.end));
|
|
scope.loc = mergeLocation(scope.loc, identifier.loc);
|
|
}
|
|
identifier.scope = scope;
|
|
identifier.mutableRange = scope.range;
|
|
});
|
|
let maxInstruction = 0;
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
maxInstruction = makeInstructionId(Math.max(maxInstruction, instr.id));
|
|
}
|
|
maxInstruction = makeInstructionId(Math.max(maxInstruction, block.terminal.id));
|
|
}
|
|
for (const [, scope] of scopes) {
|
|
if (scope.range.start === 0 ||
|
|
scope.range.end === 0 ||
|
|
maxInstruction === 0 ||
|
|
scope.range.end > maxInstruction + 1) {
|
|
(_b = (_a = fn.env.logger) === null || _a === void 0 ? void 0 : _a.debugLogIRs) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
|
kind: 'hir',
|
|
name: 'InferReactiveScopeVariables (invalid scope)',
|
|
value: fn,
|
|
});
|
|
CompilerError.invariant(false, {
|
|
reason: `Invalid mutable range for scope`,
|
|
description: `Scope @${scope.id} has range [${scope.range.start}:${scope.range.end}] but the valid range is [1:${maxInstruction + 1}]`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
function mergeLocation(l, r) {
|
|
if (l === GeneratedSource) {
|
|
return r;
|
|
}
|
|
else if (r === GeneratedSource) {
|
|
return l;
|
|
}
|
|
else {
|
|
return {
|
|
filename: l.filename,
|
|
identifierName: l.identifierName,
|
|
start: {
|
|
index: Math.min(l.start.index, r.start.index),
|
|
line: Math.min(l.start.line, r.start.line),
|
|
column: Math.min(l.start.column, r.start.column),
|
|
},
|
|
end: {
|
|
index: Math.max(l.end.index, r.end.index),
|
|
line: Math.max(l.end.line, r.end.line),
|
|
column: Math.max(l.end.column, r.end.column),
|
|
},
|
|
};
|
|
}
|
|
}
|
|
function isMutable(instr, place) {
|
|
return inRange(instr, place.identifier.mutableRange);
|
|
}
|
|
function inRange({ id }, range) {
|
|
return id >= range.start && id < range.end;
|
|
}
|
|
function mayAllocate(_env, instruction) {
|
|
const { value } = instruction;
|
|
switch (value.kind) {
|
|
case 'Destructure': {
|
|
return doesPatternContainSpreadElement(value.lvalue.pattern);
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate':
|
|
case 'Await':
|
|
case 'DeclareLocal':
|
|
case 'DeclareContext':
|
|
case 'StoreLocal':
|
|
case 'LoadGlobal':
|
|
case 'MetaProperty':
|
|
case 'TypeCastExpression':
|
|
case 'LoadLocal':
|
|
case 'LoadContext':
|
|
case 'StoreContext':
|
|
case 'PropertyDelete':
|
|
case 'ComputedLoad':
|
|
case 'ComputedDelete':
|
|
case 'JSXText':
|
|
case 'TemplateLiteral':
|
|
case 'Primitive':
|
|
case 'GetIterator':
|
|
case 'IteratorNext':
|
|
case 'NextPropertyOf':
|
|
case 'Debugger':
|
|
case 'StartMemoize':
|
|
case 'FinishMemoize':
|
|
case 'UnaryExpression':
|
|
case 'BinaryExpression':
|
|
case 'PropertyLoad':
|
|
case 'StoreGlobal': {
|
|
return false;
|
|
}
|
|
case 'TaggedTemplateExpression':
|
|
case 'CallExpression':
|
|
case 'MethodCall': {
|
|
return instruction.lvalue.identifier.type.kind !== 'Primitive';
|
|
}
|
|
case 'RegExpLiteral':
|
|
case 'PropertyStore':
|
|
case 'ComputedStore':
|
|
case 'ArrayExpression':
|
|
case 'JsxExpression':
|
|
case 'JsxFragment':
|
|
case 'NewExpression':
|
|
case 'ObjectExpression':
|
|
case 'UnsupportedNode':
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
return true;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(value, `Unexpected value kind \`${value.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function findDisjointMutableValues(fn) {
|
|
var _a, _b;
|
|
const scopeIdentifiers = new DisjointSet();
|
|
const declarations = new Map();
|
|
function declareIdentifier(lvalue) {
|
|
if (!declarations.has(lvalue.identifier.declarationId)) {
|
|
declarations.set(lvalue.identifier.declarationId, lvalue.identifier);
|
|
}
|
|
}
|
|
for (const [_, block] of fn.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
if (phi.place.identifier.mutableRange.start + 1 !==
|
|
phi.place.identifier.mutableRange.end &&
|
|
phi.place.identifier.mutableRange.end >
|
|
((_b = (_a = block.instructions.at(0)) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : block.terminal.id)) {
|
|
const operands = [phi.place.identifier];
|
|
const declaration = declarations.get(phi.place.identifier.declarationId);
|
|
if (declaration !== undefined) {
|
|
operands.push(declaration);
|
|
}
|
|
for (const [_, phiId] of phi.operands) {
|
|
operands.push(phiId.identifier);
|
|
}
|
|
scopeIdentifiers.union(operands);
|
|
}
|
|
else if (fn.env.config.enableForest) {
|
|
for (const [, phiId] of phi.operands) {
|
|
scopeIdentifiers.union([phi.place.identifier, phiId.identifier]);
|
|
}
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
const operands = [];
|
|
const range = instr.lvalue.identifier.mutableRange;
|
|
if (range.end > range.start + 1 || mayAllocate(fn.env, instr)) {
|
|
operands.push(instr.lvalue.identifier);
|
|
}
|
|
if (instr.value.kind === 'DeclareLocal' ||
|
|
instr.value.kind === 'DeclareContext') {
|
|
declareIdentifier(instr.value.lvalue.place);
|
|
}
|
|
else if (instr.value.kind === 'StoreLocal' ||
|
|
instr.value.kind === 'StoreContext') {
|
|
declareIdentifier(instr.value.lvalue.place);
|
|
if (instr.value.lvalue.place.identifier.mutableRange.end >
|
|
instr.value.lvalue.place.identifier.mutableRange.start + 1) {
|
|
operands.push(instr.value.lvalue.place.identifier);
|
|
}
|
|
if (isMutable(instr, instr.value.value) &&
|
|
instr.value.value.identifier.mutableRange.start > 0) {
|
|
operands.push(instr.value.value.identifier);
|
|
}
|
|
}
|
|
else if (instr.value.kind === 'Destructure') {
|
|
for (const place of eachPatternOperand(instr.value.lvalue.pattern)) {
|
|
declareIdentifier(place);
|
|
if (place.identifier.mutableRange.end >
|
|
place.identifier.mutableRange.start + 1) {
|
|
operands.push(place.identifier);
|
|
}
|
|
}
|
|
if (isMutable(instr, instr.value.value) &&
|
|
instr.value.value.identifier.mutableRange.start > 0) {
|
|
operands.push(instr.value.value.identifier);
|
|
}
|
|
}
|
|
else if (instr.value.kind === 'MethodCall') {
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
if (isMutable(instr, operand) &&
|
|
operand.identifier.mutableRange.start > 0) {
|
|
operands.push(operand.identifier);
|
|
}
|
|
}
|
|
operands.push(instr.value.property.identifier);
|
|
}
|
|
else {
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
if (isMutable(instr, operand) &&
|
|
operand.identifier.mutableRange.start > 0) {
|
|
operands.push(operand.identifier);
|
|
}
|
|
}
|
|
}
|
|
if (operands.length !== 0) {
|
|
scopeIdentifiers.union(operands);
|
|
}
|
|
}
|
|
}
|
|
return scopeIdentifiers;
|
|
}
|
|
|
|
function mergeOverlappingReactiveScopesHIR(fn) {
|
|
const scopesInfo = collectScopeInfo(fn);
|
|
const joinedScopes = getOverlappingReactiveScopes(fn, scopesInfo);
|
|
joinedScopes.forEach((scope, groupScope) => {
|
|
if (scope !== groupScope) {
|
|
groupScope.range.start = makeInstructionId(Math.min(groupScope.range.start, scope.range.start));
|
|
groupScope.range.end = makeInstructionId(Math.max(groupScope.range.end, scope.range.end));
|
|
}
|
|
});
|
|
for (const [place, originalScope] of scopesInfo.placeScopes) {
|
|
const nextScope = joinedScopes.find(originalScope);
|
|
if (nextScope !== null && nextScope !== originalScope) {
|
|
place.identifier.scope = nextScope;
|
|
}
|
|
}
|
|
}
|
|
function collectScopeInfo(fn) {
|
|
const scopeStarts = new Map();
|
|
const scopeEnds = new Map();
|
|
const placeScopes = new Map();
|
|
function collectPlaceScope(place) {
|
|
const scope = place.identifier.scope;
|
|
if (scope != null) {
|
|
placeScopes.set(place, scope);
|
|
if (scope.range.start !== scope.range.end) {
|
|
getOrInsertDefault(scopeStarts, scope.range.start, new Set()).add(scope);
|
|
getOrInsertDefault(scopeEnds, scope.range.end, new Set()).add(scope);
|
|
}
|
|
}
|
|
}
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
for (const operand of eachInstructionLValue(instr)) {
|
|
collectPlaceScope(operand);
|
|
}
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
collectPlaceScope(operand);
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
collectPlaceScope(operand);
|
|
}
|
|
}
|
|
return {
|
|
scopeStarts: [...scopeStarts.entries()]
|
|
.map(([id, scopes]) => ({ id, scopes }))
|
|
.sort((a, b) => b.id - a.id),
|
|
scopeEnds: [...scopeEnds.entries()]
|
|
.map(([id, scopes]) => ({ id, scopes }))
|
|
.sort((a, b) => b.id - a.id),
|
|
placeScopes,
|
|
};
|
|
}
|
|
function visitInstructionId(id, { scopeEnds, scopeStarts }, { activeScopes, joined }) {
|
|
const scopeEndTop = scopeEnds.at(-1);
|
|
if (scopeEndTop != null && scopeEndTop.id <= id) {
|
|
scopeEnds.pop();
|
|
const scopesSortedStartDescending = [...scopeEndTop.scopes].sort((a, b) => b.range.start - a.range.start);
|
|
for (const scope of scopesSortedStartDescending) {
|
|
const idx = activeScopes.indexOf(scope);
|
|
if (idx !== -1) {
|
|
if (idx !== activeScopes.length - 1) {
|
|
joined.union([scope, ...activeScopes.slice(idx + 1)]);
|
|
}
|
|
activeScopes.splice(idx, 1);
|
|
}
|
|
}
|
|
}
|
|
const scopeStartTop = scopeStarts.at(-1);
|
|
if (scopeStartTop != null && scopeStartTop.id <= id) {
|
|
scopeStarts.pop();
|
|
const scopesSortedEndDescending = [...scopeStartTop.scopes].sort((a, b) => b.range.end - a.range.end);
|
|
activeScopes.push(...scopesSortedEndDescending);
|
|
for (let i = 1; i < scopesSortedEndDescending.length; i++) {
|
|
const prev = scopesSortedEndDescending[i - 1];
|
|
const curr = scopesSortedEndDescending[i];
|
|
if (prev.range.end === curr.range.end) {
|
|
joined.union([prev, curr]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function visitPlace(id, place, { activeScopes, joined }) {
|
|
const placeScope = getPlaceScope(id, place);
|
|
if (placeScope != null && isMutable({ id }, place)) {
|
|
const placeScopeIdx = activeScopes.indexOf(placeScope);
|
|
if (placeScopeIdx !== -1 && placeScopeIdx !== activeScopes.length - 1) {
|
|
joined.union([placeScope, ...activeScopes.slice(placeScopeIdx + 1)]);
|
|
}
|
|
}
|
|
}
|
|
function getOverlappingReactiveScopes(fn, context) {
|
|
const state = {
|
|
joined: new DisjointSet(),
|
|
activeScopes: [],
|
|
};
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
visitInstructionId(instr.id, context, state);
|
|
for (const place of eachInstructionOperand(instr)) {
|
|
if ((instr.value.kind === 'FunctionExpression' ||
|
|
instr.value.kind === 'ObjectMethod') &&
|
|
place.identifier.type.kind === 'Primitive') {
|
|
continue;
|
|
}
|
|
visitPlace(instr.id, place, state);
|
|
}
|
|
for (const place of eachInstructionLValue(instr)) {
|
|
visitPlace(instr.id, place, state);
|
|
}
|
|
}
|
|
visitInstructionId(block.terminal.id, context, state);
|
|
for (const place of eachTerminalOperand(block.terminal)) {
|
|
visitPlace(block.terminal.id, place, state);
|
|
}
|
|
}
|
|
return state.joined;
|
|
}
|
|
|
|
function pruneUnusedLabelsHIR(fn) {
|
|
var _a;
|
|
const merged = [];
|
|
const rewrites = new Map();
|
|
for (const [blockId, block] of fn.body.blocks) {
|
|
const terminal = block.terminal;
|
|
if (terminal.kind === 'label') {
|
|
const { block: nextId, fallthrough: fallthroughId } = terminal;
|
|
const next = fn.body.blocks.get(nextId);
|
|
const fallthrough = fn.body.blocks.get(fallthroughId);
|
|
if (next.terminal.kind === 'goto' &&
|
|
next.terminal.variant === GotoVariant.Break &&
|
|
next.terminal.block === fallthroughId) {
|
|
if (next.kind === 'block' && fallthrough.kind === 'block') {
|
|
merged.push({
|
|
label: blockId,
|
|
next: nextId,
|
|
fallthrough: fallthroughId,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const { label: originalLabelId, next: nextId, fallthrough: fallthroughId, } of merged) {
|
|
const labelId = (_a = rewrites.get(originalLabelId)) !== null && _a !== void 0 ? _a : originalLabelId;
|
|
const label = fn.body.blocks.get(labelId);
|
|
const next = fn.body.blocks.get(nextId);
|
|
const fallthrough = fn.body.blocks.get(fallthroughId);
|
|
CompilerError.invariant(next.phis.size === 0 && fallthrough.phis.size === 0, {
|
|
reason: 'Unexpected phis when merging label blocks',
|
|
loc: label.terminal.loc,
|
|
});
|
|
CompilerError.invariant(next.preds.size === 1 &&
|
|
fallthrough.preds.size === 1 &&
|
|
next.preds.has(originalLabelId) &&
|
|
fallthrough.preds.has(nextId), {
|
|
reason: 'Unexpected block predecessors when merging label blocks',
|
|
loc: label.terminal.loc,
|
|
});
|
|
label.instructions.push(...next.instructions, ...fallthrough.instructions);
|
|
label.terminal = fallthrough.terminal;
|
|
fn.body.blocks.delete(nextId);
|
|
fn.body.blocks.delete(fallthroughId);
|
|
rewrites.set(fallthroughId, labelId);
|
|
}
|
|
for (const [_, block] of fn.body.blocks) {
|
|
for (const pred of block.preds) {
|
|
const rewritten = rewrites.get(pred);
|
|
if (rewritten != null) {
|
|
block.preds.delete(pred);
|
|
block.preds.add(rewritten);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function insertAdditionalFunctionDeclaration(fnPath, compiled, programContext, gatingFunctionIdentifierName) {
|
|
var _a, _b;
|
|
const originalFnName = fnPath.node.id;
|
|
const originalFnParams = fnPath.node.params;
|
|
const compiledParams = fnPath.node.params;
|
|
CompilerError.invariant(originalFnName != null && compiled.id != null, {
|
|
reason: 'Expected function declarations that are referenced elsewhere to have a named identifier',
|
|
loc: (_a = fnPath.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
});
|
|
CompilerError.invariant(originalFnParams.length === compiledParams.length, {
|
|
reason: 'Expected React Compiler optimized function declarations to have the same number of parameters as source',
|
|
loc: (_b = fnPath.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
});
|
|
const gatingCondition = libExports$1.identifier(programContext.newUid(`${gatingFunctionIdentifierName}_result`));
|
|
const unoptimizedFnName = libExports$1.identifier(programContext.newUid(`${originalFnName.name}_unoptimized`));
|
|
const optimizedFnName = libExports$1.identifier(programContext.newUid(`${originalFnName.name}_optimized`));
|
|
compiled.id.name = optimizedFnName.name;
|
|
fnPath.get('id').replaceInline(unoptimizedFnName);
|
|
const newParams = [];
|
|
const genNewArgs = [];
|
|
for (let i = 0; i < originalFnParams.length; i++) {
|
|
const argName = `arg${i}`;
|
|
if (originalFnParams[i].type === 'RestElement') {
|
|
newParams.push(libExports$1.restElement(libExports$1.identifier(argName)));
|
|
genNewArgs.push(() => libExports$1.spreadElement(libExports$1.identifier(argName)));
|
|
}
|
|
else {
|
|
newParams.push(libExports$1.identifier(argName));
|
|
genNewArgs.push(() => libExports$1.identifier(argName));
|
|
}
|
|
}
|
|
fnPath.insertAfter(libExports$1.functionDeclaration(originalFnName, newParams, libExports$1.blockStatement([
|
|
libExports$1.ifStatement(gatingCondition, libExports$1.returnStatement(libExports$1.callExpression(compiled.id, genNewArgs.map(fn => fn()))), libExports$1.returnStatement(libExports$1.callExpression(unoptimizedFnName, genNewArgs.map(fn => fn())))),
|
|
])));
|
|
fnPath.insertBefore(libExports$1.variableDeclaration('const', [
|
|
libExports$1.variableDeclarator(gatingCondition, libExports$1.callExpression(libExports$1.identifier(gatingFunctionIdentifierName), [])),
|
|
]));
|
|
fnPath.insertBefore(compiled);
|
|
}
|
|
function insertGatedFunctionDeclaration(fnPath, compiled, programContext, gating, referencedBeforeDeclaration) {
|
|
var _a;
|
|
const gatingImportedName = programContext.addImportSpecifier(gating).name;
|
|
if (referencedBeforeDeclaration && fnPath.isFunctionDeclaration()) {
|
|
CompilerError.invariant(compiled.type === 'FunctionDeclaration', {
|
|
reason: 'Expected compiled node type to match input type',
|
|
description: `Got ${compiled.type} but expected FunctionDeclaration`,
|
|
loc: (_a = fnPath.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
});
|
|
insertAdditionalFunctionDeclaration(fnPath, compiled, programContext, gatingImportedName);
|
|
}
|
|
else {
|
|
const gatingExpression = libExports$1.conditionalExpression(libExports$1.callExpression(libExports$1.identifier(gatingImportedName), []), buildFunctionExpression(compiled), buildFunctionExpression(fnPath.node));
|
|
if (fnPath.parentPath.node.type !== 'ExportDefaultDeclaration' &&
|
|
fnPath.node.type === 'FunctionDeclaration' &&
|
|
fnPath.node.id != null) {
|
|
fnPath.replaceWith(libExports$1.variableDeclaration('const', [
|
|
libExports$1.variableDeclarator(fnPath.node.id, gatingExpression),
|
|
]));
|
|
}
|
|
else if (fnPath.parentPath.node.type === 'ExportDefaultDeclaration' &&
|
|
fnPath.node.type !== 'ArrowFunctionExpression' &&
|
|
fnPath.node.id != null) {
|
|
fnPath.insertAfter(libExports$1.exportDefaultDeclaration(libExports$1.identifier(fnPath.node.id.name)));
|
|
fnPath.parentPath.replaceWith(libExports$1.variableDeclaration('const', [
|
|
libExports$1.variableDeclarator(libExports$1.identifier(fnPath.node.id.name), gatingExpression),
|
|
]));
|
|
}
|
|
else {
|
|
fnPath.replaceWith(gatingExpression);
|
|
}
|
|
}
|
|
}
|
|
function buildFunctionExpression(node) {
|
|
var _a, _b;
|
|
if (node.type === 'ArrowFunctionExpression' ||
|
|
node.type === 'FunctionExpression') {
|
|
return node;
|
|
}
|
|
else {
|
|
const fn = {
|
|
type: 'FunctionExpression',
|
|
async: node.async,
|
|
generator: node.generator,
|
|
loc: (_a = node.loc) !== null && _a !== void 0 ? _a : null,
|
|
id: (_b = node.id) !== null && _b !== void 0 ? _b : null,
|
|
params: node.params,
|
|
body: node.body,
|
|
};
|
|
return fn;
|
|
}
|
|
}
|
|
|
|
function isComponentDeclaration(node) {
|
|
return Object.prototype.hasOwnProperty.call(node, '__componentDeclaration');
|
|
}
|
|
|
|
function isHookDeclaration(node) {
|
|
return Object.prototype.hasOwnProperty.call(node, '__hookDeclaration');
|
|
}
|
|
|
|
const DEFAULT_IDENTIFIER_INFO = {
|
|
reassigned: false,
|
|
reassignedByInnerFn: false,
|
|
referencedByInnerFn: false,
|
|
};
|
|
const withFunctionScope = {
|
|
enter: function (path, state) {
|
|
state.currentFn.push(path);
|
|
},
|
|
exit: function (_, state) {
|
|
state.currentFn.pop();
|
|
},
|
|
};
|
|
function findContextIdentifiers(func) {
|
|
const state = {
|
|
currentFn: [],
|
|
identifiers: new Map(),
|
|
};
|
|
func.traverse({
|
|
FunctionDeclaration: withFunctionScope,
|
|
FunctionExpression: withFunctionScope,
|
|
ArrowFunctionExpression: withFunctionScope,
|
|
ObjectMethod: withFunctionScope,
|
|
AssignmentExpression(path, state) {
|
|
var _a, _b;
|
|
const left = path.get('left');
|
|
if (left.isLVal()) {
|
|
const currentFn = (_a = state.currentFn.at(-1)) !== null && _a !== void 0 ? _a : null;
|
|
handleAssignment(currentFn, state.identifiers, left);
|
|
}
|
|
else {
|
|
CompilerError.throwTodo({
|
|
reason: `Unsupported syntax on the left side of an AssignmentExpression`,
|
|
description: `Expected an LVal, got: ${left.type}`,
|
|
loc: (_b = left.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
});
|
|
}
|
|
},
|
|
UpdateExpression(path, state) {
|
|
var _a;
|
|
const argument = path.get('argument');
|
|
const currentFn = (_a = state.currentFn.at(-1)) !== null && _a !== void 0 ? _a : null;
|
|
if (argument.isLVal()) {
|
|
handleAssignment(currentFn, state.identifiers, argument);
|
|
}
|
|
},
|
|
Identifier(path, state) {
|
|
var _a;
|
|
const currentFn = (_a = state.currentFn.at(-1)) !== null && _a !== void 0 ? _a : null;
|
|
if (path.isReferencedIdentifier()) {
|
|
handleIdentifier(currentFn, state.identifiers, path);
|
|
}
|
|
},
|
|
}, state);
|
|
const result = new Set();
|
|
for (const [id, info] of state.identifiers.entries()) {
|
|
if (info.reassignedByInnerFn) {
|
|
result.add(id);
|
|
}
|
|
else if (info.reassigned && info.referencedByInnerFn) {
|
|
result.add(id);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function handleIdentifier(currentFn, identifiers, path) {
|
|
const name = path.node.name;
|
|
const binding = path.scope.getBinding(name);
|
|
if (binding == null) {
|
|
return;
|
|
}
|
|
const identifier = getOrInsertDefault(identifiers, binding.identifier, Object.assign({}, DEFAULT_IDENTIFIER_INFO));
|
|
if (currentFn != null) {
|
|
const bindingAboveLambdaScope = currentFn.scope.parent.getBinding(name);
|
|
if (binding === bindingAboveLambdaScope) {
|
|
identifier.referencedByInnerFn = true;
|
|
}
|
|
}
|
|
}
|
|
function handleAssignment(currentFn, identifiers, lvalPath) {
|
|
var _a, _b, _c;
|
|
const lvalNode = lvalPath.node;
|
|
switch (lvalNode.type) {
|
|
case 'Identifier': {
|
|
const path = lvalPath;
|
|
const name = path.node.name;
|
|
const binding = path.scope.getBinding(name);
|
|
if (binding == null) {
|
|
break;
|
|
}
|
|
const state = getOrInsertDefault(identifiers, binding.identifier, Object.assign({}, DEFAULT_IDENTIFIER_INFO));
|
|
state.reassigned = true;
|
|
if (currentFn != null) {
|
|
const bindingAboveLambdaScope = currentFn.scope.parent.getBinding(name);
|
|
if (binding === bindingAboveLambdaScope) {
|
|
state.reassignedByInnerFn = true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'ArrayPattern': {
|
|
const path = lvalPath;
|
|
for (const element of path.get('elements')) {
|
|
if (nonNull(element)) {
|
|
handleAssignment(currentFn, identifiers, element);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectPattern': {
|
|
const path = lvalPath;
|
|
for (const property of path.get('properties')) {
|
|
if (property.isObjectProperty()) {
|
|
const valuePath = property.get('value');
|
|
CompilerError.invariant(valuePath.isLVal(), {
|
|
reason: `[FindContextIdentifiers] Expected object property value to be an LVal, got: ${valuePath.type}`,
|
|
loc: (_a = valuePath.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
});
|
|
handleAssignment(currentFn, identifiers, valuePath);
|
|
}
|
|
else {
|
|
CompilerError.invariant(property.isRestElement(), {
|
|
reason: `[FindContextIdentifiers] Invalid assumptions for babel types.`,
|
|
loc: (_b = property.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
});
|
|
handleAssignment(currentFn, identifiers, property);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'AssignmentPattern': {
|
|
const path = lvalPath;
|
|
const left = path.get('left');
|
|
handleAssignment(currentFn, identifiers, left);
|
|
break;
|
|
}
|
|
case 'RestElement': {
|
|
const path = lvalPath;
|
|
handleAssignment(currentFn, identifiers, path.get('argument'));
|
|
break;
|
|
}
|
|
case 'MemberExpression': {
|
|
break;
|
|
}
|
|
default: {
|
|
CompilerError.throwTodo({
|
|
reason: `[FindContextIdentifiers] Cannot handle Object destructuring assignment target ${lvalNode.type}`,
|
|
description: null,
|
|
loc: (_c = lvalNode.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
function nonNull(t) {
|
|
return t.node != null;
|
|
}
|
|
|
|
function eliminateRedundantPhi(fn, sharedRewrites) {
|
|
const ir = fn.body;
|
|
const rewrites = sharedRewrites != null ? sharedRewrites : new Map();
|
|
let hasBackEdge = false;
|
|
const visited = new Set();
|
|
let size = rewrites.size;
|
|
do {
|
|
size = rewrites.size;
|
|
for (const [blockId, block] of ir.blocks) {
|
|
if (!hasBackEdge) {
|
|
for (const predId of block.preds) {
|
|
if (!visited.has(predId)) {
|
|
hasBackEdge = true;
|
|
}
|
|
}
|
|
}
|
|
visited.add(blockId);
|
|
phis: for (const phi of block.phis) {
|
|
phi.operands.forEach((place, _) => rewritePlace(place, rewrites));
|
|
let same = null;
|
|
for (const [_, operand] of phi.operands) {
|
|
if ((same !== null && operand.identifier.id === same.id) ||
|
|
operand.identifier.id === phi.place.identifier.id) {
|
|
continue;
|
|
}
|
|
else if (same !== null) {
|
|
continue phis;
|
|
}
|
|
else {
|
|
same = operand.identifier;
|
|
}
|
|
}
|
|
CompilerError.invariant(same !== null, {
|
|
reason: 'Expected phis to be non-empty',
|
|
loc: GeneratedSource,
|
|
});
|
|
rewrites.set(phi.place.identifier, same);
|
|
block.phis.delete(phi);
|
|
}
|
|
for (const instr of block.instructions) {
|
|
for (const place of eachInstructionLValue(instr)) {
|
|
rewritePlace(place, rewrites);
|
|
}
|
|
for (const place of eachInstructionOperand(instr)) {
|
|
rewritePlace(place, rewrites);
|
|
}
|
|
if (instr.value.kind === 'FunctionExpression' ||
|
|
instr.value.kind === 'ObjectMethod') {
|
|
const { context } = instr.value.loweredFunc.func;
|
|
for (const place of context) {
|
|
rewritePlace(place, rewrites);
|
|
}
|
|
eliminateRedundantPhi(instr.value.loweredFunc.func, rewrites);
|
|
}
|
|
}
|
|
const { terminal } = block;
|
|
for (const place of eachTerminalOperand(terminal)) {
|
|
rewritePlace(place, rewrites);
|
|
}
|
|
}
|
|
} while (rewrites.size > size && hasBackEdge);
|
|
}
|
|
function rewritePlace(place, rewrites) {
|
|
const rewrite = rewrites.get(place.identifier);
|
|
if (rewrite != null) {
|
|
place.identifier = rewrite;
|
|
}
|
|
}
|
|
|
|
var _SSABuilder_states, _SSABuilder_current, _SSABuilder_blocks, _SSABuilder_env, _SSABuilder_unknown, _SSABuilder_context;
|
|
class SSABuilder {
|
|
constructor(env, blocks) {
|
|
_SSABuilder_states.set(this, new Map());
|
|
_SSABuilder_current.set(this, null);
|
|
this.unsealedPreds = new Map();
|
|
_SSABuilder_blocks.set(this, void 0);
|
|
_SSABuilder_env.set(this, void 0);
|
|
_SSABuilder_unknown.set(this, new Set());
|
|
_SSABuilder_context.set(this, new Set());
|
|
__classPrivateFieldSet(this, _SSABuilder_blocks, new Map(blocks), "f");
|
|
__classPrivateFieldSet(this, _SSABuilder_env, env, "f");
|
|
}
|
|
get nextSsaId() {
|
|
return __classPrivateFieldGet(this, _SSABuilder_env, "f").nextIdentifierId;
|
|
}
|
|
defineFunction(func) {
|
|
for (const [id, block] of func.body.blocks) {
|
|
__classPrivateFieldGet(this, _SSABuilder_blocks, "f").set(id, block);
|
|
}
|
|
}
|
|
enter(fn) {
|
|
const current = __classPrivateFieldGet(this, _SSABuilder_current, "f");
|
|
fn();
|
|
__classPrivateFieldSet(this, _SSABuilder_current, current, "f");
|
|
}
|
|
state() {
|
|
CompilerError.invariant(__classPrivateFieldGet(this, _SSABuilder_current, "f") !== null, {
|
|
reason: 'we need to be in a block to access state!',
|
|
loc: GeneratedSource,
|
|
});
|
|
return __classPrivateFieldGet(this, _SSABuilder_states, "f").get(__classPrivateFieldGet(this, _SSABuilder_current, "f"));
|
|
}
|
|
makeId(oldId) {
|
|
return {
|
|
id: this.nextSsaId,
|
|
declarationId: oldId.declarationId,
|
|
name: oldId.name,
|
|
mutableRange: {
|
|
start: makeInstructionId(0),
|
|
end: makeInstructionId(0),
|
|
},
|
|
scope: null,
|
|
type: makeType(),
|
|
loc: oldId.loc,
|
|
};
|
|
}
|
|
defineContext(oldPlace) {
|
|
const newPlace = this.definePlace(oldPlace);
|
|
__classPrivateFieldGet(this, _SSABuilder_context, "f").add(oldPlace.identifier);
|
|
return newPlace;
|
|
}
|
|
definePlace(oldPlace) {
|
|
const oldId = oldPlace.identifier;
|
|
if (__classPrivateFieldGet(this, _SSABuilder_unknown, "f").has(oldId)) {
|
|
CompilerError.throwTodo({
|
|
reason: `[hoisting] EnterSSA: Expected identifier to be defined before being used`,
|
|
description: `Identifier ${printIdentifier(oldId)} is undefined`,
|
|
loc: oldPlace.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
if (__classPrivateFieldGet(this, _SSABuilder_context, "f").has(oldId)) {
|
|
return this.getPlace(oldPlace);
|
|
}
|
|
const newId = this.makeId(oldId);
|
|
this.state().defs.set(oldId, newId);
|
|
return Object.assign(Object.assign({}, oldPlace), { identifier: newId });
|
|
}
|
|
getPlace(oldPlace) {
|
|
const newId = this.getIdAt(oldPlace, __classPrivateFieldGet(this, _SSABuilder_current, "f").id);
|
|
return Object.assign(Object.assign({}, oldPlace), { identifier: newId });
|
|
}
|
|
getIdAt(oldPlace, blockId) {
|
|
const block = __classPrivateFieldGet(this, _SSABuilder_blocks, "f").get(blockId);
|
|
const state = __classPrivateFieldGet(this, _SSABuilder_states, "f").get(block);
|
|
if (state.defs.has(oldPlace.identifier)) {
|
|
return state.defs.get(oldPlace.identifier);
|
|
}
|
|
if (block.preds.size == 0) {
|
|
__classPrivateFieldGet(this, _SSABuilder_unknown, "f").add(oldPlace.identifier);
|
|
return oldPlace.identifier;
|
|
}
|
|
if (this.unsealedPreds.get(block) > 0) {
|
|
const newId = this.makeId(oldPlace.identifier);
|
|
state.incompletePhis.push({
|
|
oldPlace,
|
|
newPlace: Object.assign(Object.assign({}, oldPlace), { identifier: newId }),
|
|
});
|
|
state.defs.set(oldPlace.identifier, newId);
|
|
return newId;
|
|
}
|
|
if (block.preds.size == 1) {
|
|
const [pred] = block.preds;
|
|
const newId = this.getIdAt(oldPlace, pred);
|
|
state.defs.set(oldPlace.identifier, newId);
|
|
return newId;
|
|
}
|
|
const newId = this.makeId(oldPlace.identifier);
|
|
state.defs.set(oldPlace.identifier, newId);
|
|
return this.addPhi(block, oldPlace, Object.assign(Object.assign({}, oldPlace), { identifier: newId }));
|
|
}
|
|
addPhi(block, oldPlace, newPlace) {
|
|
const predDefs = new Map();
|
|
for (const predBlockId of block.preds) {
|
|
const predId = this.getIdAt(oldPlace, predBlockId);
|
|
predDefs.set(predBlockId, Object.assign(Object.assign({}, oldPlace), { identifier: predId }));
|
|
}
|
|
const phi = {
|
|
kind: 'Phi',
|
|
place: newPlace,
|
|
operands: predDefs,
|
|
};
|
|
block.phis.add(phi);
|
|
return newPlace.identifier;
|
|
}
|
|
fixIncompletePhis(block) {
|
|
const state = __classPrivateFieldGet(this, _SSABuilder_states, "f").get(block);
|
|
for (const phi of state.incompletePhis) {
|
|
this.addPhi(block, phi.oldPlace, phi.newPlace);
|
|
}
|
|
}
|
|
startBlock(block) {
|
|
__classPrivateFieldSet(this, _SSABuilder_current, block, "f");
|
|
__classPrivateFieldGet(this, _SSABuilder_states, "f").set(block, {
|
|
defs: new Map(),
|
|
incompletePhis: [],
|
|
});
|
|
}
|
|
print() {
|
|
var _a;
|
|
const text = [];
|
|
for (const [block, state] of __classPrivateFieldGet(this, _SSABuilder_states, "f")) {
|
|
text.push(`bb${block.id}:`);
|
|
for (const [oldId, newId] of state.defs) {
|
|
text.push(` \$${printIdentifier(oldId)}: \$${printIdentifier(newId)}`);
|
|
}
|
|
for (const incompletePhi of state.incompletePhis) {
|
|
text.push(` iphi \$${printPlace(incompletePhi.newPlace)} = \$${printPlace(incompletePhi.oldPlace)}`);
|
|
}
|
|
}
|
|
text.push(`current block: bb${(_a = __classPrivateFieldGet(this, _SSABuilder_current, "f")) === null || _a === void 0 ? void 0 : _a.id}`);
|
|
console.log(text.join('\n'));
|
|
}
|
|
}
|
|
_SSABuilder_states = new WeakMap(), _SSABuilder_current = new WeakMap(), _SSABuilder_blocks = new WeakMap(), _SSABuilder_env = new WeakMap(), _SSABuilder_unknown = new WeakMap(), _SSABuilder_context = new WeakMap();
|
|
function enterSSA(func) {
|
|
const builder = new SSABuilder(func.env, func.body.blocks);
|
|
enterSSAImpl(func, builder, func.body.entry);
|
|
}
|
|
function enterSSAImpl(func, builder, rootEntry) {
|
|
const visitedBlocks = new Set();
|
|
for (const [blockId, block] of func.body.blocks) {
|
|
CompilerError.invariant(!visitedBlocks.has(block), {
|
|
reason: `found a cycle! visiting bb${block.id} again`,
|
|
loc: GeneratedSource,
|
|
});
|
|
visitedBlocks.add(block);
|
|
builder.startBlock(block);
|
|
if (blockId === rootEntry) {
|
|
CompilerError.invariant(func.context.length === 0, {
|
|
reason: `Expected function context to be empty for outer function declarations`,
|
|
loc: func.loc,
|
|
});
|
|
func.params = func.params.map(param => {
|
|
if (param.kind === 'Identifier') {
|
|
return builder.definePlace(param);
|
|
}
|
|
else {
|
|
return {
|
|
kind: 'Spread',
|
|
place: builder.definePlace(param.place),
|
|
};
|
|
}
|
|
});
|
|
}
|
|
for (const instr of block.instructions) {
|
|
mapInstructionOperands(instr, place => builder.getPlace(place));
|
|
mapInstructionLValues(instr, lvalue => builder.definePlace(lvalue));
|
|
if (instr.value.kind === 'FunctionExpression' ||
|
|
instr.value.kind === 'ObjectMethod') {
|
|
const loweredFunc = instr.value.loweredFunc.func;
|
|
const entry = loweredFunc.body.blocks.get(loweredFunc.body.entry);
|
|
CompilerError.invariant(entry.preds.size === 0, {
|
|
reason: 'Expected function expression entry block to have zero predecessors',
|
|
loc: GeneratedSource,
|
|
});
|
|
entry.preds.add(blockId);
|
|
builder.defineFunction(loweredFunc);
|
|
builder.enter(() => {
|
|
loweredFunc.params = loweredFunc.params.map(param => {
|
|
if (param.kind === 'Identifier') {
|
|
return builder.definePlace(param);
|
|
}
|
|
else {
|
|
return {
|
|
kind: 'Spread',
|
|
place: builder.definePlace(param.place),
|
|
};
|
|
}
|
|
});
|
|
enterSSAImpl(loweredFunc, builder, rootEntry);
|
|
});
|
|
entry.preds.clear();
|
|
}
|
|
}
|
|
mapTerminalOperands(block.terminal, place => builder.getPlace(place));
|
|
for (const outputId of eachTerminalSuccessor(block.terminal)) {
|
|
const output = func.body.blocks.get(outputId);
|
|
let count;
|
|
if (builder.unsealedPreds.has(output)) {
|
|
count = builder.unsealedPreds.get(output) - 1;
|
|
}
|
|
else {
|
|
count = output.preds.size - 1;
|
|
}
|
|
builder.unsealedPreds.set(output, count);
|
|
if (count === 0 && visitedBlocks.has(output)) {
|
|
builder.fixIncompletePhis(output);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function rewriteInstructionKindsBasedOnReassignment(fn) {
|
|
const declarations = new Map();
|
|
for (const param of fn.params) {
|
|
let place = param.kind === 'Identifier' ? param : param.place;
|
|
if (place.identifier.name !== null) {
|
|
declarations.set(place.identifier.declarationId, {
|
|
kind: InstructionKind.Let,
|
|
place,
|
|
});
|
|
}
|
|
}
|
|
for (const place of fn.context) {
|
|
if (place.identifier.name !== null) {
|
|
declarations.set(place.identifier.declarationId, {
|
|
kind: InstructionKind.Let,
|
|
place,
|
|
});
|
|
}
|
|
}
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
const { value } = instr;
|
|
switch (value.kind) {
|
|
case 'DeclareLocal': {
|
|
const lvalue = value.lvalue;
|
|
CompilerError.invariant(!declarations.has(lvalue.place.identifier.declarationId), {
|
|
reason: `Expected variable not to be defined prior to declaration`,
|
|
description: `${printPlace(lvalue.place)} was already defined`,
|
|
loc: lvalue.place.loc,
|
|
});
|
|
declarations.set(lvalue.place.identifier.declarationId, lvalue);
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
const lvalue = value.lvalue;
|
|
if (lvalue.place.identifier.name !== null) {
|
|
const declaration = declarations.get(lvalue.place.identifier.declarationId);
|
|
if (declaration === undefined) {
|
|
CompilerError.invariant(!declarations.has(lvalue.place.identifier.declarationId), {
|
|
reason: `Expected variable not to be defined prior to declaration`,
|
|
description: `${printPlace(lvalue.place)} was already defined`,
|
|
loc: lvalue.place.loc,
|
|
});
|
|
declarations.set(lvalue.place.identifier.declarationId, lvalue);
|
|
lvalue.kind = InstructionKind.Const;
|
|
}
|
|
else {
|
|
declaration.kind = InstructionKind.Let;
|
|
lvalue.kind = InstructionKind.Reassign;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
const lvalue = value.lvalue;
|
|
let kind = null;
|
|
for (const place of eachPatternOperand(lvalue.pattern)) {
|
|
if (place.identifier.name === null) {
|
|
CompilerError.invariant(kind === null || kind === InstructionKind.Const, {
|
|
reason: `Expected consistent kind for destructuring`,
|
|
description: `other places were \`${kind}\` but '${printPlace(place)}' is const`,
|
|
loc: place.loc,
|
|
});
|
|
kind = InstructionKind.Const;
|
|
}
|
|
else {
|
|
const declaration = declarations.get(place.identifier.declarationId);
|
|
if (declaration === undefined) {
|
|
CompilerError.invariant(block.kind !== 'value', {
|
|
reason: `TODO: Handle reassignment in a value block where the original declaration was removed by dead code elimination (DCE)`,
|
|
loc: place.loc,
|
|
});
|
|
declarations.set(place.identifier.declarationId, lvalue);
|
|
CompilerError.invariant(kind === null || kind === InstructionKind.Const, {
|
|
reason: `Expected consistent kind for destructuring`,
|
|
description: `Other places were \`${kind}\` but '${printPlace(place)}' is const`,
|
|
loc: place.loc,
|
|
});
|
|
kind = InstructionKind.Const;
|
|
}
|
|
else {
|
|
CompilerError.invariant(kind === null || kind === InstructionKind.Reassign, {
|
|
reason: `Expected consistent kind for destructuring`,
|
|
description: `Other places were \`${kind}\` but '${printPlace(place)}' is reassigned`,
|
|
loc: place.loc,
|
|
});
|
|
kind = InstructionKind.Reassign;
|
|
declaration.kind = InstructionKind.Let;
|
|
}
|
|
}
|
|
}
|
|
CompilerError.invariant(kind !== null, {
|
|
reason: 'Expected at least one operand',
|
|
loc: GeneratedSource,
|
|
});
|
|
lvalue.kind = kind;
|
|
break;
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
const lvalue = value.lvalue;
|
|
const declaration = declarations.get(lvalue.identifier.declarationId);
|
|
CompilerError.invariant(declaration !== undefined, {
|
|
reason: `Expected variable to have been defined`,
|
|
description: `No declaration for ${printPlace(lvalue)}`,
|
|
loc: lvalue.loc,
|
|
});
|
|
declaration.kind = InstructionKind.Let;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function constantPropagation(fn) {
|
|
const constants = new Map();
|
|
constantPropagationImpl(fn, constants);
|
|
}
|
|
function constantPropagationImpl(fn, constants) {
|
|
while (true) {
|
|
const haveTerminalsChanged = applyConstantPropagation(fn, constants);
|
|
if (!haveTerminalsChanged) {
|
|
break;
|
|
}
|
|
reversePostorderBlocks(fn.body);
|
|
removeUnreachableForUpdates(fn.body);
|
|
removeDeadDoWhileStatements(fn.body);
|
|
removeUnnecessaryTryCatch(fn.body);
|
|
markInstructionIds(fn.body);
|
|
markPredecessors(fn.body);
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
for (const [predecessor] of phi.operands) {
|
|
if (!block.preds.has(predecessor)) {
|
|
phi.operands.delete(predecessor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
eliminateRedundantPhi(fn);
|
|
mergeConsecutiveBlocks(fn);
|
|
assertConsistentIdentifiers(fn);
|
|
assertTerminalSuccessorsExist(fn);
|
|
}
|
|
}
|
|
function applyConstantPropagation(fn, constants) {
|
|
let hasChanges = false;
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
let value = evaluatePhi(phi, constants);
|
|
if (value !== null) {
|
|
constants.set(phi.place.identifier.id, value);
|
|
}
|
|
}
|
|
for (let i = 0; i < block.instructions.length; i++) {
|
|
if (block.kind === 'sequence' && i === block.instructions.length - 1) {
|
|
continue;
|
|
}
|
|
const instr = block.instructions[i];
|
|
const value = evaluateInstruction(constants, instr);
|
|
if (value !== null) {
|
|
constants.set(instr.lvalue.identifier.id, value);
|
|
}
|
|
}
|
|
const terminal = block.terminal;
|
|
switch (terminal.kind) {
|
|
case 'if': {
|
|
const testValue = read(constants, terminal.test);
|
|
if (testValue !== null && testValue.kind === 'Primitive') {
|
|
hasChanges = true;
|
|
const targetBlockId = testValue.value
|
|
? terminal.consequent
|
|
: terminal.alternate;
|
|
block.terminal = {
|
|
kind: 'goto',
|
|
variant: GotoVariant.Break,
|
|
block: targetBlockId,
|
|
id: terminal.id,
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return hasChanges;
|
|
}
|
|
function evaluatePhi(phi, constants) {
|
|
var _a;
|
|
let value = null;
|
|
for (const [, operand] of phi.operands) {
|
|
const operandValue = (_a = constants.get(operand.identifier.id)) !== null && _a !== void 0 ? _a : null;
|
|
if (operandValue === null) {
|
|
return null;
|
|
}
|
|
if (value === null) {
|
|
value = operandValue;
|
|
continue;
|
|
}
|
|
if (operandValue.kind !== value.kind) {
|
|
return null;
|
|
}
|
|
switch (operandValue.kind) {
|
|
case 'Primitive': {
|
|
CompilerError.invariant(value.kind === 'Primitive', {
|
|
reason: 'value kind expected to be Primitive',
|
|
loc: GeneratedSource,
|
|
});
|
|
if (operandValue.value !== value.value) {
|
|
return null;
|
|
}
|
|
break;
|
|
}
|
|
case 'LoadGlobal': {
|
|
CompilerError.invariant(value.kind === 'LoadGlobal', {
|
|
reason: 'value kind expected to be LoadGlobal',
|
|
loc: GeneratedSource,
|
|
});
|
|
if (operandValue.binding.name !== value.binding.name) {
|
|
return null;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
function evaluateInstruction(constants, instr) {
|
|
const value = instr.value;
|
|
switch (value.kind) {
|
|
case 'Primitive': {
|
|
return value;
|
|
}
|
|
case 'LoadGlobal': {
|
|
return value;
|
|
}
|
|
case 'ComputedLoad': {
|
|
const property = read(constants, value.property);
|
|
if (property !== null &&
|
|
property.kind === 'Primitive' &&
|
|
((typeof property.value === 'string' &&
|
|
libExports$1.isValidIdentifier(property.value)) ||
|
|
typeof property.value === 'number')) {
|
|
const nextValue = {
|
|
kind: 'PropertyLoad',
|
|
loc: value.loc,
|
|
property: makePropertyLiteral(property.value),
|
|
object: value.object,
|
|
};
|
|
instr.value = nextValue;
|
|
}
|
|
return null;
|
|
}
|
|
case 'ComputedStore': {
|
|
const property = read(constants, value.property);
|
|
if (property !== null &&
|
|
property.kind === 'Primitive' &&
|
|
((typeof property.value === 'string' &&
|
|
libExports$1.isValidIdentifier(property.value)) ||
|
|
typeof property.value === 'number')) {
|
|
const nextValue = {
|
|
kind: 'PropertyStore',
|
|
loc: value.loc,
|
|
property: makePropertyLiteral(property.value),
|
|
object: value.object,
|
|
value: value.value,
|
|
};
|
|
instr.value = nextValue;
|
|
}
|
|
return null;
|
|
}
|
|
case 'PostfixUpdate': {
|
|
const previous = read(constants, value.value);
|
|
if (previous !== null &&
|
|
previous.kind === 'Primitive' &&
|
|
typeof previous.value === 'number') {
|
|
const next = value.operation === '++' ? previous.value + 1 : previous.value - 1;
|
|
constants.set(value.lvalue.identifier.id, {
|
|
kind: 'Primitive',
|
|
value: next,
|
|
loc: value.loc,
|
|
});
|
|
return previous;
|
|
}
|
|
return null;
|
|
}
|
|
case 'PrefixUpdate': {
|
|
const previous = read(constants, value.value);
|
|
if (previous !== null &&
|
|
previous.kind === 'Primitive' &&
|
|
typeof previous.value === 'number') {
|
|
const next = {
|
|
kind: 'Primitive',
|
|
value: value.operation === '++' ? previous.value + 1 : previous.value - 1,
|
|
loc: value.loc,
|
|
};
|
|
constants.set(value.lvalue.identifier.id, next);
|
|
return next;
|
|
}
|
|
return null;
|
|
}
|
|
case 'UnaryExpression': {
|
|
switch (value.operator) {
|
|
case '!': {
|
|
const operand = read(constants, value.value);
|
|
if (operand !== null && operand.kind === 'Primitive') {
|
|
const result = {
|
|
kind: 'Primitive',
|
|
value: !operand.value,
|
|
loc: value.loc,
|
|
};
|
|
instr.value = result;
|
|
return result;
|
|
}
|
|
return null;
|
|
}
|
|
case '-': {
|
|
const operand = read(constants, value.value);
|
|
if (operand !== null &&
|
|
operand.kind === 'Primitive' &&
|
|
typeof operand.value === 'number') {
|
|
const result = {
|
|
kind: 'Primitive',
|
|
value: operand.value * -1,
|
|
loc: value.loc,
|
|
};
|
|
instr.value = result;
|
|
return result;
|
|
}
|
|
return null;
|
|
}
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
case 'BinaryExpression': {
|
|
const lhsValue = read(constants, value.left);
|
|
const rhsValue = read(constants, value.right);
|
|
if (lhsValue !== null &&
|
|
rhsValue !== null &&
|
|
lhsValue.kind === 'Primitive' &&
|
|
rhsValue.kind === 'Primitive') {
|
|
const lhs = lhsValue.value;
|
|
const rhs = rhsValue.value;
|
|
let result = null;
|
|
switch (value.operator) {
|
|
case '+': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs + rhs, loc: value.loc };
|
|
}
|
|
else if (typeof lhs === 'string' && typeof rhs === 'string') {
|
|
result = { kind: 'Primitive', value: lhs + rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '-': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs - rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '*': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs * rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '/': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs / rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '|': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs | rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '&': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs & rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '^': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs ^ rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '<<': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs << rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '>>': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs >> rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '>>>': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = {
|
|
kind: 'Primitive',
|
|
value: lhs >>> rhs,
|
|
loc: value.loc,
|
|
};
|
|
}
|
|
break;
|
|
}
|
|
case '%': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs % rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '**': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: Math.pow(lhs, rhs), loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '<': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs < rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '<=': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs <= rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '>': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs > rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '>=': {
|
|
if (typeof lhs === 'number' && typeof rhs === 'number') {
|
|
result = { kind: 'Primitive', value: lhs >= rhs, loc: value.loc };
|
|
}
|
|
break;
|
|
}
|
|
case '==': {
|
|
result = { kind: 'Primitive', value: lhs == rhs, loc: value.loc };
|
|
break;
|
|
}
|
|
case '===': {
|
|
result = { kind: 'Primitive', value: lhs === rhs, loc: value.loc };
|
|
break;
|
|
}
|
|
case '!=': {
|
|
result = { kind: 'Primitive', value: lhs != rhs, loc: value.loc };
|
|
break;
|
|
}
|
|
case '!==': {
|
|
result = { kind: 'Primitive', value: lhs !== rhs, loc: value.loc };
|
|
break;
|
|
}
|
|
}
|
|
if (result !== null) {
|
|
instr.value = result;
|
|
return result;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
case 'PropertyLoad': {
|
|
const objectValue = read(constants, value.object);
|
|
if (objectValue !== null) {
|
|
if (objectValue.kind === 'Primitive' &&
|
|
typeof objectValue.value === 'string' &&
|
|
value.property === 'length') {
|
|
const result = {
|
|
kind: 'Primitive',
|
|
value: objectValue.value.length,
|
|
loc: value.loc,
|
|
};
|
|
instr.value = result;
|
|
return result;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
case 'TemplateLiteral': {
|
|
if (value.subexprs.length === 0) {
|
|
const result = {
|
|
kind: 'Primitive',
|
|
value: value.quasis.map(q => q.cooked).join(''),
|
|
loc: value.loc,
|
|
};
|
|
instr.value = result;
|
|
return result;
|
|
}
|
|
if (value.subexprs.length !== value.quasis.length - 1) {
|
|
return null;
|
|
}
|
|
if (value.quasis.some(q => q.cooked === undefined)) {
|
|
return null;
|
|
}
|
|
let quasiIndex = 0;
|
|
let resultString = value.quasis[quasiIndex].cooked;
|
|
++quasiIndex;
|
|
for (const subExpr of value.subexprs) {
|
|
const subExprValue = read(constants, subExpr);
|
|
if (!subExprValue || subExprValue.kind !== 'Primitive') {
|
|
return null;
|
|
}
|
|
const expressionValue = subExprValue.value;
|
|
if (typeof expressionValue !== 'number' &&
|
|
typeof expressionValue !== 'string' &&
|
|
typeof expressionValue !== 'boolean' &&
|
|
!(typeof expressionValue === 'object' && expressionValue === null)) {
|
|
return null;
|
|
}
|
|
const suffix = value.quasis[quasiIndex].cooked;
|
|
++quasiIndex;
|
|
if (suffix === undefined) {
|
|
return null;
|
|
}
|
|
resultString = resultString.concat(expressionValue, suffix);
|
|
}
|
|
const result = {
|
|
kind: 'Primitive',
|
|
value: resultString,
|
|
loc: value.loc,
|
|
};
|
|
instr.value = result;
|
|
return result;
|
|
}
|
|
case 'LoadLocal': {
|
|
const placeValue = read(constants, value.place);
|
|
if (placeValue !== null) {
|
|
instr.value = placeValue;
|
|
}
|
|
return placeValue;
|
|
}
|
|
case 'StoreLocal': {
|
|
const placeValue = read(constants, value.value);
|
|
if (placeValue !== null) {
|
|
constants.set(value.lvalue.place.identifier.id, placeValue);
|
|
}
|
|
return placeValue;
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
constantPropagationImpl(value.loweredFunc.func, constants);
|
|
return null;
|
|
}
|
|
case 'StartMemoize': {
|
|
if (value.deps != null) {
|
|
for (const dep of value.deps) {
|
|
if (dep.root.kind === 'NamedLocal') {
|
|
const placeValue = read(constants, dep.root.value);
|
|
if (placeValue != null && placeValue.kind === 'Primitive') {
|
|
dep.root.constant = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
default: {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
function read(constants, place) {
|
|
var _a;
|
|
return (_a = constants.get(place.identifier.id)) !== null && _a !== void 0 ? _a : null;
|
|
}
|
|
|
|
function deadCodeElimination(fn) {
|
|
const state = findReferencedIdentifiers(fn);
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
if (!state.isIdOrNameUsed(phi.place.identifier)) {
|
|
block.phis.delete(phi);
|
|
}
|
|
}
|
|
retainWhere(block.instructions, instr => state.isIdOrNameUsed(instr.lvalue.identifier));
|
|
for (let i = 0; i < block.instructions.length; i++) {
|
|
const isBlockValue = block.kind !== 'block' && i === block.instructions.length - 1;
|
|
if (!isBlockValue) {
|
|
rewriteInstruction(block.instructions[i], state);
|
|
}
|
|
}
|
|
}
|
|
retainWhere(fn.context, contextVar => state.isIdOrNameUsed(contextVar.identifier));
|
|
}
|
|
let State$2 = class State {
|
|
constructor(env) {
|
|
this.named = new Set();
|
|
this.identifiers = new Set();
|
|
this.env = env;
|
|
}
|
|
reference(identifier) {
|
|
this.identifiers.add(identifier.id);
|
|
if (identifier.name !== null) {
|
|
this.named.add(identifier.name.value);
|
|
}
|
|
}
|
|
isIdOrNameUsed(identifier) {
|
|
return (this.identifiers.has(identifier.id) ||
|
|
(identifier.name !== null && this.named.has(identifier.name.value)));
|
|
}
|
|
isIdUsed(identifier) {
|
|
return this.identifiers.has(identifier.id);
|
|
}
|
|
get count() {
|
|
return this.identifiers.size;
|
|
}
|
|
};
|
|
function findReferencedIdentifiers(fn) {
|
|
const hasLoop = hasBackEdge(fn);
|
|
const reversedBlocks = [...fn.body.blocks.values()].reverse();
|
|
const state = new State$2(fn.env);
|
|
let size = state.count;
|
|
do {
|
|
size = state.count;
|
|
for (const block of reversedBlocks) {
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
state.reference(operand.identifier);
|
|
}
|
|
for (let i = block.instructions.length - 1; i >= 0; i--) {
|
|
const instr = block.instructions[i];
|
|
const isBlockValue = block.kind !== 'block' && i === block.instructions.length - 1;
|
|
if (isBlockValue) {
|
|
state.reference(instr.lvalue.identifier);
|
|
for (const place of eachInstructionValueOperand(instr.value)) {
|
|
state.reference(place.identifier);
|
|
}
|
|
}
|
|
else if (state.isIdOrNameUsed(instr.lvalue.identifier) ||
|
|
!pruneableValue(instr.value, state)) {
|
|
state.reference(instr.lvalue.identifier);
|
|
if (instr.value.kind === 'StoreLocal') {
|
|
if (instr.value.lvalue.kind === InstructionKind.Reassign ||
|
|
state.isIdUsed(instr.value.lvalue.place.identifier)) {
|
|
state.reference(instr.value.value.identifier);
|
|
}
|
|
}
|
|
else {
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
state.reference(operand.identifier);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const phi of block.phis) {
|
|
if (state.isIdOrNameUsed(phi.place.identifier)) {
|
|
for (const [_pred, operand] of phi.operands) {
|
|
state.reference(operand.identifier);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (state.count > size && hasLoop);
|
|
return state;
|
|
}
|
|
function rewriteInstruction(instr, state) {
|
|
if (instr.value.kind === 'Destructure') {
|
|
switch (instr.value.lvalue.pattern.kind) {
|
|
case 'ArrayPattern': {
|
|
let lastEntryIndex = 0;
|
|
const items = instr.value.lvalue.pattern.items;
|
|
for (let i = 0; i < items.length; i++) {
|
|
const item = items[i];
|
|
if (item.kind === 'Identifier') {
|
|
if (!state.isIdOrNameUsed(item.identifier)) {
|
|
items[i] = { kind: 'Hole' };
|
|
}
|
|
else {
|
|
lastEntryIndex = i;
|
|
}
|
|
}
|
|
else if (item.kind === 'Spread') {
|
|
if (!state.isIdOrNameUsed(item.place.identifier)) {
|
|
items[i] = { kind: 'Hole' };
|
|
}
|
|
else {
|
|
lastEntryIndex = i;
|
|
}
|
|
}
|
|
}
|
|
items.length = lastEntryIndex + 1;
|
|
break;
|
|
}
|
|
case 'ObjectPattern': {
|
|
let nextProperties = null;
|
|
for (const property of instr.value.lvalue.pattern.properties) {
|
|
if (property.kind === 'ObjectProperty') {
|
|
if (state.isIdOrNameUsed(property.place.identifier)) {
|
|
nextProperties !== null && nextProperties !== void 0 ? nextProperties : (nextProperties = []);
|
|
nextProperties.push(property);
|
|
}
|
|
}
|
|
else {
|
|
if (state.isIdOrNameUsed(property.place.identifier)) {
|
|
nextProperties = null;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (nextProperties !== null) {
|
|
instr.value.lvalue.pattern.properties = nextProperties;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(instr.value.lvalue.pattern, `Unexpected pattern kind '${instr.value.lvalue.pattern.kind}'`);
|
|
}
|
|
}
|
|
}
|
|
else if (instr.value.kind === 'StoreLocal') {
|
|
if (instr.value.lvalue.kind !== InstructionKind.Reassign &&
|
|
!state.isIdUsed(instr.value.lvalue.place.identifier)) {
|
|
instr.value = {
|
|
kind: 'DeclareLocal',
|
|
lvalue: instr.value.lvalue,
|
|
type: instr.value.type,
|
|
loc: instr.value.loc,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
function pruneableValue(value, state) {
|
|
switch (value.kind) {
|
|
case 'DeclareLocal': {
|
|
return !state.isIdOrNameUsed(value.lvalue.place.identifier);
|
|
}
|
|
case 'StoreLocal': {
|
|
if (value.lvalue.kind === InstructionKind.Reassign) {
|
|
return !state.isIdUsed(value.lvalue.place.identifier);
|
|
}
|
|
return !state.isIdOrNameUsed(value.lvalue.place.identifier);
|
|
}
|
|
case 'Destructure': {
|
|
let isIdOrNameUsed = false;
|
|
let isIdUsed = false;
|
|
for (const place of eachPatternOperand(value.lvalue.pattern)) {
|
|
if (state.isIdUsed(place.identifier)) {
|
|
isIdOrNameUsed = true;
|
|
isIdUsed = true;
|
|
}
|
|
else if (state.isIdOrNameUsed(place.identifier)) {
|
|
isIdOrNameUsed = true;
|
|
}
|
|
}
|
|
if (value.lvalue.kind === InstructionKind.Reassign) {
|
|
return !isIdUsed;
|
|
}
|
|
else {
|
|
return !isIdOrNameUsed;
|
|
}
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
return !state.isIdUsed(value.lvalue.identifier);
|
|
}
|
|
case 'Debugger': {
|
|
return false;
|
|
}
|
|
case 'CallExpression':
|
|
case 'MethodCall': {
|
|
if (state.env.outputMode === 'ssr') {
|
|
const calleee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
const hookKind = getHookKind(state.env, calleee.identifier);
|
|
switch (hookKind) {
|
|
case 'useState':
|
|
case 'useReducer':
|
|
case 'useRef': {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
case 'Await':
|
|
case 'ComputedDelete':
|
|
case 'ComputedStore':
|
|
case 'PropertyDelete':
|
|
case 'PropertyStore':
|
|
case 'StoreGlobal': {
|
|
return false;
|
|
}
|
|
case 'NewExpression':
|
|
case 'UnsupportedNode':
|
|
case 'TaggedTemplateExpression': {
|
|
return false;
|
|
}
|
|
case 'GetIterator':
|
|
case 'NextPropertyOf':
|
|
case 'IteratorNext': {
|
|
return false;
|
|
}
|
|
case 'LoadContext':
|
|
case 'DeclareContext':
|
|
case 'StoreContext': {
|
|
return false;
|
|
}
|
|
case 'StartMemoize':
|
|
case 'FinishMemoize': {
|
|
return false;
|
|
}
|
|
case 'RegExpLiteral':
|
|
case 'MetaProperty':
|
|
case 'LoadGlobal':
|
|
case 'ArrayExpression':
|
|
case 'BinaryExpression':
|
|
case 'ComputedLoad':
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression':
|
|
case 'LoadLocal':
|
|
case 'JsxExpression':
|
|
case 'JsxFragment':
|
|
case 'JSXText':
|
|
case 'ObjectExpression':
|
|
case 'Primitive':
|
|
case 'PropertyLoad':
|
|
case 'TemplateLiteral':
|
|
case 'TypeCastExpression':
|
|
case 'UnaryExpression': {
|
|
return true;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(value, `Unexepcted value kind \`${value.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function hasBackEdge(fn) {
|
|
return findBlocksWithBackEdges(fn).size > 0;
|
|
}
|
|
function findBlocksWithBackEdges(fn) {
|
|
const visited = new Set();
|
|
const blocks = new Set();
|
|
for (const [blockId, block] of fn.body.blocks) {
|
|
for (const predId of block.preds) {
|
|
if (!visited.has(predId)) {
|
|
blocks.add(blockId);
|
|
}
|
|
}
|
|
visited.add(blockId);
|
|
}
|
|
return blocks;
|
|
}
|
|
|
|
function pruneMaybeThrows(fn) {
|
|
const terminalMapping = pruneMaybeThrowsImpl(fn);
|
|
if (terminalMapping) {
|
|
reversePostorderBlocks(fn.body);
|
|
removeUnreachableForUpdates(fn.body);
|
|
removeDeadDoWhileStatements(fn.body);
|
|
removeUnnecessaryTryCatch(fn.body);
|
|
markInstructionIds(fn.body);
|
|
mergeConsecutiveBlocks(fn);
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
for (const [predecessor, operand] of phi.operands) {
|
|
if (!block.preds.has(predecessor)) {
|
|
const mappedTerminal = terminalMapping.get(predecessor);
|
|
CompilerError.invariant(mappedTerminal != null, {
|
|
reason: `Expected non-existing phi operand's predecessor to have been mapped to a new terminal`,
|
|
description: `Could not find mapping for predecessor bb${predecessor} in block bb${block.id} for phi ${printPlace(phi.place)}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
phi.operands.delete(predecessor);
|
|
phi.operands.set(mappedTerminal, operand);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
assertConsistentIdentifiers(fn);
|
|
assertTerminalSuccessorsExist(fn);
|
|
}
|
|
}
|
|
function pruneMaybeThrowsImpl(fn) {
|
|
var _a;
|
|
const terminalMapping = new Map();
|
|
for (const [_, block] of fn.body.blocks) {
|
|
const terminal = block.terminal;
|
|
if (terminal.kind !== 'maybe-throw') {
|
|
continue;
|
|
}
|
|
const canThrow = block.instructions.some(instr => instructionMayThrow(instr));
|
|
if (!canThrow) {
|
|
const source = (_a = terminalMapping.get(block.id)) !== null && _a !== void 0 ? _a : block.id;
|
|
terminalMapping.set(terminal.continuation, source);
|
|
terminal.handler = null;
|
|
}
|
|
}
|
|
return terminalMapping.size > 0 ? terminalMapping : null;
|
|
}
|
|
function instructionMayThrow(instr) {
|
|
switch (instr.value.kind) {
|
|
case 'Primitive':
|
|
case 'ArrayExpression':
|
|
case 'ObjectExpression': {
|
|
return false;
|
|
}
|
|
default: {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
function findScopesToMerge(fn) {
|
|
const objectMethodDecls = new Set();
|
|
const mergeScopesBuilder = new DisjointSet();
|
|
for (const [_, block] of fn.body.blocks) {
|
|
for (const { lvalue, value } of block.instructions) {
|
|
if (value.kind === 'ObjectMethod') {
|
|
objectMethodDecls.add(lvalue.identifier);
|
|
}
|
|
else if (value.kind === 'ObjectExpression') {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
if (objectMethodDecls.has(operand.identifier)) {
|
|
const operandScope = operand.identifier.scope;
|
|
const lvalueScope = lvalue.identifier.scope;
|
|
CompilerError.invariant(operandScope != null && lvalueScope != null, {
|
|
reason: 'Internal error: Expected all ObjectExpressions and ObjectMethods to have non-null scope.',
|
|
loc: GeneratedSource,
|
|
});
|
|
mergeScopesBuilder.union([operandScope, lvalueScope]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return mergeScopesBuilder;
|
|
}
|
|
function alignObjectMethodScopes(fn) {
|
|
for (const [_, block] of fn.body.blocks) {
|
|
for (const { value } of block.instructions) {
|
|
if (value.kind === 'ObjectMethod' ||
|
|
value.kind === 'FunctionExpression') {
|
|
alignObjectMethodScopes(value.loweredFunc.func);
|
|
}
|
|
}
|
|
}
|
|
const scopeGroupsMap = findScopesToMerge(fn).canonicalize();
|
|
for (const [scope, root] of scopeGroupsMap) {
|
|
if (scope !== root) {
|
|
root.range.start = makeInstructionId(Math.min(scope.range.start, root.range.start));
|
|
root.range.end = makeInstructionId(Math.max(scope.range.end, root.range.end));
|
|
}
|
|
}
|
|
for (const [_, block] of fn.body.blocks) {
|
|
for (const { lvalue: { identifier }, } of block.instructions) {
|
|
if (identifier.scope != null) {
|
|
const root = scopeGroupsMap.get(identifier.scope);
|
|
if (root != null) {
|
|
identifier.scope = root;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function visitReactiveFunction(fn, visitor, state) {
|
|
visitor.visitBlock(fn.body, state);
|
|
}
|
|
class ReactiveFunctionVisitor {
|
|
visitID(_id, _state) { }
|
|
visitParam(_place, _state) { }
|
|
visitLValue(_id, _lvalue, _state) { }
|
|
visitPlace(_id, _place, _state) { }
|
|
visitReactiveFunctionValue(_id, _dependencies, _fn, _state) { }
|
|
visitValue(id, value, state) {
|
|
this.traverseValue(id, value, state);
|
|
}
|
|
traverseValue(id, value, state) {
|
|
switch (value.kind) {
|
|
case 'OptionalExpression': {
|
|
this.visitValue(id, value.value, state);
|
|
break;
|
|
}
|
|
case 'LogicalExpression': {
|
|
this.visitValue(id, value.left, state);
|
|
this.visitValue(id, value.right, state);
|
|
break;
|
|
}
|
|
case 'ConditionalExpression': {
|
|
this.visitValue(id, value.test, state);
|
|
this.visitValue(id, value.consequent, state);
|
|
this.visitValue(id, value.alternate, state);
|
|
break;
|
|
}
|
|
case 'SequenceExpression': {
|
|
for (const instr of value.instructions) {
|
|
this.visitInstruction(instr, state);
|
|
}
|
|
this.visitValue(value.id, value.value, state);
|
|
break;
|
|
}
|
|
default: {
|
|
for (const place of eachInstructionValueOperand(value)) {
|
|
this.visitPlace(id, place, state);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
visitInstruction(instruction, state) {
|
|
this.traverseInstruction(instruction, state);
|
|
}
|
|
traverseInstruction(instruction, state) {
|
|
this.visitID(instruction.id, state);
|
|
for (const operand of eachInstructionLValue(instruction)) {
|
|
this.visitLValue(instruction.id, operand, state);
|
|
}
|
|
this.visitValue(instruction.id, instruction.value, state);
|
|
}
|
|
visitTerminal(stmt, state) {
|
|
this.traverseTerminal(stmt, state);
|
|
}
|
|
traverseTerminal(stmt, state) {
|
|
const { terminal } = stmt;
|
|
if (terminal.id !== null) {
|
|
this.visitID(terminal.id, state);
|
|
}
|
|
switch (terminal.kind) {
|
|
case 'break':
|
|
case 'continue': {
|
|
break;
|
|
}
|
|
case 'return': {
|
|
this.visitPlace(terminal.id, terminal.value, state);
|
|
break;
|
|
}
|
|
case 'throw': {
|
|
this.visitPlace(terminal.id, terminal.value, state);
|
|
break;
|
|
}
|
|
case 'for': {
|
|
this.visitValue(terminal.id, terminal.init, state);
|
|
this.visitValue(terminal.id, terminal.test, state);
|
|
this.visitBlock(terminal.loop, state);
|
|
if (terminal.update !== null) {
|
|
this.visitValue(terminal.id, terminal.update, state);
|
|
}
|
|
break;
|
|
}
|
|
case 'for-of': {
|
|
this.visitValue(terminal.id, terminal.init, state);
|
|
this.visitValue(terminal.id, terminal.test, state);
|
|
this.visitBlock(terminal.loop, state);
|
|
break;
|
|
}
|
|
case 'for-in': {
|
|
this.visitValue(terminal.id, terminal.init, state);
|
|
this.visitBlock(terminal.loop, state);
|
|
break;
|
|
}
|
|
case 'do-while': {
|
|
this.visitBlock(terminal.loop, state);
|
|
this.visitValue(terminal.id, terminal.test, state);
|
|
break;
|
|
}
|
|
case 'while': {
|
|
this.visitValue(terminal.id, terminal.test, state);
|
|
this.visitBlock(terminal.loop, state);
|
|
break;
|
|
}
|
|
case 'if': {
|
|
this.visitPlace(terminal.id, terminal.test, state);
|
|
this.visitBlock(terminal.consequent, state);
|
|
if (terminal.alternate !== null) {
|
|
this.visitBlock(terminal.alternate, state);
|
|
}
|
|
break;
|
|
}
|
|
case 'switch': {
|
|
this.visitPlace(terminal.id, terminal.test, state);
|
|
for (const case_ of terminal.cases) {
|
|
if (case_.test !== null) {
|
|
this.visitPlace(terminal.id, case_.test, state);
|
|
}
|
|
if (case_.block !== undefined) {
|
|
this.visitBlock(case_.block, state);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'label': {
|
|
this.visitBlock(terminal.block, state);
|
|
break;
|
|
}
|
|
case 'try': {
|
|
this.visitBlock(terminal.block, state);
|
|
this.visitBlock(terminal.handler, state);
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, `Unexpected terminal kind \`${terminal.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
visitScope(scope, state) {
|
|
this.traverseScope(scope, state);
|
|
}
|
|
traverseScope(scope, state) {
|
|
this.visitBlock(scope.instructions, state);
|
|
}
|
|
visitPrunedScope(scopeBlock, state) {
|
|
this.traversePrunedScope(scopeBlock, state);
|
|
}
|
|
traversePrunedScope(scopeBlock, state) {
|
|
this.visitBlock(scopeBlock.instructions, state);
|
|
}
|
|
visitBlock(block, state) {
|
|
this.traverseBlock(block, state);
|
|
}
|
|
traverseBlock(block, state) {
|
|
for (const instr of block) {
|
|
switch (instr.kind) {
|
|
case 'instruction': {
|
|
this.visitInstruction(instr.instruction, state);
|
|
break;
|
|
}
|
|
case 'scope': {
|
|
this.visitScope(instr, state);
|
|
break;
|
|
}
|
|
case 'pruned-scope': {
|
|
this.visitPrunedScope(instr, state);
|
|
break;
|
|
}
|
|
case 'terminal': {
|
|
this.visitTerminal(instr, state);
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(instr, `Unexpected instruction kind \`${instr.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
visitHirFunction(fn, state) {
|
|
for (const param of fn.params) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
this.visitParam(place, state);
|
|
}
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
this.visitInstruction(instr, state);
|
|
if (instr.value.kind === 'FunctionExpression' ||
|
|
instr.value.kind === 'ObjectMethod') {
|
|
this.visitHirFunction(instr.value.loweredFunc.func, state);
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
this.visitPlace(block.terminal.id, operand, state);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
class ReactiveFunctionTransform extends ReactiveFunctionVisitor {
|
|
traverseBlock(block, state) {
|
|
let nextBlock = null;
|
|
for (let i = 0; i < block.length; i++) {
|
|
const instr = block[i];
|
|
let transformed;
|
|
switch (instr.kind) {
|
|
case 'instruction': {
|
|
transformed = this.transformInstruction(instr.instruction, state);
|
|
break;
|
|
}
|
|
case 'scope': {
|
|
transformed = this.transformScope(instr, state);
|
|
break;
|
|
}
|
|
case 'pruned-scope': {
|
|
transformed = this.transformPrunedScope(instr, state);
|
|
break;
|
|
}
|
|
case 'terminal': {
|
|
transformed = this.transformTerminal(instr, state);
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(instr, `Unexpected instruction kind \`${instr.kind}\``);
|
|
}
|
|
}
|
|
switch (transformed.kind) {
|
|
case 'keep': {
|
|
if (nextBlock !== null) {
|
|
nextBlock.push(instr);
|
|
}
|
|
break;
|
|
}
|
|
case 'remove': {
|
|
if (nextBlock === null) {
|
|
nextBlock = block.slice(0, i);
|
|
}
|
|
break;
|
|
}
|
|
case 'replace': {
|
|
nextBlock !== null && nextBlock !== void 0 ? nextBlock : (nextBlock = block.slice(0, i));
|
|
nextBlock.push(transformed.value);
|
|
break;
|
|
}
|
|
case 'replace-many': {
|
|
nextBlock !== null && nextBlock !== void 0 ? nextBlock : (nextBlock = block.slice(0, i));
|
|
nextBlock.push(...transformed.value);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (nextBlock !== null) {
|
|
block.length = 0;
|
|
block.push(...nextBlock);
|
|
}
|
|
}
|
|
transformInstruction(instruction, state) {
|
|
this.visitInstruction(instruction, state);
|
|
return { kind: 'keep' };
|
|
}
|
|
transformTerminal(stmt, state) {
|
|
this.visitTerminal(stmt, state);
|
|
return { kind: 'keep' };
|
|
}
|
|
transformScope(scope, state) {
|
|
this.visitScope(scope, state);
|
|
return { kind: 'keep' };
|
|
}
|
|
transformPrunedScope(scope, state) {
|
|
this.visitPrunedScope(scope, state);
|
|
return { kind: 'keep' };
|
|
}
|
|
transformValue(id, value, state) {
|
|
this.visitValue(id, value, state);
|
|
return { kind: 'keep' };
|
|
}
|
|
transformReactiveFunctionValue(id, dependencies, fn, state) {
|
|
this.visitReactiveFunctionValue(id, dependencies, fn, state);
|
|
return { kind: 'keep' };
|
|
}
|
|
traverseValue(id, value, state) {
|
|
switch (value.kind) {
|
|
case 'OptionalExpression': {
|
|
const nextValue = this.transformValue(id, value.value, state);
|
|
if (nextValue.kind === 'replace') {
|
|
value.value = nextValue.value;
|
|
}
|
|
break;
|
|
}
|
|
case 'LogicalExpression': {
|
|
const left = this.transformValue(id, value.left, state);
|
|
if (left.kind === 'replace') {
|
|
value.left = left.value;
|
|
}
|
|
const right = this.transformValue(id, value.right, state);
|
|
if (right.kind === 'replace') {
|
|
value.right = right.value;
|
|
}
|
|
break;
|
|
}
|
|
case 'ConditionalExpression': {
|
|
const test = this.transformValue(id, value.test, state);
|
|
if (test.kind === 'replace') {
|
|
value.test = test.value;
|
|
}
|
|
const consequent = this.transformValue(id, value.consequent, state);
|
|
if (consequent.kind === 'replace') {
|
|
value.consequent = consequent.value;
|
|
}
|
|
const alternate = this.transformValue(id, value.alternate, state);
|
|
if (alternate.kind === 'replace') {
|
|
value.alternate = alternate.value;
|
|
}
|
|
break;
|
|
}
|
|
case 'SequenceExpression': {
|
|
for (const instr of value.instructions) {
|
|
this.visitInstruction(instr, state);
|
|
}
|
|
const nextValue = this.transformValue(value.id, value.value, state);
|
|
if (nextValue.kind === 'replace') {
|
|
value.value = nextValue.value;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
for (const place of eachInstructionValueOperand(value)) {
|
|
this.visitPlace(id, place, state);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
traverseInstruction(instruction, state) {
|
|
this.visitID(instruction.id, state);
|
|
for (const operand of eachInstructionLValue(instruction)) {
|
|
this.visitLValue(instruction.id, operand, state);
|
|
}
|
|
const nextValue = this.transformValue(instruction.id, instruction.value, state);
|
|
if (nextValue.kind === 'replace') {
|
|
instruction.value = nextValue.value;
|
|
}
|
|
}
|
|
traverseTerminal(stmt, state) {
|
|
const { terminal } = stmt;
|
|
if (terminal.id !== null) {
|
|
this.visitID(terminal.id, state);
|
|
}
|
|
switch (terminal.kind) {
|
|
case 'break':
|
|
case 'continue': {
|
|
break;
|
|
}
|
|
case 'return': {
|
|
this.visitPlace(terminal.id, terminal.value, state);
|
|
break;
|
|
}
|
|
case 'throw': {
|
|
this.visitPlace(terminal.id, terminal.value, state);
|
|
break;
|
|
}
|
|
case 'for': {
|
|
const init = this.transformValue(terminal.id, terminal.init, state);
|
|
if (init.kind === 'replace') {
|
|
terminal.init = init.value;
|
|
}
|
|
const test = this.transformValue(terminal.id, terminal.test, state);
|
|
if (test.kind === 'replace') {
|
|
terminal.test = test.value;
|
|
}
|
|
if (terminal.update !== null) {
|
|
const update = this.transformValue(terminal.id, terminal.update, state);
|
|
if (update.kind === 'replace') {
|
|
terminal.update = update.value;
|
|
}
|
|
}
|
|
this.visitBlock(terminal.loop, state);
|
|
break;
|
|
}
|
|
case 'for-of': {
|
|
const init = this.transformValue(terminal.id, terminal.init, state);
|
|
if (init.kind === 'replace') {
|
|
terminal.init = init.value;
|
|
}
|
|
const test = this.transformValue(terminal.id, terminal.test, state);
|
|
if (test.kind === 'replace') {
|
|
terminal.test = test.value;
|
|
}
|
|
this.visitBlock(terminal.loop, state);
|
|
break;
|
|
}
|
|
case 'for-in': {
|
|
const init = this.transformValue(terminal.id, terminal.init, state);
|
|
if (init.kind === 'replace') {
|
|
terminal.init = init.value;
|
|
}
|
|
this.visitBlock(terminal.loop, state);
|
|
break;
|
|
}
|
|
case 'do-while': {
|
|
this.visitBlock(terminal.loop, state);
|
|
const test = this.transformValue(terminal.id, terminal.test, state);
|
|
if (test.kind === 'replace') {
|
|
terminal.test = test.value;
|
|
}
|
|
break;
|
|
}
|
|
case 'while': {
|
|
const test = this.transformValue(terminal.id, terminal.test, state);
|
|
if (test.kind === 'replace') {
|
|
terminal.test = test.value;
|
|
}
|
|
this.visitBlock(terminal.loop, state);
|
|
break;
|
|
}
|
|
case 'if': {
|
|
this.visitPlace(terminal.id, terminal.test, state);
|
|
this.visitBlock(terminal.consequent, state);
|
|
if (terminal.alternate !== null) {
|
|
this.visitBlock(terminal.alternate, state);
|
|
}
|
|
break;
|
|
}
|
|
case 'switch': {
|
|
this.visitPlace(terminal.id, terminal.test, state);
|
|
for (const case_ of terminal.cases) {
|
|
if (case_.test !== null) {
|
|
this.visitPlace(terminal.id, case_.test, state);
|
|
}
|
|
if (case_.block !== undefined) {
|
|
this.visitBlock(case_.block, state);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'label': {
|
|
this.visitBlock(terminal.block, state);
|
|
break;
|
|
}
|
|
case 'try': {
|
|
this.visitBlock(terminal.block, state);
|
|
if (terminal.handlerBinding !== null) {
|
|
this.visitPlace(terminal.id, terminal.handlerBinding, state);
|
|
}
|
|
this.visitBlock(terminal.handler, state);
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, `Unexpected terminal kind \`${terminal.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function* eachReactiveValueOperand(instrValue) {
|
|
switch (instrValue.kind) {
|
|
case 'OptionalExpression': {
|
|
yield* eachReactiveValueOperand(instrValue.value);
|
|
break;
|
|
}
|
|
case 'LogicalExpression': {
|
|
yield* eachReactiveValueOperand(instrValue.left);
|
|
yield* eachReactiveValueOperand(instrValue.right);
|
|
break;
|
|
}
|
|
case 'SequenceExpression': {
|
|
for (const instr of instrValue.instructions) {
|
|
yield* eachReactiveValueOperand(instr.value);
|
|
}
|
|
yield* eachReactiveValueOperand(instrValue.value);
|
|
break;
|
|
}
|
|
case 'ConditionalExpression': {
|
|
yield* eachReactiveValueOperand(instrValue.test);
|
|
yield* eachReactiveValueOperand(instrValue.consequent);
|
|
yield* eachReactiveValueOperand(instrValue.alternate);
|
|
break;
|
|
}
|
|
default: {
|
|
yield* eachInstructionValueOperand(instrValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
function assertScopeInstructionsWithinScopes(fn) {
|
|
const existingScopes = new Set();
|
|
visitReactiveFunction(fn, new FindAllScopesVisitor(), existingScopes);
|
|
visitReactiveFunction(fn, new CheckInstructionsAgainstScopesVisitor(), existingScopes);
|
|
}
|
|
class FindAllScopesVisitor extends ReactiveFunctionVisitor {
|
|
visitScope(block, state) {
|
|
this.traverseScope(block, state);
|
|
state.add(block.scope.id);
|
|
}
|
|
}
|
|
class CheckInstructionsAgainstScopesVisitor extends ReactiveFunctionVisitor {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.activeScopes = new Set();
|
|
}
|
|
visitPlace(id, place, state) {
|
|
const scope = getPlaceScope(id, place);
|
|
if (scope !== null &&
|
|
state.has(scope.id) &&
|
|
!this.activeScopes.has(scope.id)) {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Encountered an instruction that should be part of a scope, but where that scope has already completed',
|
|
description: `Instruction [${id}] is part of scope @${scope.id}, but that scope has already completed`,
|
|
loc: place.loc,
|
|
});
|
|
}
|
|
}
|
|
visitScope(block, state) {
|
|
this.activeScopes.add(block.scope.id);
|
|
this.traverseScope(block, state);
|
|
this.activeScopes.delete(block.scope.id);
|
|
}
|
|
}
|
|
|
|
function assertWellFormedBreakTargets(fn) {
|
|
visitReactiveFunction(fn, new Visitor$8(), new Set());
|
|
}
|
|
let Visitor$8 = class Visitor extends ReactiveFunctionVisitor {
|
|
visitTerminal(stmt, seenLabels) {
|
|
if (stmt.label != null) {
|
|
seenLabels.add(stmt.label.id);
|
|
}
|
|
const terminal = stmt.terminal;
|
|
if (terminal.kind === 'break' || terminal.kind === 'continue') {
|
|
CompilerError.invariant(seenLabels.has(terminal.target), {
|
|
reason: 'Unexpected break to invalid label',
|
|
loc: stmt.terminal.loc,
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
var _Context_nextScheduleId, _Context_scheduled, _Context_catchHandlers, _Context_controlFlowStack;
|
|
function buildReactiveFunction(fn) {
|
|
const cx = new Context$2(fn.body);
|
|
const driver = new Driver(cx);
|
|
const body = driver.traverseBlock(cx.block(fn.body.entry));
|
|
return {
|
|
loc: fn.loc,
|
|
id: fn.id,
|
|
nameHint: fn.nameHint,
|
|
params: fn.params,
|
|
generator: fn.generator,
|
|
async: fn.async,
|
|
body,
|
|
env: fn.env,
|
|
directives: fn.directives,
|
|
};
|
|
}
|
|
class Driver {
|
|
constructor(cx) {
|
|
this.cx = cx;
|
|
}
|
|
wrapWithSequence(instructions, continuation, loc) {
|
|
if (instructions.length === 0) {
|
|
return continuation;
|
|
}
|
|
const sequence = {
|
|
kind: 'SequenceExpression',
|
|
instructions,
|
|
id: continuation.id,
|
|
value: continuation.value,
|
|
loc,
|
|
};
|
|
return {
|
|
block: continuation.block,
|
|
value: sequence,
|
|
place: continuation.place,
|
|
id: continuation.id,
|
|
};
|
|
}
|
|
extractValueBlockResult(instructions, blockId, loc) {
|
|
CompilerError.invariant(instructions.length !== 0, {
|
|
reason: `Expected non-empty instructions in extractValueBlockResult`,
|
|
description: null,
|
|
loc,
|
|
});
|
|
const instr = instructions.at(-1);
|
|
let place = instr.lvalue;
|
|
let value = instr.value;
|
|
if (value.kind === 'StoreLocal' &&
|
|
value.lvalue.place.identifier.name === null) {
|
|
place = value.lvalue.place;
|
|
value = {
|
|
kind: 'LoadLocal',
|
|
place: value.value,
|
|
loc: value.value.loc,
|
|
};
|
|
}
|
|
if (instructions.length === 1) {
|
|
return { block: blockId, place, value, id: instr.id };
|
|
}
|
|
const sequence = {
|
|
kind: 'SequenceExpression',
|
|
instructions: instructions.slice(0, -1),
|
|
id: instr.id,
|
|
value,
|
|
loc,
|
|
};
|
|
return { block: blockId, place, value: sequence, id: instr.id };
|
|
}
|
|
valueBlockResultToSequence(result, loc) {
|
|
const instructions = [];
|
|
let innerValue = result.value;
|
|
while (innerValue.kind === 'SequenceExpression') {
|
|
instructions.push(...innerValue.instructions);
|
|
innerValue = innerValue.value;
|
|
}
|
|
const isLoadOfSamePlace = innerValue.kind === 'LoadLocal' &&
|
|
innerValue.place.identifier.id === result.place.identifier.id;
|
|
if (!isLoadOfSamePlace) {
|
|
instructions.push({
|
|
id: result.id,
|
|
lvalue: result.place,
|
|
value: innerValue,
|
|
loc,
|
|
});
|
|
}
|
|
return {
|
|
kind: 'SequenceExpression',
|
|
instructions,
|
|
id: result.id,
|
|
value: { kind: 'Primitive', value: undefined, loc },
|
|
loc,
|
|
};
|
|
}
|
|
traverseBlock(block) {
|
|
const blockValue = [];
|
|
this.visitBlock(block, blockValue);
|
|
return blockValue;
|
|
}
|
|
visitBlock(block, blockValue) {
|
|
var _a;
|
|
CompilerError.invariant(!this.cx.emitted.has(block.id), {
|
|
reason: `Cannot emit the same block twice: bb${block.id}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
this.cx.emitted.add(block.id);
|
|
for (const instruction of block.instructions) {
|
|
blockValue.push({
|
|
kind: 'instruction',
|
|
instruction,
|
|
});
|
|
}
|
|
const terminal = block.terminal;
|
|
const scheduleIds = [];
|
|
switch (terminal.kind) {
|
|
case 'return': {
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'return',
|
|
loc: terminal.loc,
|
|
value: terminal.value,
|
|
id: terminal.id,
|
|
},
|
|
label: null,
|
|
});
|
|
break;
|
|
}
|
|
case 'throw': {
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'throw',
|
|
loc: terminal.loc,
|
|
value: terminal.value,
|
|
id: terminal.id,
|
|
},
|
|
label: null,
|
|
});
|
|
break;
|
|
}
|
|
case 'if': {
|
|
const fallthroughId = this.cx.reachable(terminal.fallthrough) &&
|
|
!this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
const alternateId = terminal.alternate !== terminal.fallthrough
|
|
? terminal.alternate
|
|
: null;
|
|
if (fallthroughId !== null) {
|
|
const scheduleId = this.cx.schedule(fallthroughId, 'if');
|
|
scheduleIds.push(scheduleId);
|
|
}
|
|
let consequent = null;
|
|
if (this.cx.isScheduled(terminal.consequent)) {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected 'if' where the consequent is already scheduled`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
else {
|
|
consequent = this.traverseBlock(this.cx.ir.blocks.get(terminal.consequent));
|
|
}
|
|
let alternate = null;
|
|
if (alternateId !== null) {
|
|
if (this.cx.isScheduled(alternateId)) {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected 'if' where the alternate is already scheduled`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
else {
|
|
alternate = this.traverseBlock(this.cx.ir.blocks.get(alternateId));
|
|
}
|
|
}
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'if',
|
|
loc: terminal.loc,
|
|
test: terminal.test,
|
|
consequent: consequent !== null && consequent !== void 0 ? consequent : this.emptyBlock(),
|
|
alternate: alternate,
|
|
id: terminal.id,
|
|
},
|
|
label: fallthroughId == null
|
|
? null
|
|
: {
|
|
id: fallthroughId,
|
|
implicit: false,
|
|
},
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'switch': {
|
|
const fallthroughId = this.cx.reachable(terminal.fallthrough) &&
|
|
!this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
if (fallthroughId !== null) {
|
|
const scheduleId = this.cx.schedule(fallthroughId, 'switch');
|
|
scheduleIds.push(scheduleId);
|
|
}
|
|
const cases = [];
|
|
[...terminal.cases].reverse().forEach((case_, _index) => {
|
|
const test = case_.test;
|
|
let consequent;
|
|
if (this.cx.isScheduled(case_.block)) {
|
|
CompilerError.invariant(case_.block === terminal.fallthrough, {
|
|
reason: `Unexpected 'switch' where a case is already scheduled and block is not the fallthrough`,
|
|
loc: terminal.loc,
|
|
});
|
|
return;
|
|
}
|
|
else {
|
|
consequent = this.traverseBlock(this.cx.ir.blocks.get(case_.block));
|
|
const scheduleId = this.cx.schedule(case_.block, 'case');
|
|
scheduleIds.push(scheduleId);
|
|
}
|
|
cases.push({ test, block: consequent });
|
|
});
|
|
cases.reverse();
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'switch',
|
|
loc: terminal.loc,
|
|
test: terminal.test,
|
|
cases,
|
|
id: terminal.id,
|
|
},
|
|
label: fallthroughId == null
|
|
? null
|
|
: {
|
|
id: fallthroughId,
|
|
implicit: false,
|
|
},
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'do-while': {
|
|
const fallthroughId = !this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
const loopId = !this.cx.isScheduled(terminal.loop) &&
|
|
terminal.loop !== terminal.fallthrough
|
|
? terminal.loop
|
|
: null;
|
|
const scheduleId = this.cx.scheduleLoop(terminal.fallthrough, terminal.test, terminal.loop);
|
|
scheduleIds.push(scheduleId);
|
|
let loopBody;
|
|
if (loopId) {
|
|
loopBody = this.traverseBlock(this.cx.ir.blocks.get(loopId));
|
|
}
|
|
else {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected 'do-while' where the loop is already scheduled`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
const testValue = this.visitValueBlock(terminal.test, terminal.loc).value;
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'do-while',
|
|
loc: terminal.loc,
|
|
test: testValue,
|
|
loop: loopBody,
|
|
id: terminal.id,
|
|
},
|
|
label: fallthroughId == null
|
|
? null
|
|
: {
|
|
id: fallthroughId,
|
|
implicit: false,
|
|
},
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'while': {
|
|
const fallthroughId = this.cx.reachable(terminal.fallthrough) &&
|
|
!this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
const loopId = !this.cx.isScheduled(terminal.loop) &&
|
|
terminal.loop !== terminal.fallthrough
|
|
? terminal.loop
|
|
: null;
|
|
const scheduleId = this.cx.scheduleLoop(terminal.fallthrough, terminal.test, terminal.loop);
|
|
scheduleIds.push(scheduleId);
|
|
const testValue = this.visitValueBlock(terminal.test, terminal.loc).value;
|
|
let loopBody;
|
|
if (loopId) {
|
|
loopBody = this.traverseBlock(this.cx.ir.blocks.get(loopId));
|
|
}
|
|
else {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected 'while' where the loop is already scheduled`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'while',
|
|
loc: terminal.loc,
|
|
test: testValue,
|
|
loop: loopBody,
|
|
id: terminal.id,
|
|
},
|
|
label: fallthroughId == null
|
|
? null
|
|
: {
|
|
id: fallthroughId,
|
|
implicit: false,
|
|
},
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'for': {
|
|
const loopId = !this.cx.isScheduled(terminal.loop) &&
|
|
terminal.loop !== terminal.fallthrough
|
|
? terminal.loop
|
|
: null;
|
|
const fallthroughId = !this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
const scheduleId = this.cx.scheduleLoop(terminal.fallthrough, (_a = terminal.update) !== null && _a !== void 0 ? _a : terminal.test, terminal.loop);
|
|
scheduleIds.push(scheduleId);
|
|
const init = this.visitValueBlock(terminal.init, terminal.loc);
|
|
const initValue = this.valueBlockResultToSequence(init, terminal.loc);
|
|
const testValue = this.visitValueBlock(terminal.test, terminal.loc).value;
|
|
const updateValue = terminal.update !== null
|
|
? this.visitValueBlock(terminal.update, terminal.loc).value
|
|
: null;
|
|
let loopBody;
|
|
if (loopId) {
|
|
loopBody = this.traverseBlock(this.cx.ir.blocks.get(loopId));
|
|
}
|
|
else {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected 'for' where the loop is already scheduled`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'for',
|
|
loc: terminal.loc,
|
|
init: initValue,
|
|
test: testValue,
|
|
update: updateValue,
|
|
loop: loopBody,
|
|
id: terminal.id,
|
|
},
|
|
label: fallthroughId == null ? null : { id: fallthroughId, implicit: false },
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'for-of': {
|
|
const loopId = !this.cx.isScheduled(terminal.loop) &&
|
|
terminal.loop !== terminal.fallthrough
|
|
? terminal.loop
|
|
: null;
|
|
const fallthroughId = !this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
const scheduleId = this.cx.scheduleLoop(terminal.fallthrough, terminal.init, terminal.loop);
|
|
scheduleIds.push(scheduleId);
|
|
const init = this.visitValueBlock(terminal.init, terminal.loc);
|
|
const initValue = this.valueBlockResultToSequence(init, terminal.loc);
|
|
const test = this.visitValueBlock(terminal.test, terminal.loc);
|
|
const testValue = this.valueBlockResultToSequence(test, terminal.loc);
|
|
let loopBody;
|
|
if (loopId) {
|
|
loopBody = this.traverseBlock(this.cx.ir.blocks.get(loopId));
|
|
}
|
|
else {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected 'for-of' where the loop is already scheduled`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'for-of',
|
|
loc: terminal.loc,
|
|
init: initValue,
|
|
test: testValue,
|
|
loop: loopBody,
|
|
id: terminal.id,
|
|
},
|
|
label: fallthroughId == null ? null : { id: fallthroughId, implicit: false },
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'for-in': {
|
|
const loopId = !this.cx.isScheduled(terminal.loop) &&
|
|
terminal.loop !== terminal.fallthrough
|
|
? terminal.loop
|
|
: null;
|
|
const fallthroughId = !this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
const scheduleId = this.cx.scheduleLoop(terminal.fallthrough, terminal.init, terminal.loop);
|
|
scheduleIds.push(scheduleId);
|
|
const init = this.visitValueBlock(terminal.init, terminal.loc);
|
|
const initValue = this.valueBlockResultToSequence(init, terminal.loc);
|
|
let loopBody;
|
|
if (loopId) {
|
|
loopBody = this.traverseBlock(this.cx.ir.blocks.get(loopId));
|
|
}
|
|
else {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected 'for-in' where the loop is already scheduled`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'for-in',
|
|
loc: terminal.loc,
|
|
init: initValue,
|
|
loop: loopBody,
|
|
id: terminal.id,
|
|
},
|
|
label: fallthroughId == null ? null : { id: fallthroughId, implicit: false },
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'branch': {
|
|
let consequent = null;
|
|
if (this.cx.isScheduled(terminal.consequent)) {
|
|
const break_ = this.visitBreak(terminal.consequent, terminal.id, terminal.loc);
|
|
if (break_ !== null) {
|
|
consequent = [break_];
|
|
}
|
|
}
|
|
else {
|
|
consequent = this.traverseBlock(this.cx.ir.blocks.get(terminal.consequent));
|
|
}
|
|
let alternate = null;
|
|
if (this.cx.isScheduled(terminal.alternate)) {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected 'branch' where the alternate is already scheduled`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
else {
|
|
alternate = this.traverseBlock(this.cx.ir.blocks.get(terminal.alternate));
|
|
}
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'if',
|
|
loc: terminal.loc,
|
|
test: terminal.test,
|
|
consequent: consequent !== null && consequent !== void 0 ? consequent : this.emptyBlock(),
|
|
alternate: alternate,
|
|
id: terminal.id,
|
|
},
|
|
label: null,
|
|
});
|
|
break;
|
|
}
|
|
case 'label': {
|
|
const fallthroughId = this.cx.reachable(terminal.fallthrough) &&
|
|
!this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
if (fallthroughId !== null) {
|
|
const scheduleId = this.cx.schedule(fallthroughId, 'if');
|
|
scheduleIds.push(scheduleId);
|
|
}
|
|
let block;
|
|
if (this.cx.isScheduled(terminal.block)) {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected 'label' where the block is already scheduled`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
else {
|
|
block = this.traverseBlock(this.cx.ir.blocks.get(terminal.block));
|
|
}
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'label',
|
|
loc: terminal.loc,
|
|
block,
|
|
id: terminal.id,
|
|
},
|
|
label: fallthroughId == null ? null : { id: fallthroughId, implicit: false },
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'sequence':
|
|
case 'optional':
|
|
case 'ternary':
|
|
case 'logical': {
|
|
const fallthroughId = terminal.fallthrough !== null &&
|
|
!this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
if (fallthroughId !== null) {
|
|
const scheduleId = this.cx.schedule(fallthroughId, 'if');
|
|
scheduleIds.push(scheduleId);
|
|
}
|
|
const { place, value } = this.visitValueBlockTerminal(terminal);
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: 'instruction',
|
|
instruction: {
|
|
id: terminal.id,
|
|
lvalue: place,
|
|
value,
|
|
loc: terminal.loc,
|
|
},
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'goto': {
|
|
switch (terminal.variant) {
|
|
case GotoVariant.Break: {
|
|
const break_ = this.visitBreak(terminal.block, terminal.id, terminal.loc);
|
|
if (break_ !== null) {
|
|
blockValue.push(break_);
|
|
}
|
|
break;
|
|
}
|
|
case GotoVariant.Continue: {
|
|
const continue_ = this.visitContinue(terminal.block, terminal.id, terminal.loc);
|
|
if (continue_ !== null) {
|
|
blockValue.push(continue_);
|
|
}
|
|
break;
|
|
}
|
|
case GotoVariant.Try: {
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal.variant, `Unexpected goto variant \`${terminal.variant}\``);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'maybe-throw': {
|
|
if (!this.cx.isScheduled(terminal.continuation)) {
|
|
this.visitBlock(this.cx.ir.blocks.get(terminal.continuation), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'try': {
|
|
const fallthroughId = this.cx.reachable(terminal.fallthrough) &&
|
|
!this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
if (fallthroughId !== null) {
|
|
const scheduleId = this.cx.schedule(fallthroughId, 'if');
|
|
scheduleIds.push(scheduleId);
|
|
}
|
|
this.cx.scheduleCatchHandler(terminal.handler);
|
|
const block = this.traverseBlock(this.cx.ir.blocks.get(terminal.block));
|
|
const handler = this.traverseBlock(this.cx.ir.blocks.get(terminal.handler));
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: 'terminal',
|
|
label: fallthroughId == null ? null : { id: fallthroughId, implicit: false },
|
|
terminal: {
|
|
kind: 'try',
|
|
loc: terminal.loc,
|
|
block,
|
|
handlerBinding: terminal.handlerBinding,
|
|
handler,
|
|
id: terminal.id,
|
|
},
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'pruned-scope':
|
|
case 'scope': {
|
|
const fallthroughId = !this.cx.isScheduled(terminal.fallthrough)
|
|
? terminal.fallthrough
|
|
: null;
|
|
if (fallthroughId !== null) {
|
|
const scheduleId = this.cx.schedule(fallthroughId, 'if');
|
|
scheduleIds.push(scheduleId);
|
|
this.cx.scopeFallthroughs.add(fallthroughId);
|
|
}
|
|
let block;
|
|
if (this.cx.isScheduled(terminal.block)) {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected 'scope' where the block is already scheduled`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
else {
|
|
block = this.traverseBlock(this.cx.ir.blocks.get(terminal.block));
|
|
}
|
|
this.cx.unscheduleAll(scheduleIds);
|
|
blockValue.push({
|
|
kind: terminal.kind,
|
|
instructions: block,
|
|
scope: terminal.scope,
|
|
});
|
|
if (fallthroughId !== null) {
|
|
this.visitBlock(this.cx.ir.blocks.get(fallthroughId), blockValue);
|
|
}
|
|
break;
|
|
}
|
|
case 'unreachable': {
|
|
break;
|
|
}
|
|
case 'unsupported': {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Unexpected unsupported terminal',
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, 'Unexpected terminal');
|
|
}
|
|
}
|
|
}
|
|
visitValueBlock(blockId, loc, fallthrough = null) {
|
|
const block = this.cx.ir.blocks.get(blockId);
|
|
if (fallthrough !== null && blockId === fallthrough) {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Did not expect to reach the fallthrough of a value block',
|
|
description: `Reached bb${blockId}, which is the fallthrough for this value block`,
|
|
loc,
|
|
});
|
|
}
|
|
if (block.terminal.kind === 'branch') {
|
|
if (block.instructions.length === 0) {
|
|
return {
|
|
block: block.id,
|
|
place: block.terminal.test,
|
|
value: {
|
|
kind: 'LoadLocal',
|
|
place: block.terminal.test,
|
|
loc: block.terminal.test.loc,
|
|
},
|
|
id: block.terminal.id,
|
|
};
|
|
}
|
|
return this.extractValueBlockResult(block.instructions, block.id, loc);
|
|
}
|
|
else if (block.terminal.kind === 'goto') {
|
|
if (block.instructions.length === 0) {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Unexpected empty block with `goto` terminal',
|
|
description: `Block bb${block.id} is empty`,
|
|
loc,
|
|
});
|
|
}
|
|
return this.extractValueBlockResult(block.instructions, block.id, loc);
|
|
}
|
|
else if (block.terminal.kind === 'maybe-throw') {
|
|
const continuationId = block.terminal.continuation;
|
|
const continuationBlock = this.cx.ir.blocks.get(continuationId);
|
|
if (continuationBlock.instructions.length === 0 &&
|
|
continuationBlock.terminal.kind === 'goto') {
|
|
return this.extractValueBlockResult(block.instructions, continuationBlock.id, loc);
|
|
}
|
|
const continuation = this.visitValueBlock(continuationId, loc, fallthrough);
|
|
return this.wrapWithSequence(block.instructions, continuation, loc);
|
|
}
|
|
else {
|
|
const init = this.visitValueBlockTerminal(block.terminal);
|
|
const final = this.visitValueBlock(init.fallthrough, loc);
|
|
return this.wrapWithSequence([
|
|
...block.instructions,
|
|
{ id: init.id, loc, lvalue: init.place, value: init.value },
|
|
], final, loc);
|
|
}
|
|
}
|
|
visitTestBlock(testBlockId, loc, terminalKind) {
|
|
const test = this.visitValueBlock(testBlockId, loc);
|
|
const testBlock = this.cx.ir.blocks.get(test.block);
|
|
if (testBlock.terminal.kind !== 'branch') {
|
|
CompilerError.invariant(false, {
|
|
reason: `Expected a branch terminal for ${terminalKind} test block`,
|
|
description: `Got \`${testBlock.terminal.kind}\``,
|
|
loc: testBlock.terminal.loc,
|
|
});
|
|
}
|
|
return {
|
|
test,
|
|
branch: {
|
|
consequent: testBlock.terminal.consequent,
|
|
alternate: testBlock.terminal.alternate,
|
|
loc: testBlock.terminal.loc,
|
|
},
|
|
};
|
|
}
|
|
visitValueBlockTerminal(terminal) {
|
|
switch (terminal.kind) {
|
|
case 'sequence': {
|
|
const block = this.visitValueBlock(terminal.block, terminal.loc, terminal.fallthrough);
|
|
return {
|
|
value: block.value,
|
|
place: block.place,
|
|
fallthrough: terminal.fallthrough,
|
|
id: terminal.id,
|
|
};
|
|
}
|
|
case 'optional': {
|
|
const { test, branch } = this.visitTestBlock(terminal.test, terminal.loc, 'optional');
|
|
const consequent = this.visitValueBlock(branch.consequent, terminal.loc, terminal.fallthrough);
|
|
const call = {
|
|
kind: 'SequenceExpression',
|
|
instructions: [
|
|
{
|
|
id: test.id,
|
|
loc: branch.loc,
|
|
lvalue: test.place,
|
|
value: test.value,
|
|
},
|
|
],
|
|
id: consequent.id,
|
|
value: consequent.value,
|
|
loc: terminal.loc,
|
|
};
|
|
return {
|
|
place: Object.assign({}, consequent.place),
|
|
value: {
|
|
kind: 'OptionalExpression',
|
|
optional: terminal.optional,
|
|
value: call,
|
|
id: terminal.id,
|
|
loc: terminal.loc,
|
|
},
|
|
fallthrough: terminal.fallthrough,
|
|
id: terminal.id,
|
|
};
|
|
}
|
|
case 'logical': {
|
|
const { test, branch } = this.visitTestBlock(terminal.test, terminal.loc, 'logical');
|
|
const leftFinal = this.visitValueBlock(branch.consequent, terminal.loc, terminal.fallthrough);
|
|
const left = {
|
|
kind: 'SequenceExpression',
|
|
instructions: [
|
|
{
|
|
id: test.id,
|
|
loc: terminal.loc,
|
|
lvalue: test.place,
|
|
value: test.value,
|
|
},
|
|
],
|
|
id: leftFinal.id,
|
|
value: leftFinal.value,
|
|
loc: terminal.loc,
|
|
};
|
|
const right = this.visitValueBlock(branch.alternate, terminal.loc, terminal.fallthrough);
|
|
const value = {
|
|
kind: 'LogicalExpression',
|
|
operator: terminal.operator,
|
|
left: left,
|
|
right: right.value,
|
|
loc: terminal.loc,
|
|
};
|
|
return {
|
|
place: Object.assign({}, leftFinal.place),
|
|
value,
|
|
fallthrough: terminal.fallthrough,
|
|
id: terminal.id,
|
|
};
|
|
}
|
|
case 'ternary': {
|
|
const { test, branch } = this.visitTestBlock(terminal.test, terminal.loc, 'ternary');
|
|
const consequent = this.visitValueBlock(branch.consequent, terminal.loc, terminal.fallthrough);
|
|
const alternate = this.visitValueBlock(branch.alternate, terminal.loc, terminal.fallthrough);
|
|
const value = {
|
|
kind: 'ConditionalExpression',
|
|
test: test.value,
|
|
consequent: consequent.value,
|
|
alternate: alternate.value,
|
|
loc: terminal.loc,
|
|
};
|
|
return {
|
|
place: Object.assign({}, consequent.place),
|
|
value,
|
|
fallthrough: terminal.fallthrough,
|
|
id: terminal.id,
|
|
};
|
|
}
|
|
case 'maybe-throw': {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected maybe-throw in visitValueBlockTerminal - should be handled in visitValueBlock`,
|
|
description: null,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
case 'label': {
|
|
CompilerError.throwTodo({
|
|
reason: `Support labeled statements combined with value blocks (conditional, logical, optional chaining, etc)`,
|
|
description: null,
|
|
loc: terminal.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
default: {
|
|
CompilerError.throwTodo({
|
|
reason: `Support \`${terminal.kind}\` as a value block terminal (conditional, logical, optional chaining, etc)`,
|
|
description: null,
|
|
loc: terminal.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
emptyBlock() {
|
|
return [];
|
|
}
|
|
visitBreak(block, id, loc) {
|
|
const target = this.cx.getBreakTarget(block);
|
|
if (target === null) {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Expected a break target',
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
if (this.cx.scopeFallthroughs.has(target.block)) {
|
|
CompilerError.invariant(target.type === 'implicit', {
|
|
reason: 'Expected reactive scope to implicitly break to fallthrough',
|
|
loc,
|
|
});
|
|
return null;
|
|
}
|
|
return {
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'break',
|
|
loc,
|
|
target: target.block,
|
|
id,
|
|
targetKind: target.type,
|
|
},
|
|
label: null,
|
|
};
|
|
}
|
|
visitContinue(block, id, loc) {
|
|
const target = this.cx.getContinueTarget(block);
|
|
CompilerError.invariant(target !== null, {
|
|
reason: `Expected continue target to be scheduled for bb${block}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
return {
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'continue',
|
|
loc,
|
|
target: target.block,
|
|
id,
|
|
targetKind: target.type,
|
|
},
|
|
label: null,
|
|
};
|
|
}
|
|
}
|
|
let Context$2 = class Context {
|
|
constructor(ir) {
|
|
_Context_nextScheduleId.set(this, 0);
|
|
this.emitted = new Set();
|
|
this.scopeFallthroughs = new Set();
|
|
_Context_scheduled.set(this, new Set());
|
|
_Context_catchHandlers.set(this, new Set());
|
|
_Context_controlFlowStack.set(this, []);
|
|
this.ir = ir;
|
|
}
|
|
block(id) {
|
|
return this.ir.blocks.get(id);
|
|
}
|
|
scheduleCatchHandler(block) {
|
|
__classPrivateFieldGet(this, _Context_catchHandlers, "f").add(block);
|
|
}
|
|
reachable(id) {
|
|
const block = this.ir.blocks.get(id);
|
|
return block.terminal.kind !== 'unreachable';
|
|
}
|
|
schedule(block, type) {
|
|
var _a, _b;
|
|
const id = (__classPrivateFieldSet(this, _Context_nextScheduleId, (_b = __classPrivateFieldGet(this, _Context_nextScheduleId, "f"), _a = _b++, _b), "f"), _a);
|
|
CompilerError.invariant(!__classPrivateFieldGet(this, _Context_scheduled, "f").has(block), {
|
|
reason: `Break block is already scheduled: bb${block}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
__classPrivateFieldGet(this, _Context_scheduled, "f").add(block);
|
|
__classPrivateFieldGet(this, _Context_controlFlowStack, "f").push({ block, id, type });
|
|
return id;
|
|
}
|
|
scheduleLoop(fallthroughBlock, continueBlock, loopBlock) {
|
|
var _a, _b;
|
|
const id = (__classPrivateFieldSet(this, _Context_nextScheduleId, (_b = __classPrivateFieldGet(this, _Context_nextScheduleId, "f"), _a = _b++, _b), "f"), _a);
|
|
const ownsBlock = !__classPrivateFieldGet(this, _Context_scheduled, "f").has(fallthroughBlock);
|
|
__classPrivateFieldGet(this, _Context_scheduled, "f").add(fallthroughBlock);
|
|
CompilerError.invariant(!__classPrivateFieldGet(this, _Context_scheduled, "f").has(continueBlock), {
|
|
reason: `Continue block is already scheduled: bb${continueBlock}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
__classPrivateFieldGet(this, _Context_scheduled, "f").add(continueBlock);
|
|
let ownsLoop = false;
|
|
if (loopBlock !== null) {
|
|
ownsLoop = !__classPrivateFieldGet(this, _Context_scheduled, "f").has(loopBlock);
|
|
__classPrivateFieldGet(this, _Context_scheduled, "f").add(loopBlock);
|
|
}
|
|
__classPrivateFieldGet(this, _Context_controlFlowStack, "f").push({
|
|
block: fallthroughBlock,
|
|
ownsBlock,
|
|
id,
|
|
type: 'loop',
|
|
continueBlock,
|
|
loopBlock,
|
|
ownsLoop,
|
|
});
|
|
return id;
|
|
}
|
|
unschedule(scheduleId) {
|
|
const last = __classPrivateFieldGet(this, _Context_controlFlowStack, "f").pop();
|
|
CompilerError.invariant(last !== undefined && last.id === scheduleId, {
|
|
reason: 'Can only unschedule the last target',
|
|
loc: GeneratedSource,
|
|
});
|
|
if (last.type !== 'loop' || last.ownsBlock !== null) {
|
|
__classPrivateFieldGet(this, _Context_scheduled, "f").delete(last.block);
|
|
}
|
|
if (last.type === 'loop') {
|
|
__classPrivateFieldGet(this, _Context_scheduled, "f").delete(last.continueBlock);
|
|
if (last.ownsLoop && last.loopBlock !== null) {
|
|
__classPrivateFieldGet(this, _Context_scheduled, "f").delete(last.loopBlock);
|
|
}
|
|
}
|
|
}
|
|
unscheduleAll(scheduleIds) {
|
|
for (let i = scheduleIds.length - 1; i >= 0; i--) {
|
|
this.unschedule(scheduleIds[i]);
|
|
}
|
|
}
|
|
isScheduled(block) {
|
|
return __classPrivateFieldGet(this, _Context_scheduled, "f").has(block) || __classPrivateFieldGet(this, _Context_catchHandlers, "f").has(block);
|
|
}
|
|
getBreakTarget(block) {
|
|
let hasPrecedingLoop = false;
|
|
for (let i = __classPrivateFieldGet(this, _Context_controlFlowStack, "f").length - 1; i >= 0; i--) {
|
|
const target = __classPrivateFieldGet(this, _Context_controlFlowStack, "f")[i];
|
|
if (target.block === block) {
|
|
let type;
|
|
if (target.type === 'loop') {
|
|
type = hasPrecedingLoop ? 'labeled' : 'unlabeled';
|
|
}
|
|
else if (i === __classPrivateFieldGet(this, _Context_controlFlowStack, "f").length - 1) {
|
|
type = 'implicit';
|
|
}
|
|
else {
|
|
type = 'labeled';
|
|
}
|
|
return {
|
|
block: target.block,
|
|
type,
|
|
};
|
|
}
|
|
hasPrecedingLoop || (hasPrecedingLoop = target.type === 'loop');
|
|
}
|
|
CompilerError.invariant(false, {
|
|
reason: 'Expected a break target',
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
getContinueTarget(block) {
|
|
let hasPrecedingLoop = false;
|
|
for (let i = __classPrivateFieldGet(this, _Context_controlFlowStack, "f").length - 1; i >= 0; i--) {
|
|
const target = __classPrivateFieldGet(this, _Context_controlFlowStack, "f")[i];
|
|
if (target.type == 'loop' && target.continueBlock === block) {
|
|
let type;
|
|
if (hasPrecedingLoop) {
|
|
type = 'labeled';
|
|
}
|
|
else if (i === __classPrivateFieldGet(this, _Context_controlFlowStack, "f").length - 1) {
|
|
type = 'implicit';
|
|
}
|
|
else {
|
|
type = 'unlabeled';
|
|
}
|
|
return {
|
|
block: target.block,
|
|
type,
|
|
};
|
|
}
|
|
hasPrecedingLoop || (hasPrecedingLoop = target.type === 'loop');
|
|
}
|
|
return null;
|
|
}
|
|
debugBreakTargets() {
|
|
return __classPrivateFieldGet(this, _Context_controlFlowStack, "f").map(target => (Object.assign({}, target)));
|
|
}
|
|
};
|
|
_Context_nextScheduleId = new WeakMap(), _Context_scheduled = new WeakMap(), _Context_catchHandlers = new WeakMap(), _Context_controlFlowStack = new WeakMap();
|
|
|
|
var GuardKind;
|
|
(function (GuardKind) {
|
|
GuardKind[GuardKind["PushHookGuard"] = 0] = "PushHookGuard";
|
|
GuardKind[GuardKind["PopHookGuard"] = 1] = "PopHookGuard";
|
|
GuardKind[GuardKind["AllowHook"] = 2] = "AllowHook";
|
|
GuardKind[GuardKind["DisallowHook"] = 3] = "DisallowHook";
|
|
})(GuardKind || (GuardKind = {}));
|
|
|
|
var InlineLevel;
|
|
(function (InlineLevel) {
|
|
InlineLevel["Transitive"] = "Transitive";
|
|
InlineLevel["Shallow"] = "Shallow";
|
|
})(InlineLevel || (InlineLevel = {}));
|
|
const SHALLOW_MACRO = {
|
|
level: InlineLevel.Shallow,
|
|
properties: null,
|
|
};
|
|
const TRANSITIVE_MACRO = {
|
|
level: InlineLevel.Transitive,
|
|
properties: null,
|
|
};
|
|
const FBT_MACRO = {
|
|
level: InlineLevel.Transitive,
|
|
properties: new Map([['*', SHALLOW_MACRO]]),
|
|
};
|
|
FBT_MACRO.properties.set('enum', FBT_MACRO);
|
|
function memoizeFbtAndMacroOperandsInSameScope(fn) {
|
|
var _a;
|
|
const macroKinds = new Map([
|
|
...Array.from(FBT_TAGS.entries()),
|
|
...((_a = fn.env.config.customMacros) !== null && _a !== void 0 ? _a : []).map(name => [name, TRANSITIVE_MACRO]),
|
|
]);
|
|
const macroTags = populateMacroTags(fn, macroKinds);
|
|
const macroValues = mergeMacroArguments(fn, macroTags, macroKinds);
|
|
return macroValues;
|
|
}
|
|
const FBT_TAGS = new Map([
|
|
['fbt', FBT_MACRO],
|
|
['fbt:param', SHALLOW_MACRO],
|
|
['fbt:enum', FBT_MACRO],
|
|
['fbt:plural', SHALLOW_MACRO],
|
|
['fbs', FBT_MACRO],
|
|
['fbs:param', SHALLOW_MACRO],
|
|
['fbs:enum', FBT_MACRO],
|
|
['fbs:plural', SHALLOW_MACRO],
|
|
]);
|
|
const SINGLE_CHILD_FBT_TAGS = new Set([
|
|
'fbt:param',
|
|
'fbs:param',
|
|
]);
|
|
function populateMacroTags(fn, macroKinds) {
|
|
var _a;
|
|
const macroTags = new Map();
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
switch (value.kind) {
|
|
case 'Primitive': {
|
|
if (typeof value.value === 'string') {
|
|
const macroDefinition = macroKinds.get(value.value);
|
|
if (macroDefinition != null) {
|
|
macroTags.set(lvalue.identifier.id, macroDefinition);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'LoadGlobal': {
|
|
let macroDefinition = macroKinds.get(value.binding.name);
|
|
if (macroDefinition != null) {
|
|
macroTags.set(lvalue.identifier.id, macroDefinition);
|
|
}
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
if (typeof value.property === 'string') {
|
|
const macroDefinition = macroTags.get(value.object.identifier.id);
|
|
if (macroDefinition != null) {
|
|
const propertyDefinition = macroDefinition.properties != null
|
|
? ((_a = macroDefinition.properties.get(value.property)) !== null && _a !== void 0 ? _a : macroDefinition.properties.get('*'))
|
|
: null;
|
|
const propertyMacro = propertyDefinition !== null && propertyDefinition !== void 0 ? propertyDefinition : macroDefinition;
|
|
macroTags.set(lvalue.identifier.id, propertyMacro);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return macroTags;
|
|
}
|
|
function mergeMacroArguments(fn, macroTags, macroKinds) {
|
|
var _a;
|
|
const macroValues = new Set(macroTags.keys());
|
|
for (const block of Array.from(fn.body.blocks.values()).reverse()) {
|
|
for (let i = block.instructions.length - 1; i >= 0; i--) {
|
|
const instr = block.instructions[i];
|
|
const { lvalue, value } = instr;
|
|
switch (value.kind) {
|
|
case 'DeclareContext':
|
|
case 'DeclareLocal':
|
|
case 'Destructure':
|
|
case 'LoadContext':
|
|
case 'LoadLocal':
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate':
|
|
case 'StoreContext':
|
|
case 'StoreLocal': {
|
|
break;
|
|
}
|
|
case 'CallExpression':
|
|
case 'MethodCall': {
|
|
const scope = lvalue.identifier.scope;
|
|
if (scope == null) {
|
|
continue;
|
|
}
|
|
const callee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
const macroDefinition = (_a = macroTags.get(callee.identifier.id)) !== null && _a !== void 0 ? _a : macroTags.get(lvalue.identifier.id);
|
|
if (macroDefinition != null) {
|
|
visitOperands(macroDefinition, scope, lvalue, value, macroValues, macroTags);
|
|
}
|
|
break;
|
|
}
|
|
case 'JsxExpression': {
|
|
const scope = lvalue.identifier.scope;
|
|
if (scope == null) {
|
|
continue;
|
|
}
|
|
let macroDefinition;
|
|
if (value.tag.kind === 'Identifier') {
|
|
macroDefinition = macroTags.get(value.tag.identifier.id);
|
|
}
|
|
else {
|
|
macroDefinition = macroKinds.get(value.tag.name);
|
|
}
|
|
macroDefinition !== null && macroDefinition !== void 0 ? macroDefinition : (macroDefinition = macroTags.get(lvalue.identifier.id));
|
|
if (macroDefinition != null) {
|
|
visitOperands(macroDefinition, scope, lvalue, value, macroValues, macroTags);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
const scope = lvalue.identifier.scope;
|
|
if (scope == null) {
|
|
continue;
|
|
}
|
|
const macroDefinition = macroTags.get(lvalue.identifier.id);
|
|
if (macroDefinition != null) {
|
|
visitOperands(macroDefinition, scope, lvalue, value, macroValues, macroTags);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for (const phi of block.phis) {
|
|
const scope = phi.place.identifier.scope;
|
|
if (scope == null) {
|
|
continue;
|
|
}
|
|
const macroDefinition = macroTags.get(phi.place.identifier.id);
|
|
if (macroDefinition == null ||
|
|
macroDefinition.level === InlineLevel.Shallow) {
|
|
continue;
|
|
}
|
|
macroValues.add(phi.place.identifier.id);
|
|
for (const operand of phi.operands.values()) {
|
|
operand.identifier.scope = scope;
|
|
expandFbtScopeRange(scope.range, operand.identifier.mutableRange);
|
|
macroTags.set(operand.identifier.id, macroDefinition);
|
|
macroValues.add(operand.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
return macroValues;
|
|
}
|
|
function expandFbtScopeRange(fbtRange, extendWith) {
|
|
if (extendWith.start !== 0) {
|
|
fbtRange.start = makeInstructionId(Math.min(fbtRange.start, extendWith.start));
|
|
}
|
|
}
|
|
function visitOperands(macroDefinition, scope, lvalue, value, macroValues, macroTags) {
|
|
macroValues.add(lvalue.identifier.id);
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
if (macroDefinition.level === InlineLevel.Transitive) {
|
|
operand.identifier.scope = scope;
|
|
expandFbtScopeRange(scope.range, operand.identifier.mutableRange);
|
|
macroTags.set(operand.identifier.id, macroDefinition);
|
|
}
|
|
macroValues.add(operand.identifier.id);
|
|
}
|
|
}
|
|
|
|
var _Context_nextCacheIndex, _Context_declarations;
|
|
const MEMO_CACHE_SENTINEL = 'react.memo_cache_sentinel';
|
|
const EARLY_RETURN_SENTINEL = 'react.early_return_sentinel';
|
|
function codegenFunction(fn, { uniqueIdentifiers, fbtOperands, }) {
|
|
var _a, _b, _c;
|
|
const cx = new Context$1(fn.env, (_a = fn.id) !== null && _a !== void 0 ? _a : '[[ anonymous ]]', uniqueIdentifiers, fbtOperands, null);
|
|
let fastRefreshState = null;
|
|
if (fn.env.config.enableResetCacheOnSourceFileChanges &&
|
|
fn.env.code !== null) {
|
|
const hash = crypto.createHmac('sha256', fn.env.code).digest('hex');
|
|
fastRefreshState = {
|
|
cacheIndex: cx.nextCacheIndex,
|
|
hash,
|
|
};
|
|
}
|
|
const compiled = codegenReactiveFunction(cx, fn);
|
|
const hookGuard = fn.env.config.enableEmitHookGuards;
|
|
if (hookGuard != null && fn.env.outputMode === 'client') {
|
|
compiled.body = libExports$1.blockStatement([
|
|
createHookGuard(hookGuard, fn.env.programContext, compiled.body.body, GuardKind.PushHookGuard, GuardKind.PopHookGuard),
|
|
]);
|
|
}
|
|
const cacheCount = compiled.memoSlotsUsed;
|
|
if (cacheCount !== 0) {
|
|
const preface = [];
|
|
const useMemoCacheIdentifier = fn.env.programContext.addMemoCacheImport().name;
|
|
preface.push(libExports$1.variableDeclaration('const', [
|
|
libExports$1.variableDeclarator(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.callExpression(libExports$1.identifier(useMemoCacheIdentifier), [
|
|
libExports$1.numericLiteral(cacheCount),
|
|
])),
|
|
]));
|
|
if (fastRefreshState !== null) {
|
|
const index = cx.synthesizeName('$i');
|
|
preface.push(libExports$1.ifStatement(libExports$1.binaryExpression('!==', libExports$1.memberExpression(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.numericLiteral(fastRefreshState.cacheIndex), true), libExports$1.stringLiteral(fastRefreshState.hash)), libExports$1.blockStatement([
|
|
libExports$1.forStatement(libExports$1.variableDeclaration('let', [
|
|
libExports$1.variableDeclarator(libExports$1.identifier(index), libExports$1.numericLiteral(0)),
|
|
]), libExports$1.binaryExpression('<', libExports$1.identifier(index), libExports$1.numericLiteral(cacheCount)), libExports$1.assignmentExpression('+=', libExports$1.identifier(index), libExports$1.numericLiteral(1)), libExports$1.blockStatement([
|
|
libExports$1.expressionStatement(libExports$1.assignmentExpression('=', libExports$1.memberExpression(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.identifier(index), true), libExports$1.callExpression(libExports$1.memberExpression(libExports$1.identifier('Symbol'), libExports$1.identifier('for')), [libExports$1.stringLiteral(MEMO_CACHE_SENTINEL)]))),
|
|
])),
|
|
libExports$1.expressionStatement(libExports$1.assignmentExpression('=', libExports$1.memberExpression(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.numericLiteral(fastRefreshState.cacheIndex), true), libExports$1.stringLiteral(fastRefreshState.hash))),
|
|
])));
|
|
}
|
|
compiled.body.body.unshift(...preface);
|
|
}
|
|
const emitInstrumentForget = fn.env.config.enableEmitInstrumentForget;
|
|
if (emitInstrumentForget != null &&
|
|
fn.id != null &&
|
|
fn.env.outputMode === 'client') {
|
|
const gating = emitInstrumentForget.gating != null
|
|
? libExports$1.identifier(fn.env.programContext.addImportSpecifier(emitInstrumentForget.gating).name)
|
|
: null;
|
|
const globalGating = emitInstrumentForget.globalGating != null
|
|
? libExports$1.identifier(emitInstrumentForget.globalGating)
|
|
: null;
|
|
if (emitInstrumentForget.globalGating != null) {
|
|
const assertResult = fn.env.programContext.assertGlobalBinding(emitInstrumentForget.globalGating);
|
|
if (assertResult.isErr()) {
|
|
fn.env.recordErrors(assertResult.unwrapErr());
|
|
}
|
|
}
|
|
let ifTest;
|
|
if (gating != null && globalGating != null) {
|
|
ifTest = libExports$1.logicalExpression('&&', globalGating, gating);
|
|
}
|
|
else if (gating != null) {
|
|
ifTest = gating;
|
|
}
|
|
else {
|
|
CompilerError.invariant(globalGating != null, {
|
|
reason: 'Bad config not caught! Expected at least one of gating or globalGating',
|
|
loc: GeneratedSource,
|
|
});
|
|
ifTest = globalGating;
|
|
}
|
|
const instrumentFnIdentifier = fn.env.programContext.addImportSpecifier(emitInstrumentForget.fn).name;
|
|
const test = libExports$1.ifStatement(ifTest, libExports$1.expressionStatement(libExports$1.callExpression(libExports$1.identifier(instrumentFnIdentifier), [
|
|
libExports$1.stringLiteral(fn.id),
|
|
libExports$1.stringLiteral((_b = fn.env.filename) !== null && _b !== void 0 ? _b : ''),
|
|
])));
|
|
compiled.body.body.unshift(test);
|
|
}
|
|
const outlined = [];
|
|
for (const { fn: outlinedFunction, type } of cx.env.getOutlinedFunctions()) {
|
|
const reactiveFunction = buildReactiveFunction(outlinedFunction);
|
|
pruneUnusedLabels(reactiveFunction);
|
|
pruneUnusedLValues(reactiveFunction);
|
|
pruneHoistedContexts(reactiveFunction);
|
|
const identifiers = renameVariables(reactiveFunction);
|
|
const codegen = codegenReactiveFunction(new Context$1(cx.env, (_c = reactiveFunction.id) !== null && _c !== void 0 ? _c : '[[ anonymous ]]', identifiers, cx.fbtOperands), reactiveFunction);
|
|
outlined.push({ fn: codegen, type });
|
|
}
|
|
compiled.outlined = outlined;
|
|
return compiled;
|
|
}
|
|
function codegenReactiveFunction(cx, fn) {
|
|
for (const param of fn.params) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
cx.temp.set(place.identifier.declarationId, null);
|
|
cx.declare(place.identifier);
|
|
}
|
|
const params = fn.params.map(param => convertParameter(param));
|
|
const body = codegenBlock(cx, fn.body);
|
|
body.directives = fn.directives.map(d => libExports$1.directive(libExports$1.directiveLiteral(d)));
|
|
const statements = body.body;
|
|
if (statements.length !== 0) {
|
|
const last = statements[statements.length - 1];
|
|
if (last.type === 'ReturnStatement' && last.argument == null) {
|
|
statements.pop();
|
|
}
|
|
}
|
|
const countMemoBlockVisitor = new CountMemoBlockVisitor(fn.env);
|
|
visitReactiveFunction(fn, countMemoBlockVisitor, undefined);
|
|
return {
|
|
type: 'CodegenFunction',
|
|
loc: fn.loc,
|
|
id: fn.id !== null ? libExports$1.identifier(fn.id) : null,
|
|
nameHint: fn.nameHint,
|
|
params,
|
|
body,
|
|
generator: fn.generator,
|
|
async: fn.async,
|
|
memoSlotsUsed: cx.nextCacheIndex,
|
|
memoBlocks: countMemoBlockVisitor.memoBlocks,
|
|
memoValues: countMemoBlockVisitor.memoValues,
|
|
prunedMemoBlocks: countMemoBlockVisitor.prunedMemoBlocks,
|
|
prunedMemoValues: countMemoBlockVisitor.prunedMemoValues,
|
|
outlined: [],
|
|
};
|
|
}
|
|
class CountMemoBlockVisitor extends ReactiveFunctionVisitor {
|
|
constructor(env) {
|
|
super();
|
|
this.memoBlocks = 0;
|
|
this.memoValues = 0;
|
|
this.prunedMemoBlocks = 0;
|
|
this.prunedMemoValues = 0;
|
|
this.env = env;
|
|
}
|
|
visitScope(scopeBlock, state) {
|
|
this.memoBlocks += 1;
|
|
this.memoValues += scopeBlock.scope.declarations.size;
|
|
this.traverseScope(scopeBlock, state);
|
|
}
|
|
visitPrunedScope(scopeBlock, state) {
|
|
this.prunedMemoBlocks += 1;
|
|
this.prunedMemoValues += scopeBlock.scope.declarations.size;
|
|
this.traversePrunedScope(scopeBlock, state);
|
|
}
|
|
}
|
|
function convertParameter(param) {
|
|
if (param.kind === 'Identifier') {
|
|
return convertIdentifier(param.identifier);
|
|
}
|
|
else {
|
|
return libExports$1.restElement(convertIdentifier(param.place.identifier));
|
|
}
|
|
}
|
|
let Context$1 = class Context {
|
|
constructor(env, fnName, uniqueIdentifiers, fbtOperands, temporaries = null) {
|
|
_Context_nextCacheIndex.set(this, 0);
|
|
_Context_declarations.set(this, new Set());
|
|
this.objectMethods = new Map();
|
|
this.synthesizedNames = new Map();
|
|
this.env = env;
|
|
this.fnName = fnName;
|
|
this.uniqueIdentifiers = uniqueIdentifiers;
|
|
this.fbtOperands = fbtOperands;
|
|
this.temp = temporaries !== null ? new Map(temporaries) : new Map();
|
|
}
|
|
recordError(error) {
|
|
this.env.recordError(error);
|
|
}
|
|
get nextCacheIndex() {
|
|
var _a, _b;
|
|
return __classPrivateFieldSet(this, _Context_nextCacheIndex, (_b = __classPrivateFieldGet(this, _Context_nextCacheIndex, "f"), _a = _b++, _b), "f"), _a;
|
|
}
|
|
declare(identifier) {
|
|
__classPrivateFieldGet(this, _Context_declarations, "f").add(identifier.declarationId);
|
|
}
|
|
hasDeclared(identifier) {
|
|
return __classPrivateFieldGet(this, _Context_declarations, "f").has(identifier.declarationId);
|
|
}
|
|
synthesizeName(name) {
|
|
const previous = this.synthesizedNames.get(name);
|
|
if (previous !== undefined) {
|
|
return previous;
|
|
}
|
|
let validated = makeIdentifierName(name).value;
|
|
let index = 0;
|
|
while (this.uniqueIdentifiers.has(validated)) {
|
|
validated = makeIdentifierName(`${name}${index++}`).value;
|
|
}
|
|
this.uniqueIdentifiers.add(validated);
|
|
this.synthesizedNames.set(name, validated);
|
|
return validated;
|
|
}
|
|
};
|
|
_Context_nextCacheIndex = new WeakMap(), _Context_declarations = new WeakMap();
|
|
function codegenBlock(cx, block) {
|
|
const temp = new Map(cx.temp);
|
|
const result = codegenBlockNoReset(cx, block);
|
|
for (const [key, value] of cx.temp) {
|
|
if (!temp.has(key)) {
|
|
continue;
|
|
}
|
|
CompilerError.invariant(temp.get(key) === value, {
|
|
reason: 'Expected temporary value to be unchanged',
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
cx.temp = temp;
|
|
return result;
|
|
}
|
|
function codegenBlockNoReset(cx, block) {
|
|
const statements = [];
|
|
for (const item of block) {
|
|
switch (item.kind) {
|
|
case 'instruction': {
|
|
const statement = codegenInstructionNullable(cx, item.instruction);
|
|
if (statement !== null) {
|
|
statements.push(statement);
|
|
}
|
|
break;
|
|
}
|
|
case 'pruned-scope': {
|
|
const scopeBlock = codegenBlockNoReset(cx, item.instructions);
|
|
statements.push(...scopeBlock.body);
|
|
break;
|
|
}
|
|
case 'scope': {
|
|
const temp = new Map(cx.temp);
|
|
codegenReactiveScope(cx, statements, item.scope, item.instructions);
|
|
cx.temp = temp;
|
|
break;
|
|
}
|
|
case 'terminal': {
|
|
const statement = codegenTerminal(cx, item.terminal);
|
|
if (statement === null) {
|
|
break;
|
|
}
|
|
if (item.label !== null && !item.label.implicit) {
|
|
const block = statement.type === 'BlockStatement' && statement.body.length === 1
|
|
? statement.body[0]
|
|
: statement;
|
|
statements.push(libExports$1.labeledStatement(libExports$1.identifier(codegenLabel(item.label.id)), block));
|
|
}
|
|
else if (statement.type === 'BlockStatement') {
|
|
statements.push(...statement.body);
|
|
}
|
|
else {
|
|
statements.push(statement);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(item, `Unexpected item kind \`${item.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
return libExports$1.blockStatement(statements);
|
|
}
|
|
function codegenReactiveScope(cx, statements, scope, block) {
|
|
const cacheStoreStatements = [];
|
|
const cacheLoadStatements = [];
|
|
const cacheLoads = [];
|
|
const changeExpressions = [];
|
|
for (const dep of [...scope.dependencies].sort(compareScopeDependency)) {
|
|
const index = cx.nextCacheIndex;
|
|
const comparison = libExports$1.binaryExpression('!==', libExports$1.memberExpression(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.numericLiteral(index), true), codegenDependency(cx, dep));
|
|
changeExpressions.push(comparison);
|
|
cacheStoreStatements.push(libExports$1.expressionStatement(libExports$1.assignmentExpression('=', libExports$1.memberExpression(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.numericLiteral(index), true), codegenDependency(cx, dep))));
|
|
}
|
|
let firstOutputIndex = null;
|
|
for (const [, { identifier }] of [...scope.declarations].sort(([, a], [, b]) => compareScopeDeclaration(a, b))) {
|
|
const index = cx.nextCacheIndex;
|
|
if (firstOutputIndex === null) {
|
|
firstOutputIndex = index;
|
|
}
|
|
CompilerError.invariant(identifier.name != null, {
|
|
reason: `Expected scope declaration identifier to be named`,
|
|
description: `Declaration \`${printIdentifier(identifier)}\` is unnamed in scope @${scope.id}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
const name = convertIdentifier(identifier);
|
|
if (!cx.hasDeclared(identifier)) {
|
|
statements.push(libExports$1.variableDeclaration('let', [createVariableDeclarator(name, null)]));
|
|
}
|
|
cacheLoads.push({ name, index, value: name });
|
|
cx.declare(identifier);
|
|
}
|
|
for (const reassignment of scope.reassignments) {
|
|
const index = cx.nextCacheIndex;
|
|
if (firstOutputIndex === null) {
|
|
firstOutputIndex = index;
|
|
}
|
|
const name = convertIdentifier(reassignment);
|
|
cacheLoads.push({ name, index, value: name });
|
|
}
|
|
let testCondition = changeExpressions.reduce((acc, ident) => {
|
|
if (acc == null) {
|
|
return ident;
|
|
}
|
|
return libExports$1.logicalExpression('||', acc, ident);
|
|
}, null);
|
|
if (testCondition === null) {
|
|
CompilerError.invariant(firstOutputIndex !== null, {
|
|
reason: `Expected scope to have at least one declaration`,
|
|
description: `Scope '@${scope.id}' has no declarations`,
|
|
loc: GeneratedSource,
|
|
});
|
|
testCondition = libExports$1.binaryExpression('===', libExports$1.memberExpression(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.numericLiteral(firstOutputIndex), true), libExports$1.callExpression(libExports$1.memberExpression(libExports$1.identifier('Symbol'), libExports$1.identifier('for')), [libExports$1.stringLiteral(MEMO_CACHE_SENTINEL)]));
|
|
}
|
|
let computationBlock = codegenBlock(cx, block);
|
|
let memoStatement;
|
|
for (const { name, index, value } of cacheLoads) {
|
|
cacheStoreStatements.push(libExports$1.expressionStatement(libExports$1.assignmentExpression('=', libExports$1.memberExpression(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.numericLiteral(index), true), value)));
|
|
cacheLoadStatements.push(libExports$1.expressionStatement(libExports$1.assignmentExpression('=', name, libExports$1.memberExpression(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.numericLiteral(index), true))));
|
|
}
|
|
computationBlock.body.push(...cacheStoreStatements);
|
|
memoStatement = libExports$1.ifStatement(testCondition, computationBlock, libExports$1.blockStatement(cacheLoadStatements));
|
|
statements.push(memoStatement);
|
|
const earlyReturnValue = scope.earlyReturnValue;
|
|
if (earlyReturnValue !== null) {
|
|
CompilerError.invariant(earlyReturnValue.value.name !== null &&
|
|
earlyReturnValue.value.name.kind === 'named', {
|
|
reason: `Expected early return value to be promoted to a named variable`,
|
|
loc: earlyReturnValue.loc,
|
|
});
|
|
const name = earlyReturnValue.value.name.value;
|
|
statements.push(libExports$1.ifStatement(libExports$1.binaryExpression('!==', libExports$1.identifier(name), libExports$1.callExpression(libExports$1.memberExpression(libExports$1.identifier('Symbol'), libExports$1.identifier('for')), [libExports$1.stringLiteral(EARLY_RETURN_SENTINEL)])), libExports$1.blockStatement([libExports$1.returnStatement(libExports$1.identifier(name))])));
|
|
}
|
|
}
|
|
function codegenTerminal(cx, terminal) {
|
|
switch (terminal.kind) {
|
|
case 'break': {
|
|
if (terminal.targetKind === 'implicit') {
|
|
return null;
|
|
}
|
|
return createBreakStatement(terminal.loc, terminal.targetKind === 'labeled'
|
|
? libExports$1.identifier(codegenLabel(terminal.target))
|
|
: null);
|
|
}
|
|
case 'continue': {
|
|
if (terminal.targetKind === 'implicit') {
|
|
return null;
|
|
}
|
|
return createContinueStatement(terminal.loc, terminal.targetKind === 'labeled'
|
|
? libExports$1.identifier(codegenLabel(terminal.target))
|
|
: null);
|
|
}
|
|
case 'for': {
|
|
return createForStatement(terminal.loc, codegenForInit(cx, terminal.init), codegenInstructionValueToExpression(cx, terminal.test), terminal.update !== null
|
|
? codegenInstructionValueToExpression(cx, terminal.update)
|
|
: null, codegenBlock(cx, terminal.loop));
|
|
}
|
|
case 'for-in': {
|
|
CompilerError.invariant(terminal.init.kind === 'SequenceExpression', {
|
|
reason: `Expected a sequence expression init for for..in`,
|
|
description: `Got \`${terminal.init.kind}\` expression instead`,
|
|
loc: terminal.init.loc,
|
|
});
|
|
if (terminal.init.instructions.length !== 2) {
|
|
cx.recordError(new CompilerErrorDetail({
|
|
reason: 'Support non-trivial for..in inits',
|
|
category: ErrorCategory.Todo,
|
|
loc: terminal.init.loc,
|
|
suggestions: null,
|
|
}));
|
|
return libExports$1.emptyStatement();
|
|
}
|
|
const iterableCollection = terminal.init.instructions[0];
|
|
const iterableItem = terminal.init.instructions[1];
|
|
let lval;
|
|
switch (iterableItem.value.kind) {
|
|
case 'StoreLocal': {
|
|
lval = codegenLValue(cx, iterableItem.value.lvalue.place);
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
lval = codegenLValue(cx, iterableItem.value.lvalue.pattern);
|
|
break;
|
|
}
|
|
case 'StoreContext': {
|
|
cx.recordError(new CompilerErrorDetail({
|
|
reason: 'Support non-trivial for..in inits',
|
|
category: ErrorCategory.Todo,
|
|
loc: terminal.init.loc,
|
|
suggestions: null,
|
|
}));
|
|
return libExports$1.emptyStatement();
|
|
}
|
|
default:
|
|
CompilerError.invariant(false, {
|
|
reason: `Expected a StoreLocal or Destructure to be assigned to the collection`,
|
|
description: `Found ${iterableItem.value.kind}`,
|
|
loc: iterableItem.value.loc,
|
|
});
|
|
}
|
|
let varDeclKind;
|
|
switch (iterableItem.value.lvalue.kind) {
|
|
case InstructionKind.Const:
|
|
varDeclKind = 'const';
|
|
break;
|
|
case InstructionKind.Let:
|
|
varDeclKind = 'let';
|
|
break;
|
|
case InstructionKind.Reassign:
|
|
CompilerError.invariant(false, {
|
|
reason: 'Destructure should never be Reassign as it would be an Object/ArrayPattern',
|
|
loc: iterableItem.loc,
|
|
});
|
|
case InstructionKind.Catch:
|
|
case InstructionKind.HoistedConst:
|
|
case InstructionKind.HoistedLet:
|
|
case InstructionKind.HoistedFunction:
|
|
case InstructionKind.Function:
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected ${iterableItem.value.lvalue.kind} variable in for..in collection`,
|
|
loc: iterableItem.loc,
|
|
});
|
|
default:
|
|
assertExhaustive$1(iterableItem.value.lvalue.kind, `Unhandled lvalue kind: ${iterableItem.value.lvalue.kind}`);
|
|
}
|
|
return createForInStatement(terminal.loc, createVariableDeclaration(iterableItem.value.loc, varDeclKind, [
|
|
libExports$1.variableDeclarator(lval, null),
|
|
]), codegenInstructionValueToExpression(cx, iterableCollection.value), codegenBlock(cx, terminal.loop));
|
|
}
|
|
case 'for-of': {
|
|
CompilerError.invariant(terminal.init.kind === 'SequenceExpression' &&
|
|
terminal.init.instructions.length === 1 &&
|
|
terminal.init.instructions[0].value.kind === 'GetIterator', {
|
|
reason: `Expected a single-expression sequence expression init for for..of`,
|
|
description: `Got \`${terminal.init.kind}\` expression instead`,
|
|
loc: terminal.init.loc,
|
|
});
|
|
const iterableCollection = terminal.init.instructions[0].value;
|
|
CompilerError.invariant(terminal.test.kind === 'SequenceExpression', {
|
|
reason: `Expected a sequence expression test for for..of`,
|
|
description: `Got \`${terminal.init.kind}\` expression instead`,
|
|
loc: terminal.test.loc,
|
|
});
|
|
if (terminal.test.instructions.length !== 2) {
|
|
cx.recordError(new CompilerErrorDetail({
|
|
reason: 'Support non-trivial for..of inits',
|
|
category: ErrorCategory.Todo,
|
|
loc: terminal.init.loc,
|
|
suggestions: null,
|
|
}));
|
|
return libExports$1.emptyStatement();
|
|
}
|
|
const iterableItem = terminal.test.instructions[1];
|
|
let lval;
|
|
switch (iterableItem.value.kind) {
|
|
case 'StoreLocal': {
|
|
lval = codegenLValue(cx, iterableItem.value.lvalue.place);
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
lval = codegenLValue(cx, iterableItem.value.lvalue.pattern);
|
|
break;
|
|
}
|
|
case 'StoreContext': {
|
|
cx.recordError(new CompilerErrorDetail({
|
|
reason: 'Support non-trivial for..of inits',
|
|
category: ErrorCategory.Todo,
|
|
loc: terminal.init.loc,
|
|
suggestions: null,
|
|
}));
|
|
return libExports$1.emptyStatement();
|
|
}
|
|
default:
|
|
CompilerError.invariant(false, {
|
|
reason: `Expected a StoreLocal or Destructure to be assigned to the collection`,
|
|
description: `Found ${iterableItem.value.kind}`,
|
|
loc: iterableItem.value.loc,
|
|
});
|
|
}
|
|
let varDeclKind;
|
|
switch (iterableItem.value.lvalue.kind) {
|
|
case InstructionKind.Const:
|
|
varDeclKind = 'const';
|
|
break;
|
|
case InstructionKind.Let:
|
|
varDeclKind = 'let';
|
|
break;
|
|
case InstructionKind.Reassign:
|
|
case InstructionKind.Catch:
|
|
case InstructionKind.HoistedConst:
|
|
case InstructionKind.HoistedLet:
|
|
case InstructionKind.HoistedFunction:
|
|
case InstructionKind.Function:
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected ${iterableItem.value.lvalue.kind} variable in for..of collection`,
|
|
loc: iterableItem.loc,
|
|
});
|
|
default:
|
|
assertExhaustive$1(iterableItem.value.lvalue.kind, `Unhandled lvalue kind: ${iterableItem.value.lvalue.kind}`);
|
|
}
|
|
return createForOfStatement(terminal.loc, createVariableDeclaration(iterableItem.value.loc, varDeclKind, [
|
|
libExports$1.variableDeclarator(lval, null),
|
|
]), codegenInstructionValueToExpression(cx, iterableCollection), codegenBlock(cx, terminal.loop));
|
|
}
|
|
case 'if': {
|
|
const test = codegenPlaceToExpression(cx, terminal.test);
|
|
const consequent = codegenBlock(cx, terminal.consequent);
|
|
let alternate = null;
|
|
if (terminal.alternate !== null) {
|
|
const block = codegenBlock(cx, terminal.alternate);
|
|
if (block.body.length !== 0) {
|
|
alternate = block;
|
|
}
|
|
}
|
|
return createIfStatement(terminal.loc, test, consequent, alternate);
|
|
}
|
|
case 'return': {
|
|
const value = codegenPlaceToExpression(cx, terminal.value);
|
|
if (value.type === 'Identifier' && value.name === 'undefined') {
|
|
return createReturnStatement(terminal.loc);
|
|
}
|
|
return createReturnStatement(terminal.loc, value);
|
|
}
|
|
case 'switch': {
|
|
return createSwitchStatement(terminal.loc, codegenPlaceToExpression(cx, terminal.test), terminal.cases.map(case_ => {
|
|
const test = case_.test !== null
|
|
? codegenPlaceToExpression(cx, case_.test)
|
|
: null;
|
|
const block = codegenBlock(cx, case_.block);
|
|
return libExports$1.switchCase(test, block.body.length === 0 ? [] : [block]);
|
|
}));
|
|
}
|
|
case 'throw': {
|
|
return createThrowStatement(terminal.loc, codegenPlaceToExpression(cx, terminal.value));
|
|
}
|
|
case 'do-while': {
|
|
const test = codegenInstructionValueToExpression(cx, terminal.test);
|
|
return createDoWhileStatement(terminal.loc, test, codegenBlock(cx, terminal.loop));
|
|
}
|
|
case 'while': {
|
|
const test = codegenInstructionValueToExpression(cx, terminal.test);
|
|
return createWhileStatement(terminal.loc, test, codegenBlock(cx, terminal.loop));
|
|
}
|
|
case 'label': {
|
|
return codegenBlock(cx, terminal.block);
|
|
}
|
|
case 'try': {
|
|
let catchParam = null;
|
|
if (terminal.handlerBinding !== null) {
|
|
catchParam = convertIdentifier(terminal.handlerBinding.identifier);
|
|
cx.temp.set(terminal.handlerBinding.identifier.declarationId, null);
|
|
}
|
|
return createTryStatement(terminal.loc, codegenBlock(cx, terminal.block), libExports$1.catchClause(catchParam, codegenBlock(cx, terminal.handler)));
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, `Unexpected terminal kind \`${terminal.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function codegenInstructionNullable(cx, instr) {
|
|
if (instr.value.kind === 'StoreLocal' ||
|
|
instr.value.kind === 'StoreContext' ||
|
|
instr.value.kind === 'Destructure' ||
|
|
instr.value.kind === 'DeclareLocal' ||
|
|
instr.value.kind === 'DeclareContext') {
|
|
let kind = instr.value.lvalue.kind;
|
|
let lvalue;
|
|
let value;
|
|
if (instr.value.kind === 'StoreLocal') {
|
|
kind = cx.hasDeclared(instr.value.lvalue.place.identifier)
|
|
? InstructionKind.Reassign
|
|
: kind;
|
|
lvalue = instr.value.lvalue.place;
|
|
value = codegenPlaceToExpression(cx, instr.value.value);
|
|
}
|
|
else if (instr.value.kind === 'StoreContext') {
|
|
lvalue = instr.value.lvalue.place;
|
|
value = codegenPlaceToExpression(cx, instr.value.value);
|
|
}
|
|
else if (instr.value.kind === 'DeclareLocal' ||
|
|
instr.value.kind === 'DeclareContext') {
|
|
if (cx.hasDeclared(instr.value.lvalue.place.identifier)) {
|
|
return null;
|
|
}
|
|
kind = instr.value.lvalue.kind;
|
|
lvalue = instr.value.lvalue.place;
|
|
value = null;
|
|
}
|
|
else {
|
|
lvalue = instr.value.lvalue.pattern;
|
|
for (const place of eachPatternOperand(lvalue)) {
|
|
if (kind !== InstructionKind.Reassign &&
|
|
place.identifier.name === null) {
|
|
cx.temp.set(place.identifier.declarationId, null);
|
|
}
|
|
}
|
|
value = codegenPlaceToExpression(cx, instr.value.value);
|
|
}
|
|
switch (kind) {
|
|
case InstructionKind.Const: {
|
|
CompilerError.invariant(instr.lvalue === null, {
|
|
reason: `Const declaration cannot be referenced as an expression`,
|
|
message: `this is ${kind}`,
|
|
loc: instr.value.loc,
|
|
});
|
|
return createVariableDeclaration(instr.loc, 'const', [
|
|
createVariableDeclarator(codegenLValue(cx, lvalue), value),
|
|
]);
|
|
}
|
|
case InstructionKind.Function: {
|
|
CompilerError.invariant(instr.lvalue === null, {
|
|
reason: `Function declaration cannot be referenced as an expression`,
|
|
loc: instr.value.loc,
|
|
});
|
|
const genLvalue = codegenLValue(cx, lvalue);
|
|
CompilerError.invariant(genLvalue.type === 'Identifier', {
|
|
reason: 'Expected an identifier as a function declaration lvalue',
|
|
loc: instr.value.loc,
|
|
});
|
|
CompilerError.invariant((value === null || value === void 0 ? void 0 : value.type) === 'FunctionExpression', {
|
|
reason: 'Expected a function as a function declaration value',
|
|
description: `Got ${value == null ? String(value) : value.type} at ${printInstruction(instr)}`,
|
|
loc: instr.value.loc,
|
|
});
|
|
return createFunctionDeclaration(instr.loc, genLvalue, value.params, value.body, value.generator, value.async);
|
|
}
|
|
case InstructionKind.Let: {
|
|
CompilerError.invariant(instr.lvalue === null, {
|
|
reason: `Const declaration cannot be referenced as an expression`,
|
|
message: `this is ${kind}`,
|
|
loc: instr.value.loc,
|
|
});
|
|
return createVariableDeclaration(instr.loc, 'let', [
|
|
createVariableDeclarator(codegenLValue(cx, lvalue), value),
|
|
]);
|
|
}
|
|
case InstructionKind.Reassign: {
|
|
CompilerError.invariant(value !== null, {
|
|
reason: 'Expected a value for reassignment',
|
|
loc: instr.value.loc,
|
|
});
|
|
const expr = libExports$1.assignmentExpression('=', codegenLValue(cx, lvalue), value);
|
|
if (instr.lvalue !== null) {
|
|
if (instr.value.kind !== 'StoreContext') {
|
|
cx.temp.set(instr.lvalue.identifier.declarationId, expr);
|
|
return null;
|
|
}
|
|
else {
|
|
const statement = codegenInstruction(cx, instr, expr);
|
|
if (statement.type === 'EmptyStatement') {
|
|
return null;
|
|
}
|
|
return statement;
|
|
}
|
|
}
|
|
else {
|
|
return createExpressionStatement(instr.loc, expr);
|
|
}
|
|
}
|
|
case InstructionKind.Catch: {
|
|
return libExports$1.emptyStatement();
|
|
}
|
|
case InstructionKind.HoistedLet:
|
|
case InstructionKind.HoistedConst:
|
|
case InstructionKind.HoistedFunction: {
|
|
CompilerError.invariant(false, {
|
|
reason: `Expected ${kind} to have been pruned in PruneHoistedContexts`,
|
|
loc: instr.loc,
|
|
});
|
|
}
|
|
default: {
|
|
assertExhaustive$1(kind, `Unexpected instruction kind \`${kind}\``);
|
|
}
|
|
}
|
|
}
|
|
else if (instr.value.kind === 'StartMemoize' ||
|
|
instr.value.kind === 'FinishMemoize') {
|
|
return null;
|
|
}
|
|
else if (instr.value.kind === 'Debugger') {
|
|
return libExports$1.debuggerStatement();
|
|
}
|
|
else if (instr.value.kind === 'ObjectMethod') {
|
|
CompilerError.invariant(instr.lvalue, {
|
|
reason: 'Expected object methods to have a temp lvalue',
|
|
loc: GeneratedSource,
|
|
});
|
|
cx.objectMethods.set(instr.lvalue.identifier.id, instr.value);
|
|
return null;
|
|
}
|
|
else {
|
|
const value = codegenInstructionValue(cx, instr.value);
|
|
const statement = codegenInstruction(cx, instr, value);
|
|
if (statement.type === 'EmptyStatement') {
|
|
return null;
|
|
}
|
|
return statement;
|
|
}
|
|
}
|
|
function codegenForInit(cx, init) {
|
|
if (init.kind === 'SequenceExpression') {
|
|
const body = codegenBlock(cx, init.instructions.map(instruction => ({
|
|
kind: 'instruction',
|
|
instruction,
|
|
}))).body;
|
|
const declarators = [];
|
|
let kind = 'const';
|
|
body.forEach(instr => {
|
|
var _a;
|
|
let top = undefined;
|
|
if (instr.type === 'ExpressionStatement' &&
|
|
instr.expression.type === 'AssignmentExpression' &&
|
|
instr.expression.operator === '=' &&
|
|
instr.expression.left.type === 'Identifier' &&
|
|
((_a = (top = declarators.at(-1))) === null || _a === void 0 ? void 0 : _a.id.type) === 'Identifier' &&
|
|
(top === null || top === void 0 ? void 0 : top.id.name) === instr.expression.left.name &&
|
|
(top === null || top === void 0 ? void 0 : top.init) == null) {
|
|
top.init = instr.expression.right;
|
|
}
|
|
else {
|
|
CompilerError.invariant(instr.type === 'VariableDeclaration' &&
|
|
(instr.kind === 'let' || instr.kind === 'const'), {
|
|
reason: 'Expected a variable declaration',
|
|
description: `Got ${instr.type}`,
|
|
loc: init.loc,
|
|
});
|
|
if (instr.kind === 'let') {
|
|
kind = 'let';
|
|
}
|
|
declarators.push(...instr.declarations);
|
|
}
|
|
});
|
|
CompilerError.invariant(declarators.length > 0, {
|
|
reason: 'Expected a variable declaration',
|
|
loc: init.loc,
|
|
});
|
|
return libExports$1.variableDeclaration(kind, declarators);
|
|
}
|
|
else {
|
|
return codegenInstructionValueToExpression(cx, init);
|
|
}
|
|
}
|
|
function codegenDependency(cx, dependency) {
|
|
let object = convertIdentifier(dependency.identifier);
|
|
if (dependency.path.length !== 0) {
|
|
const hasOptional = dependency.path.some(path => path.optional);
|
|
for (const path of dependency.path) {
|
|
const property = typeof path.property === 'string'
|
|
? libExports$1.identifier(path.property)
|
|
: libExports$1.numericLiteral(path.property);
|
|
const isComputed = typeof path.property !== 'string';
|
|
if (hasOptional) {
|
|
object = libExports$1.optionalMemberExpression(object, property, isComputed, path.optional);
|
|
}
|
|
else {
|
|
object = libExports$1.memberExpression(object, property, isComputed);
|
|
}
|
|
}
|
|
}
|
|
return object;
|
|
}
|
|
function withLoc(fn) {
|
|
return (loc, ...args) => {
|
|
const node = fn(...args);
|
|
if (loc != null && loc != GeneratedSource) {
|
|
node.loc = loc;
|
|
}
|
|
return node;
|
|
};
|
|
}
|
|
const createIdentifier = withLoc(libExports$1.identifier);
|
|
const createArrayPattern = withLoc(libExports$1.arrayPattern);
|
|
const createObjectPattern = withLoc(libExports$1.objectPattern);
|
|
const createBinaryExpression = withLoc(libExports$1.binaryExpression);
|
|
const createExpressionStatement = withLoc(libExports$1.expressionStatement);
|
|
const createVariableDeclaration = withLoc(libExports$1.variableDeclaration);
|
|
const createFunctionDeclaration = withLoc(libExports$1.functionDeclaration);
|
|
const createWhileStatement = withLoc(libExports$1.whileStatement);
|
|
const createDoWhileStatement = withLoc(libExports$1.doWhileStatement);
|
|
const createSwitchStatement = withLoc(libExports$1.switchStatement);
|
|
const createIfStatement = withLoc(libExports$1.ifStatement);
|
|
const createForStatement = withLoc(libExports$1.forStatement);
|
|
const createForOfStatement = withLoc(libExports$1.forOfStatement);
|
|
const createForInStatement = withLoc(libExports$1.forInStatement);
|
|
const createTaggedTemplateExpression = withLoc(libExports$1.taggedTemplateExpression);
|
|
const createLogicalExpression = withLoc(libExports$1.logicalExpression);
|
|
const createSequenceExpression = withLoc(libExports$1.sequenceExpression);
|
|
const createConditionalExpression = withLoc(libExports$1.conditionalExpression);
|
|
const createTemplateLiteral = withLoc(libExports$1.templateLiteral);
|
|
const createJsxNamespacedName = withLoc(libExports$1.jsxNamespacedName);
|
|
const createJsxElement = withLoc(libExports$1.jsxElement);
|
|
const createJsxAttribute = withLoc(libExports$1.jsxAttribute);
|
|
const createJsxIdentifier = withLoc(libExports$1.jsxIdentifier);
|
|
const createJsxExpressionContainer = withLoc(libExports$1.jsxExpressionContainer);
|
|
const createJsxText = withLoc(libExports$1.jsxText);
|
|
const createJsxClosingElement = withLoc(libExports$1.jsxClosingElement);
|
|
const createJsxOpeningElement = withLoc(libExports$1.jsxOpeningElement);
|
|
const createStringLiteral = withLoc(libExports$1.stringLiteral);
|
|
const createThrowStatement = withLoc(libExports$1.throwStatement);
|
|
const createTryStatement = withLoc(libExports$1.tryStatement);
|
|
const createBreakStatement = withLoc(libExports$1.breakStatement);
|
|
const createContinueStatement = withLoc(libExports$1.continueStatement);
|
|
const createReturnStatement = withLoc(libExports$1.returnStatement);
|
|
function createVariableDeclarator(id, init) {
|
|
var _a, _b;
|
|
const node = libExports$1.variableDeclarator(id, init);
|
|
if (id.loc && (init === null || (init === null || init === void 0 ? void 0 : init.loc))) {
|
|
node.loc = {
|
|
start: id.loc.start,
|
|
end: (_b = (_a = init === null || init === void 0 ? void 0 : init.loc) === null || _a === void 0 ? void 0 : _a.end) !== null && _b !== void 0 ? _b : id.loc.end,
|
|
filename: id.loc.filename,
|
|
identifierName: undefined,
|
|
};
|
|
}
|
|
return node;
|
|
}
|
|
function createHookGuard(guard, context, stmts, before, after) {
|
|
const guardFnName = context.addImportSpecifier(guard).name;
|
|
function createHookGuardImpl(kind) {
|
|
return libExports$1.expressionStatement(libExports$1.callExpression(libExports$1.identifier(guardFnName), [libExports$1.numericLiteral(kind)]));
|
|
}
|
|
return libExports$1.tryStatement(libExports$1.blockStatement([createHookGuardImpl(before), ...stmts]), null, libExports$1.blockStatement([createHookGuardImpl(after)]));
|
|
}
|
|
function createCallExpression(env, callee, args, loc, isHook) {
|
|
const callExpr = libExports$1.callExpression(callee, args);
|
|
if (loc != null && loc != GeneratedSource) {
|
|
callExpr.loc = loc;
|
|
}
|
|
const hookGuard = env.config.enableEmitHookGuards;
|
|
if (hookGuard != null && isHook && env.outputMode === 'client') {
|
|
const iife = libExports$1.functionExpression(null, [], libExports$1.blockStatement([
|
|
createHookGuard(hookGuard, env.programContext, [libExports$1.returnStatement(callExpr)], GuardKind.AllowHook, GuardKind.DisallowHook),
|
|
]));
|
|
return libExports$1.callExpression(iife, []);
|
|
}
|
|
else {
|
|
return callExpr;
|
|
}
|
|
}
|
|
function codegenLabel(id) {
|
|
return `bb${id}`;
|
|
}
|
|
function codegenInstruction(cx, instr, value) {
|
|
if (libExports$1.isStatement(value)) {
|
|
return value;
|
|
}
|
|
if (instr.lvalue === null) {
|
|
return libExports$1.expressionStatement(convertValueToExpression(value));
|
|
}
|
|
if (instr.lvalue.identifier.name === null) {
|
|
cx.temp.set(instr.lvalue.identifier.declarationId, value);
|
|
return libExports$1.emptyStatement();
|
|
}
|
|
else {
|
|
const expressionValue = convertValueToExpression(value);
|
|
if (cx.hasDeclared(instr.lvalue.identifier)) {
|
|
return createExpressionStatement(instr.loc, libExports$1.assignmentExpression('=', convertIdentifier(instr.lvalue.identifier), expressionValue));
|
|
}
|
|
else {
|
|
return createVariableDeclaration(instr.loc, 'const', [
|
|
createVariableDeclarator(convertIdentifier(instr.lvalue.identifier), expressionValue),
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
function convertValueToExpression(value) {
|
|
if (value.type === 'JSXText') {
|
|
return createStringLiteral(value.loc, value.value);
|
|
}
|
|
return value;
|
|
}
|
|
function codegenInstructionValueToExpression(cx, instrValue) {
|
|
const value = codegenInstructionValue(cx, instrValue);
|
|
return convertValueToExpression(value);
|
|
}
|
|
function codegenInstructionValue(cx, instrValue) {
|
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
let value;
|
|
switch (instrValue.kind) {
|
|
case 'ArrayExpression': {
|
|
const elements = instrValue.elements.map(element => {
|
|
if (element.kind === 'Identifier') {
|
|
return codegenPlaceToExpression(cx, element);
|
|
}
|
|
else if (element.kind === 'Spread') {
|
|
return libExports$1.spreadElement(codegenPlaceToExpression(cx, element.place));
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
});
|
|
value = libExports$1.arrayExpression(elements);
|
|
break;
|
|
}
|
|
case 'BinaryExpression': {
|
|
const left = codegenPlaceToExpression(cx, instrValue.left);
|
|
const right = codegenPlaceToExpression(cx, instrValue.right);
|
|
value = createBinaryExpression(instrValue.loc, instrValue.operator, left, right);
|
|
break;
|
|
}
|
|
case 'UnaryExpression': {
|
|
value = libExports$1.unaryExpression(instrValue.operator, codegenPlaceToExpression(cx, instrValue.value));
|
|
break;
|
|
}
|
|
case 'Primitive': {
|
|
value = codegenValue(cx, instrValue.loc, instrValue.value);
|
|
break;
|
|
}
|
|
case 'CallExpression': {
|
|
if (cx.env.config.enableForest) {
|
|
const callee = codegenPlaceToExpression(cx, instrValue.callee);
|
|
const args = instrValue.args.map(arg => codegenArgument(cx, arg));
|
|
value = libExports$1.callExpression(callee, args);
|
|
if (instrValue.typeArguments != null) {
|
|
value.typeArguments = libExports$1.typeParameterInstantiation(instrValue.typeArguments);
|
|
}
|
|
break;
|
|
}
|
|
const isHook = getHookKind(cx.env, instrValue.callee.identifier) != null;
|
|
const callee = codegenPlaceToExpression(cx, instrValue.callee);
|
|
const args = instrValue.args.map(arg => codegenArgument(cx, arg));
|
|
value = createCallExpression(cx.env, callee, args, instrValue.loc, isHook);
|
|
break;
|
|
}
|
|
case 'OptionalExpression': {
|
|
const optionalValue = codegenInstructionValueToExpression(cx, instrValue.value);
|
|
switch (optionalValue.type) {
|
|
case 'OptionalCallExpression':
|
|
case 'CallExpression': {
|
|
CompilerError.invariant(libExports$1.isExpression(optionalValue.callee), {
|
|
reason: 'v8 intrinsics are validated during lowering',
|
|
loc: (_a = optionalValue.callee.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
});
|
|
value = libExports$1.optionalCallExpression(optionalValue.callee, optionalValue.arguments, instrValue.optional);
|
|
break;
|
|
}
|
|
case 'OptionalMemberExpression':
|
|
case 'MemberExpression': {
|
|
const property = optionalValue.property;
|
|
CompilerError.invariant(libExports$1.isExpression(property), {
|
|
reason: 'Private names are validated during lowering',
|
|
loc: (_b = property.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
});
|
|
value = libExports$1.optionalMemberExpression(optionalValue.object, property, optionalValue.computed, instrValue.optional);
|
|
break;
|
|
}
|
|
default: {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Expected an optional value to resolve to a call expression or member expression',
|
|
description: `Got a \`${optionalValue.type}\``,
|
|
loc: instrValue.loc,
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'MethodCall': {
|
|
const isHook = getHookKind(cx.env, instrValue.property.identifier) != null;
|
|
const memberExpr = codegenPlaceToExpression(cx, instrValue.property);
|
|
CompilerError.invariant(libExports$1.isMemberExpression(memberExpr) ||
|
|
libExports$1.isOptionalMemberExpression(memberExpr), {
|
|
reason: '[Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression',
|
|
message: `Got: '${memberExpr.type}'`,
|
|
loc: (_c = memberExpr.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
});
|
|
CompilerError.invariant(libExports$1.isNodesEquivalent(memberExpr.object, codegenPlaceToExpression(cx, instrValue.receiver)), {
|
|
reason: '[Codegen] Internal error: Forget should always generate MethodCall::property ' +
|
|
'as a MemberExpression of MethodCall::receiver',
|
|
loc: (_d = memberExpr.loc) !== null && _d !== void 0 ? _d : GeneratedSource,
|
|
});
|
|
const args = instrValue.args.map(arg => codegenArgument(cx, arg));
|
|
value = createCallExpression(cx.env, memberExpr, args, instrValue.loc, isHook);
|
|
break;
|
|
}
|
|
case 'NewExpression': {
|
|
const callee = codegenPlaceToExpression(cx, instrValue.callee);
|
|
const args = instrValue.args.map(arg => codegenArgument(cx, arg));
|
|
value = libExports$1.newExpression(callee, args);
|
|
break;
|
|
}
|
|
case 'ObjectExpression': {
|
|
const properties = [];
|
|
for (const property of instrValue.properties) {
|
|
if (property.kind === 'ObjectProperty') {
|
|
const key = codegenObjectPropertyKey(cx, property.key);
|
|
switch (property.type) {
|
|
case 'property': {
|
|
const value = codegenPlaceToExpression(cx, property.place);
|
|
properties.push(libExports$1.objectProperty(key, value, property.key.kind === 'computed', key.type === 'Identifier' &&
|
|
value.type === 'Identifier' &&
|
|
value.name === key.name));
|
|
break;
|
|
}
|
|
case 'method': {
|
|
const method = cx.objectMethods.get(property.place.identifier.id);
|
|
CompilerError.invariant(method, {
|
|
reason: 'Expected ObjectMethod instruction',
|
|
loc: GeneratedSource,
|
|
});
|
|
const loweredFunc = method.loweredFunc;
|
|
const reactiveFunction = buildReactiveFunction(loweredFunc.func);
|
|
pruneUnusedLabels(reactiveFunction);
|
|
pruneUnusedLValues(reactiveFunction);
|
|
const fn = codegenReactiveFunction(new Context$1(cx.env, (_e = reactiveFunction.id) !== null && _e !== void 0 ? _e : '[[ anonymous ]]', cx.uniqueIdentifiers, cx.fbtOperands, cx.temp), reactiveFunction);
|
|
const babelNode = libExports$1.objectMethod('method', key, fn.params, fn.body, false);
|
|
babelNode.async = fn.async;
|
|
babelNode.generator = fn.generator;
|
|
properties.push(babelNode);
|
|
break;
|
|
}
|
|
default:
|
|
assertExhaustive$1(property.type, `Unexpected property type: ${property.type}`);
|
|
}
|
|
}
|
|
else {
|
|
properties.push(libExports$1.spreadElement(codegenPlaceToExpression(cx, property.place)));
|
|
}
|
|
}
|
|
value = libExports$1.objectExpression(properties);
|
|
break;
|
|
}
|
|
case 'JSXText': {
|
|
value = createJsxText(instrValue.loc, instrValue.value);
|
|
break;
|
|
}
|
|
case 'JsxExpression': {
|
|
const attributes = [];
|
|
for (const attribute of instrValue.props) {
|
|
attributes.push(codegenJsxAttribute(cx, attribute));
|
|
}
|
|
let tagValue = instrValue.tag.kind === 'Identifier'
|
|
? codegenPlaceToExpression(cx, instrValue.tag)
|
|
: libExports$1.stringLiteral(instrValue.tag.name);
|
|
let tag;
|
|
if (tagValue.type === 'Identifier') {
|
|
tag = createJsxIdentifier(instrValue.tag.loc, tagValue.name);
|
|
}
|
|
else if (tagValue.type === 'MemberExpression') {
|
|
tag = convertMemberExpressionToJsx(tagValue);
|
|
}
|
|
else {
|
|
CompilerError.invariant(tagValue.type === 'StringLiteral', {
|
|
reason: `Expected JSX tag to be an identifier or string, got \`${tagValue.type}\``,
|
|
loc: (_f = tagValue.loc) !== null && _f !== void 0 ? _f : GeneratedSource,
|
|
});
|
|
if (tagValue.value.indexOf(':') >= 0) {
|
|
const [namespace, name] = tagValue.value.split(':', 2);
|
|
tag = createJsxNamespacedName(instrValue.tag.loc, createJsxIdentifier(instrValue.tag.loc, namespace), createJsxIdentifier(instrValue.tag.loc, name));
|
|
}
|
|
else {
|
|
tag = createJsxIdentifier(instrValue.loc, tagValue.value);
|
|
}
|
|
}
|
|
let children;
|
|
if (tagValue.type === 'StringLiteral' &&
|
|
SINGLE_CHILD_FBT_TAGS.has(tagValue.value)) {
|
|
CompilerError.invariant(instrValue.children != null, {
|
|
reason: 'Expected fbt element to have children',
|
|
loc: instrValue.loc,
|
|
});
|
|
children = instrValue.children.map(child => codegenJsxFbtChildElement(cx, child));
|
|
}
|
|
else {
|
|
children =
|
|
instrValue.children !== null
|
|
? instrValue.children.map(child => codegenJsxElement(cx, child))
|
|
: [];
|
|
}
|
|
value = createJsxElement(instrValue.loc, createJsxOpeningElement(instrValue.openingLoc, tag, attributes, instrValue.children === null), instrValue.children !== null
|
|
? createJsxClosingElement(instrValue.closingLoc, tag)
|
|
: null, children, instrValue.children === null);
|
|
break;
|
|
}
|
|
case 'JsxFragment': {
|
|
value = libExports$1.jsxFragment(libExports$1.jsxOpeningFragment(), libExports$1.jsxClosingFragment(), instrValue.children.map(child => codegenJsxElement(cx, child)));
|
|
break;
|
|
}
|
|
case 'UnsupportedNode': {
|
|
const node = instrValue.node;
|
|
if (!libExports$1.isExpression(node)) {
|
|
return node;
|
|
}
|
|
value = node;
|
|
break;
|
|
}
|
|
case 'PropertyStore':
|
|
case 'PropertyLoad':
|
|
case 'PropertyDelete': {
|
|
let memberExpr;
|
|
if (typeof instrValue.property === 'string') {
|
|
memberExpr = libExports$1.memberExpression(codegenPlaceToExpression(cx, instrValue.object), libExports$1.identifier(instrValue.property));
|
|
}
|
|
else {
|
|
memberExpr = libExports$1.memberExpression(codegenPlaceToExpression(cx, instrValue.object), libExports$1.numericLiteral(instrValue.property), true);
|
|
}
|
|
if (instrValue.kind === 'PropertyStore') {
|
|
value = libExports$1.assignmentExpression('=', memberExpr, codegenPlaceToExpression(cx, instrValue.value));
|
|
}
|
|
else if (instrValue.kind === 'PropertyLoad') {
|
|
value = memberExpr;
|
|
}
|
|
else {
|
|
value = libExports$1.unaryExpression('delete', memberExpr);
|
|
}
|
|
break;
|
|
}
|
|
case 'ComputedStore': {
|
|
value = libExports$1.assignmentExpression('=', libExports$1.memberExpression(codegenPlaceToExpression(cx, instrValue.object), codegenPlaceToExpression(cx, instrValue.property), true), codegenPlaceToExpression(cx, instrValue.value));
|
|
break;
|
|
}
|
|
case 'ComputedLoad': {
|
|
const object = codegenPlaceToExpression(cx, instrValue.object);
|
|
const property = codegenPlaceToExpression(cx, instrValue.property);
|
|
value = libExports$1.memberExpression(object, property, true);
|
|
break;
|
|
}
|
|
case 'ComputedDelete': {
|
|
value = libExports$1.unaryExpression('delete', libExports$1.memberExpression(codegenPlaceToExpression(cx, instrValue.object), codegenPlaceToExpression(cx, instrValue.property), true));
|
|
break;
|
|
}
|
|
case 'LoadLocal':
|
|
case 'LoadContext': {
|
|
value = codegenPlaceToExpression(cx, instrValue.place);
|
|
break;
|
|
}
|
|
case 'FunctionExpression': {
|
|
const loweredFunc = instrValue.loweredFunc.func;
|
|
const reactiveFunction = buildReactiveFunction(loweredFunc);
|
|
pruneUnusedLabels(reactiveFunction);
|
|
pruneUnusedLValues(reactiveFunction);
|
|
pruneHoistedContexts(reactiveFunction);
|
|
const fn = codegenReactiveFunction(new Context$1(cx.env, (_g = reactiveFunction.id) !== null && _g !== void 0 ? _g : '[[ anonymous ]]', cx.uniqueIdentifiers, cx.fbtOperands, cx.temp), reactiveFunction);
|
|
if (instrValue.type === 'ArrowFunctionExpression') {
|
|
let body = fn.body;
|
|
if (body.body.length === 1 && loweredFunc.directives.length == 0) {
|
|
const stmt = body.body[0];
|
|
if (stmt.type === 'ReturnStatement' && stmt.argument != null) {
|
|
body = stmt.argument;
|
|
}
|
|
}
|
|
value = libExports$1.arrowFunctionExpression(fn.params, body, fn.async);
|
|
}
|
|
else {
|
|
value = libExports$1.functionExpression(instrValue.name != null ? libExports$1.identifier(instrValue.name) : null, fn.params, fn.body, fn.generator, fn.async);
|
|
}
|
|
if (cx.env.config.enableNameAnonymousFunctions &&
|
|
instrValue.name == null &&
|
|
instrValue.nameHint != null) {
|
|
const name = instrValue.nameHint;
|
|
value = libExports$1.memberExpression(libExports$1.objectExpression([libExports$1.objectProperty(libExports$1.stringLiteral(name), value)]), libExports$1.stringLiteral(name), true, false);
|
|
}
|
|
break;
|
|
}
|
|
case 'TaggedTemplateExpression': {
|
|
value = createTaggedTemplateExpression(instrValue.loc, codegenPlaceToExpression(cx, instrValue.tag), libExports$1.templateLiteral([libExports$1.templateElement(instrValue.value)], []));
|
|
break;
|
|
}
|
|
case 'TypeCastExpression': {
|
|
if (libExports$1.isTSType(instrValue.typeAnnotation)) {
|
|
if (instrValue.typeAnnotationKind === 'satisfies') {
|
|
value = libExports$1.tsSatisfiesExpression(codegenPlaceToExpression(cx, instrValue.value), instrValue.typeAnnotation);
|
|
}
|
|
else {
|
|
value = libExports$1.tsAsExpression(codegenPlaceToExpression(cx, instrValue.value), instrValue.typeAnnotation);
|
|
}
|
|
}
|
|
else {
|
|
value = libExports$1.typeCastExpression(codegenPlaceToExpression(cx, instrValue.value), libExports$1.typeAnnotation(instrValue.typeAnnotation));
|
|
}
|
|
break;
|
|
}
|
|
case 'LogicalExpression': {
|
|
value = createLogicalExpression(instrValue.loc, instrValue.operator, codegenInstructionValueToExpression(cx, instrValue.left), codegenInstructionValueToExpression(cx, instrValue.right));
|
|
break;
|
|
}
|
|
case 'ConditionalExpression': {
|
|
value = createConditionalExpression(instrValue.loc, codegenInstructionValueToExpression(cx, instrValue.test), codegenInstructionValueToExpression(cx, instrValue.consequent), codegenInstructionValueToExpression(cx, instrValue.alternate));
|
|
break;
|
|
}
|
|
case 'SequenceExpression': {
|
|
const body = codegenBlockNoReset(cx, instrValue.instructions.map(instruction => ({
|
|
kind: 'instruction',
|
|
instruction,
|
|
}))).body;
|
|
const expressions = body.map(stmt => {
|
|
var _a, _b;
|
|
if (stmt.type === 'ExpressionStatement') {
|
|
return stmt.expression;
|
|
}
|
|
else {
|
|
if (libExports$1.isVariableDeclaration(stmt)) {
|
|
const declarator = stmt.declarations[0];
|
|
cx.recordError(new CompilerErrorDetail({
|
|
reason: `(CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare '${declarator.id.name}'`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_a = declarator.loc) !== null && _a !== void 0 ? _a : null,
|
|
suggestions: null,
|
|
}));
|
|
return libExports$1.stringLiteral(`TODO handle ${declarator.id}`);
|
|
}
|
|
else {
|
|
cx.recordError(new CompilerErrorDetail({
|
|
reason: `(CodegenReactiveFunction::codegenInstructionValue) Handle conversion of ${stmt.type} to expression`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_b = stmt.loc) !== null && _b !== void 0 ? _b : null,
|
|
suggestions: null,
|
|
}));
|
|
return libExports$1.stringLiteral(`TODO handle ${stmt.type}`);
|
|
}
|
|
}
|
|
});
|
|
if (expressions.length === 0) {
|
|
value = codegenInstructionValueToExpression(cx, instrValue.value);
|
|
}
|
|
else {
|
|
value = createSequenceExpression(instrValue.loc, [
|
|
...expressions,
|
|
codegenInstructionValueToExpression(cx, instrValue.value),
|
|
]);
|
|
}
|
|
break;
|
|
}
|
|
case 'TemplateLiteral': {
|
|
value = createTemplateLiteral(instrValue.loc, instrValue.quasis.map(q => libExports$1.templateElement(q)), instrValue.subexprs.map(p => codegenPlaceToExpression(cx, p)));
|
|
break;
|
|
}
|
|
case 'LoadGlobal': {
|
|
value = libExports$1.identifier(instrValue.binding.name);
|
|
break;
|
|
}
|
|
case 'RegExpLiteral': {
|
|
value = libExports$1.regExpLiteral(instrValue.pattern, instrValue.flags);
|
|
break;
|
|
}
|
|
case 'MetaProperty': {
|
|
value = libExports$1.metaProperty(libExports$1.identifier(instrValue.meta), libExports$1.identifier(instrValue.property));
|
|
break;
|
|
}
|
|
case 'Await': {
|
|
value = libExports$1.awaitExpression(codegenPlaceToExpression(cx, instrValue.value));
|
|
break;
|
|
}
|
|
case 'GetIterator': {
|
|
value = codegenPlaceToExpression(cx, instrValue.collection);
|
|
break;
|
|
}
|
|
case 'IteratorNext': {
|
|
value = codegenPlaceToExpression(cx, instrValue.iterator);
|
|
break;
|
|
}
|
|
case 'NextPropertyOf': {
|
|
value = codegenPlaceToExpression(cx, instrValue.value);
|
|
break;
|
|
}
|
|
case 'PostfixUpdate': {
|
|
value = libExports$1.updateExpression(instrValue.operation, codegenPlaceToExpression(cx, instrValue.lvalue), false);
|
|
break;
|
|
}
|
|
case 'PrefixUpdate': {
|
|
value = libExports$1.updateExpression(instrValue.operation, codegenPlaceToExpression(cx, instrValue.lvalue), true);
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
CompilerError.invariant(instrValue.lvalue.kind === InstructionKind.Reassign, {
|
|
reason: `Unexpected StoreLocal in codegenInstructionValue`,
|
|
loc: instrValue.loc,
|
|
});
|
|
value = libExports$1.assignmentExpression('=', codegenLValue(cx, instrValue.lvalue.place), codegenPlaceToExpression(cx, instrValue.value));
|
|
break;
|
|
}
|
|
case 'StoreGlobal': {
|
|
value = libExports$1.assignmentExpression('=', libExports$1.identifier(instrValue.name), codegenPlaceToExpression(cx, instrValue.value));
|
|
break;
|
|
}
|
|
case 'StartMemoize':
|
|
case 'FinishMemoize':
|
|
case 'Debugger':
|
|
case 'DeclareLocal':
|
|
case 'DeclareContext':
|
|
case 'Destructure':
|
|
case 'ObjectMethod':
|
|
case 'StoreContext': {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected ${instrValue.kind} in codegenInstructionValue`,
|
|
loc: instrValue.loc,
|
|
});
|
|
}
|
|
default: {
|
|
assertExhaustive$1(instrValue, `Unexpected instruction value kind \`${instrValue.kind}\``);
|
|
}
|
|
}
|
|
if (instrValue.loc != null && instrValue.loc != GeneratedSource) {
|
|
value.loc = instrValue.loc;
|
|
}
|
|
return value;
|
|
}
|
|
const STRING_REQUIRES_EXPR_CONTAINER_PATTERN = /[\u{0000}-\u{001F}\u{007F}\u{0080}-\u{FFFF}\u{010000}-\u{10FFFF}]|"|\\/u;
|
|
function codegenJsxAttribute(cx, attribute) {
|
|
switch (attribute.kind) {
|
|
case 'JsxAttribute': {
|
|
let propName;
|
|
if (attribute.name.indexOf(':') === -1) {
|
|
propName = createJsxIdentifier(attribute.place.loc, attribute.name);
|
|
}
|
|
else {
|
|
const [namespace, name] = attribute.name.split(':', 2);
|
|
propName = createJsxNamespacedName(attribute.place.loc, createJsxIdentifier(attribute.place.loc, namespace), createJsxIdentifier(attribute.place.loc, name));
|
|
}
|
|
const innerValue = codegenPlaceToExpression(cx, attribute.place);
|
|
let value;
|
|
switch (innerValue.type) {
|
|
case 'StringLiteral': {
|
|
value = innerValue;
|
|
if (STRING_REQUIRES_EXPR_CONTAINER_PATTERN.test(value.value) &&
|
|
!cx.fbtOperands.has(attribute.place.identifier.id)) {
|
|
value = createJsxExpressionContainer(value.loc, value);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
value = createJsxExpressionContainer(attribute.place.loc, innerValue);
|
|
break;
|
|
}
|
|
}
|
|
return createJsxAttribute(attribute.place.loc, propName, value);
|
|
}
|
|
case 'JsxSpreadAttribute': {
|
|
return libExports$1.jsxSpreadAttribute(codegenPlaceToExpression(cx, attribute.argument));
|
|
}
|
|
default: {
|
|
assertExhaustive$1(attribute, `Unexpected attribute kind \`${attribute.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
const JSX_TEXT_CHILD_REQUIRES_EXPR_CONTAINER_PATTERN = /[<>&{}]/;
|
|
function codegenJsxElement(cx, place) {
|
|
const value = codegenPlace(cx, place);
|
|
switch (value.type) {
|
|
case 'JSXText': {
|
|
if (JSX_TEXT_CHILD_REQUIRES_EXPR_CONTAINER_PATTERN.test(value.value)) {
|
|
return createJsxExpressionContainer(place.loc, createStringLiteral(place.loc, value.value));
|
|
}
|
|
return createJsxText(place.loc, value.value);
|
|
}
|
|
case 'JSXElement':
|
|
case 'JSXFragment': {
|
|
return value;
|
|
}
|
|
default: {
|
|
return createJsxExpressionContainer(place.loc, value);
|
|
}
|
|
}
|
|
}
|
|
function codegenJsxFbtChildElement(cx, place) {
|
|
const value = codegenPlace(cx, place);
|
|
switch (value.type) {
|
|
case 'JSXText':
|
|
case 'JSXElement': {
|
|
return value;
|
|
}
|
|
default: {
|
|
return createJsxExpressionContainer(place.loc, value);
|
|
}
|
|
}
|
|
}
|
|
function convertMemberExpressionToJsx(expr) {
|
|
var _a, _b;
|
|
CompilerError.invariant(expr.property.type === 'Identifier', {
|
|
reason: 'Expected JSX member expression property to be a string',
|
|
loc: (_a = expr.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
});
|
|
const property = libExports$1.jsxIdentifier(expr.property.name);
|
|
if (expr.object.type === 'Identifier') {
|
|
return libExports$1.jsxMemberExpression(libExports$1.jsxIdentifier(expr.object.name), property);
|
|
}
|
|
else {
|
|
CompilerError.invariant(expr.object.type === 'MemberExpression', {
|
|
reason: 'Expected JSX member expression to be an identifier or nested member expression',
|
|
loc: (_b = expr.object.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
});
|
|
const object = convertMemberExpressionToJsx(expr.object);
|
|
return libExports$1.jsxMemberExpression(object, property);
|
|
}
|
|
}
|
|
function codegenObjectPropertyKey(cx, key) {
|
|
switch (key.kind) {
|
|
case 'string': {
|
|
return libExports$1.stringLiteral(key.name);
|
|
}
|
|
case 'identifier': {
|
|
return libExports$1.identifier(key.name);
|
|
}
|
|
case 'computed': {
|
|
const expr = codegenPlace(cx, key.name);
|
|
CompilerError.invariant(libExports$1.isExpression(expr), {
|
|
reason: 'Expected object property key to be an expression',
|
|
loc: key.name.loc,
|
|
});
|
|
return expr;
|
|
}
|
|
case 'number': {
|
|
return libExports$1.numericLiteral(key.name);
|
|
}
|
|
}
|
|
}
|
|
function codegenArrayPattern(cx, pattern) {
|
|
const hasHoles = !pattern.items.every(e => e.kind !== 'Hole');
|
|
if (hasHoles) {
|
|
const result = createArrayPattern(pattern.loc, []);
|
|
for (const item of pattern.items) {
|
|
if (item.kind === 'Hole') {
|
|
result.elements.push(null);
|
|
}
|
|
else {
|
|
result.elements.push(codegenLValue(cx, item));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
else {
|
|
return createArrayPattern(pattern.loc, pattern.items.map(item => {
|
|
if (item.kind === 'Hole') {
|
|
return null;
|
|
}
|
|
return codegenLValue(cx, item);
|
|
}));
|
|
}
|
|
}
|
|
function codegenLValue(cx, pattern) {
|
|
switch (pattern.kind) {
|
|
case 'ArrayPattern': {
|
|
return codegenArrayPattern(cx, pattern);
|
|
}
|
|
case 'ObjectPattern': {
|
|
return createObjectPattern(pattern.loc, pattern.properties.map(property => {
|
|
if (property.kind === 'ObjectProperty') {
|
|
const key = codegenObjectPropertyKey(cx, property.key);
|
|
const value = codegenLValue(cx, property.place);
|
|
return libExports$1.objectProperty(key, value, property.key.kind === 'computed', key.type === 'Identifier' &&
|
|
value.type === 'Identifier' &&
|
|
value.name === key.name);
|
|
}
|
|
else {
|
|
return libExports$1.restElement(codegenLValue(cx, property.place));
|
|
}
|
|
}));
|
|
}
|
|
case 'Spread': {
|
|
return libExports$1.restElement(codegenLValue(cx, pattern.place));
|
|
}
|
|
case 'Identifier': {
|
|
return convertIdentifier(pattern.identifier);
|
|
}
|
|
default: {
|
|
assertExhaustive$1(pattern, `Unexpected pattern kind \`${pattern.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
function codegenValue(cx, loc, value) {
|
|
if (typeof value === 'number') {
|
|
if (value < 0) {
|
|
return libExports$1.unaryExpression('-', libExports$1.numericLiteral(-value), false);
|
|
}
|
|
else {
|
|
return libExports$1.numericLiteral(value);
|
|
}
|
|
}
|
|
else if (typeof value === 'boolean') {
|
|
return libExports$1.booleanLiteral(value);
|
|
}
|
|
else if (typeof value === 'string') {
|
|
return createStringLiteral(loc, value);
|
|
}
|
|
else if (value === null) {
|
|
return libExports$1.nullLiteral();
|
|
}
|
|
else if (value === undefined) {
|
|
return libExports$1.identifier('undefined');
|
|
}
|
|
else {
|
|
assertExhaustive$1(value, 'Unexpected primitive value kind');
|
|
}
|
|
}
|
|
function codegenArgument(cx, arg) {
|
|
if (arg.kind === 'Identifier') {
|
|
return codegenPlaceToExpression(cx, arg);
|
|
}
|
|
else {
|
|
return libExports$1.spreadElement(codegenPlaceToExpression(cx, arg.place));
|
|
}
|
|
}
|
|
function codegenPlaceToExpression(cx, place) {
|
|
const value = codegenPlace(cx, place);
|
|
return convertValueToExpression(value);
|
|
}
|
|
function codegenPlace(cx, place) {
|
|
let tmp = cx.temp.get(place.identifier.declarationId);
|
|
if (tmp != null) {
|
|
return tmp;
|
|
}
|
|
CompilerError.invariant(place.identifier.name !== null || tmp !== undefined, {
|
|
reason: `[Codegen] No value found for temporary`,
|
|
description: `Value for '${printPlace(place)}' was not set in the codegen context`,
|
|
loc: place.loc,
|
|
});
|
|
const identifier = convertIdentifier(place.identifier);
|
|
identifier.loc = place.loc;
|
|
return identifier;
|
|
}
|
|
function convertIdentifier(identifier) {
|
|
CompilerError.invariant(identifier.name !== null && identifier.name.kind === 'named', {
|
|
reason: `Expected temporaries to be promoted to named identifiers in an earlier pass`,
|
|
description: `identifier ${identifier.id} is unnamed`,
|
|
loc: GeneratedSource,
|
|
});
|
|
return createIdentifier(identifier.loc, identifier.name.value);
|
|
}
|
|
function compareScopeDependency(a, b) {
|
|
var _a, _b;
|
|
CompilerError.invariant(((_a = a.identifier.name) === null || _a === void 0 ? void 0 : _a.kind) === 'named' && ((_b = b.identifier.name) === null || _b === void 0 ? void 0 : _b.kind) === 'named', {
|
|
reason: '[Codegen] Expected named identifier for dependency',
|
|
loc: a.identifier.loc,
|
|
});
|
|
const aName = [
|
|
a.identifier.name.value,
|
|
...a.path.map(entry => `${entry.optional ? '?' : ''}${entry.property}`),
|
|
].join('.');
|
|
const bName = [
|
|
b.identifier.name.value,
|
|
...b.path.map(entry => `${entry.optional ? '?' : ''}${entry.property}`),
|
|
].join('.');
|
|
if (aName < bName)
|
|
return -1;
|
|
else if (aName > bName)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
function compareScopeDeclaration(a, b) {
|
|
var _a, _b;
|
|
CompilerError.invariant(((_a = a.identifier.name) === null || _a === void 0 ? void 0 : _a.kind) === 'named' && ((_b = b.identifier.name) === null || _b === void 0 ? void 0 : _b.kind) === 'named', {
|
|
reason: '[Codegen] Expected named identifier for declaration',
|
|
loc: a.identifier.loc,
|
|
});
|
|
const aName = a.identifier.name.value;
|
|
const bName = b.identifier.name.value;
|
|
if (aName < bName)
|
|
return -1;
|
|
else if (aName > bName)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
function extractScopeDeclarationsFromDestructuring(fn) {
|
|
const state = new State$1(fn.env);
|
|
for (const param of fn.params) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
state.declared.add(place.identifier.declarationId);
|
|
}
|
|
visitReactiveFunction(fn, new Visitor$7(), state);
|
|
}
|
|
let State$1 = class State {
|
|
constructor(env) {
|
|
this.declared = new Set();
|
|
this.env = env;
|
|
}
|
|
};
|
|
let Visitor$7 = class Visitor extends ReactiveFunctionTransform {
|
|
visitScope(scope, state) {
|
|
for (const [, declaration] of scope.scope.declarations) {
|
|
state.declared.add(declaration.identifier.declarationId);
|
|
}
|
|
this.traverseScope(scope, state);
|
|
}
|
|
transformInstruction(instruction, state) {
|
|
this.visitInstruction(instruction, state);
|
|
let instructionsToProcess = [instruction];
|
|
let result = { kind: 'keep' };
|
|
if (instruction.value.kind === 'Destructure') {
|
|
const transformed = transformDestructuring(state, instruction, instruction.value);
|
|
if (transformed) {
|
|
instructionsToProcess = transformed;
|
|
result = {
|
|
kind: 'replace-many',
|
|
value: transformed.map(instruction => ({
|
|
kind: 'instruction',
|
|
instruction,
|
|
})),
|
|
};
|
|
}
|
|
}
|
|
for (const instr of instructionsToProcess) {
|
|
for (const [place, kind] of eachInstructionLValueWithKind(instr)) {
|
|
if (kind !== InstructionKind.Reassign) {
|
|
state.declared.add(place.identifier.declarationId);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
function transformDestructuring(state, instr, destructure) {
|
|
let reassigned = new Set();
|
|
let hasDeclaration = false;
|
|
for (const place of eachPatternOperand(destructure.lvalue.pattern)) {
|
|
const isDeclared = state.declared.has(place.identifier.declarationId);
|
|
if (isDeclared) {
|
|
reassigned.add(place.identifier.id);
|
|
}
|
|
else {
|
|
hasDeclaration = true;
|
|
}
|
|
}
|
|
if (!hasDeclaration) {
|
|
destructure.lvalue.kind = InstructionKind.Reassign;
|
|
return null;
|
|
}
|
|
const instructions = [];
|
|
const renamed = new Map();
|
|
mapPatternOperands(destructure.lvalue.pattern, place => {
|
|
if (!reassigned.has(place.identifier.id)) {
|
|
return place;
|
|
}
|
|
const temporary = clonePlaceToTemporary(state.env, place);
|
|
promoteTemporary(temporary.identifier);
|
|
renamed.set(place, temporary);
|
|
return temporary;
|
|
});
|
|
instructions.push(instr);
|
|
for (const [original, temporary] of renamed) {
|
|
instructions.push({
|
|
id: instr.id,
|
|
lvalue: null,
|
|
value: {
|
|
kind: 'StoreLocal',
|
|
lvalue: {
|
|
kind: InstructionKind.Reassign,
|
|
place: original,
|
|
},
|
|
value: temporary,
|
|
type: null,
|
|
loc: destructure.loc,
|
|
},
|
|
loc: instr.loc,
|
|
});
|
|
}
|
|
return instructions;
|
|
}
|
|
|
|
function mergeReactiveScopesThatInvalidateTogether(fn) {
|
|
const lastUsageVisitor = new FindLastUsageVisitor();
|
|
visitReactiveFunction(fn, lastUsageVisitor, undefined);
|
|
visitReactiveFunction(fn, new Transform$4(lastUsageVisitor.lastUsage), null);
|
|
}
|
|
function log(msg) {
|
|
}
|
|
class FindLastUsageVisitor extends ReactiveFunctionVisitor {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.lastUsage = new Map();
|
|
}
|
|
visitPlace(id, place, _state) {
|
|
const previousUsage = this.lastUsage.get(place.identifier.declarationId);
|
|
const lastUsage = previousUsage !== undefined
|
|
? makeInstructionId(Math.max(previousUsage, id))
|
|
: id;
|
|
this.lastUsage.set(place.identifier.declarationId, lastUsage);
|
|
}
|
|
}
|
|
let Transform$4 = class Transform extends ReactiveFunctionTransform {
|
|
constructor(lastUsage) {
|
|
super();
|
|
this.temporaries = new Map();
|
|
this.lastUsage = lastUsage;
|
|
}
|
|
transformScope(scopeBlock, state) {
|
|
this.visitScope(scopeBlock, scopeBlock.scope.dependencies);
|
|
if (state !== null &&
|
|
areEqualDependencies(state, scopeBlock.scope.dependencies)) {
|
|
return { kind: 'replace-many', value: scopeBlock.instructions };
|
|
}
|
|
else {
|
|
return { kind: 'keep' };
|
|
}
|
|
}
|
|
visitBlock(block, state) {
|
|
var _a;
|
|
this.traverseBlock(block, state);
|
|
let current = null;
|
|
const merged = [];
|
|
function reset() {
|
|
CompilerError.invariant(current !== null, {
|
|
reason: 'MergeConsecutiveScopes: expected current scope to be non-null if reset()',
|
|
loc: GeneratedSource,
|
|
});
|
|
if (current.to > current.from + 1) {
|
|
merged.push(current);
|
|
}
|
|
current = null;
|
|
}
|
|
for (let i = 0; i < block.length; i++) {
|
|
const instr = block[i];
|
|
switch (instr.kind) {
|
|
case 'terminal': {
|
|
if (current !== null) {
|
|
reset();
|
|
}
|
|
break;
|
|
}
|
|
case 'pruned-scope': {
|
|
if (current !== null) {
|
|
reset();
|
|
}
|
|
break;
|
|
}
|
|
case 'instruction': {
|
|
switch (instr.instruction.value.kind) {
|
|
case 'BinaryExpression':
|
|
case 'ComputedLoad':
|
|
case 'JSXText':
|
|
case 'LoadGlobal':
|
|
case 'LoadLocal':
|
|
case 'Primitive':
|
|
case 'PropertyLoad':
|
|
case 'TemplateLiteral':
|
|
case 'UnaryExpression': {
|
|
if (current !== null && instr.instruction.lvalue !== null) {
|
|
current.lvalues.add(instr.instruction.lvalue.identifier.declarationId);
|
|
if (instr.instruction.value.kind === 'LoadLocal') {
|
|
this.temporaries.set(instr.instruction.lvalue.identifier.declarationId, instr.instruction.value.place.identifier.declarationId);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
if (current !== null) {
|
|
if (instr.instruction.value.lvalue.kind === InstructionKind.Const) {
|
|
for (const lvalue of eachInstructionLValue(instr.instruction)) {
|
|
current.lvalues.add(lvalue.identifier.declarationId);
|
|
}
|
|
this.temporaries.set(instr.instruction.value.lvalue.place.identifier
|
|
.declarationId, (_a = this.temporaries.get(instr.instruction.value.value.identifier.declarationId)) !== null && _a !== void 0 ? _a : instr.instruction.value.value.identifier.declarationId);
|
|
}
|
|
else {
|
|
reset();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if (current !== null) {
|
|
reset();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'scope': {
|
|
if (current !== null &&
|
|
canMergeScopes(current.block, instr, this.temporaries) &&
|
|
areLValuesLastUsedByScope(instr.scope, current.lvalues, this.lastUsage)) {
|
|
current.block.scope.range.end = makeInstructionId(Math.max(current.block.scope.range.end, instr.scope.range.end));
|
|
for (const [key, value] of instr.scope.declarations) {
|
|
current.block.scope.declarations.set(key, value);
|
|
}
|
|
updateScopeDeclarations(current.block.scope, this.lastUsage);
|
|
current.to = i + 1;
|
|
current.lvalues.clear();
|
|
if (!scopeIsEligibleForMerging(instr)) {
|
|
reset();
|
|
}
|
|
}
|
|
else {
|
|
if (current !== null) {
|
|
reset();
|
|
}
|
|
if (scopeIsEligibleForMerging(instr)) {
|
|
current = {
|
|
block: instr,
|
|
from: i,
|
|
to: i + 1,
|
|
lvalues: new Set(),
|
|
};
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(instr, `Unexpected instruction kind \`${instr.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
if (current !== null) {
|
|
reset();
|
|
}
|
|
if (merged.length) {
|
|
for (const entry of merged) {
|
|
log(printReactiveScopeSummary(entry.block.scope) +
|
|
` from=${entry.from} to=${entry.to}`);
|
|
}
|
|
}
|
|
if (merged.length === 0) {
|
|
return;
|
|
}
|
|
const nextInstructions = [];
|
|
let index = 0;
|
|
for (const entry of merged) {
|
|
if (index < entry.from) {
|
|
nextInstructions.push(...block.slice(index, entry.from));
|
|
index = entry.from;
|
|
}
|
|
const mergedScope = block[entry.from];
|
|
CompilerError.invariant(mergedScope.kind === 'scope', {
|
|
reason: 'MergeConsecutiveScopes: Expected scope starting index to be a scope',
|
|
loc: GeneratedSource,
|
|
});
|
|
nextInstructions.push(mergedScope);
|
|
index++;
|
|
while (index < entry.to) {
|
|
const instr = block[index++];
|
|
if (instr.kind === 'scope') {
|
|
mergedScope.instructions.push(...instr.instructions);
|
|
mergedScope.scope.merged.add(instr.scope.id);
|
|
}
|
|
else {
|
|
mergedScope.instructions.push(instr);
|
|
}
|
|
}
|
|
}
|
|
while (index < block.length) {
|
|
nextInstructions.push(block[index++]);
|
|
}
|
|
block.length = 0;
|
|
block.push(...nextInstructions);
|
|
}
|
|
};
|
|
function updateScopeDeclarations(scope, lastUsage) {
|
|
for (const [id, decl] of scope.declarations) {
|
|
const lastUsedAt = lastUsage.get(decl.identifier.declarationId);
|
|
if (lastUsedAt < scope.range.end) {
|
|
scope.declarations.delete(id);
|
|
}
|
|
}
|
|
}
|
|
function areLValuesLastUsedByScope(scope, lvalues, lastUsage) {
|
|
for (const lvalue of lvalues) {
|
|
const lastUsedAt = lastUsage.get(lvalue);
|
|
if (lastUsedAt >= scope.range.end) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function canMergeScopes(current, next, temporaries) {
|
|
if (current.scope.reassignments.size !== 0 ||
|
|
next.scope.reassignments.size !== 0) {
|
|
return false;
|
|
}
|
|
if (areEqualDependencies(current.scope.dependencies, next.scope.dependencies)) {
|
|
return true;
|
|
}
|
|
if (areEqualDependencies(new Set([...current.scope.declarations.values()].map(declaration => ({
|
|
identifier: declaration.identifier,
|
|
reactive: true,
|
|
path: [],
|
|
loc: GeneratedSource,
|
|
}))), next.scope.dependencies) ||
|
|
(next.scope.dependencies.size !== 0 &&
|
|
[...next.scope.dependencies].every(dep => dep.path.length === 0 &&
|
|
isAlwaysInvalidatingType(dep.identifier.type) &&
|
|
Iterable_some(current.scope.declarations.values(), decl => decl.identifier.declarationId === dep.identifier.declarationId ||
|
|
decl.identifier.declarationId ===
|
|
temporaries.get(dep.identifier.declarationId))))) {
|
|
return true;
|
|
}
|
|
log(` ${printReactiveScopeSummary(current.scope)} ${[...current.scope.declarations.values()].map(decl => decl.identifier.declarationId)}`);
|
|
log(` ${printReactiveScopeSummary(next.scope)} ${[...next.scope.dependencies].map(dep => { var _a; return `${dep.identifier.declarationId} ${(_a = temporaries.get(dep.identifier.declarationId)) !== null && _a !== void 0 ? _a : dep.identifier.declarationId}`; })}`);
|
|
return false;
|
|
}
|
|
function isAlwaysInvalidatingType(type) {
|
|
switch (type.kind) {
|
|
case 'Object': {
|
|
switch (type.shapeId) {
|
|
case BuiltInArrayId:
|
|
case BuiltInObjectId:
|
|
case BuiltInFunctionId:
|
|
case BuiltInJsxId: {
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'Function': {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function areEqualDependencies(a, b) {
|
|
if (a.size !== b.size) {
|
|
return false;
|
|
}
|
|
for (const aValue of a) {
|
|
let found = false;
|
|
for (const bValue of b) {
|
|
if (aValue.identifier.declarationId === bValue.identifier.declarationId &&
|
|
areEqualPaths(aValue.path, bValue.path)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function scopeIsEligibleForMerging(scopeBlock) {
|
|
if (scopeBlock.scope.dependencies.size === 0) {
|
|
return true;
|
|
}
|
|
return [...scopeBlock.scope.declarations].some(([, decl]) => isAlwaysInvalidatingType(decl.identifier.type));
|
|
}
|
|
|
|
var _PromoteInterposedTemporaries_promotable, _PromoteInterposedTemporaries_consts, _PromoteInterposedTemporaries_globals;
|
|
class PromoteTemporaries extends ReactiveFunctionVisitor {
|
|
visitScope(scopeBlock, state) {
|
|
for (const dep of scopeBlock.scope.dependencies) {
|
|
const { identifier } = dep;
|
|
if (identifier.name == null) {
|
|
promoteIdentifier(identifier, state);
|
|
}
|
|
}
|
|
for (const [, declaration] of scopeBlock.scope.declarations) {
|
|
if (declaration.identifier.name == null) {
|
|
promoteIdentifier(declaration.identifier, state);
|
|
}
|
|
}
|
|
this.traverseScope(scopeBlock, state);
|
|
}
|
|
visitPrunedScope(scopeBlock, state) {
|
|
var _a;
|
|
for (const [, declaration] of scopeBlock.scope.declarations) {
|
|
if (declaration.identifier.name == null &&
|
|
((_a = state.pruned.get(declaration.identifier.declarationId)) === null || _a === void 0 ? void 0 : _a.usedOutsideScope) === true) {
|
|
promoteIdentifier(declaration.identifier, state);
|
|
}
|
|
}
|
|
this.traversePrunedScope(scopeBlock, state);
|
|
}
|
|
visitParam(place, state) {
|
|
if (place.identifier.name === null) {
|
|
promoteIdentifier(place.identifier, state);
|
|
}
|
|
}
|
|
visitValue(id, value, state) {
|
|
this.traverseValue(id, value, state);
|
|
if (value.kind === 'FunctionExpression' || value.kind === 'ObjectMethod') {
|
|
this.visitHirFunction(value.loweredFunc.func, state);
|
|
}
|
|
}
|
|
visitReactiveFunctionValue(_id, _dependencies, fn, state) {
|
|
for (const operand of fn.params) {
|
|
const place = operand.kind === 'Identifier' ? operand : operand.place;
|
|
if (place.identifier.name === null) {
|
|
promoteIdentifier(place.identifier, state);
|
|
}
|
|
}
|
|
visitReactiveFunction(fn, this, state);
|
|
}
|
|
}
|
|
class PromoteAllInstancedOfPromotedTemporaries extends ReactiveFunctionVisitor {
|
|
visitPlace(_id, place, state) {
|
|
if (place.identifier.name === null &&
|
|
state.promoted.has(place.identifier.declarationId)) {
|
|
promoteIdentifier(place.identifier, state);
|
|
}
|
|
}
|
|
visitLValue(_id, _lvalue, _state) {
|
|
this.visitPlace(_id, _lvalue, _state);
|
|
}
|
|
traverseScopeIdentifiers(scope, state) {
|
|
for (const [, decl] of scope.declarations) {
|
|
if (decl.identifier.name === null &&
|
|
state.promoted.has(decl.identifier.declarationId)) {
|
|
promoteIdentifier(decl.identifier, state);
|
|
}
|
|
}
|
|
for (const dep of scope.dependencies) {
|
|
if (dep.identifier.name === null &&
|
|
state.promoted.has(dep.identifier.declarationId)) {
|
|
promoteIdentifier(dep.identifier, state);
|
|
}
|
|
}
|
|
for (const reassignment of scope.reassignments) {
|
|
if (reassignment.name === null &&
|
|
state.promoted.has(reassignment.declarationId)) {
|
|
promoteIdentifier(reassignment, state);
|
|
}
|
|
}
|
|
}
|
|
visitScope(scope, state) {
|
|
this.traverseScope(scope, state);
|
|
this.traverseScopeIdentifiers(scope.scope, state);
|
|
}
|
|
visitPrunedScope(scopeBlock, state) {
|
|
this.traversePrunedScope(scopeBlock, state);
|
|
this.traverseScopeIdentifiers(scopeBlock.scope, state);
|
|
}
|
|
visitReactiveFunctionValue(_id, _dependencies, fn, state) {
|
|
visitReactiveFunction(fn, this, state);
|
|
}
|
|
}
|
|
class CollectPromotableTemporaries extends ReactiveFunctionVisitor {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.activeScopes = [];
|
|
}
|
|
visitPlace(_id, place, state) {
|
|
if (this.activeScopes.length !== 0 &&
|
|
state.pruned.has(place.identifier.declarationId)) {
|
|
const prunedPlace = state.pruned.get(place.identifier.declarationId);
|
|
if (prunedPlace.activeScopes.indexOf(this.activeScopes.at(-1)) === -1) {
|
|
prunedPlace.usedOutsideScope = true;
|
|
}
|
|
}
|
|
}
|
|
visitValue(id, value, state) {
|
|
this.traverseValue(id, value, state);
|
|
if (value.kind === 'JsxExpression' && value.tag.kind === 'Identifier') {
|
|
state.tags.add(value.tag.identifier.declarationId);
|
|
}
|
|
}
|
|
visitPrunedScope(scopeBlock, state) {
|
|
for (const [_id, decl] of scopeBlock.scope.declarations) {
|
|
state.pruned.set(decl.identifier.declarationId, {
|
|
activeScopes: [...this.activeScopes],
|
|
usedOutsideScope: false,
|
|
});
|
|
}
|
|
this.visitBlock(scopeBlock.instructions, state);
|
|
}
|
|
visitScope(scopeBlock, state) {
|
|
this.activeScopes.push(scopeBlock.scope.id);
|
|
this.traverseScope(scopeBlock, state);
|
|
this.activeScopes.pop();
|
|
}
|
|
}
|
|
class PromoteInterposedTemporaries extends ReactiveFunctionVisitor {
|
|
constructor(promotable, params) {
|
|
super();
|
|
_PromoteInterposedTemporaries_promotable.set(this, void 0);
|
|
_PromoteInterposedTemporaries_consts.set(this, new Set());
|
|
_PromoteInterposedTemporaries_globals.set(this, new Set());
|
|
params.forEach(param => {
|
|
switch (param.kind) {
|
|
case 'Identifier':
|
|
__classPrivateFieldGet(this, _PromoteInterposedTemporaries_consts, "f").add(param.identifier.id);
|
|
break;
|
|
case 'Spread':
|
|
__classPrivateFieldGet(this, _PromoteInterposedTemporaries_consts, "f").add(param.place.identifier.id);
|
|
break;
|
|
}
|
|
});
|
|
__classPrivateFieldSet(this, _PromoteInterposedTemporaries_promotable, promotable, "f");
|
|
}
|
|
visitPlace(_id, place, state) {
|
|
const promo = state.get(place.identifier.id);
|
|
if (promo) {
|
|
const [identifier, needsPromotion] = promo;
|
|
if (needsPromotion &&
|
|
identifier.name === null &&
|
|
!__classPrivateFieldGet(this, _PromoteInterposedTemporaries_consts, "f").has(identifier.id)) {
|
|
promoteIdentifier(identifier, __classPrivateFieldGet(this, _PromoteInterposedTemporaries_promotable, "f"));
|
|
}
|
|
}
|
|
}
|
|
visitInstruction(instruction, state) {
|
|
for (const lval of eachInstructionValueLValue(instruction.value)) {
|
|
CompilerError.invariant(lval.identifier.name != null, {
|
|
reason: 'PromoteInterposedTemporaries: Assignment targets not expected to be temporaries',
|
|
loc: instruction.loc,
|
|
});
|
|
}
|
|
switch (instruction.value.kind) {
|
|
case 'CallExpression':
|
|
case 'MethodCall':
|
|
case 'Await':
|
|
case 'PropertyStore':
|
|
case 'PropertyDelete':
|
|
case 'ComputedStore':
|
|
case 'ComputedDelete':
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate':
|
|
case 'StoreLocal':
|
|
case 'StoreContext':
|
|
case 'StoreGlobal':
|
|
case 'Destructure': {
|
|
let constStore = false;
|
|
if ((instruction.value.kind === 'StoreContext' ||
|
|
instruction.value.kind === 'StoreLocal') &&
|
|
(instruction.value.lvalue.kind === 'Const' ||
|
|
instruction.value.lvalue.kind === 'HoistedConst')) {
|
|
__classPrivateFieldGet(this, _PromoteInterposedTemporaries_consts, "f").add(instruction.value.lvalue.place.identifier.id);
|
|
constStore = true;
|
|
}
|
|
if (instruction.value.kind === 'Destructure' &&
|
|
(instruction.value.lvalue.kind === 'Const' ||
|
|
instruction.value.lvalue.kind === 'HoistedConst')) {
|
|
[...eachPatternOperand(instruction.value.lvalue.pattern)].forEach(ident => __classPrivateFieldGet(this, _PromoteInterposedTemporaries_consts, "f").add(ident.identifier.id));
|
|
constStore = true;
|
|
}
|
|
if (instruction.value.kind === 'MethodCall') {
|
|
__classPrivateFieldGet(this, _PromoteInterposedTemporaries_consts, "f").add(instruction.value.property.identifier.id);
|
|
}
|
|
super.visitInstruction(instruction, state);
|
|
if (!constStore &&
|
|
(instruction.lvalue == null ||
|
|
instruction.lvalue.identifier.name != null)) {
|
|
for (const [key, [ident, _]] of state.entries()) {
|
|
state.set(key, [ident, true]);
|
|
}
|
|
}
|
|
if (instruction.lvalue && instruction.lvalue.identifier.name === null) {
|
|
state.set(instruction.lvalue.identifier.id, [
|
|
instruction.lvalue.identifier,
|
|
false,
|
|
]);
|
|
}
|
|
break;
|
|
}
|
|
case 'DeclareContext':
|
|
case 'DeclareLocal': {
|
|
if (instruction.value.lvalue.kind === 'Const' ||
|
|
instruction.value.lvalue.kind === 'HoistedConst') {
|
|
__classPrivateFieldGet(this, _PromoteInterposedTemporaries_consts, "f").add(instruction.value.lvalue.place.identifier.id);
|
|
}
|
|
super.visitInstruction(instruction, state);
|
|
break;
|
|
}
|
|
case 'LoadContext':
|
|
case 'LoadLocal': {
|
|
if (instruction.lvalue && instruction.lvalue.identifier.name === null) {
|
|
if (__classPrivateFieldGet(this, _PromoteInterposedTemporaries_consts, "f").has(instruction.value.place.identifier.id)) {
|
|
__classPrivateFieldGet(this, _PromoteInterposedTemporaries_consts, "f").add(instruction.lvalue.identifier.id);
|
|
}
|
|
state.set(instruction.lvalue.identifier.id, [
|
|
instruction.lvalue.identifier,
|
|
false,
|
|
]);
|
|
}
|
|
super.visitInstruction(instruction, state);
|
|
break;
|
|
}
|
|
case 'PropertyLoad':
|
|
case 'ComputedLoad': {
|
|
if (instruction.lvalue) {
|
|
if (__classPrivateFieldGet(this, _PromoteInterposedTemporaries_globals, "f").has(instruction.value.object.identifier.id)) {
|
|
__classPrivateFieldGet(this, _PromoteInterposedTemporaries_globals, "f").add(instruction.lvalue.identifier.id);
|
|
__classPrivateFieldGet(this, _PromoteInterposedTemporaries_consts, "f").add(instruction.lvalue.identifier.id);
|
|
}
|
|
if (instruction.lvalue.identifier.name === null) {
|
|
state.set(instruction.lvalue.identifier.id, [
|
|
instruction.lvalue.identifier,
|
|
false,
|
|
]);
|
|
}
|
|
}
|
|
super.visitInstruction(instruction, state);
|
|
break;
|
|
}
|
|
case 'LoadGlobal': {
|
|
instruction.lvalue &&
|
|
__classPrivateFieldGet(this, _PromoteInterposedTemporaries_globals, "f").add(instruction.lvalue.identifier.id);
|
|
super.visitInstruction(instruction, state);
|
|
break;
|
|
}
|
|
default: {
|
|
super.visitInstruction(instruction, state);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_PromoteInterposedTemporaries_promotable = new WeakMap(), _PromoteInterposedTemporaries_consts = new WeakMap(), _PromoteInterposedTemporaries_globals = new WeakMap();
|
|
function promoteUsedTemporaries(fn) {
|
|
const state = {
|
|
tags: new Set(),
|
|
promoted: new Set(),
|
|
pruned: new Map(),
|
|
};
|
|
visitReactiveFunction(fn, new CollectPromotableTemporaries(), state);
|
|
for (const operand of fn.params) {
|
|
const place = operand.kind === 'Identifier' ? operand : operand.place;
|
|
if (place.identifier.name === null) {
|
|
promoteIdentifier(place.identifier, state);
|
|
}
|
|
}
|
|
visitReactiveFunction(fn, new PromoteTemporaries(), state);
|
|
visitReactiveFunction(fn, new PromoteInterposedTemporaries(state, fn.params), new Map());
|
|
visitReactiveFunction(fn, new PromoteAllInstancedOfPromotedTemporaries(), state);
|
|
}
|
|
function promoteIdentifier(identifier, state) {
|
|
CompilerError.invariant(identifier.name === null, {
|
|
reason: 'promoteTemporary: Expected to be called only for temporary variables',
|
|
loc: GeneratedSource,
|
|
});
|
|
if (state.tags.has(identifier.declarationId)) {
|
|
promoteTemporaryJsxTag(identifier);
|
|
}
|
|
else {
|
|
promoteTemporary(identifier);
|
|
}
|
|
state.promoted.add(identifier.declarationId);
|
|
}
|
|
|
|
function propagateEarlyReturns(fn) {
|
|
visitReactiveFunction(fn, new Transform$3(fn.env), {
|
|
withinReactiveScope: false,
|
|
earlyReturnValue: null,
|
|
});
|
|
}
|
|
let Transform$3 = class Transform extends ReactiveFunctionTransform {
|
|
constructor(env) {
|
|
super();
|
|
this.env = env;
|
|
}
|
|
visitScope(scopeBlock, parentState) {
|
|
if (scopeBlock.scope.earlyReturnValue !== null) {
|
|
return;
|
|
}
|
|
const innerState = {
|
|
withinReactiveScope: true,
|
|
earlyReturnValue: parentState.earlyReturnValue,
|
|
};
|
|
this.traverseScope(scopeBlock, innerState);
|
|
const earlyReturnValue = innerState.earlyReturnValue;
|
|
if (earlyReturnValue !== null) {
|
|
if (!parentState.withinReactiveScope) {
|
|
scopeBlock.scope.earlyReturnValue = earlyReturnValue;
|
|
scopeBlock.scope.declarations.set(earlyReturnValue.value.id, {
|
|
identifier: earlyReturnValue.value,
|
|
scope: scopeBlock.scope,
|
|
});
|
|
const instructions = scopeBlock.instructions;
|
|
const loc = earlyReturnValue.loc;
|
|
const sentinelTemp = createTemporaryPlace(this.env, loc);
|
|
const symbolTemp = createTemporaryPlace(this.env, loc);
|
|
const forTemp = createTemporaryPlace(this.env, loc);
|
|
const argTemp = createTemporaryPlace(this.env, loc);
|
|
scopeBlock.instructions = [
|
|
{
|
|
kind: 'instruction',
|
|
instruction: {
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
lvalue: Object.assign({}, symbolTemp),
|
|
value: {
|
|
kind: 'LoadGlobal',
|
|
binding: {
|
|
kind: 'Global',
|
|
name: 'Symbol',
|
|
},
|
|
loc,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
kind: 'instruction',
|
|
instruction: {
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
lvalue: Object.assign({}, forTemp),
|
|
value: {
|
|
kind: 'PropertyLoad',
|
|
object: Object.assign({}, symbolTemp),
|
|
property: makePropertyLiteral('for'),
|
|
loc,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
kind: 'instruction',
|
|
instruction: {
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
lvalue: Object.assign({}, argTemp),
|
|
value: {
|
|
kind: 'Primitive',
|
|
value: EARLY_RETURN_SENTINEL,
|
|
loc,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
kind: 'instruction',
|
|
instruction: {
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
lvalue: Object.assign({}, sentinelTemp),
|
|
value: {
|
|
kind: 'MethodCall',
|
|
receiver: symbolTemp,
|
|
property: forTemp,
|
|
args: [argTemp],
|
|
loc,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
kind: 'instruction',
|
|
instruction: {
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
lvalue: null,
|
|
value: {
|
|
kind: 'StoreLocal',
|
|
loc,
|
|
type: null,
|
|
lvalue: {
|
|
kind: InstructionKind.Let,
|
|
place: {
|
|
kind: 'Identifier',
|
|
effect: Effect.ConditionallyMutate,
|
|
loc,
|
|
reactive: true,
|
|
identifier: earlyReturnValue.value,
|
|
},
|
|
},
|
|
value: Object.assign({}, sentinelTemp),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
kind: 'terminal',
|
|
label: {
|
|
id: earlyReturnValue.label,
|
|
implicit: false,
|
|
},
|
|
terminal: {
|
|
kind: 'label',
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
block: instructions,
|
|
},
|
|
},
|
|
];
|
|
}
|
|
else {
|
|
parentState.earlyReturnValue = earlyReturnValue;
|
|
}
|
|
}
|
|
}
|
|
transformTerminal(stmt, state) {
|
|
if (state.withinReactiveScope && stmt.terminal.kind === 'return') {
|
|
const loc = stmt.terminal.value.loc;
|
|
let earlyReturnValue;
|
|
if (state.earlyReturnValue !== null) {
|
|
earlyReturnValue = state.earlyReturnValue;
|
|
}
|
|
else {
|
|
const identifier = createTemporaryPlace(this.env, loc).identifier;
|
|
promoteTemporary(identifier);
|
|
earlyReturnValue = {
|
|
label: this.env.nextBlockId,
|
|
loc,
|
|
value: identifier,
|
|
};
|
|
}
|
|
state.earlyReturnValue = earlyReturnValue;
|
|
return {
|
|
kind: 'replace-many',
|
|
value: [
|
|
{
|
|
kind: 'instruction',
|
|
instruction: {
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
lvalue: null,
|
|
value: {
|
|
kind: 'StoreLocal',
|
|
loc,
|
|
type: null,
|
|
lvalue: {
|
|
kind: InstructionKind.Reassign,
|
|
place: {
|
|
kind: 'Identifier',
|
|
identifier: earlyReturnValue.value,
|
|
effect: Effect.Capture,
|
|
loc,
|
|
reactive: true,
|
|
},
|
|
},
|
|
value: stmt.terminal.value,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
kind: 'terminal',
|
|
label: null,
|
|
terminal: {
|
|
kind: 'break',
|
|
id: makeInstructionId(0),
|
|
loc,
|
|
targetKind: 'labeled',
|
|
target: earlyReturnValue.label,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
}
|
|
this.traverseTerminal(stmt, state);
|
|
return { kind: 'keep' };
|
|
}
|
|
};
|
|
|
|
var _Node_value, _Node_next;
|
|
function empty() {
|
|
return EMPTY;
|
|
}
|
|
class Node {
|
|
constructor(value, next = EMPTY) {
|
|
_Node_value.set(this, void 0);
|
|
_Node_next.set(this, void 0);
|
|
__classPrivateFieldSet(this, _Node_value, value, "f");
|
|
__classPrivateFieldSet(this, _Node_next, next, "f");
|
|
}
|
|
push(value) {
|
|
return new Node(value, this);
|
|
}
|
|
pop() {
|
|
return __classPrivateFieldGet(this, _Node_next, "f");
|
|
}
|
|
find(fn) {
|
|
return fn(__classPrivateFieldGet(this, _Node_value, "f")) ? true : __classPrivateFieldGet(this, _Node_next, "f").find(fn);
|
|
}
|
|
contains(value) {
|
|
return (value === __classPrivateFieldGet(this, _Node_value, "f") ||
|
|
(__classPrivateFieldGet(this, _Node_next, "f") !== null && __classPrivateFieldGet(this, _Node_next, "f").contains(value)));
|
|
}
|
|
each(fn) {
|
|
fn(__classPrivateFieldGet(this, _Node_value, "f"));
|
|
__classPrivateFieldGet(this, _Node_next, "f").each(fn);
|
|
}
|
|
get value() {
|
|
return __classPrivateFieldGet(this, _Node_value, "f");
|
|
}
|
|
print(fn) {
|
|
return fn(__classPrivateFieldGet(this, _Node_value, "f")) + __classPrivateFieldGet(this, _Node_next, "f").print(fn);
|
|
}
|
|
}
|
|
_Node_value = new WeakMap(), _Node_next = new WeakMap();
|
|
class Empty {
|
|
push(value) {
|
|
return new Node(value, this);
|
|
}
|
|
pop() {
|
|
return this;
|
|
}
|
|
find(_fn) {
|
|
return false;
|
|
}
|
|
contains(_value) {
|
|
return false;
|
|
}
|
|
each(_fn) {
|
|
return;
|
|
}
|
|
get value() {
|
|
return null;
|
|
}
|
|
print(_) {
|
|
return '';
|
|
}
|
|
}
|
|
const EMPTY = new Empty();
|
|
|
|
function pruneHoistedContexts(fn) {
|
|
visitReactiveFunction(fn, new Visitor$6(), {
|
|
activeScopes: empty(),
|
|
uninitialized: new Map(),
|
|
});
|
|
}
|
|
let Visitor$6 = class Visitor extends ReactiveFunctionTransform {
|
|
visitScope(scope, state) {
|
|
state.activeScopes = state.activeScopes.push(new Set(scope.scope.declarations.keys()));
|
|
for (const decl of scope.scope.declarations.values()) {
|
|
state.uninitialized.set(decl.identifier.id, { kind: 'unknown-kind' });
|
|
}
|
|
this.traverseScope(scope, state);
|
|
state.activeScopes.pop();
|
|
for (const decl of scope.scope.declarations.values()) {
|
|
state.uninitialized.delete(decl.identifier.id);
|
|
}
|
|
}
|
|
visitPlace(_id, place, state) {
|
|
const maybeHoistedFn = state.uninitialized.get(place.identifier.id);
|
|
if ((maybeHoistedFn === null || maybeHoistedFn === void 0 ? void 0 : maybeHoistedFn.kind) === 'func' &&
|
|
maybeHoistedFn.definition !== place) {
|
|
CompilerError.throwTodo({
|
|
reason: '[PruneHoistedContexts] Rewrite hoisted function references',
|
|
loc: place.loc,
|
|
});
|
|
}
|
|
}
|
|
transformInstruction(instruction, state) {
|
|
if (instruction.value.kind === 'DeclareContext') {
|
|
const maybeNonHoisted = convertHoistedLValueKind(instruction.value.lvalue.kind);
|
|
if (maybeNonHoisted != null) {
|
|
if (maybeNonHoisted === InstructionKind.Function &&
|
|
state.uninitialized.has(instruction.value.lvalue.place.identifier.id)) {
|
|
state.uninitialized.set(instruction.value.lvalue.place.identifier.id, {
|
|
kind: 'func',
|
|
definition: null,
|
|
});
|
|
}
|
|
return { kind: 'remove' };
|
|
}
|
|
}
|
|
if (instruction.value.kind === 'StoreContext' &&
|
|
instruction.value.lvalue.kind !== InstructionKind.Reassign) {
|
|
const lvalueId = instruction.value.lvalue.place.identifier.id;
|
|
const isDeclaredByScope = state.activeScopes.find(scope => scope.has(lvalueId));
|
|
if (isDeclaredByScope) {
|
|
if (instruction.value.lvalue.kind === InstructionKind.Let ||
|
|
instruction.value.lvalue.kind === InstructionKind.Const) {
|
|
instruction.value.lvalue.kind = InstructionKind.Reassign;
|
|
}
|
|
else if (instruction.value.lvalue.kind === InstructionKind.Function) {
|
|
const maybeHoistedFn = state.uninitialized.get(lvalueId);
|
|
if (maybeHoistedFn != null) {
|
|
CompilerError.invariant(maybeHoistedFn.kind === 'func', {
|
|
reason: '[PruneHoistedContexts] Unexpected hoisted function',
|
|
loc: instruction.loc,
|
|
});
|
|
maybeHoistedFn.definition = instruction.value.lvalue.place;
|
|
state.uninitialized.delete(lvalueId);
|
|
}
|
|
}
|
|
else {
|
|
CompilerError.throwTodo({
|
|
reason: '[PruneHoistedContexts] Unexpected kind',
|
|
description: `(${instruction.value.lvalue.kind})`,
|
|
loc: instruction.loc,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
this.visitInstruction(instruction, state);
|
|
return { kind: 'keep' };
|
|
}
|
|
};
|
|
|
|
function hashEffect(effect) {
|
|
var _a;
|
|
switch (effect.kind) {
|
|
case 'Apply': {
|
|
return [
|
|
effect.kind,
|
|
effect.receiver.identifier.id,
|
|
effect.function.identifier.id,
|
|
effect.mutatesFunction,
|
|
effect.args
|
|
.map(a => {
|
|
if (a.kind === 'Hole') {
|
|
return '';
|
|
}
|
|
else if (a.kind === 'Identifier') {
|
|
return a.identifier.id;
|
|
}
|
|
else {
|
|
return `...${a.place.identifier.id}`;
|
|
}
|
|
})
|
|
.join(','),
|
|
effect.into.identifier.id,
|
|
].join(':');
|
|
}
|
|
case 'CreateFrom':
|
|
case 'ImmutableCapture':
|
|
case 'Assign':
|
|
case 'Alias':
|
|
case 'Capture':
|
|
case 'MaybeAlias': {
|
|
return [
|
|
effect.kind,
|
|
effect.from.identifier.id,
|
|
effect.into.identifier.id,
|
|
].join(':');
|
|
}
|
|
case 'Create': {
|
|
return [
|
|
effect.kind,
|
|
effect.into.identifier.id,
|
|
effect.value,
|
|
effect.reason,
|
|
].join(':');
|
|
}
|
|
case 'Freeze': {
|
|
return [effect.kind, effect.value.identifier.id, effect.reason].join(':');
|
|
}
|
|
case 'Impure':
|
|
case 'Render': {
|
|
return [effect.kind, effect.place.identifier.id].join(':');
|
|
}
|
|
case 'MutateFrozen':
|
|
case 'MutateGlobal': {
|
|
return [
|
|
effect.kind,
|
|
effect.place.identifier.id,
|
|
effect.error.severity,
|
|
effect.error.reason,
|
|
effect.error.description,
|
|
printSourceLocation((_a = effect.error.primaryLocation()) !== null && _a !== void 0 ? _a : GeneratedSource),
|
|
].join(':');
|
|
}
|
|
case 'Mutate':
|
|
case 'MutateConditionally':
|
|
case 'MutateTransitive':
|
|
case 'MutateTransitiveConditionally': {
|
|
return [effect.kind, effect.value.identifier.id].join(':');
|
|
}
|
|
case 'CreateFunction': {
|
|
return [
|
|
effect.kind,
|
|
effect.into.identifier.id,
|
|
effect.function.loweredFunc.func.returns.identifier.id,
|
|
effect.captures.map(p => p.identifier.id).join(','),
|
|
].join(':');
|
|
}
|
|
}
|
|
}
|
|
|
|
var _InferenceState_isFunctionExpression, _InferenceState_values, _InferenceState_variables;
|
|
function inferMutationAliasingEffects(fn, { isFunctionExpression } = {
|
|
isFunctionExpression: false,
|
|
}) {
|
|
const initialState = InferenceState.empty(fn.env, isFunctionExpression);
|
|
const statesByBlock = new Map();
|
|
for (const ref of fn.context) {
|
|
const value = {
|
|
kind: 'ObjectExpression',
|
|
properties: [],
|
|
loc: ref.loc,
|
|
};
|
|
initialState.initialize(value, {
|
|
kind: ValueKind.Context,
|
|
reason: new Set([ValueReason.Other]),
|
|
});
|
|
initialState.define(ref, value);
|
|
}
|
|
const paramKind = isFunctionExpression
|
|
? {
|
|
kind: ValueKind.Mutable,
|
|
reason: new Set([ValueReason.Other]),
|
|
}
|
|
: {
|
|
kind: ValueKind.Frozen,
|
|
reason: new Set([ValueReason.ReactiveFunctionArgument]),
|
|
};
|
|
if (fn.fnType === 'Component') {
|
|
CompilerError.invariant(fn.params.length <= 2, {
|
|
reason: 'Expected React component to have not more than two parameters: one for props and for ref',
|
|
loc: fn.loc,
|
|
});
|
|
const [props, ref] = fn.params;
|
|
if (props != null) {
|
|
inferParam(props, initialState, paramKind);
|
|
}
|
|
if (ref != null) {
|
|
const place = ref.kind === 'Identifier' ? ref : ref.place;
|
|
const value = {
|
|
kind: 'ObjectExpression',
|
|
properties: [],
|
|
loc: place.loc,
|
|
};
|
|
initialState.initialize(value, {
|
|
kind: ValueKind.Mutable,
|
|
reason: new Set([ValueReason.Other]),
|
|
});
|
|
initialState.define(place, value);
|
|
}
|
|
}
|
|
else {
|
|
for (const param of fn.params) {
|
|
inferParam(param, initialState, paramKind);
|
|
}
|
|
}
|
|
const queuedStates = new Map();
|
|
function queue(blockId, state) {
|
|
var _a;
|
|
let queuedState = queuedStates.get(blockId);
|
|
if (queuedState != null) {
|
|
state = (_a = queuedState.merge(state)) !== null && _a !== void 0 ? _a : queuedState;
|
|
queuedStates.set(blockId, state);
|
|
}
|
|
else {
|
|
const prevState = statesByBlock.get(blockId);
|
|
const nextState = prevState != null ? prevState.merge(state) : state;
|
|
if (nextState != null) {
|
|
queuedStates.set(blockId, nextState);
|
|
}
|
|
}
|
|
}
|
|
queue(fn.body.entry, initialState);
|
|
const hoistedContextDeclarations = findHoistedContextDeclarations(fn);
|
|
const context = new Context(isFunctionExpression, fn, hoistedContextDeclarations, findNonMutatedDestructureSpreads(fn));
|
|
let iterationCount = 0;
|
|
while (queuedStates.size !== 0) {
|
|
iterationCount++;
|
|
if (iterationCount > 100) {
|
|
CompilerError.invariant(false, {
|
|
reason: `[InferMutationAliasingEffects] Potential infinite loop`,
|
|
description: `A value, temporary place, or effect was not cached properly`,
|
|
loc: fn.loc,
|
|
});
|
|
}
|
|
for (const [blockId, block] of fn.body.blocks) {
|
|
const incomingState = queuedStates.get(blockId);
|
|
queuedStates.delete(blockId);
|
|
if (incomingState == null) {
|
|
continue;
|
|
}
|
|
statesByBlock.set(blockId, incomingState);
|
|
const state = incomingState.clone();
|
|
inferBlock(context, state, block);
|
|
for (const nextBlockId of eachTerminalSuccessor(block.terminal)) {
|
|
queue(nextBlockId, state);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
function findHoistedContextDeclarations(fn) {
|
|
const hoisted = new Map();
|
|
function visit(place) {
|
|
if (hoisted.has(place.identifier.declarationId) &&
|
|
hoisted.get(place.identifier.declarationId) == null) {
|
|
hoisted.set(place.identifier.declarationId, place);
|
|
}
|
|
}
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
if (instr.value.kind === 'DeclareContext') {
|
|
const kind = instr.value.lvalue.kind;
|
|
if (kind == InstructionKind.HoistedConst ||
|
|
kind == InstructionKind.HoistedFunction ||
|
|
kind == InstructionKind.HoistedLet) {
|
|
hoisted.set(instr.value.lvalue.place.identifier.declarationId, null);
|
|
}
|
|
}
|
|
else {
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
visit(operand);
|
|
}
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
visit(operand);
|
|
}
|
|
}
|
|
return hoisted;
|
|
}
|
|
class Context {
|
|
constructor(isFunctionExpression, fn, hoistedContextDeclarations, nonMutatingSpreads) {
|
|
this.internedEffects = new Map();
|
|
this.instructionSignatureCache = new Map();
|
|
this.effectInstructionValueCache = new Map();
|
|
this.applySignatureCache = new Map();
|
|
this.catchHandlers = new Map();
|
|
this.functionSignatureCache = new Map();
|
|
this.isFuctionExpression = isFunctionExpression;
|
|
this.fn = fn;
|
|
this.hoistedContextDeclarations = hoistedContextDeclarations;
|
|
this.nonMutatingSpreads = nonMutatingSpreads;
|
|
}
|
|
cacheApplySignature(signature, effect, f) {
|
|
const inner = getOrInsertDefault(this.applySignatureCache, signature, new Map());
|
|
return getOrInsertWith(inner, effect, f);
|
|
}
|
|
internEffect(effect) {
|
|
const hash = hashEffect(effect);
|
|
let interned = this.internedEffects.get(hash);
|
|
if (interned == null) {
|
|
this.internedEffects.set(hash, effect);
|
|
interned = effect;
|
|
}
|
|
return interned;
|
|
}
|
|
}
|
|
function findNonMutatedDestructureSpreads(fn) {
|
|
const knownFrozen = new Set();
|
|
if (fn.fnType === 'Component') {
|
|
const [props] = fn.params;
|
|
if (props != null && props.kind === 'Identifier') {
|
|
knownFrozen.add(props.identifier.id);
|
|
}
|
|
}
|
|
else {
|
|
for (const param of fn.params) {
|
|
if (param.kind === 'Identifier') {
|
|
knownFrozen.add(param.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
const candidateNonMutatingSpreads = new Map();
|
|
for (const block of fn.body.blocks.values()) {
|
|
if (candidateNonMutatingSpreads.size !== 0) {
|
|
for (const phi of block.phis) {
|
|
for (const operand of phi.operands.values()) {
|
|
const spread = candidateNonMutatingSpreads.get(operand.identifier.id);
|
|
if (spread != null) {
|
|
candidateNonMutatingSpreads.delete(spread);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
switch (value.kind) {
|
|
case 'Destructure': {
|
|
if (!knownFrozen.has(value.value.identifier.id) ||
|
|
!(value.lvalue.kind === InstructionKind.Let ||
|
|
value.lvalue.kind === InstructionKind.Const) ||
|
|
value.lvalue.pattern.kind !== 'ObjectPattern') {
|
|
continue;
|
|
}
|
|
for (const item of value.lvalue.pattern.properties) {
|
|
if (item.kind !== 'Spread') {
|
|
continue;
|
|
}
|
|
candidateNonMutatingSpreads.set(item.place.identifier.id, item.place.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
const spread = candidateNonMutatingSpreads.get(value.place.identifier.id);
|
|
if (spread != null) {
|
|
candidateNonMutatingSpreads.set(lvalue.identifier.id, spread);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
const spread = candidateNonMutatingSpreads.get(value.value.identifier.id);
|
|
if (spread != null) {
|
|
candidateNonMutatingSpreads.set(lvalue.identifier.id, spread);
|
|
candidateNonMutatingSpreads.set(value.lvalue.place.identifier.id, spread);
|
|
}
|
|
break;
|
|
}
|
|
case 'JsxFragment':
|
|
case 'JsxExpression': {
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
break;
|
|
}
|
|
case 'CallExpression':
|
|
case 'MethodCall': {
|
|
const callee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
if (getHookKind(fn.env, callee.identifier) != null) {
|
|
if (!isRefOrRefValue(lvalue.identifier)) {
|
|
knownFrozen.add(lvalue.identifier.id);
|
|
}
|
|
}
|
|
else {
|
|
if (candidateNonMutatingSpreads.size !== 0) {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
const spread = candidateNonMutatingSpreads.get(operand.identifier.id);
|
|
if (spread != null) {
|
|
candidateNonMutatingSpreads.delete(spread);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if (candidateNonMutatingSpreads.size !== 0) {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
const spread = candidateNonMutatingSpreads.get(operand.identifier.id);
|
|
if (spread != null) {
|
|
candidateNonMutatingSpreads.delete(spread);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const nonMutatingSpreads = new Set();
|
|
for (const [key, value] of candidateNonMutatingSpreads) {
|
|
if (key === value) {
|
|
nonMutatingSpreads.add(key);
|
|
}
|
|
}
|
|
return nonMutatingSpreads;
|
|
}
|
|
function inferParam(param, initialState, paramKind) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
const value = {
|
|
kind: 'Primitive',
|
|
loc: place.loc,
|
|
value: undefined,
|
|
};
|
|
initialState.initialize(value, paramKind);
|
|
initialState.define(place, value);
|
|
}
|
|
function inferBlock(context, state, block) {
|
|
for (const phi of block.phis) {
|
|
state.inferPhi(phi);
|
|
}
|
|
for (const instr of block.instructions) {
|
|
let instructionSignature = context.instructionSignatureCache.get(instr);
|
|
if (instructionSignature == null) {
|
|
instructionSignature = computeSignatureForInstruction(context, state.env, instr);
|
|
context.instructionSignatureCache.set(instr, instructionSignature);
|
|
}
|
|
const effects = applySignature(context, state, instructionSignature, instr);
|
|
instr.effects = effects;
|
|
}
|
|
const terminal = block.terminal;
|
|
if (terminal.kind === 'try' && terminal.handlerBinding != null) {
|
|
context.catchHandlers.set(terminal.handler, terminal.handlerBinding);
|
|
}
|
|
else if (terminal.kind === 'maybe-throw' && terminal.handler !== null) {
|
|
const handlerParam = context.catchHandlers.get(terminal.handler);
|
|
if (handlerParam != null) {
|
|
CompilerError.invariant(state.kind(handlerParam) != null, {
|
|
reason: 'Expected catch binding to be initialized with a DeclareLocal Catch instruction',
|
|
loc: terminal.loc,
|
|
});
|
|
const effects = [];
|
|
for (const instr of block.instructions) {
|
|
if (instr.value.kind === 'CallExpression' ||
|
|
instr.value.kind === 'MethodCall') {
|
|
state.appendAlias(handlerParam, instr.lvalue);
|
|
const kind = state.kind(instr.lvalue).kind;
|
|
if (kind === ValueKind.Mutable || kind == ValueKind.Context) {
|
|
effects.push(context.internEffect({
|
|
kind: 'Alias',
|
|
from: instr.lvalue,
|
|
into: handlerParam,
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
terminal.effects = effects.length !== 0 ? effects : null;
|
|
}
|
|
}
|
|
else if (terminal.kind === 'return') {
|
|
if (!context.isFuctionExpression) {
|
|
terminal.effects = [
|
|
context.internEffect({
|
|
kind: 'Freeze',
|
|
value: terminal.value,
|
|
reason: ValueReason.JsxCaptured,
|
|
}),
|
|
];
|
|
}
|
|
}
|
|
}
|
|
function applySignature(context, state, signature, instruction) {
|
|
var _a, _b;
|
|
const effects = [];
|
|
if (instruction.value.kind === 'FunctionExpression' ||
|
|
instruction.value.kind === 'ObjectMethod') {
|
|
const aliasingEffects = (_a = instruction.value.loweredFunc.func.aliasingEffects) !== null && _a !== void 0 ? _a : [];
|
|
const context = new Set(instruction.value.loweredFunc.func.context.map(p => p.identifier.id));
|
|
for (const effect of aliasingEffects) {
|
|
if (effect.kind === 'Mutate' || effect.kind === 'MutateTransitive') {
|
|
if (!context.has(effect.value.identifier.id)) {
|
|
continue;
|
|
}
|
|
const value = state.kind(effect.value);
|
|
switch (value.kind) {
|
|
case ValueKind.Frozen: {
|
|
const reason = getWriteErrorReason({
|
|
kind: value.kind,
|
|
reason: value.reason,
|
|
});
|
|
const variable = effect.value.identifier.name !== null &&
|
|
effect.value.identifier.name.kind === 'named'
|
|
? `\`${effect.value.identifier.name.value}\``
|
|
: 'value';
|
|
const diagnostic = CompilerDiagnostic.create({
|
|
category: ErrorCategory.Immutability,
|
|
reason: 'This value cannot be modified',
|
|
description: reason,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: effect.value.loc,
|
|
message: `${variable} cannot be modified`,
|
|
});
|
|
if (effect.kind === 'Mutate' &&
|
|
((_b = effect.reason) === null || _b === void 0 ? void 0 : _b.kind) === 'AssignCurrentProperty') {
|
|
diagnostic.withDetails({
|
|
kind: 'hint',
|
|
message: `Hint: If this value is a Ref (value returned by \`useRef()\`), rename the variable to end in "Ref".`,
|
|
});
|
|
}
|
|
effects.push({
|
|
kind: 'MutateFrozen',
|
|
place: effect.value,
|
|
error: diagnostic,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const initialized = new Set();
|
|
for (const effect of signature.effects) {
|
|
applyEffect(context, state, effect, initialized, effects);
|
|
}
|
|
if (!(state.isDefined(instruction.lvalue) && state.kind(instruction.lvalue))) {
|
|
CompilerError.invariant(false, {
|
|
reason: `Expected instruction lvalue to be initialized`,
|
|
loc: instruction.loc,
|
|
});
|
|
}
|
|
return effects.length !== 0 ? effects : null;
|
|
}
|
|
function applyEffect(context, state, _effect, initialized, effects) {
|
|
var _a, _b, _c, _d, _e;
|
|
const effect = context.internEffect(_effect);
|
|
switch (effect.kind) {
|
|
case 'Freeze': {
|
|
const didFreeze = state.freeze(effect.value, effect.reason);
|
|
if (didFreeze) {
|
|
effects.push(effect);
|
|
}
|
|
break;
|
|
}
|
|
case 'Create': {
|
|
CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
|
|
reason: `Cannot re-initialize variable within an instruction`,
|
|
description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
|
|
loc: effect.into.loc,
|
|
});
|
|
initialized.add(effect.into.identifier.id);
|
|
let value = context.effectInstructionValueCache.get(effect);
|
|
if (value == null) {
|
|
value = {
|
|
kind: 'ObjectExpression',
|
|
properties: [],
|
|
loc: effect.into.loc,
|
|
};
|
|
context.effectInstructionValueCache.set(effect, value);
|
|
}
|
|
state.initialize(value, {
|
|
kind: effect.value,
|
|
reason: new Set([effect.reason]),
|
|
});
|
|
state.define(effect.into, value);
|
|
effects.push(effect);
|
|
break;
|
|
}
|
|
case 'ImmutableCapture': {
|
|
const kind = state.kind(effect.from).kind;
|
|
switch (kind) {
|
|
case ValueKind.Global:
|
|
case ValueKind.Primitive: {
|
|
break;
|
|
}
|
|
default: {
|
|
effects.push(effect);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'CreateFrom': {
|
|
CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
|
|
reason: `Cannot re-initialize variable within an instruction`,
|
|
description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
|
|
loc: effect.into.loc,
|
|
});
|
|
initialized.add(effect.into.identifier.id);
|
|
const fromValue = state.kind(effect.from);
|
|
let value = context.effectInstructionValueCache.get(effect);
|
|
if (value == null) {
|
|
value = {
|
|
kind: 'ObjectExpression',
|
|
properties: [],
|
|
loc: effect.into.loc,
|
|
};
|
|
context.effectInstructionValueCache.set(effect, value);
|
|
}
|
|
state.initialize(value, {
|
|
kind: fromValue.kind,
|
|
reason: new Set(fromValue.reason),
|
|
});
|
|
state.define(effect.into, value);
|
|
switch (fromValue.kind) {
|
|
case ValueKind.Primitive:
|
|
case ValueKind.Global: {
|
|
effects.push({
|
|
kind: 'Create',
|
|
value: fromValue.kind,
|
|
into: effect.into,
|
|
reason: (_a = [...fromValue.reason][0]) !== null && _a !== void 0 ? _a : ValueReason.Other,
|
|
});
|
|
break;
|
|
}
|
|
case ValueKind.Frozen: {
|
|
effects.push({
|
|
kind: 'Create',
|
|
value: fromValue.kind,
|
|
into: effect.into,
|
|
reason: (_b = [...fromValue.reason][0]) !== null && _b !== void 0 ? _b : ValueReason.Other,
|
|
});
|
|
applyEffect(context, state, {
|
|
kind: 'ImmutableCapture',
|
|
from: effect.from,
|
|
into: effect.into,
|
|
}, initialized, effects);
|
|
break;
|
|
}
|
|
default: {
|
|
effects.push(effect);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'CreateFunction': {
|
|
CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
|
|
reason: `Cannot re-initialize variable within an instruction`,
|
|
description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
|
|
loc: effect.into.loc,
|
|
});
|
|
initialized.add(effect.into.identifier.id);
|
|
effects.push(effect);
|
|
const hasCaptures = effect.captures.some(capture => {
|
|
switch (state.kind(capture).kind) {
|
|
case ValueKind.Context:
|
|
case ValueKind.Mutable: {
|
|
return true;
|
|
}
|
|
default: {
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
const hasTrackedSideEffects = (_c = effect.function.loweredFunc.func.aliasingEffects) === null || _c === void 0 ? void 0 : _c.some(effect => effect.kind === 'MutateFrozen' ||
|
|
effect.kind === 'MutateGlobal' ||
|
|
effect.kind === 'Impure');
|
|
const capturesRef = effect.function.loweredFunc.func.context.some(operand => isRefOrRefValue(operand.identifier));
|
|
const isMutable = hasCaptures || hasTrackedSideEffects || capturesRef;
|
|
for (const operand of effect.function.loweredFunc.func.context) {
|
|
if (operand.effect !== Effect.Capture) {
|
|
continue;
|
|
}
|
|
const kind = state.kind(operand).kind;
|
|
if (kind === ValueKind.Primitive ||
|
|
kind == ValueKind.Frozen ||
|
|
kind == ValueKind.Global) {
|
|
operand.effect = Effect.Read;
|
|
}
|
|
}
|
|
state.initialize(effect.function, {
|
|
kind: isMutable ? ValueKind.Mutable : ValueKind.Frozen,
|
|
reason: new Set([]),
|
|
});
|
|
state.define(effect.into, effect.function);
|
|
for (const capture of effect.captures) {
|
|
applyEffect(context, state, {
|
|
kind: 'Capture',
|
|
from: capture,
|
|
into: effect.into,
|
|
}, initialized, effects);
|
|
}
|
|
break;
|
|
}
|
|
case 'MaybeAlias':
|
|
case 'Alias':
|
|
case 'Capture': {
|
|
CompilerError.invariant(effect.kind === 'Capture' ||
|
|
effect.kind === 'MaybeAlias' ||
|
|
initialized.has(effect.into.identifier.id), {
|
|
reason: `Expected destination to already be initialized within this instruction`,
|
|
description: `Destination ${printPlace(effect.into)} is not initialized in this ` +
|
|
`instruction for effect ${printAliasingEffect(effect)}`,
|
|
loc: effect.into.loc,
|
|
});
|
|
const intoKind = state.kind(effect.into).kind;
|
|
let destinationType = null;
|
|
switch (intoKind) {
|
|
case ValueKind.Context: {
|
|
destinationType = 'context';
|
|
break;
|
|
}
|
|
case ValueKind.Mutable:
|
|
case ValueKind.MaybeFrozen: {
|
|
destinationType = 'mutable';
|
|
break;
|
|
}
|
|
}
|
|
const fromKind = state.kind(effect.from).kind;
|
|
let sourceType = null;
|
|
switch (fromKind) {
|
|
case ValueKind.Context: {
|
|
sourceType = 'context';
|
|
break;
|
|
}
|
|
case ValueKind.Global:
|
|
case ValueKind.Primitive: {
|
|
break;
|
|
}
|
|
case ValueKind.MaybeFrozen:
|
|
case ValueKind.Frozen: {
|
|
sourceType = 'frozen';
|
|
break;
|
|
}
|
|
default: {
|
|
sourceType = 'mutable';
|
|
break;
|
|
}
|
|
}
|
|
if (sourceType === 'frozen') {
|
|
applyEffect(context, state, {
|
|
kind: 'ImmutableCapture',
|
|
from: effect.from,
|
|
into: effect.into,
|
|
}, initialized, effects);
|
|
}
|
|
else if ((sourceType === 'mutable' && destinationType === 'mutable') ||
|
|
effect.kind === 'MaybeAlias') {
|
|
effects.push(effect);
|
|
}
|
|
else if ((sourceType === 'context' && destinationType != null) ||
|
|
(sourceType === 'mutable' && destinationType === 'context')) {
|
|
applyEffect(context, state, { kind: 'MaybeAlias', from: effect.from, into: effect.into }, initialized, effects);
|
|
}
|
|
break;
|
|
}
|
|
case 'Assign': {
|
|
CompilerError.invariant(!initialized.has(effect.into.identifier.id), {
|
|
reason: `Cannot re-initialize variable within an instruction`,
|
|
description: `Re-initialized ${printPlace(effect.into)} in ${printAliasingEffect(effect)}`,
|
|
loc: effect.into.loc,
|
|
});
|
|
initialized.add(effect.into.identifier.id);
|
|
const fromValue = state.kind(effect.from);
|
|
const fromKind = fromValue.kind;
|
|
switch (fromKind) {
|
|
case ValueKind.Frozen: {
|
|
applyEffect(context, state, {
|
|
kind: 'ImmutableCapture',
|
|
from: effect.from,
|
|
into: effect.into,
|
|
}, initialized, effects);
|
|
let value = context.effectInstructionValueCache.get(effect);
|
|
if (value == null) {
|
|
value = {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: effect.from.loc,
|
|
};
|
|
context.effectInstructionValueCache.set(effect, value);
|
|
}
|
|
state.initialize(value, {
|
|
kind: fromKind,
|
|
reason: new Set(fromValue.reason),
|
|
});
|
|
state.define(effect.into, value);
|
|
break;
|
|
}
|
|
case ValueKind.Global:
|
|
case ValueKind.Primitive: {
|
|
let value = context.effectInstructionValueCache.get(effect);
|
|
if (value == null) {
|
|
value = {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: effect.from.loc,
|
|
};
|
|
context.effectInstructionValueCache.set(effect, value);
|
|
}
|
|
state.initialize(value, {
|
|
kind: fromKind,
|
|
reason: new Set(fromValue.reason),
|
|
});
|
|
state.define(effect.into, value);
|
|
break;
|
|
}
|
|
default: {
|
|
state.assign(effect.into, effect.from);
|
|
effects.push(effect);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'Apply': {
|
|
const functionValues = state.values(effect.function);
|
|
if (functionValues.length === 1 &&
|
|
functionValues[0].kind === 'FunctionExpression' &&
|
|
functionValues[0].loweredFunc.func.aliasingEffects != null) {
|
|
const functionExpr = functionValues[0];
|
|
let signature = context.functionSignatureCache.get(functionExpr);
|
|
if (signature == null) {
|
|
signature = buildSignatureFromFunctionExpression(state.env, functionExpr);
|
|
context.functionSignatureCache.set(functionExpr, signature);
|
|
}
|
|
const signatureEffects = context.cacheApplySignature(signature, effect, () => computeEffectsForSignature(state.env, signature, effect.into, effect.receiver, effect.args, functionExpr.loweredFunc.func.context, effect.loc));
|
|
if (signatureEffects != null) {
|
|
applyEffect(context, state, { kind: 'MutateTransitiveConditionally', value: effect.function }, initialized, effects);
|
|
for (const signatureEffect of signatureEffects) {
|
|
applyEffect(context, state, signatureEffect, initialized, effects);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
let signatureEffects = null;
|
|
if (((_d = effect.signature) === null || _d === void 0 ? void 0 : _d.aliasing) != null) {
|
|
const signature = effect.signature.aliasing;
|
|
signatureEffects = context.cacheApplySignature(effect.signature.aliasing, effect, () => computeEffectsForSignature(state.env, signature, effect.into, effect.receiver, effect.args, [], effect.loc));
|
|
}
|
|
if (signatureEffects != null) {
|
|
for (const signatureEffect of signatureEffects) {
|
|
applyEffect(context, state, signatureEffect, initialized, effects);
|
|
}
|
|
}
|
|
else if (effect.signature != null) {
|
|
const legacyEffects = computeEffectsForLegacySignature(state, effect.signature, effect.into, effect.receiver, effect.args, effect.loc);
|
|
for (const legacyEffect of legacyEffects) {
|
|
applyEffect(context, state, legacyEffect, initialized, effects);
|
|
}
|
|
}
|
|
else {
|
|
applyEffect(context, state, {
|
|
kind: 'Create',
|
|
into: effect.into,
|
|
value: ValueKind.Mutable,
|
|
reason: ValueReason.Other,
|
|
}, initialized, effects);
|
|
for (const arg of [effect.receiver, effect.function, ...effect.args]) {
|
|
if (arg.kind === 'Hole') {
|
|
continue;
|
|
}
|
|
const operand = arg.kind === 'Identifier' ? arg : arg.place;
|
|
if (operand !== effect.function || effect.mutatesFunction) {
|
|
applyEffect(context, state, {
|
|
kind: 'MutateTransitiveConditionally',
|
|
value: operand,
|
|
}, initialized, effects);
|
|
}
|
|
const mutateIterator = arg.kind === 'Spread' ? conditionallyMutateIterator(operand) : null;
|
|
if (mutateIterator) {
|
|
applyEffect(context, state, mutateIterator, initialized, effects);
|
|
}
|
|
applyEffect(context, state, { kind: 'MaybeAlias', from: operand, into: effect.into }, initialized, effects);
|
|
for (const otherArg of [
|
|
effect.receiver,
|
|
effect.function,
|
|
...effect.args,
|
|
]) {
|
|
if (otherArg.kind === 'Hole') {
|
|
continue;
|
|
}
|
|
const other = otherArg.kind === 'Identifier' ? otherArg : otherArg.place;
|
|
if (other === arg) {
|
|
continue;
|
|
}
|
|
applyEffect(context, state, {
|
|
kind: 'Capture',
|
|
from: operand,
|
|
into: other,
|
|
}, initialized, effects);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'Mutate':
|
|
case 'MutateConditionally':
|
|
case 'MutateTransitive':
|
|
case 'MutateTransitiveConditionally': {
|
|
const mutationKind = state.mutate(effect.kind, effect.value);
|
|
if (mutationKind === 'mutate') {
|
|
effects.push(effect);
|
|
}
|
|
else if (mutationKind === 'mutate-ref') ;
|
|
else if (mutationKind !== 'none' &&
|
|
(effect.kind === 'Mutate' || effect.kind === 'MutateTransitive')) {
|
|
const value = state.kind(effect.value);
|
|
if (mutationKind === 'mutate-frozen' &&
|
|
context.hoistedContextDeclarations.has(effect.value.identifier.declarationId)) {
|
|
const variable = effect.value.identifier.name !== null &&
|
|
effect.value.identifier.name.kind === 'named'
|
|
? `\`${effect.value.identifier.name.value}\``
|
|
: null;
|
|
const hoistedAccess = context.hoistedContextDeclarations.get(effect.value.identifier.declarationId);
|
|
const diagnostic = CompilerDiagnostic.create({
|
|
category: ErrorCategory.Immutability,
|
|
reason: 'Cannot access variable before it is declared',
|
|
description: `${variable !== null && variable !== void 0 ? variable : 'This variable'} is accessed before it is declared, which prevents the earlier access from updating when this value changes over time`,
|
|
});
|
|
if (hoistedAccess != null && hoistedAccess.loc != effect.value.loc) {
|
|
diagnostic.withDetails({
|
|
kind: 'error',
|
|
loc: hoistedAccess.loc,
|
|
message: `${variable !== null && variable !== void 0 ? variable : 'variable'} accessed before it is declared`,
|
|
});
|
|
}
|
|
diagnostic.withDetails({
|
|
kind: 'error',
|
|
loc: effect.value.loc,
|
|
message: `${variable !== null && variable !== void 0 ? variable : 'variable'} is declared here`,
|
|
});
|
|
applyEffect(context, state, {
|
|
kind: 'MutateFrozen',
|
|
place: effect.value,
|
|
error: diagnostic,
|
|
}, initialized, effects);
|
|
}
|
|
else {
|
|
const reason = getWriteErrorReason({
|
|
kind: value.kind,
|
|
reason: value.reason,
|
|
});
|
|
const variable = effect.value.identifier.name !== null &&
|
|
effect.value.identifier.name.kind === 'named'
|
|
? `\`${effect.value.identifier.name.value}\``
|
|
: 'value';
|
|
const diagnostic = CompilerDiagnostic.create({
|
|
category: ErrorCategory.Immutability,
|
|
reason: 'This value cannot be modified',
|
|
description: reason,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: effect.value.loc,
|
|
message: `${variable} cannot be modified`,
|
|
});
|
|
if (effect.kind === 'Mutate' &&
|
|
((_e = effect.reason) === null || _e === void 0 ? void 0 : _e.kind) === 'AssignCurrentProperty') {
|
|
diagnostic.withDetails({
|
|
kind: 'hint',
|
|
message: `Hint: If this value is a Ref (value returned by \`useRef()\`), rename the variable to end in "Ref".`,
|
|
});
|
|
}
|
|
applyEffect(context, state, {
|
|
kind: value.kind === ValueKind.Frozen
|
|
? 'MutateFrozen'
|
|
: 'MutateGlobal',
|
|
place: effect.value,
|
|
error: diagnostic,
|
|
}, initialized, effects);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'Impure':
|
|
case 'Render':
|
|
case 'MutateFrozen':
|
|
case 'MutateGlobal': {
|
|
effects.push(effect);
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(effect, `Unexpected effect kind '${effect.kind}'`);
|
|
}
|
|
}
|
|
}
|
|
class InferenceState {
|
|
constructor(env, isFunctionExpression, values, variables) {
|
|
_InferenceState_isFunctionExpression.set(this, void 0);
|
|
_InferenceState_values.set(this, void 0);
|
|
_InferenceState_variables.set(this, void 0);
|
|
this.env = env;
|
|
__classPrivateFieldSet(this, _InferenceState_isFunctionExpression, isFunctionExpression, "f");
|
|
__classPrivateFieldSet(this, _InferenceState_values, values, "f");
|
|
__classPrivateFieldSet(this, _InferenceState_variables, variables, "f");
|
|
}
|
|
static empty(env, isFunctionExpression) {
|
|
return new InferenceState(env, isFunctionExpression, new Map(), new Map());
|
|
}
|
|
get isFunctionExpression() {
|
|
return __classPrivateFieldGet(this, _InferenceState_isFunctionExpression, "f");
|
|
}
|
|
initialize(value, kind) {
|
|
CompilerError.invariant(value.kind !== 'LoadLocal', {
|
|
reason: '[InferMutationAliasingEffects] Expected all top-level identifiers to be defined as variables, not values',
|
|
loc: value.loc,
|
|
});
|
|
__classPrivateFieldGet(this, _InferenceState_values, "f").set(value, kind);
|
|
}
|
|
values(place) {
|
|
const values = __classPrivateFieldGet(this, _InferenceState_variables, "f").get(place.identifier.id);
|
|
CompilerError.invariant(values != null, {
|
|
reason: `[InferMutationAliasingEffects] Expected value kind to be initialized`,
|
|
description: `${printPlace(place)}`,
|
|
message: 'this is uninitialized',
|
|
loc: place.loc,
|
|
});
|
|
return Array.from(values);
|
|
}
|
|
kind(place) {
|
|
const values = __classPrivateFieldGet(this, _InferenceState_variables, "f").get(place.identifier.id);
|
|
CompilerError.invariant(values != null, {
|
|
reason: `[InferMutationAliasingEffects] Expected value kind to be initialized`,
|
|
description: `${printPlace(place)}`,
|
|
message: 'this is uninitialized',
|
|
loc: place.loc,
|
|
});
|
|
let mergedKind = null;
|
|
for (const value of values) {
|
|
const kind = __classPrivateFieldGet(this, _InferenceState_values, "f").get(value);
|
|
mergedKind =
|
|
mergedKind !== null ? mergeAbstractValues(mergedKind, kind) : kind;
|
|
}
|
|
CompilerError.invariant(mergedKind !== null, {
|
|
reason: `[InferMutationAliasingEffects] Expected at least one value`,
|
|
description: `No value found at \`${printPlace(place)}\``,
|
|
loc: place.loc,
|
|
});
|
|
return mergedKind;
|
|
}
|
|
assign(place, value) {
|
|
const values = __classPrivateFieldGet(this, _InferenceState_variables, "f").get(value.identifier.id);
|
|
CompilerError.invariant(values != null, {
|
|
reason: `[InferMutationAliasingEffects] Expected value for identifier to be initialized`,
|
|
description: `${printIdentifier(value.identifier)}`,
|
|
message: 'Expected value for identifier to be initialized',
|
|
loc: value.loc,
|
|
});
|
|
__classPrivateFieldGet(this, _InferenceState_variables, "f").set(place.identifier.id, new Set(values));
|
|
}
|
|
appendAlias(place, value) {
|
|
const values = __classPrivateFieldGet(this, _InferenceState_variables, "f").get(value.identifier.id);
|
|
CompilerError.invariant(values != null, {
|
|
reason: `[InferMutationAliasingEffects] Expected value for identifier to be initialized`,
|
|
description: `${printIdentifier(value.identifier)}`,
|
|
message: 'Expected value for identifier to be initialized',
|
|
loc: value.loc,
|
|
});
|
|
const prevValues = this.values(place);
|
|
__classPrivateFieldGet(this, _InferenceState_variables, "f").set(place.identifier.id, new Set([...prevValues, ...values]));
|
|
}
|
|
define(place, value) {
|
|
CompilerError.invariant(__classPrivateFieldGet(this, _InferenceState_values, "f").has(value), {
|
|
reason: `[InferMutationAliasingEffects] Expected value to be initialized`,
|
|
description: printInstructionValue(value),
|
|
loc: value.loc,
|
|
});
|
|
__classPrivateFieldGet(this, _InferenceState_variables, "f").set(place.identifier.id, new Set([value]));
|
|
}
|
|
isDefined(place) {
|
|
return __classPrivateFieldGet(this, _InferenceState_variables, "f").has(place.identifier.id);
|
|
}
|
|
freeze(place, reason) {
|
|
const value = this.kind(place);
|
|
switch (value.kind) {
|
|
case ValueKind.Context:
|
|
case ValueKind.Mutable:
|
|
case ValueKind.MaybeFrozen: {
|
|
const values = this.values(place);
|
|
for (const instrValue of values) {
|
|
this.freezeValue(instrValue, reason);
|
|
}
|
|
return true;
|
|
}
|
|
case ValueKind.Frozen:
|
|
case ValueKind.Global:
|
|
case ValueKind.Primitive: {
|
|
return false;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(value.kind, `Unexpected value kind '${value.kind}'`);
|
|
}
|
|
}
|
|
}
|
|
freezeValue(value, reason) {
|
|
__classPrivateFieldGet(this, _InferenceState_values, "f").set(value, {
|
|
kind: ValueKind.Frozen,
|
|
reason: new Set([reason]),
|
|
});
|
|
if (value.kind === 'FunctionExpression' &&
|
|
(this.env.config.enablePreserveExistingMemoizationGuarantees ||
|
|
this.env.config.enableTransitivelyFreezeFunctionExpressions)) {
|
|
for (const place of value.loweredFunc.func.context) {
|
|
this.freeze(place, reason);
|
|
}
|
|
}
|
|
}
|
|
mutate(variant, place) {
|
|
if (isRefOrRefValue(place.identifier)) {
|
|
return 'mutate-ref';
|
|
}
|
|
const kind = this.kind(place).kind;
|
|
switch (variant) {
|
|
case 'MutateConditionally':
|
|
case 'MutateTransitiveConditionally': {
|
|
switch (kind) {
|
|
case ValueKind.Mutable:
|
|
case ValueKind.Context: {
|
|
return 'mutate';
|
|
}
|
|
default: {
|
|
return 'none';
|
|
}
|
|
}
|
|
}
|
|
case 'Mutate':
|
|
case 'MutateTransitive': {
|
|
switch (kind) {
|
|
case ValueKind.Mutable:
|
|
case ValueKind.Context: {
|
|
return 'mutate';
|
|
}
|
|
case ValueKind.Primitive: {
|
|
return 'none';
|
|
}
|
|
case ValueKind.Frozen: {
|
|
return 'mutate-frozen';
|
|
}
|
|
case ValueKind.Global: {
|
|
return 'mutate-global';
|
|
}
|
|
case ValueKind.MaybeFrozen: {
|
|
return 'mutate-frozen';
|
|
}
|
|
default: {
|
|
assertExhaustive$1(kind, `Unexpected kind ${kind}`);
|
|
}
|
|
}
|
|
}
|
|
default: {
|
|
assertExhaustive$1(variant, `Unexpected mutation variant ${variant}`);
|
|
}
|
|
}
|
|
}
|
|
merge(other) {
|
|
let nextValues = null;
|
|
let nextVariables = null;
|
|
for (const [id, thisValue] of __classPrivateFieldGet(this, _InferenceState_values, "f")) {
|
|
const otherValue = __classPrivateFieldGet(other, _InferenceState_values, "f").get(id);
|
|
if (otherValue !== undefined) {
|
|
const mergedValue = mergeAbstractValues(thisValue, otherValue);
|
|
if (mergedValue !== thisValue) {
|
|
nextValues = nextValues !== null && nextValues !== void 0 ? nextValues : new Map(__classPrivateFieldGet(this, _InferenceState_values, "f"));
|
|
nextValues.set(id, mergedValue);
|
|
}
|
|
}
|
|
}
|
|
for (const [id, otherValue] of __classPrivateFieldGet(other, _InferenceState_values, "f")) {
|
|
if (__classPrivateFieldGet(this, _InferenceState_values, "f").has(id)) {
|
|
continue;
|
|
}
|
|
nextValues = nextValues !== null && nextValues !== void 0 ? nextValues : new Map(__classPrivateFieldGet(this, _InferenceState_values, "f"));
|
|
nextValues.set(id, otherValue);
|
|
}
|
|
for (const [id, thisValues] of __classPrivateFieldGet(this, _InferenceState_variables, "f")) {
|
|
const otherValues = __classPrivateFieldGet(other, _InferenceState_variables, "f").get(id);
|
|
if (otherValues !== undefined) {
|
|
let mergedValues = null;
|
|
for (const otherValue of otherValues) {
|
|
if (!thisValues.has(otherValue)) {
|
|
mergedValues = mergedValues !== null && mergedValues !== void 0 ? mergedValues : new Set(thisValues);
|
|
mergedValues.add(otherValue);
|
|
}
|
|
}
|
|
if (mergedValues !== null) {
|
|
nextVariables = nextVariables !== null && nextVariables !== void 0 ? nextVariables : new Map(__classPrivateFieldGet(this, _InferenceState_variables, "f"));
|
|
nextVariables.set(id, mergedValues);
|
|
}
|
|
}
|
|
}
|
|
for (const [id, otherValues] of __classPrivateFieldGet(other, _InferenceState_variables, "f")) {
|
|
if (__classPrivateFieldGet(this, _InferenceState_variables, "f").has(id)) {
|
|
continue;
|
|
}
|
|
nextVariables = nextVariables !== null && nextVariables !== void 0 ? nextVariables : new Map(__classPrivateFieldGet(this, _InferenceState_variables, "f"));
|
|
nextVariables.set(id, new Set(otherValues));
|
|
}
|
|
if (nextVariables === null && nextValues === null) {
|
|
return null;
|
|
}
|
|
else {
|
|
return new InferenceState(this.env, __classPrivateFieldGet(this, _InferenceState_isFunctionExpression, "f"), nextValues !== null && nextValues !== void 0 ? nextValues : new Map(__classPrivateFieldGet(this, _InferenceState_values, "f")), nextVariables !== null && nextVariables !== void 0 ? nextVariables : new Map(__classPrivateFieldGet(this, _InferenceState_variables, "f")));
|
|
}
|
|
}
|
|
clone() {
|
|
return new InferenceState(this.env, __classPrivateFieldGet(this, _InferenceState_isFunctionExpression, "f"), new Map(__classPrivateFieldGet(this, _InferenceState_values, "f")), new Map(__classPrivateFieldGet(this, _InferenceState_variables, "f")));
|
|
}
|
|
debug() {
|
|
const result = { values: {}, variables: {} };
|
|
const objects = new Map();
|
|
function identify(value) {
|
|
let id = objects.get(value);
|
|
if (id == null) {
|
|
id = objects.size;
|
|
objects.set(value, id);
|
|
}
|
|
return id;
|
|
}
|
|
for (const [value, kind] of __classPrivateFieldGet(this, _InferenceState_values, "f")) {
|
|
const id = identify(value);
|
|
result.values[id] = {
|
|
abstract: this.debugAbstractValue(kind),
|
|
value: printInstructionValue(value),
|
|
};
|
|
}
|
|
for (const [variable, values] of __classPrivateFieldGet(this, _InferenceState_variables, "f")) {
|
|
result.variables[`$${variable}`] = [...values].map(identify);
|
|
}
|
|
return result;
|
|
}
|
|
debugAbstractValue(value) {
|
|
return {
|
|
kind: value.kind,
|
|
reason: [...value.reason],
|
|
};
|
|
}
|
|
inferPhi(phi) {
|
|
const values = new Set();
|
|
for (const [_, operand] of phi.operands) {
|
|
const operandValues = __classPrivateFieldGet(this, _InferenceState_variables, "f").get(operand.identifier.id);
|
|
if (operandValues === undefined)
|
|
continue;
|
|
for (const v of operandValues) {
|
|
values.add(v);
|
|
}
|
|
}
|
|
if (values.size > 0) {
|
|
__classPrivateFieldGet(this, _InferenceState_variables, "f").set(phi.place.identifier.id, values);
|
|
}
|
|
}
|
|
}
|
|
_InferenceState_isFunctionExpression = new WeakMap(), _InferenceState_values = new WeakMap(), _InferenceState_variables = new WeakMap();
|
|
function mergeAbstractValues(a, b) {
|
|
const kind = mergeValueKinds(a.kind, b.kind);
|
|
if (kind === a.kind &&
|
|
kind === b.kind &&
|
|
Set_isSuperset(a.reason, b.reason)) {
|
|
return a;
|
|
}
|
|
const reason = new Set(a.reason);
|
|
for (const r of b.reason) {
|
|
reason.add(r);
|
|
}
|
|
return { kind, reason };
|
|
}
|
|
function conditionallyMutateIterator(place) {
|
|
if (!(isArrayType(place.identifier) ||
|
|
isSetType(place.identifier) ||
|
|
isMapType(place.identifier))) {
|
|
return {
|
|
kind: 'MutateTransitiveConditionally',
|
|
value: place,
|
|
};
|
|
}
|
|
return null;
|
|
}
|
|
function computeSignatureForInstruction(context, env, instr) {
|
|
const { lvalue, value } = instr;
|
|
const effects = [];
|
|
switch (value.kind) {
|
|
case 'ArrayExpression': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Mutable,
|
|
reason: ValueReason.Other,
|
|
});
|
|
for (const element of value.elements) {
|
|
if (element.kind === 'Identifier') {
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: element,
|
|
into: lvalue,
|
|
});
|
|
}
|
|
else if (element.kind === 'Spread') {
|
|
const mutateIterator = conditionallyMutateIterator(element.place);
|
|
if (mutateIterator != null) {
|
|
effects.push(mutateIterator);
|
|
}
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: element.place,
|
|
into: lvalue,
|
|
});
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectExpression': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Mutable,
|
|
reason: ValueReason.Other,
|
|
});
|
|
for (const property of value.properties) {
|
|
if (property.kind === 'ObjectProperty') {
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: property.place,
|
|
into: lvalue,
|
|
});
|
|
}
|
|
else {
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: property.place,
|
|
into: lvalue,
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'Await': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Mutable,
|
|
reason: ValueReason.Other,
|
|
});
|
|
effects.push({ kind: 'MutateTransitiveConditionally', value: value.value });
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: value.value,
|
|
into: lvalue,
|
|
});
|
|
break;
|
|
}
|
|
case 'NewExpression':
|
|
case 'CallExpression':
|
|
case 'MethodCall': {
|
|
let callee;
|
|
let receiver;
|
|
let mutatesCallee;
|
|
if (value.kind === 'NewExpression') {
|
|
callee = value.callee;
|
|
receiver = value.callee;
|
|
mutatesCallee = false;
|
|
}
|
|
else if (value.kind === 'CallExpression') {
|
|
callee = value.callee;
|
|
receiver = value.callee;
|
|
mutatesCallee = true;
|
|
}
|
|
else if (value.kind === 'MethodCall') {
|
|
callee = value.property;
|
|
receiver = value.receiver;
|
|
mutatesCallee = false;
|
|
}
|
|
else {
|
|
assertExhaustive$1(value, `Unexpected value kind '${value.kind}'`);
|
|
}
|
|
const signature = getFunctionCallSignature(env, callee.identifier.type);
|
|
effects.push({
|
|
kind: 'Apply',
|
|
receiver,
|
|
function: callee,
|
|
mutatesFunction: mutatesCallee,
|
|
args: value.args,
|
|
into: lvalue,
|
|
signature,
|
|
loc: value.loc,
|
|
});
|
|
break;
|
|
}
|
|
case 'PropertyDelete':
|
|
case 'ComputedDelete': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
effects.push({ kind: 'Mutate', value: value.object });
|
|
break;
|
|
}
|
|
case 'PropertyLoad':
|
|
case 'ComputedLoad': {
|
|
if (isPrimitiveType(lvalue.identifier)) {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
}
|
|
else {
|
|
effects.push({
|
|
kind: 'CreateFrom',
|
|
from: value.object,
|
|
into: lvalue,
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case 'PropertyStore':
|
|
case 'ComputedStore': {
|
|
const mutationReason = value.kind === 'PropertyStore' &&
|
|
value.property === 'current' &&
|
|
value.object.identifier.type.kind === 'Type'
|
|
? { kind: 'AssignCurrentProperty' }
|
|
: null;
|
|
effects.push({
|
|
kind: 'Mutate',
|
|
value: value.object,
|
|
reason: mutationReason,
|
|
});
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: value.value,
|
|
into: value.object,
|
|
});
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
break;
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
effects.push({
|
|
kind: 'CreateFunction',
|
|
into: lvalue,
|
|
function: value,
|
|
captures: value.loweredFunc.func.context.filter(operand => operand.effect === Effect.Capture),
|
|
});
|
|
break;
|
|
}
|
|
case 'GetIterator': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Mutable,
|
|
reason: ValueReason.Other,
|
|
});
|
|
if (isArrayType(value.collection.identifier) ||
|
|
isMapType(value.collection.identifier) ||
|
|
isSetType(value.collection.identifier)) {
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: value.collection,
|
|
into: lvalue,
|
|
});
|
|
}
|
|
else {
|
|
effects.push({ kind: 'Alias', from: value.collection, into: lvalue });
|
|
effects.push({
|
|
kind: 'MutateTransitiveConditionally',
|
|
value: value.collection,
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case 'IteratorNext': {
|
|
effects.push({ kind: 'MutateConditionally', value: value.iterator });
|
|
effects.push({
|
|
kind: 'CreateFrom',
|
|
from: value.collection,
|
|
into: lvalue,
|
|
});
|
|
break;
|
|
}
|
|
case 'NextPropertyOf': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
break;
|
|
}
|
|
case 'JsxExpression':
|
|
case 'JsxFragment': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Frozen,
|
|
reason: ValueReason.JsxCaptured,
|
|
});
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
effects.push({
|
|
kind: 'Freeze',
|
|
value: operand,
|
|
reason: ValueReason.JsxCaptured,
|
|
});
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: operand,
|
|
into: lvalue,
|
|
});
|
|
}
|
|
if (value.kind === 'JsxExpression') {
|
|
if (value.tag.kind === 'Identifier') {
|
|
effects.push({
|
|
kind: 'Render',
|
|
place: value.tag,
|
|
});
|
|
}
|
|
if (value.children != null) {
|
|
for (const child of value.children) {
|
|
effects.push({
|
|
kind: 'Render',
|
|
place: child,
|
|
});
|
|
}
|
|
}
|
|
for (const prop of value.props) {
|
|
if (prop.kind === 'JsxAttribute' &&
|
|
prop.place.identifier.type.kind === 'Function' &&
|
|
(isJsxType(prop.place.identifier.type.return) ||
|
|
(prop.place.identifier.type.return.kind === 'Phi' &&
|
|
prop.place.identifier.type.return.operands.some(operand => isJsxType(operand))))) {
|
|
effects.push({
|
|
kind: 'Render',
|
|
place: prop.place,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'DeclareLocal': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: value.lvalue.place,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
for (const patternItem of eachPatternItem(value.lvalue.pattern)) {
|
|
const place = patternItem.kind === 'Identifier' ? patternItem : patternItem.place;
|
|
if (isPrimitiveType(place.identifier)) {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: place,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
}
|
|
else if (patternItem.kind === 'Identifier') {
|
|
effects.push({
|
|
kind: 'CreateFrom',
|
|
from: value.value,
|
|
into: place,
|
|
});
|
|
}
|
|
else {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: place,
|
|
reason: ValueReason.Other,
|
|
value: context.nonMutatingSpreads.has(place.identifier.id)
|
|
? ValueKind.Frozen
|
|
: ValueKind.Mutable,
|
|
});
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: value.value,
|
|
into: place,
|
|
});
|
|
}
|
|
}
|
|
effects.push({ kind: 'Assign', from: value.value, into: lvalue });
|
|
break;
|
|
}
|
|
case 'LoadContext': {
|
|
effects.push({ kind: 'CreateFrom', from: value.place, into: lvalue });
|
|
break;
|
|
}
|
|
case 'DeclareContext': {
|
|
const kind = value.lvalue.kind;
|
|
if (!context.hoistedContextDeclarations.has(value.lvalue.place.identifier.declarationId) ||
|
|
kind === InstructionKind.HoistedConst ||
|
|
kind === InstructionKind.HoistedFunction ||
|
|
kind === InstructionKind.HoistedLet) {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: value.lvalue.place,
|
|
value: ValueKind.Mutable,
|
|
reason: ValueReason.Other,
|
|
});
|
|
}
|
|
else {
|
|
effects.push({ kind: 'Mutate', value: value.lvalue.place });
|
|
}
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
break;
|
|
}
|
|
case 'StoreContext': {
|
|
if (value.lvalue.kind === InstructionKind.Reassign ||
|
|
context.hoistedContextDeclarations.has(value.lvalue.place.identifier.declarationId)) {
|
|
effects.push({ kind: 'Mutate', value: value.lvalue.place });
|
|
}
|
|
else {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: value.lvalue.place,
|
|
value: ValueKind.Mutable,
|
|
reason: ValueReason.Other,
|
|
});
|
|
}
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: value.value,
|
|
into: value.lvalue.place,
|
|
});
|
|
effects.push({ kind: 'Assign', from: value.value, into: lvalue });
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
effects.push({ kind: 'Assign', from: value.place, into: lvalue });
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
effects.push({
|
|
kind: 'Assign',
|
|
from: value.value,
|
|
into: value.lvalue.place,
|
|
});
|
|
effects.push({ kind: 'Assign', from: value.value, into: lvalue });
|
|
break;
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: value.lvalue,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
break;
|
|
}
|
|
case 'StoreGlobal': {
|
|
const variable = `\`${value.name}\``;
|
|
effects.push({
|
|
kind: 'MutateGlobal',
|
|
place: value.value,
|
|
error: CompilerDiagnostic.create({
|
|
category: ErrorCategory.Globals,
|
|
reason: 'Cannot reassign variables declared outside of the component/hook',
|
|
description: `Variable ${variable} is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)`,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: instr.loc,
|
|
message: `${variable} cannot be reassigned`,
|
|
}),
|
|
});
|
|
effects.push({ kind: 'Assign', from: value.value, into: lvalue });
|
|
break;
|
|
}
|
|
case 'TypeCastExpression': {
|
|
effects.push({ kind: 'Assign', from: value.value, into: lvalue });
|
|
break;
|
|
}
|
|
case 'LoadGlobal': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Global,
|
|
reason: ValueReason.Global,
|
|
});
|
|
break;
|
|
}
|
|
case 'StartMemoize':
|
|
case 'FinishMemoize': {
|
|
if (env.config.enablePreserveExistingMemoizationGuarantees) {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
effects.push({
|
|
kind: 'Freeze',
|
|
value: operand,
|
|
reason: ValueReason.HookCaptured,
|
|
});
|
|
}
|
|
}
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
break;
|
|
}
|
|
case 'TaggedTemplateExpression':
|
|
case 'BinaryExpression':
|
|
case 'Debugger':
|
|
case 'JSXText':
|
|
case 'MetaProperty':
|
|
case 'Primitive':
|
|
case 'RegExpLiteral':
|
|
case 'TemplateLiteral':
|
|
case 'UnaryExpression':
|
|
case 'UnsupportedNode': {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: ValueKind.Primitive,
|
|
reason: ValueReason.Other,
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
return {
|
|
effects,
|
|
};
|
|
}
|
|
function computeEffectsForLegacySignature(state, signature, lvalue, receiver, args, loc) {
|
|
var _a, _b;
|
|
const returnValueReason = (_a = signature.returnValueReason) !== null && _a !== void 0 ? _a : ValueReason.Other;
|
|
const effects = [];
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: lvalue,
|
|
value: signature.returnValueKind,
|
|
reason: returnValueReason,
|
|
});
|
|
if (signature.impure && state.env.config.validateNoImpureFunctionsInRender) {
|
|
effects.push({
|
|
kind: 'Impure',
|
|
place: receiver,
|
|
error: CompilerDiagnostic.create({
|
|
category: ErrorCategory.Purity,
|
|
reason: 'Cannot call impure function during render',
|
|
description: (signature.canonicalName != null
|
|
? `\`${signature.canonicalName}\` is an impure function. `
|
|
: '') +
|
|
'Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent)',
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc,
|
|
message: 'Cannot call impure function',
|
|
}),
|
|
});
|
|
}
|
|
if (signature.knownIncompatible != null && state.env.enableValidations) {
|
|
const errors = new CompilerError();
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.IncompatibleLibrary,
|
|
reason: 'Use of incompatible library',
|
|
description: [
|
|
'This API returns functions which cannot be memoized without leading to stale UI. ' +
|
|
'To prevent this, by default React Compiler will skip memoizing this component/hook. ' +
|
|
'However, you may see issues if values from this API are passed to other components/hooks that are ' +
|
|
'memoized',
|
|
].join(''),
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: receiver.loc,
|
|
message: signature.knownIncompatible,
|
|
}));
|
|
throw errors;
|
|
}
|
|
const stores = [];
|
|
const captures = [];
|
|
function visit(place, effect) {
|
|
switch (effect) {
|
|
case Effect.Store: {
|
|
effects.push({
|
|
kind: 'Mutate',
|
|
value: place,
|
|
});
|
|
stores.push(place);
|
|
break;
|
|
}
|
|
case Effect.Capture: {
|
|
captures.push(place);
|
|
break;
|
|
}
|
|
case Effect.ConditionallyMutate: {
|
|
effects.push({
|
|
kind: 'MutateTransitiveConditionally',
|
|
value: place,
|
|
});
|
|
break;
|
|
}
|
|
case Effect.ConditionallyMutateIterator: {
|
|
const mutateIterator = conditionallyMutateIterator(place);
|
|
if (mutateIterator != null) {
|
|
effects.push(mutateIterator);
|
|
}
|
|
effects.push({
|
|
kind: 'Capture',
|
|
from: place,
|
|
into: lvalue,
|
|
});
|
|
break;
|
|
}
|
|
case Effect.Freeze: {
|
|
effects.push({
|
|
kind: 'Freeze',
|
|
value: place,
|
|
reason: returnValueReason,
|
|
});
|
|
break;
|
|
}
|
|
case Effect.Mutate: {
|
|
effects.push({ kind: 'MutateTransitive', value: place });
|
|
break;
|
|
}
|
|
case Effect.Read: {
|
|
effects.push({
|
|
kind: 'ImmutableCapture',
|
|
from: place,
|
|
into: lvalue,
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (signature.mutableOnlyIfOperandsAreMutable &&
|
|
areArgumentsImmutableAndNonMutating(state, args)) {
|
|
effects.push({
|
|
kind: 'Alias',
|
|
from: receiver,
|
|
into: lvalue,
|
|
});
|
|
for (const arg of args) {
|
|
if (arg.kind === 'Hole') {
|
|
continue;
|
|
}
|
|
const place = arg.kind === 'Identifier' ? arg : arg.place;
|
|
effects.push({
|
|
kind: 'ImmutableCapture',
|
|
from: place,
|
|
into: lvalue,
|
|
});
|
|
}
|
|
return effects;
|
|
}
|
|
if (signature.calleeEffect !== Effect.Capture) {
|
|
effects.push({
|
|
kind: 'Alias',
|
|
from: receiver,
|
|
into: lvalue,
|
|
});
|
|
}
|
|
visit(receiver, signature.calleeEffect);
|
|
for (let i = 0; i < args.length; i++) {
|
|
const arg = args[i];
|
|
if (arg.kind === 'Hole') {
|
|
continue;
|
|
}
|
|
const place = arg.kind === 'Identifier' ? arg : arg.place;
|
|
const signatureEffect = arg.kind === 'Identifier' && i < signature.positionalParams.length
|
|
? signature.positionalParams[i]
|
|
: ((_b = signature.restParam) !== null && _b !== void 0 ? _b : Effect.ConditionallyMutate);
|
|
const effect = getArgumentEffect(signatureEffect, arg);
|
|
visit(place, effect);
|
|
}
|
|
if (captures.length !== 0) {
|
|
if (stores.length === 0) {
|
|
for (const capture of captures) {
|
|
effects.push({ kind: 'Alias', from: capture, into: lvalue });
|
|
}
|
|
}
|
|
else {
|
|
for (const capture of captures) {
|
|
for (const store of stores) {
|
|
effects.push({ kind: 'Capture', from: capture, into: store });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return effects;
|
|
}
|
|
function areArgumentsImmutableAndNonMutating(state, args) {
|
|
for (const arg of args) {
|
|
if (arg.kind === 'Hole') {
|
|
continue;
|
|
}
|
|
if (arg.kind === 'Identifier' && arg.identifier.type.kind === 'Function') {
|
|
const fnShape = state.env.getFunctionSignature(arg.identifier.type);
|
|
if (fnShape != null) {
|
|
return (!fnShape.positionalParams.some(isKnownMutableEffect) &&
|
|
(fnShape.restParam == null ||
|
|
!isKnownMutableEffect(fnShape.restParam)));
|
|
}
|
|
}
|
|
const place = arg.kind === 'Identifier' ? arg : arg.place;
|
|
const kind = state.kind(place).kind;
|
|
switch (kind) {
|
|
case ValueKind.Primitive:
|
|
case ValueKind.Frozen: {
|
|
break;
|
|
}
|
|
default: {
|
|
return false;
|
|
}
|
|
}
|
|
const values = state.values(place);
|
|
for (const value of values) {
|
|
if (value.kind === 'FunctionExpression' &&
|
|
value.loweredFunc.func.params.some(param => {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
const range = place.identifier.mutableRange;
|
|
return range.end > range.start + 1;
|
|
})) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function computeEffectsForSignature(env, signature, lvalue, receiver, args, context = [], loc) {
|
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
if (signature.params.length > args.length ||
|
|
(args.length > signature.params.length && signature.rest == null)) {
|
|
return null;
|
|
}
|
|
const mutableSpreads = new Set();
|
|
const substitutions = new Map();
|
|
substitutions.set(signature.receiver, [receiver]);
|
|
substitutions.set(signature.returns, [lvalue]);
|
|
const params = signature.params;
|
|
for (let i = 0; i < args.length; i++) {
|
|
const arg = args[i];
|
|
if (arg.kind === 'Hole') {
|
|
continue;
|
|
}
|
|
else if (params == null || i >= params.length || arg.kind === 'Spread') {
|
|
if (signature.rest == null) {
|
|
return null;
|
|
}
|
|
const place = arg.kind === 'Identifier' ? arg : arg.place;
|
|
getOrInsertWith(substitutions, signature.rest, () => []).push(place);
|
|
if (arg.kind === 'Spread') {
|
|
const mutateIterator = conditionallyMutateIterator(arg.place);
|
|
if (mutateIterator != null) {
|
|
mutableSpreads.add(arg.place.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
const param = params[i];
|
|
substitutions.set(param, [arg]);
|
|
}
|
|
}
|
|
for (const operand of context) {
|
|
substitutions.set(operand.identifier.id, [operand]);
|
|
}
|
|
const effects = [];
|
|
for (const signatureTemporary of signature.temporaries) {
|
|
const temp = createTemporaryPlace(env, receiver.loc);
|
|
substitutions.set(signatureTemporary.identifier.id, [temp]);
|
|
}
|
|
for (const effect of signature.effects) {
|
|
switch (effect.kind) {
|
|
case 'MaybeAlias':
|
|
case 'Assign':
|
|
case 'ImmutableCapture':
|
|
case 'Alias':
|
|
case 'CreateFrom':
|
|
case 'Capture': {
|
|
const from = (_a = substitutions.get(effect.from.identifier.id)) !== null && _a !== void 0 ? _a : [];
|
|
const to = (_b = substitutions.get(effect.into.identifier.id)) !== null && _b !== void 0 ? _b : [];
|
|
for (const fromId of from) {
|
|
for (const toId of to) {
|
|
effects.push({
|
|
kind: effect.kind,
|
|
from: fromId,
|
|
into: toId,
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'Impure':
|
|
case 'MutateFrozen':
|
|
case 'MutateGlobal': {
|
|
const values = (_c = substitutions.get(effect.place.identifier.id)) !== null && _c !== void 0 ? _c : [];
|
|
for (const value of values) {
|
|
effects.push({ kind: effect.kind, place: value, error: effect.error });
|
|
}
|
|
break;
|
|
}
|
|
case 'Render': {
|
|
const values = (_d = substitutions.get(effect.place.identifier.id)) !== null && _d !== void 0 ? _d : [];
|
|
for (const value of values) {
|
|
effects.push({ kind: effect.kind, place: value });
|
|
}
|
|
break;
|
|
}
|
|
case 'Mutate':
|
|
case 'MutateTransitive':
|
|
case 'MutateTransitiveConditionally':
|
|
case 'MutateConditionally': {
|
|
const values = (_e = substitutions.get(effect.value.identifier.id)) !== null && _e !== void 0 ? _e : [];
|
|
for (const id of values) {
|
|
effects.push({ kind: effect.kind, value: id });
|
|
}
|
|
break;
|
|
}
|
|
case 'Freeze': {
|
|
const values = (_f = substitutions.get(effect.value.identifier.id)) !== null && _f !== void 0 ? _f : [];
|
|
for (const value of values) {
|
|
if (mutableSpreads.has(value.identifier.id)) {
|
|
CompilerError.throwTodo({
|
|
reason: 'Support spread syntax for hook arguments',
|
|
loc: value.loc,
|
|
});
|
|
}
|
|
effects.push({ kind: 'Freeze', value, reason: effect.reason });
|
|
}
|
|
break;
|
|
}
|
|
case 'Create': {
|
|
const into = (_g = substitutions.get(effect.into.identifier.id)) !== null && _g !== void 0 ? _g : [];
|
|
for (const value of into) {
|
|
effects.push({
|
|
kind: 'Create',
|
|
into: value,
|
|
value: effect.value,
|
|
reason: effect.reason,
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case 'Apply': {
|
|
const applyReceiver = substitutions.get(effect.receiver.identifier.id);
|
|
if (applyReceiver == null || applyReceiver.length !== 1) {
|
|
return null;
|
|
}
|
|
const applyFunction = substitutions.get(effect.function.identifier.id);
|
|
if (applyFunction == null || applyFunction.length !== 1) {
|
|
return null;
|
|
}
|
|
const applyInto = substitutions.get(effect.into.identifier.id);
|
|
if (applyInto == null || applyInto.length !== 1) {
|
|
return null;
|
|
}
|
|
const applyArgs = [];
|
|
for (const arg of effect.args) {
|
|
if (arg.kind === 'Hole') {
|
|
applyArgs.push(arg);
|
|
}
|
|
else if (arg.kind === 'Identifier') {
|
|
const applyArg = substitutions.get(arg.identifier.id);
|
|
if (applyArg == null || applyArg.length !== 1) {
|
|
return null;
|
|
}
|
|
applyArgs.push(applyArg[0]);
|
|
}
|
|
else {
|
|
const applyArg = substitutions.get(arg.place.identifier.id);
|
|
if (applyArg == null || applyArg.length !== 1) {
|
|
return null;
|
|
}
|
|
applyArgs.push({ kind: 'Spread', place: applyArg[0] });
|
|
}
|
|
}
|
|
effects.push({
|
|
kind: 'Apply',
|
|
mutatesFunction: effect.mutatesFunction,
|
|
receiver: applyReceiver[0],
|
|
args: applyArgs,
|
|
function: applyFunction[0],
|
|
into: applyInto[0],
|
|
signature: effect.signature,
|
|
loc,
|
|
});
|
|
break;
|
|
}
|
|
case 'CreateFunction': {
|
|
CompilerError.throwTodo({
|
|
reason: `Support CreateFrom effects in signatures`,
|
|
loc: receiver.loc,
|
|
});
|
|
}
|
|
default: {
|
|
assertExhaustive$1(effect, `Unexpected effect kind '${effect.kind}'`);
|
|
}
|
|
}
|
|
}
|
|
return effects;
|
|
}
|
|
function buildSignatureFromFunctionExpression(env, fn) {
|
|
var _a;
|
|
let rest = null;
|
|
const params = [];
|
|
for (const param of fn.loweredFunc.func.params) {
|
|
if (param.kind === 'Identifier') {
|
|
params.push(param.identifier.id);
|
|
}
|
|
else {
|
|
rest = param.place.identifier.id;
|
|
}
|
|
}
|
|
return {
|
|
receiver: makeIdentifierId(0),
|
|
params,
|
|
rest: rest !== null && rest !== void 0 ? rest : createTemporaryPlace(env, fn.loc).identifier.id,
|
|
returns: fn.loweredFunc.func.returns.identifier.id,
|
|
effects: (_a = fn.loweredFunc.func.aliasingEffects) !== null && _a !== void 0 ? _a : [],
|
|
temporaries: [],
|
|
};
|
|
}
|
|
function getWriteErrorReason(abstractValue) {
|
|
if (abstractValue.reason.has(ValueReason.Global)) {
|
|
return 'Modifying a variable defined outside a component or hook is not allowed. Consider using an effect';
|
|
}
|
|
else if (abstractValue.reason.has(ValueReason.JsxCaptured)) {
|
|
return 'Modifying a value used previously in JSX is not allowed. Consider moving the modification before the JSX';
|
|
}
|
|
else if (abstractValue.reason.has(ValueReason.Context)) {
|
|
return `Modifying a value returned from 'useContext()' is not allowed.`;
|
|
}
|
|
else if (abstractValue.reason.has(ValueReason.KnownReturnSignature)) {
|
|
return 'Modifying a value returned from a function whose return value should not be mutated';
|
|
}
|
|
else if (abstractValue.reason.has(ValueReason.ReactiveFunctionArgument)) {
|
|
return 'Modifying component props or hook arguments is not allowed. Consider using a local variable instead';
|
|
}
|
|
else if (abstractValue.reason.has(ValueReason.State)) {
|
|
return "Modifying a value returned from 'useState()', which should not be modified directly. Use the setter function to update instead";
|
|
}
|
|
else if (abstractValue.reason.has(ValueReason.ReducerState)) {
|
|
return "Modifying a value returned from 'useReducer()', which should not be modified directly. Use the dispatch function to update instead";
|
|
}
|
|
else if (abstractValue.reason.has(ValueReason.Effect)) {
|
|
return 'Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect()';
|
|
}
|
|
else if (abstractValue.reason.has(ValueReason.HookCaptured)) {
|
|
return 'Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook';
|
|
}
|
|
else if (abstractValue.reason.has(ValueReason.HookReturn)) {
|
|
return 'Modifying a value returned from a hook is not allowed. Consider moving the modification into the hook where the value is constructed';
|
|
}
|
|
else {
|
|
return 'This modifies a variable that React considers immutable';
|
|
}
|
|
}
|
|
function getArgumentEffect(signatureEffect, arg) {
|
|
if (signatureEffect != null) {
|
|
if (arg.kind === 'Identifier') {
|
|
return signatureEffect;
|
|
}
|
|
else if (signatureEffect === Effect.Mutate ||
|
|
signatureEffect === Effect.ConditionallyMutate) {
|
|
return signatureEffect;
|
|
}
|
|
else {
|
|
if (signatureEffect === Effect.Freeze) {
|
|
CompilerError.throwTodo({
|
|
reason: 'Support spread syntax for hook arguments',
|
|
loc: arg.place.loc,
|
|
});
|
|
}
|
|
return Effect.ConditionallyMutateIterator;
|
|
}
|
|
}
|
|
else {
|
|
return Effect.ConditionallyMutate;
|
|
}
|
|
}
|
|
function getFunctionCallSignature(env, type) {
|
|
if (type.kind !== 'Function') {
|
|
return null;
|
|
}
|
|
return env.getFunctionSignature(type);
|
|
}
|
|
function isKnownMutableEffect(effect) {
|
|
switch (effect) {
|
|
case Effect.Store:
|
|
case Effect.ConditionallyMutate:
|
|
case Effect.ConditionallyMutateIterator:
|
|
case Effect.Mutate: {
|
|
return true;
|
|
}
|
|
case Effect.Unknown: {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Unexpected unknown effect',
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
case Effect.Read:
|
|
case Effect.Capture:
|
|
case Effect.Freeze: {
|
|
return false;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(effect, `Unexpected effect \`${effect}\``);
|
|
}
|
|
}
|
|
}
|
|
function mergeValueKinds(a, b) {
|
|
if (a === b) {
|
|
return a;
|
|
}
|
|
else if (a === ValueKind.MaybeFrozen || b === ValueKind.MaybeFrozen) {
|
|
return ValueKind.MaybeFrozen;
|
|
}
|
|
else if (a === ValueKind.Mutable || b === ValueKind.Mutable) {
|
|
if (a === ValueKind.Frozen || b === ValueKind.Frozen) {
|
|
return ValueKind.MaybeFrozen;
|
|
}
|
|
else if (a === ValueKind.Context || b === ValueKind.Context) {
|
|
return ValueKind.Context;
|
|
}
|
|
else {
|
|
return ValueKind.Mutable;
|
|
}
|
|
}
|
|
else if (a === ValueKind.Context || b === ValueKind.Context) {
|
|
if (a === ValueKind.Frozen || b === ValueKind.Frozen) {
|
|
return ValueKind.MaybeFrozen;
|
|
}
|
|
else {
|
|
return ValueKind.Context;
|
|
}
|
|
}
|
|
else if (a === ValueKind.Frozen || b === ValueKind.Frozen) {
|
|
return ValueKind.Frozen;
|
|
}
|
|
else if (a === ValueKind.Global || b === ValueKind.Global) {
|
|
return ValueKind.Global;
|
|
}
|
|
else {
|
|
CompilerError.invariant(a === ValueKind.Primitive && b == ValueKind.Primitive, {
|
|
reason: `Unexpected value kind in mergeValues()`,
|
|
description: `Found kinds ${a} and ${b}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
return ValueKind.Primitive;
|
|
}
|
|
}
|
|
|
|
function pruneNonEscapingScopes(fn) {
|
|
const state = new State(fn.env);
|
|
for (const param of fn.params) {
|
|
if (param.kind === 'Identifier') {
|
|
state.declare(param.identifier.declarationId);
|
|
}
|
|
else {
|
|
state.declare(param.place.identifier.declarationId);
|
|
}
|
|
}
|
|
visitReactiveFunction(fn, new CollectDependenciesVisitor(fn.env, state), []);
|
|
const memoized = computeMemoizedIdentifiers(state);
|
|
visitReactiveFunction(fn, new PruneScopesTransform(), memoized);
|
|
}
|
|
var MemoizationLevel;
|
|
(function (MemoizationLevel) {
|
|
MemoizationLevel["Memoized"] = "Memoized";
|
|
MemoizationLevel["Conditional"] = "Conditional";
|
|
MemoizationLevel["Unmemoized"] = "Unmemoized";
|
|
MemoizationLevel["Never"] = "Never";
|
|
})(MemoizationLevel || (MemoizationLevel = {}));
|
|
function joinAliases(kind1, kind2) {
|
|
if (kind1 === MemoizationLevel.Memoized ||
|
|
kind2 === MemoizationLevel.Memoized) {
|
|
return MemoizationLevel.Memoized;
|
|
}
|
|
else if (kind1 === MemoizationLevel.Conditional ||
|
|
kind2 === MemoizationLevel.Conditional) {
|
|
return MemoizationLevel.Conditional;
|
|
}
|
|
else if (kind1 === MemoizationLevel.Unmemoized ||
|
|
kind2 === MemoizationLevel.Unmemoized) {
|
|
return MemoizationLevel.Unmemoized;
|
|
}
|
|
else {
|
|
return MemoizationLevel.Never;
|
|
}
|
|
}
|
|
class State {
|
|
constructor(env) {
|
|
this.definitions = new Map();
|
|
this.identifiers = new Map();
|
|
this.scopes = new Map();
|
|
this.escapingValues = new Set();
|
|
this.env = env;
|
|
}
|
|
declare(id) {
|
|
this.identifiers.set(id, {
|
|
level: MemoizationLevel.Never,
|
|
memoized: false,
|
|
dependencies: new Set(),
|
|
scopes: new Set(),
|
|
seen: false,
|
|
});
|
|
}
|
|
visitOperand(id, place, identifier) {
|
|
const scope = getPlaceScope(id, place);
|
|
if (scope !== null) {
|
|
let node = this.scopes.get(scope.id);
|
|
if (node === undefined) {
|
|
node = {
|
|
dependencies: [...scope.dependencies].map(dep => dep.identifier.declarationId),
|
|
seen: false,
|
|
};
|
|
this.scopes.set(scope.id, node);
|
|
}
|
|
const identifierNode = this.identifiers.get(identifier);
|
|
CompilerError.invariant(identifierNode !== undefined, {
|
|
reason: 'Expected identifier to be initialized',
|
|
description: `[${id}] operand=${printPlace(place)} for identifier declaration ${identifier}`,
|
|
loc: place.loc,
|
|
});
|
|
identifierNode.scopes.add(scope.id);
|
|
}
|
|
}
|
|
}
|
|
function computeMemoizedIdentifiers(state) {
|
|
const memoized = new Set();
|
|
function visit(id, forceMemoize = false) {
|
|
const node = state.identifiers.get(id);
|
|
CompilerError.invariant(node !== undefined, {
|
|
reason: `Expected a node for all identifiers, none found for \`${id}\``,
|
|
loc: GeneratedSource,
|
|
});
|
|
if (node.seen) {
|
|
return node.memoized;
|
|
}
|
|
node.seen = true;
|
|
node.memoized = false;
|
|
let hasMemoizedDependency = false;
|
|
for (const dep of node.dependencies) {
|
|
const isDepMemoized = visit(dep);
|
|
hasMemoizedDependency || (hasMemoizedDependency = isDepMemoized);
|
|
}
|
|
if (node.level === MemoizationLevel.Memoized ||
|
|
(node.level === MemoizationLevel.Conditional &&
|
|
(hasMemoizedDependency || forceMemoize)) ||
|
|
(node.level === MemoizationLevel.Unmemoized && forceMemoize)) {
|
|
node.memoized = true;
|
|
memoized.add(id);
|
|
for (const scope of node.scopes) {
|
|
forceMemoizeScopeDependencies(scope);
|
|
}
|
|
}
|
|
return node.memoized;
|
|
}
|
|
function forceMemoizeScopeDependencies(id) {
|
|
const node = state.scopes.get(id);
|
|
CompilerError.invariant(node !== undefined, {
|
|
reason: 'Expected a node for all scopes',
|
|
loc: GeneratedSource,
|
|
});
|
|
if (node.seen) {
|
|
return;
|
|
}
|
|
node.seen = true;
|
|
for (const dep of node.dependencies) {
|
|
visit(dep, true);
|
|
}
|
|
return;
|
|
}
|
|
for (const value of state.escapingValues) {
|
|
visit(value);
|
|
}
|
|
return memoized;
|
|
}
|
|
function computePatternLValues(pattern) {
|
|
const lvalues = [];
|
|
switch (pattern.kind) {
|
|
case 'ArrayPattern': {
|
|
for (const item of pattern.items) {
|
|
if (item.kind === 'Identifier') {
|
|
lvalues.push({ place: item, level: MemoizationLevel.Conditional });
|
|
}
|
|
else if (item.kind === 'Spread') {
|
|
lvalues.push({ place: item.place, level: MemoizationLevel.Memoized });
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectPattern': {
|
|
for (const property of pattern.properties) {
|
|
if (property.kind === 'ObjectProperty') {
|
|
lvalues.push({
|
|
place: property.place,
|
|
level: MemoizationLevel.Conditional,
|
|
});
|
|
}
|
|
else {
|
|
lvalues.push({
|
|
place: property.place,
|
|
level: MemoizationLevel.Memoized,
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(pattern, `Unexpected pattern kind \`${pattern.kind}\``);
|
|
}
|
|
}
|
|
return lvalues;
|
|
}
|
|
class CollectDependenciesVisitor extends ReactiveFunctionVisitor {
|
|
constructor(env, state) {
|
|
super();
|
|
this.env = env;
|
|
this.state = state;
|
|
this.options = {
|
|
memoizeJsxElements: !this.env.config.enableForest,
|
|
forceMemoizePrimitives: this.env.config.enableForest ||
|
|
this.env.config.enablePreserveExistingMemoizationGuarantees,
|
|
};
|
|
}
|
|
computeMemoizationInputs(value, lvalue) {
|
|
const env = this.env;
|
|
const options = this.options;
|
|
switch (value.kind) {
|
|
case 'ConditionalExpression': {
|
|
return {
|
|
lvalues: lvalue !== null
|
|
? [{ place: lvalue, level: MemoizationLevel.Conditional }]
|
|
: [],
|
|
rvalues: [
|
|
...this.computeMemoizationInputs(value.consequent, null).rvalues,
|
|
...this.computeMemoizationInputs(value.alternate, null).rvalues,
|
|
],
|
|
};
|
|
}
|
|
case 'LogicalExpression': {
|
|
return {
|
|
lvalues: lvalue !== null
|
|
? [{ place: lvalue, level: MemoizationLevel.Conditional }]
|
|
: [],
|
|
rvalues: [
|
|
...this.computeMemoizationInputs(value.left, null).rvalues,
|
|
...this.computeMemoizationInputs(value.right, null).rvalues,
|
|
],
|
|
};
|
|
}
|
|
case 'SequenceExpression': {
|
|
for (const instr of value.instructions) {
|
|
this.visitValueForMemoization(instr.id, instr.value, instr.lvalue);
|
|
}
|
|
return {
|
|
lvalues: lvalue !== null
|
|
? [{ place: lvalue, level: MemoizationLevel.Conditional }]
|
|
: [],
|
|
rvalues: this.computeMemoizationInputs(value.value, null).rvalues,
|
|
};
|
|
}
|
|
case 'JsxExpression': {
|
|
const operands = [];
|
|
if (value.tag.kind === 'Identifier') {
|
|
operands.push(value.tag);
|
|
}
|
|
for (const prop of value.props) {
|
|
if (prop.kind === 'JsxAttribute') {
|
|
operands.push(prop.place);
|
|
}
|
|
else {
|
|
operands.push(prop.argument);
|
|
}
|
|
}
|
|
if (value.children !== null) {
|
|
for (const child of value.children) {
|
|
operands.push(child);
|
|
}
|
|
}
|
|
const level = options.memoizeJsxElements
|
|
? MemoizationLevel.Memoized
|
|
: MemoizationLevel.Unmemoized;
|
|
return {
|
|
lvalues: lvalue !== null ? [{ place: lvalue, level }] : [],
|
|
rvalues: operands,
|
|
};
|
|
}
|
|
case 'JsxFragment': {
|
|
const level = options.memoizeJsxElements
|
|
? MemoizationLevel.Memoized
|
|
: MemoizationLevel.Unmemoized;
|
|
return {
|
|
lvalues: lvalue !== null ? [{ place: lvalue, level }] : [],
|
|
rvalues: value.children,
|
|
};
|
|
}
|
|
case 'NextPropertyOf':
|
|
case 'StartMemoize':
|
|
case 'FinishMemoize':
|
|
case 'Debugger':
|
|
case 'ComputedDelete':
|
|
case 'PropertyDelete':
|
|
case 'LoadGlobal':
|
|
case 'MetaProperty':
|
|
case 'TemplateLiteral':
|
|
case 'Primitive':
|
|
case 'JSXText':
|
|
case 'BinaryExpression':
|
|
case 'UnaryExpression': {
|
|
if (options.forceMemoizePrimitives) {
|
|
const level = MemoizationLevel.Conditional;
|
|
return {
|
|
lvalues: lvalue !== null ? [{ place: lvalue, level }] : [],
|
|
rvalues: [...eachReactiveValueOperand(value)],
|
|
};
|
|
}
|
|
const level = MemoizationLevel.Never;
|
|
return {
|
|
lvalues: lvalue !== null ? [{ place: lvalue, level }] : [],
|
|
rvalues: [],
|
|
};
|
|
}
|
|
case 'Await':
|
|
case 'TypeCastExpression': {
|
|
return {
|
|
lvalues: lvalue !== null
|
|
? [{ place: lvalue, level: MemoizationLevel.Conditional }]
|
|
: [],
|
|
rvalues: [value.value],
|
|
};
|
|
}
|
|
case 'IteratorNext': {
|
|
return {
|
|
lvalues: lvalue !== null
|
|
? [{ place: lvalue, level: MemoizationLevel.Conditional }]
|
|
: [],
|
|
rvalues: [value.iterator, value.collection],
|
|
};
|
|
}
|
|
case 'GetIterator': {
|
|
return {
|
|
lvalues: lvalue !== null
|
|
? [{ place: lvalue, level: MemoizationLevel.Conditional }]
|
|
: [],
|
|
rvalues: [value.collection],
|
|
};
|
|
}
|
|
case 'LoadLocal': {
|
|
return {
|
|
lvalues: lvalue !== null
|
|
? [{ place: lvalue, level: MemoizationLevel.Conditional }]
|
|
: [],
|
|
rvalues: [value.place],
|
|
};
|
|
}
|
|
case 'LoadContext': {
|
|
return {
|
|
lvalues: lvalue !== null
|
|
? [{ place: lvalue, level: MemoizationLevel.Conditional }]
|
|
: [],
|
|
rvalues: [value.place],
|
|
};
|
|
}
|
|
case 'DeclareContext': {
|
|
const lvalues = [
|
|
{ place: value.lvalue.place, level: MemoizationLevel.Memoized },
|
|
];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Unmemoized });
|
|
}
|
|
return {
|
|
lvalues,
|
|
rvalues: [],
|
|
};
|
|
}
|
|
case 'DeclareLocal': {
|
|
const lvalues = [
|
|
{ place: value.lvalue.place, level: MemoizationLevel.Unmemoized },
|
|
];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Unmemoized });
|
|
}
|
|
return {
|
|
lvalues,
|
|
rvalues: [],
|
|
};
|
|
}
|
|
case 'PrefixUpdate':
|
|
case 'PostfixUpdate': {
|
|
const lvalues = [
|
|
{ place: value.lvalue, level: MemoizationLevel.Conditional },
|
|
];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Conditional });
|
|
}
|
|
return {
|
|
lvalues,
|
|
rvalues: [value.value],
|
|
};
|
|
}
|
|
case 'StoreLocal': {
|
|
const lvalues = [
|
|
{ place: value.lvalue.place, level: MemoizationLevel.Conditional },
|
|
];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Conditional });
|
|
}
|
|
return {
|
|
lvalues,
|
|
rvalues: [value.value],
|
|
};
|
|
}
|
|
case 'StoreContext': {
|
|
const lvalues = [
|
|
{ place: value.lvalue.place, level: MemoizationLevel.Memoized },
|
|
];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Conditional });
|
|
}
|
|
return {
|
|
lvalues,
|
|
rvalues: [value.value],
|
|
};
|
|
}
|
|
case 'StoreGlobal': {
|
|
const lvalues = [];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Unmemoized });
|
|
}
|
|
return {
|
|
lvalues,
|
|
rvalues: [value.value],
|
|
};
|
|
}
|
|
case 'Destructure': {
|
|
const lvalues = [];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Conditional });
|
|
}
|
|
lvalues.push(...computePatternLValues(value.lvalue.pattern));
|
|
return {
|
|
lvalues: lvalues,
|
|
rvalues: [value.value],
|
|
};
|
|
}
|
|
case 'ComputedLoad':
|
|
case 'PropertyLoad': {
|
|
const level = MemoizationLevel.Conditional;
|
|
return {
|
|
lvalues: lvalue !== null ? [{ place: lvalue, level }] : [],
|
|
rvalues: [value.object],
|
|
};
|
|
}
|
|
case 'ComputedStore': {
|
|
const lvalues = [
|
|
{ place: value.object, level: MemoizationLevel.Conditional },
|
|
];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Conditional });
|
|
}
|
|
return {
|
|
lvalues,
|
|
rvalues: [value.value],
|
|
};
|
|
}
|
|
case 'OptionalExpression': {
|
|
const lvalues = [];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Conditional });
|
|
}
|
|
return {
|
|
lvalues: lvalues,
|
|
rvalues: [
|
|
...this.computeMemoizationInputs(value.value, null).rvalues,
|
|
],
|
|
};
|
|
}
|
|
case 'TaggedTemplateExpression': {
|
|
const signature = getFunctionCallSignature(env, value.tag.identifier.type);
|
|
let lvalues = [];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Memoized });
|
|
}
|
|
if ((signature === null || signature === void 0 ? void 0 : signature.noAlias) === true) {
|
|
return {
|
|
lvalues,
|
|
rvalues: [],
|
|
};
|
|
}
|
|
const operands = [...eachReactiveValueOperand(value)];
|
|
lvalues.push(...operands
|
|
.filter(operand => isMutableEffect(operand.effect, operand.loc))
|
|
.map(place => ({ place, level: MemoizationLevel.Memoized })));
|
|
return {
|
|
lvalues,
|
|
rvalues: operands,
|
|
};
|
|
}
|
|
case 'CallExpression': {
|
|
const signature = getFunctionCallSignature(env, value.callee.identifier.type);
|
|
let lvalues = [];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Memoized });
|
|
}
|
|
if ((signature === null || signature === void 0 ? void 0 : signature.noAlias) === true) {
|
|
return {
|
|
lvalues,
|
|
rvalues: [],
|
|
};
|
|
}
|
|
const operands = [...eachReactiveValueOperand(value)];
|
|
lvalues.push(...operands
|
|
.filter(operand => isMutableEffect(operand.effect, operand.loc))
|
|
.map(place => ({ place, level: MemoizationLevel.Memoized })));
|
|
return {
|
|
lvalues,
|
|
rvalues: operands,
|
|
};
|
|
}
|
|
case 'MethodCall': {
|
|
const signature = getFunctionCallSignature(env, value.property.identifier.type);
|
|
let lvalues = [];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Memoized });
|
|
}
|
|
if ((signature === null || signature === void 0 ? void 0 : signature.noAlias) === true) {
|
|
return {
|
|
lvalues,
|
|
rvalues: [],
|
|
};
|
|
}
|
|
const operands = [...eachReactiveValueOperand(value)];
|
|
lvalues.push(...operands
|
|
.filter(operand => isMutableEffect(operand.effect, operand.loc))
|
|
.map(place => ({ place, level: MemoizationLevel.Memoized })));
|
|
return {
|
|
lvalues,
|
|
rvalues: operands,
|
|
};
|
|
}
|
|
case 'RegExpLiteral':
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression':
|
|
case 'ArrayExpression':
|
|
case 'NewExpression':
|
|
case 'ObjectExpression':
|
|
case 'PropertyStore': {
|
|
const operands = [...eachReactiveValueOperand(value)];
|
|
const lvalues = operands
|
|
.filter(operand => isMutableEffect(operand.effect, operand.loc))
|
|
.map(place => ({ place, level: MemoizationLevel.Memoized }));
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Memoized });
|
|
}
|
|
return {
|
|
lvalues,
|
|
rvalues: operands,
|
|
};
|
|
}
|
|
case 'UnsupportedNode': {
|
|
const lvalues = [];
|
|
if (lvalue !== null) {
|
|
lvalues.push({ place: lvalue, level: MemoizationLevel.Never });
|
|
}
|
|
return {
|
|
lvalues,
|
|
rvalues: [],
|
|
};
|
|
}
|
|
default: {
|
|
assertExhaustive$1(value, `Unexpected value kind \`${value.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
visitValueForMemoization(id, value, lvalue) {
|
|
var _a, _b, _c;
|
|
const state = this.state;
|
|
const aliasing = this.computeMemoizationInputs(value, lvalue);
|
|
for (const operand of aliasing.rvalues) {
|
|
const operandId = (_a = state.definitions.get(operand.identifier.declarationId)) !== null && _a !== void 0 ? _a : operand.identifier.declarationId;
|
|
state.visitOperand(id, operand, operandId);
|
|
}
|
|
for (const { place: lvalue, level } of aliasing.lvalues) {
|
|
const lvalueId = (_b = state.definitions.get(lvalue.identifier.declarationId)) !== null && _b !== void 0 ? _b : lvalue.identifier.declarationId;
|
|
let node = state.identifiers.get(lvalueId);
|
|
if (node === undefined) {
|
|
node = {
|
|
level: MemoizationLevel.Never,
|
|
memoized: false,
|
|
dependencies: new Set(),
|
|
scopes: new Set(),
|
|
seen: false,
|
|
};
|
|
state.identifiers.set(lvalueId, node);
|
|
}
|
|
node.level = joinAliases(node.level, level);
|
|
for (const operand of aliasing.rvalues) {
|
|
const operandId = (_c = state.definitions.get(operand.identifier.declarationId)) !== null && _c !== void 0 ? _c : operand.identifier.declarationId;
|
|
if (operandId === lvalueId) {
|
|
continue;
|
|
}
|
|
node.dependencies.add(operandId);
|
|
}
|
|
state.visitOperand(id, lvalue, lvalueId);
|
|
}
|
|
if (value.kind === 'LoadLocal' && lvalue !== null) {
|
|
state.definitions.set(lvalue.identifier.declarationId, value.place.identifier.declarationId);
|
|
}
|
|
else if (value.kind === 'CallExpression' || value.kind === 'MethodCall') {
|
|
let callee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
if (getHookKind(state.env, callee.identifier) != null) {
|
|
const signature = getFunctionCallSignature(this.env, callee.identifier.type);
|
|
if (signature && signature.noAlias === true) {
|
|
return;
|
|
}
|
|
for (const operand of value.args) {
|
|
const place = operand.kind === 'Spread' ? operand.place : operand;
|
|
state.escapingValues.add(place.identifier.declarationId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
visitInstruction(instruction, _scopes) {
|
|
this.visitValueForMemoization(instruction.id, instruction.value, instruction.lvalue);
|
|
}
|
|
visitTerminal(stmt, scopes) {
|
|
this.traverseTerminal(stmt, scopes);
|
|
if (stmt.terminal.kind === 'return') {
|
|
this.state.escapingValues.add(stmt.terminal.value.identifier.declarationId);
|
|
const identifierNode = this.state.identifiers.get(stmt.terminal.value.identifier.declarationId);
|
|
CompilerError.invariant(identifierNode !== undefined, {
|
|
reason: 'Expected identifier to be initialized',
|
|
loc: stmt.terminal.loc,
|
|
});
|
|
for (const scope of scopes) {
|
|
identifierNode.scopes.add(scope.id);
|
|
}
|
|
}
|
|
}
|
|
visitScope(scope, scopes) {
|
|
for (const reassignment of scope.scope.reassignments) {
|
|
const identifierNode = this.state.identifiers.get(reassignment.declarationId);
|
|
CompilerError.invariant(identifierNode !== undefined, {
|
|
reason: 'Expected identifier to be initialized',
|
|
loc: reassignment.loc,
|
|
});
|
|
for (const scope of scopes) {
|
|
identifierNode.scopes.add(scope.id);
|
|
}
|
|
identifierNode.scopes.add(scope.scope.id);
|
|
}
|
|
this.traverseScope(scope, [...scopes, scope.scope]);
|
|
}
|
|
}
|
|
class PruneScopesTransform extends ReactiveFunctionTransform {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.prunedScopes = new Set();
|
|
this.reassignments = new Map();
|
|
}
|
|
transformScope(scopeBlock, state) {
|
|
this.visitScope(scopeBlock, state);
|
|
if ((scopeBlock.scope.declarations.size === 0 &&
|
|
scopeBlock.scope.reassignments.size === 0) ||
|
|
scopeBlock.scope.earlyReturnValue !== null) {
|
|
return { kind: 'keep' };
|
|
}
|
|
const hasMemoizedOutput = Array.from(scopeBlock.scope.declarations.values()).some(decl => state.has(decl.identifier.declarationId)) ||
|
|
Array.from(scopeBlock.scope.reassignments).some(identifier => state.has(identifier.declarationId));
|
|
if (hasMemoizedOutput) {
|
|
return { kind: 'keep' };
|
|
}
|
|
else {
|
|
this.prunedScopes.add(scopeBlock.scope.id);
|
|
return {
|
|
kind: 'replace-many',
|
|
value: scopeBlock.instructions,
|
|
};
|
|
}
|
|
}
|
|
transformInstruction(instruction, state) {
|
|
var _a;
|
|
this.traverseInstruction(instruction, state);
|
|
const value = instruction.value;
|
|
if (value.kind === 'StoreLocal' && value.lvalue.kind === 'Reassign') {
|
|
const ids = getOrInsertDefault(this.reassignments, value.lvalue.place.identifier.declarationId, new Set());
|
|
ids.add(value.value.identifier);
|
|
}
|
|
else if (value.kind === 'LoadLocal' &&
|
|
value.place.identifier.scope != null &&
|
|
instruction.lvalue != null &&
|
|
instruction.lvalue.identifier.scope == null) {
|
|
const ids = getOrInsertDefault(this.reassignments, instruction.lvalue.identifier.declarationId, new Set());
|
|
ids.add(value.place.identifier);
|
|
}
|
|
else if (value.kind === 'FinishMemoize') {
|
|
let decls;
|
|
if (value.decl.identifier.scope == null) {
|
|
decls = (_a = this.reassignments.get(value.decl.identifier.declarationId)) !== null && _a !== void 0 ? _a : [
|
|
value.decl.identifier,
|
|
];
|
|
}
|
|
else {
|
|
decls = [value.decl.identifier];
|
|
}
|
|
if ([...decls].every(decl => decl.scope == null || this.prunedScopes.has(decl.scope.id))) {
|
|
value.pruned = true;
|
|
}
|
|
}
|
|
return { kind: 'keep' };
|
|
}
|
|
}
|
|
|
|
let Visitor$5 = class Visitor extends ReactiveFunctionVisitor {
|
|
visitLValue(id, lvalue, state) {
|
|
this.visitPlace(id, lvalue, state);
|
|
}
|
|
visitPlace(_id, place, state) {
|
|
if (place.reactive) {
|
|
state.add(place.identifier.id);
|
|
}
|
|
}
|
|
visitPrunedScope(scopeBlock, state) {
|
|
this.traversePrunedScope(scopeBlock, state);
|
|
for (const [id, decl] of scopeBlock.scope.declarations) {
|
|
if (!isPrimitiveType(decl.identifier) &&
|
|
!isStableRefType(decl.identifier, state)) {
|
|
state.add(id);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
function isStableRefType(identifier, reactiveIdentifiers) {
|
|
return isUseRefType(identifier) && !reactiveIdentifiers.has(identifier.id);
|
|
}
|
|
function collectReactiveIdentifiers(fn) {
|
|
const visitor = new Visitor$5();
|
|
const state = new Set();
|
|
visitReactiveFunction(fn, visitor, state);
|
|
return state;
|
|
}
|
|
|
|
function pruneNonReactiveDependencies(fn) {
|
|
const reactiveIdentifiers = collectReactiveIdentifiers(fn);
|
|
visitReactiveFunction(fn, new Visitor$4(), reactiveIdentifiers);
|
|
}
|
|
let Visitor$4 = class Visitor extends ReactiveFunctionVisitor {
|
|
visitInstruction(instruction, state) {
|
|
this.traverseInstruction(instruction, state);
|
|
const { lvalue, value } = instruction;
|
|
switch (value.kind) {
|
|
case 'LoadLocal': {
|
|
if (lvalue !== null && state.has(value.place.identifier.id)) {
|
|
state.add(lvalue.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
if (state.has(value.value.identifier.id)) {
|
|
state.add(value.lvalue.place.identifier.id);
|
|
if (lvalue !== null) {
|
|
state.add(lvalue.identifier.id);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
if (state.has(value.value.identifier.id)) {
|
|
for (const lvalue of eachPatternOperand(value.lvalue.pattern)) {
|
|
if (isStableType(lvalue.identifier)) {
|
|
continue;
|
|
}
|
|
state.add(lvalue.identifier.id);
|
|
}
|
|
if (lvalue !== null) {
|
|
state.add(lvalue.identifier.id);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
if (lvalue !== null &&
|
|
state.has(value.object.identifier.id) &&
|
|
!isStableType(lvalue.identifier)) {
|
|
state.add(lvalue.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'ComputedLoad': {
|
|
if (lvalue !== null &&
|
|
(state.has(value.object.identifier.id) ||
|
|
state.has(value.property.identifier.id))) {
|
|
state.add(lvalue.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
visitScope(scopeBlock, state) {
|
|
this.traverseScope(scopeBlock, state);
|
|
for (const dep of scopeBlock.scope.dependencies) {
|
|
const isReactive = state.has(dep.identifier.id);
|
|
if (!isReactive) {
|
|
scopeBlock.scope.dependencies.delete(dep);
|
|
}
|
|
}
|
|
if (scopeBlock.scope.dependencies.size !== 0) {
|
|
for (const [, declaration] of scopeBlock.scope.declarations) {
|
|
state.add(declaration.identifier.id);
|
|
}
|
|
for (const reassignment of scopeBlock.scope.reassignments) {
|
|
state.add(reassignment.id);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
function pruneUnusedLValues(fn) {
|
|
const lvalues = new Map();
|
|
visitReactiveFunction(fn, new Visitor$3(), lvalues);
|
|
for (const [, instr] of lvalues) {
|
|
instr.lvalue = null;
|
|
}
|
|
}
|
|
let Visitor$3 = class Visitor extends ReactiveFunctionVisitor {
|
|
visitPlace(id, place, state) {
|
|
state.delete(place.identifier.declarationId);
|
|
}
|
|
visitInstruction(instruction, state) {
|
|
this.traverseInstruction(instruction, state);
|
|
if (instruction.lvalue !== null &&
|
|
instruction.lvalue.identifier.name === null) {
|
|
state.set(instruction.lvalue.identifier.declarationId, instruction);
|
|
}
|
|
}
|
|
};
|
|
|
|
function pruneUnusedLabels(fn) {
|
|
const labels = new Set();
|
|
visitReactiveFunction(fn, new Transform$2(), labels);
|
|
}
|
|
let Transform$2 = class Transform extends ReactiveFunctionTransform {
|
|
transformTerminal(stmt, state) {
|
|
this.traverseTerminal(stmt, state);
|
|
const { terminal } = stmt;
|
|
if ((terminal.kind === 'break' || terminal.kind === 'continue') &&
|
|
terminal.targetKind === 'labeled') {
|
|
state.add(terminal.target);
|
|
}
|
|
const isReachableLabel = stmt.label !== null && state.has(stmt.label.id);
|
|
if (stmt.terminal.kind === 'label' && !isReachableLabel) {
|
|
const block = [...stmt.terminal.block];
|
|
const last = block.at(-1);
|
|
if (last !== undefined &&
|
|
last.kind === 'terminal' &&
|
|
last.terminal.kind === 'break' &&
|
|
last.terminal.target === null) {
|
|
block.pop();
|
|
}
|
|
return { kind: 'replace-many', value: block };
|
|
}
|
|
else {
|
|
if (!isReachableLabel && stmt.label != null) {
|
|
stmt.label.implicit = true;
|
|
}
|
|
return { kind: 'keep' };
|
|
}
|
|
}
|
|
};
|
|
|
|
function pruneUnusedScopes(fn) {
|
|
visitReactiveFunction(fn, new Transform$1(), {
|
|
hasReturnStatement: false,
|
|
});
|
|
}
|
|
let Transform$1 = class Transform extends ReactiveFunctionTransform {
|
|
visitTerminal(stmt, state) {
|
|
this.traverseTerminal(stmt, state);
|
|
if (stmt.terminal.kind === 'return') {
|
|
state.hasReturnStatement = true;
|
|
}
|
|
}
|
|
transformScope(scopeBlock, _state) {
|
|
const scopeState = { hasReturnStatement: false };
|
|
this.visitScope(scopeBlock, scopeState);
|
|
if (!scopeState.hasReturnStatement &&
|
|
scopeBlock.scope.reassignments.size === 0 &&
|
|
(scopeBlock.scope.declarations.size === 0 ||
|
|
!hasOwnDeclaration(scopeBlock))) {
|
|
return {
|
|
kind: 'replace',
|
|
value: {
|
|
kind: 'pruned-scope',
|
|
scope: scopeBlock.scope,
|
|
instructions: scopeBlock.instructions,
|
|
},
|
|
};
|
|
}
|
|
else {
|
|
return { kind: 'keep' };
|
|
}
|
|
}
|
|
};
|
|
function hasOwnDeclaration(block) {
|
|
for (const declaration of block.scope.declarations.values()) {
|
|
if (declaration.scope.id === block.scope.id) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function collectReferencedGlobals(fn) {
|
|
const identifiers = new Set();
|
|
visitReactiveFunction(fn, new Visitor$2(), identifiers);
|
|
return identifiers;
|
|
}
|
|
let Visitor$2 = class Visitor extends ReactiveFunctionVisitor {
|
|
visitValue(id, value, state) {
|
|
this.traverseValue(id, value, state);
|
|
if (value.kind === 'FunctionExpression' || value.kind === 'ObjectMethod') {
|
|
this.visitHirFunction(value.loweredFunc.func, state);
|
|
}
|
|
else if (value.kind === 'LoadGlobal') {
|
|
state.add(value.binding.name);
|
|
}
|
|
}
|
|
visitReactiveFunctionValue(_id, _dependencies, fn, state) {
|
|
visitReactiveFunction(fn, this, state);
|
|
}
|
|
};
|
|
|
|
var _Scopes_instances, _Scopes_seen, _Scopes_stack, _Scopes_globals, _Scopes_programContext, _Scopes_lookup;
|
|
function renameVariables(fn) {
|
|
const globals = collectReferencedGlobals(fn);
|
|
const scopes = new Scopes(globals, fn.env.programContext);
|
|
renameVariablesImpl(fn, new Visitor$1(), scopes);
|
|
return new Set([...scopes.names, ...globals]);
|
|
}
|
|
function renameVariablesImpl(fn, visitor, scopes) {
|
|
scopes.enter(() => {
|
|
for (const param of fn.params) {
|
|
if (param.kind === 'Identifier') {
|
|
scopes.visit(param.identifier);
|
|
}
|
|
else {
|
|
scopes.visit(param.place.identifier);
|
|
}
|
|
}
|
|
visitReactiveFunction(fn, visitor, scopes);
|
|
});
|
|
}
|
|
let Visitor$1 = class Visitor extends ReactiveFunctionVisitor {
|
|
visitParam(place, state) {
|
|
state.visit(place.identifier);
|
|
}
|
|
visitLValue(_id, lvalue, state) {
|
|
state.visit(lvalue.identifier);
|
|
}
|
|
visitPlace(id, place, state) {
|
|
state.visit(place.identifier);
|
|
}
|
|
visitBlock(block, state) {
|
|
state.enter(() => {
|
|
this.traverseBlock(block, state);
|
|
});
|
|
}
|
|
visitPrunedScope(scopeBlock, state) {
|
|
this.traverseBlock(scopeBlock.instructions, state);
|
|
}
|
|
visitScope(scope, state) {
|
|
for (const [_, declaration] of scope.scope.declarations) {
|
|
state.visit(declaration.identifier);
|
|
}
|
|
this.traverseScope(scope, state);
|
|
}
|
|
visitValue(id, value, state) {
|
|
this.traverseValue(id, value, state);
|
|
if (value.kind === 'FunctionExpression' || value.kind === 'ObjectMethod') {
|
|
this.visitHirFunction(value.loweredFunc.func, state);
|
|
}
|
|
}
|
|
visitReactiveFunctionValue(_id, _dependencies, _fn, _state) {
|
|
renameVariablesImpl(_fn, this, _state);
|
|
}
|
|
};
|
|
class Scopes {
|
|
constructor(globals, programContext) {
|
|
_Scopes_instances.add(this);
|
|
_Scopes_seen.set(this, new Map());
|
|
_Scopes_stack.set(this, [new Map()]);
|
|
_Scopes_globals.set(this, void 0);
|
|
_Scopes_programContext.set(this, void 0);
|
|
this.names = new Set();
|
|
__classPrivateFieldSet(this, _Scopes_globals, globals, "f");
|
|
__classPrivateFieldSet(this, _Scopes_programContext, programContext, "f");
|
|
}
|
|
visit(identifier) {
|
|
const originalName = identifier.name;
|
|
if (originalName === null) {
|
|
return;
|
|
}
|
|
const mappedName = __classPrivateFieldGet(this, _Scopes_seen, "f").get(identifier.declarationId);
|
|
if (mappedName !== undefined) {
|
|
identifier.name = mappedName;
|
|
return;
|
|
}
|
|
let name = originalName.value;
|
|
let id = 0;
|
|
if (isPromotedTemporary(originalName.value)) {
|
|
name = `t${id++}`;
|
|
}
|
|
else if (isPromotedJsxTemporary(originalName.value)) {
|
|
name = `T${id++}`;
|
|
}
|
|
while (__classPrivateFieldGet(this, _Scopes_instances, "m", _Scopes_lookup).call(this, name) !== null || __classPrivateFieldGet(this, _Scopes_globals, "f").has(name)) {
|
|
if (isPromotedTemporary(originalName.value)) {
|
|
name = `t${id++}`;
|
|
}
|
|
else if (isPromotedJsxTemporary(originalName.value)) {
|
|
name = `T${id++}`;
|
|
}
|
|
else {
|
|
name = `${originalName.value}$${id++}`;
|
|
}
|
|
}
|
|
__classPrivateFieldGet(this, _Scopes_programContext, "f").addNewReference(name);
|
|
const identifierName = makeIdentifierName(name);
|
|
identifier.name = identifierName;
|
|
__classPrivateFieldGet(this, _Scopes_seen, "f").set(identifier.declarationId, identifierName);
|
|
__classPrivateFieldGet(this, _Scopes_stack, "f").at(-1).set(identifierName.value, identifier.declarationId);
|
|
this.names.add(identifierName.value);
|
|
}
|
|
enter(fn) {
|
|
const next = new Map();
|
|
__classPrivateFieldGet(this, _Scopes_stack, "f").push(next);
|
|
fn();
|
|
const last = __classPrivateFieldGet(this, _Scopes_stack, "f").pop();
|
|
CompilerError.invariant(last === next, {
|
|
reason: 'Mismatch push/pop calls',
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
_Scopes_seen = new WeakMap(), _Scopes_stack = new WeakMap(), _Scopes_globals = new WeakMap(), _Scopes_programContext = new WeakMap(), _Scopes_instances = new WeakSet(), _Scopes_lookup = function _Scopes_lookup(name) {
|
|
for (let i = __classPrivateFieldGet(this, _Scopes_stack, "f").length - 1; i >= 0; i--) {
|
|
const scope = __classPrivateFieldGet(this, _Scopes_stack, "f")[i];
|
|
const entry = scope.get(name);
|
|
if (entry !== undefined) {
|
|
return entry;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
function stabilizeBlockIds(fn) {
|
|
const referenced = new Set();
|
|
visitReactiveFunction(fn, new CollectReferencedLabels(), referenced);
|
|
const mappings = new Map();
|
|
for (const blockId of referenced) {
|
|
mappings.set(blockId, makeBlockId(mappings.size));
|
|
}
|
|
visitReactiveFunction(fn, new RewriteBlockIds(), mappings);
|
|
}
|
|
class CollectReferencedLabels extends ReactiveFunctionVisitor {
|
|
visitScope(scope, state) {
|
|
const { earlyReturnValue } = scope.scope;
|
|
if (earlyReturnValue != null) {
|
|
state.add(earlyReturnValue.label);
|
|
}
|
|
this.traverseScope(scope, state);
|
|
}
|
|
visitTerminal(stmt, state) {
|
|
if (stmt.label != null) {
|
|
if (!stmt.label.implicit) {
|
|
state.add(stmt.label.id);
|
|
}
|
|
}
|
|
this.traverseTerminal(stmt, state);
|
|
}
|
|
}
|
|
class RewriteBlockIds extends ReactiveFunctionVisitor {
|
|
visitScope(scope, state) {
|
|
const { earlyReturnValue } = scope.scope;
|
|
if (earlyReturnValue != null) {
|
|
const rewrittenId = getOrInsertDefault(state, earlyReturnValue.label, state.size);
|
|
earlyReturnValue.label = makeBlockId(rewrittenId);
|
|
}
|
|
this.traverseScope(scope, state);
|
|
}
|
|
visitTerminal(stmt, state) {
|
|
if (stmt.label != null) {
|
|
const rewrittenId = getOrInsertDefault(state, stmt.label.id, state.size);
|
|
stmt.label.id = makeBlockId(rewrittenId);
|
|
}
|
|
const terminal = stmt.terminal;
|
|
if (terminal.kind === 'break' || terminal.kind === 'continue') {
|
|
const rewrittenId = getOrInsertDefault(state, terminal.target, state.size);
|
|
terminal.target = makeBlockId(rewrittenId);
|
|
}
|
|
this.traverseTerminal(stmt, state);
|
|
}
|
|
}
|
|
|
|
function inferMutationAliasingRanges(fn, { isFunctionExpression }) {
|
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
const functionEffects = [];
|
|
const state = new AliasingState();
|
|
const pendingPhis = new Map();
|
|
const mutations = [];
|
|
const renders = [];
|
|
let index = 0;
|
|
const shouldRecordErrors = !isFunctionExpression && fn.env.enableValidations;
|
|
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
state.create(place, { kind: 'Object' });
|
|
}
|
|
const seenBlocks = new Set();
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const phi of block.phis) {
|
|
state.create(phi.place, { kind: 'Phi' });
|
|
for (const [pred, operand] of phi.operands) {
|
|
if (!seenBlocks.has(pred)) {
|
|
const blockPhis = getOrInsertWith(pendingPhis, pred, () => []);
|
|
blockPhis.push({ from: operand, into: phi.place, index: index++ });
|
|
}
|
|
else {
|
|
state.assign(index++, operand, phi.place);
|
|
}
|
|
}
|
|
}
|
|
seenBlocks.add(block.id);
|
|
for (const instr of block.instructions) {
|
|
if (instr.effects == null)
|
|
continue;
|
|
for (const effect of instr.effects) {
|
|
if (effect.kind === 'Create') {
|
|
state.create(effect.into, { kind: 'Object' });
|
|
}
|
|
else if (effect.kind === 'CreateFunction') {
|
|
state.create(effect.into, {
|
|
kind: 'Function',
|
|
function: effect.function.loweredFunc.func,
|
|
});
|
|
}
|
|
else if (effect.kind === 'CreateFrom') {
|
|
state.createFrom(index++, effect.from, effect.into);
|
|
}
|
|
else if (effect.kind === 'Assign') {
|
|
if (!state.nodes.has(effect.into.identifier)) {
|
|
state.create(effect.into, { kind: 'Object' });
|
|
}
|
|
state.assign(index++, effect.from, effect.into);
|
|
}
|
|
else if (effect.kind === 'Alias') {
|
|
state.assign(index++, effect.from, effect.into);
|
|
}
|
|
else if (effect.kind === 'MaybeAlias') {
|
|
state.maybeAlias(index++, effect.from, effect.into);
|
|
}
|
|
else if (effect.kind === 'Capture') {
|
|
state.capture(index++, effect.from, effect.into);
|
|
}
|
|
else if (effect.kind === 'MutateTransitive' ||
|
|
effect.kind === 'MutateTransitiveConditionally') {
|
|
mutations.push({
|
|
index: index++,
|
|
id: instr.id,
|
|
transitive: true,
|
|
kind: effect.kind === 'MutateTransitive'
|
|
? MutationKind.Definite
|
|
: MutationKind.Conditional,
|
|
reason: null,
|
|
place: effect.value,
|
|
});
|
|
}
|
|
else if (effect.kind === 'Mutate' ||
|
|
effect.kind === 'MutateConditionally') {
|
|
mutations.push({
|
|
index: index++,
|
|
id: instr.id,
|
|
transitive: false,
|
|
kind: effect.kind === 'Mutate'
|
|
? MutationKind.Definite
|
|
: MutationKind.Conditional,
|
|
reason: effect.kind === 'Mutate' ? ((_a = effect.reason) !== null && _a !== void 0 ? _a : null) : null,
|
|
place: effect.value,
|
|
});
|
|
}
|
|
else if (effect.kind === 'MutateFrozen' ||
|
|
effect.kind === 'MutateGlobal' ||
|
|
effect.kind === 'Impure') {
|
|
if (shouldRecordErrors) {
|
|
fn.env.recordError(effect.error);
|
|
}
|
|
functionEffects.push(effect);
|
|
}
|
|
else if (effect.kind === 'Render') {
|
|
renders.push({ index: index++, place: effect.place });
|
|
functionEffects.push(effect);
|
|
}
|
|
}
|
|
}
|
|
const blockPhis = pendingPhis.get(block.id);
|
|
if (blockPhis != null) {
|
|
for (const { from, into, index } of blockPhis) {
|
|
state.assign(index, from, into);
|
|
}
|
|
}
|
|
if (block.terminal.kind === 'return') {
|
|
state.assign(index++, block.terminal.value, fn.returns);
|
|
}
|
|
if ((block.terminal.kind === 'maybe-throw' ||
|
|
block.terminal.kind === 'return') &&
|
|
block.terminal.effects != null) {
|
|
for (const effect of block.terminal.effects) {
|
|
if (effect.kind === 'Alias') {
|
|
state.assign(index++, effect.from, effect.into);
|
|
}
|
|
else {
|
|
CompilerError.invariant(effect.kind === 'Freeze', {
|
|
reason: `Unexpected '${effect.kind}' effect for MaybeThrow terminal`,
|
|
loc: block.terminal.loc,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const mutation of mutations) {
|
|
state.mutate(mutation.index, mutation.place.identifier, makeInstructionId(mutation.id + 1), mutation.transitive, mutation.kind, mutation.place.loc, mutation.reason, shouldRecordErrors ? fn.env : null);
|
|
}
|
|
for (const render of renders) {
|
|
state.render(render.index, render.place.identifier, shouldRecordErrors ? fn.env : null);
|
|
}
|
|
for (const param of [...fn.context, ...fn.params]) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
const node = state.nodes.get(place.identifier);
|
|
if (node == null) {
|
|
continue;
|
|
}
|
|
let mutated = false;
|
|
if (node.local != null) {
|
|
if (node.local.kind === MutationKind.Conditional) {
|
|
mutated = true;
|
|
functionEffects.push({
|
|
kind: 'MutateConditionally',
|
|
value: Object.assign(Object.assign({}, place), { loc: node.local.loc }),
|
|
});
|
|
}
|
|
else if (node.local.kind === MutationKind.Definite) {
|
|
mutated = true;
|
|
functionEffects.push({
|
|
kind: 'Mutate',
|
|
value: Object.assign(Object.assign({}, place), { loc: node.local.loc }),
|
|
reason: node.mutationReason,
|
|
});
|
|
}
|
|
}
|
|
if (node.transitive != null) {
|
|
if (node.transitive.kind === MutationKind.Conditional) {
|
|
mutated = true;
|
|
functionEffects.push({
|
|
kind: 'MutateTransitiveConditionally',
|
|
value: Object.assign(Object.assign({}, place), { loc: node.transitive.loc }),
|
|
});
|
|
}
|
|
else if (node.transitive.kind === MutationKind.Definite) {
|
|
mutated = true;
|
|
functionEffects.push({
|
|
kind: 'MutateTransitive',
|
|
value: Object.assign(Object.assign({}, place), { loc: node.transitive.loc }),
|
|
});
|
|
}
|
|
}
|
|
if (mutated) {
|
|
place.effect = Effect.Capture;
|
|
}
|
|
}
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const phi of block.phis) {
|
|
phi.place.effect = Effect.Store;
|
|
const isPhiMutatedAfterCreation = phi.place.identifier.mutableRange.end >
|
|
((_c = (_b = block.instructions.at(0)) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : block.terminal.id);
|
|
for (const operand of phi.operands.values()) {
|
|
operand.effect = isPhiMutatedAfterCreation
|
|
? Effect.Capture
|
|
: Effect.Read;
|
|
}
|
|
if (isPhiMutatedAfterCreation &&
|
|
phi.place.identifier.mutableRange.start === 0) {
|
|
const firstInstructionIdOfBlock = (_e = (_d = block.instructions.at(0)) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : block.terminal.id;
|
|
phi.place.identifier.mutableRange.start = makeInstructionId(firstInstructionIdOfBlock - 1);
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
lvalue.effect = Effect.ConditionallyMutate;
|
|
if (lvalue.identifier.mutableRange.start === 0) {
|
|
lvalue.identifier.mutableRange.start = instr.id;
|
|
}
|
|
if (lvalue.identifier.mutableRange.end === 0) {
|
|
lvalue.identifier.mutableRange.end = makeInstructionId(Math.max(instr.id + 1, lvalue.identifier.mutableRange.end));
|
|
}
|
|
}
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
operand.effect = Effect.Read;
|
|
}
|
|
if (instr.effects == null) {
|
|
continue;
|
|
}
|
|
const operandEffects = new Map();
|
|
for (const effect of instr.effects) {
|
|
switch (effect.kind) {
|
|
case 'Assign':
|
|
case 'Alias':
|
|
case 'Capture':
|
|
case 'CreateFrom':
|
|
case 'MaybeAlias': {
|
|
const isMutatedOrReassigned = effect.into.identifier.mutableRange.end > instr.id;
|
|
if (isMutatedOrReassigned) {
|
|
operandEffects.set(effect.from.identifier.id, Effect.Capture);
|
|
operandEffects.set(effect.into.identifier.id, Effect.Store);
|
|
}
|
|
else {
|
|
operandEffects.set(effect.from.identifier.id, Effect.Read);
|
|
operandEffects.set(effect.into.identifier.id, Effect.Store);
|
|
}
|
|
break;
|
|
}
|
|
case 'CreateFunction':
|
|
case 'Create': {
|
|
break;
|
|
}
|
|
case 'Mutate': {
|
|
operandEffects.set(effect.value.identifier.id, Effect.Store);
|
|
break;
|
|
}
|
|
case 'Apply': {
|
|
CompilerError.invariant(false, {
|
|
reason: `[AnalyzeFunctions] Expected Apply effects to be replaced with more precise effects`,
|
|
loc: effect.function.loc,
|
|
});
|
|
}
|
|
case 'MutateTransitive':
|
|
case 'MutateConditionally':
|
|
case 'MutateTransitiveConditionally': {
|
|
operandEffects.set(effect.value.identifier.id, Effect.ConditionallyMutate);
|
|
break;
|
|
}
|
|
case 'Freeze': {
|
|
operandEffects.set(effect.value.identifier.id, Effect.Freeze);
|
|
break;
|
|
}
|
|
case 'ImmutableCapture': {
|
|
break;
|
|
}
|
|
case 'Impure':
|
|
case 'Render':
|
|
case 'MutateFrozen':
|
|
case 'MutateGlobal': {
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(effect, `Unexpected effect kind ${effect.kind}`);
|
|
}
|
|
}
|
|
}
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
const effect = (_f = operandEffects.get(lvalue.identifier.id)) !== null && _f !== void 0 ? _f : Effect.ConditionallyMutate;
|
|
lvalue.effect = effect;
|
|
}
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
if (operand.identifier.mutableRange.end > instr.id &&
|
|
operand.identifier.mutableRange.start === 0) {
|
|
operand.identifier.mutableRange.start = instr.id;
|
|
}
|
|
const effect = (_g = operandEffects.get(operand.identifier.id)) !== null && _g !== void 0 ? _g : Effect.Read;
|
|
operand.effect = effect;
|
|
}
|
|
if (instr.value.kind === 'StoreContext' &&
|
|
instr.value.value.identifier.mutableRange.end <= instr.id) {
|
|
instr.value.value.identifier.mutableRange.end = makeInstructionId(instr.id + 1);
|
|
}
|
|
}
|
|
if (block.terminal.kind === 'return') {
|
|
block.terminal.value.effect = isFunctionExpression
|
|
? Effect.Read
|
|
: Effect.Freeze;
|
|
}
|
|
else {
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
operand.effect = Effect.Read;
|
|
}
|
|
}
|
|
}
|
|
const returns = fn.returns.identifier;
|
|
functionEffects.push({
|
|
kind: 'Create',
|
|
into: fn.returns,
|
|
value: isPrimitiveType(returns)
|
|
? ValueKind.Primitive
|
|
: isJsxType(returns.type)
|
|
? ValueKind.Frozen
|
|
: ValueKind.Mutable,
|
|
reason: ValueReason.KnownReturnSignature,
|
|
});
|
|
const tracked = [];
|
|
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
tracked.push(place);
|
|
}
|
|
for (const into of tracked) {
|
|
const mutationIndex = index++;
|
|
state.mutate(mutationIndex, into.identifier, null, true, MutationKind.Conditional, into.loc, null, null);
|
|
for (const from of tracked) {
|
|
if (from.identifier.id === into.identifier.id ||
|
|
from.identifier.id === fn.returns.identifier.id) {
|
|
continue;
|
|
}
|
|
const fromNode = state.nodes.get(from.identifier);
|
|
CompilerError.invariant(fromNode != null, {
|
|
reason: `Expected a node to exist for all parameters and context variables`,
|
|
loc: into.loc,
|
|
});
|
|
if (fromNode.lastMutated === mutationIndex) {
|
|
if (into.identifier.id === fn.returns.identifier.id) {
|
|
functionEffects.push({
|
|
kind: 'Alias',
|
|
from,
|
|
into,
|
|
});
|
|
}
|
|
else {
|
|
functionEffects.push({
|
|
kind: 'Capture',
|
|
from,
|
|
into,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return functionEffects;
|
|
}
|
|
function appendFunctionErrors(env, fn) {
|
|
var _a;
|
|
if (env == null)
|
|
return;
|
|
for (const effect of (_a = fn.aliasingEffects) !== null && _a !== void 0 ? _a : []) {
|
|
switch (effect.kind) {
|
|
case 'Impure':
|
|
case 'MutateFrozen':
|
|
case 'MutateGlobal': {
|
|
env.recordError(effect.error);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var MutationKind;
|
|
(function (MutationKind) {
|
|
MutationKind[MutationKind["None"] = 0] = "None";
|
|
MutationKind[MutationKind["Conditional"] = 1] = "Conditional";
|
|
MutationKind[MutationKind["Definite"] = 2] = "Definite";
|
|
})(MutationKind || (MutationKind = {}));
|
|
class AliasingState {
|
|
constructor() {
|
|
this.nodes = new Map();
|
|
}
|
|
create(place, value) {
|
|
this.nodes.set(place.identifier, {
|
|
id: place.identifier,
|
|
createdFrom: new Map(),
|
|
captures: new Map(),
|
|
aliases: new Map(),
|
|
maybeAliases: new Map(),
|
|
edges: [],
|
|
transitive: null,
|
|
local: null,
|
|
lastMutated: 0,
|
|
mutationReason: null,
|
|
value,
|
|
});
|
|
}
|
|
createFrom(index, from, into) {
|
|
this.create(into, { kind: 'Object' });
|
|
const fromNode = this.nodes.get(from.identifier);
|
|
const toNode = this.nodes.get(into.identifier);
|
|
if (fromNode == null || toNode == null) {
|
|
return;
|
|
}
|
|
fromNode.edges.push({ index, node: into.identifier, kind: 'alias' });
|
|
if (!toNode.createdFrom.has(from.identifier)) {
|
|
toNode.createdFrom.set(from.identifier, index);
|
|
}
|
|
}
|
|
capture(index, from, into) {
|
|
const fromNode = this.nodes.get(from.identifier);
|
|
const toNode = this.nodes.get(into.identifier);
|
|
if (fromNode == null || toNode == null) {
|
|
return;
|
|
}
|
|
fromNode.edges.push({ index, node: into.identifier, kind: 'capture' });
|
|
if (!toNode.captures.has(from.identifier)) {
|
|
toNode.captures.set(from.identifier, index);
|
|
}
|
|
}
|
|
assign(index, from, into) {
|
|
const fromNode = this.nodes.get(from.identifier);
|
|
const toNode = this.nodes.get(into.identifier);
|
|
if (fromNode == null || toNode == null) {
|
|
return;
|
|
}
|
|
fromNode.edges.push({ index, node: into.identifier, kind: 'alias' });
|
|
if (!toNode.aliases.has(from.identifier)) {
|
|
toNode.aliases.set(from.identifier, index);
|
|
}
|
|
}
|
|
maybeAlias(index, from, into) {
|
|
const fromNode = this.nodes.get(from.identifier);
|
|
const toNode = this.nodes.get(into.identifier);
|
|
if (fromNode == null || toNode == null) {
|
|
return;
|
|
}
|
|
fromNode.edges.push({ index, node: into.identifier, kind: 'maybeAlias' });
|
|
if (!toNode.maybeAliases.has(from.identifier)) {
|
|
toNode.maybeAliases.set(from.identifier, index);
|
|
}
|
|
}
|
|
render(index, start, env) {
|
|
const seen = new Set();
|
|
const queue = [start];
|
|
while (queue.length !== 0) {
|
|
const current = queue.pop();
|
|
if (seen.has(current)) {
|
|
continue;
|
|
}
|
|
seen.add(current);
|
|
const node = this.nodes.get(current);
|
|
if (node == null || node.transitive != null || node.local != null) {
|
|
continue;
|
|
}
|
|
if (node.value.kind === 'Function') {
|
|
appendFunctionErrors(env, node.value.function);
|
|
}
|
|
for (const [alias, when] of node.createdFrom) {
|
|
if (when >= index) {
|
|
continue;
|
|
}
|
|
queue.push(alias);
|
|
}
|
|
for (const [alias, when] of node.aliases) {
|
|
if (when >= index) {
|
|
continue;
|
|
}
|
|
queue.push(alias);
|
|
}
|
|
for (const [capture, when] of node.captures) {
|
|
if (when >= index) {
|
|
continue;
|
|
}
|
|
queue.push(capture);
|
|
}
|
|
}
|
|
}
|
|
mutate(index, start, end, transitive, startKind, loc, reason, env) {
|
|
var _a;
|
|
const seen = new Map();
|
|
const queue = [{ place: start, transitive, direction: 'backwards', kind: startKind }];
|
|
while (queue.length !== 0) {
|
|
const { place: current, transitive, direction, kind } = queue.pop();
|
|
const previousKind = seen.get(current);
|
|
if (previousKind != null && previousKind >= kind) {
|
|
continue;
|
|
}
|
|
seen.set(current, kind);
|
|
const node = this.nodes.get(current);
|
|
if (node == null) {
|
|
continue;
|
|
}
|
|
(_a = node.mutationReason) !== null && _a !== void 0 ? _a : (node.mutationReason = reason);
|
|
node.lastMutated = Math.max(node.lastMutated, index);
|
|
if (end != null) {
|
|
node.id.mutableRange.end = makeInstructionId(Math.max(node.id.mutableRange.end, end));
|
|
}
|
|
if (node.value.kind === 'Function' &&
|
|
node.transitive == null &&
|
|
node.local == null) {
|
|
appendFunctionErrors(env, node.value.function);
|
|
}
|
|
if (transitive) {
|
|
if (node.transitive == null || node.transitive.kind < kind) {
|
|
node.transitive = { kind, loc };
|
|
}
|
|
}
|
|
else {
|
|
if (node.local == null || node.local.kind < kind) {
|
|
node.local = { kind, loc };
|
|
}
|
|
}
|
|
for (const edge of node.edges) {
|
|
if (edge.index >= index) {
|
|
break;
|
|
}
|
|
queue.push({
|
|
place: edge.node,
|
|
transitive,
|
|
direction: 'forwards',
|
|
kind: edge.kind === 'maybeAlias' ? MutationKind.Conditional : kind,
|
|
});
|
|
}
|
|
for (const [alias, when] of node.createdFrom) {
|
|
if (when >= index) {
|
|
continue;
|
|
}
|
|
queue.push({
|
|
place: alias,
|
|
transitive: true,
|
|
direction: 'backwards',
|
|
kind,
|
|
});
|
|
}
|
|
if (direction === 'backwards' || node.value.kind !== 'Phi') {
|
|
for (const [alias, when] of node.aliases) {
|
|
if (when >= index) {
|
|
continue;
|
|
}
|
|
queue.push({
|
|
place: alias,
|
|
transitive,
|
|
direction: 'backwards',
|
|
kind,
|
|
});
|
|
}
|
|
for (const [alias, when] of node.maybeAliases) {
|
|
if (when >= index) {
|
|
continue;
|
|
}
|
|
queue.push({
|
|
place: alias,
|
|
transitive,
|
|
direction: 'backwards',
|
|
kind: MutationKind.Conditional,
|
|
});
|
|
}
|
|
}
|
|
if (transitive) {
|
|
for (const [capture, when] of node.captures) {
|
|
if (when >= index) {
|
|
continue;
|
|
}
|
|
queue.push({
|
|
place: capture,
|
|
transitive,
|
|
direction: 'backwards',
|
|
kind,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function analyseFunctions(func) {
|
|
for (const [_, block] of func.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
switch (instr.value.kind) {
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
lowerWithMutationAliasing(instr.value.loweredFunc.func);
|
|
for (const operand of instr.value.loweredFunc.func.context) {
|
|
operand.identifier.mutableRange = {
|
|
start: makeInstructionId(0),
|
|
end: makeInstructionId(0),
|
|
};
|
|
operand.identifier.scope = null;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function lowerWithMutationAliasing(fn) {
|
|
var _a, _b;
|
|
analyseFunctions(fn);
|
|
inferMutationAliasingEffects(fn, { isFunctionExpression: true });
|
|
deadCodeElimination(fn);
|
|
const functionEffects = inferMutationAliasingRanges(fn, {
|
|
isFunctionExpression: true,
|
|
});
|
|
rewriteInstructionKindsBasedOnReassignment(fn);
|
|
inferReactiveScopeVariables(fn);
|
|
fn.aliasingEffects = functionEffects;
|
|
const capturedOrMutated = new Set();
|
|
for (const effect of functionEffects) {
|
|
switch (effect.kind) {
|
|
case 'Assign':
|
|
case 'Alias':
|
|
case 'Capture':
|
|
case 'CreateFrom':
|
|
case 'MaybeAlias': {
|
|
capturedOrMutated.add(effect.from.identifier.id);
|
|
break;
|
|
}
|
|
case 'Apply': {
|
|
CompilerError.invariant(false, {
|
|
reason: `[AnalyzeFunctions] Expected Apply effects to be replaced with more precise effects`,
|
|
loc: effect.function.loc,
|
|
});
|
|
}
|
|
case 'Mutate':
|
|
case 'MutateConditionally':
|
|
case 'MutateTransitive':
|
|
case 'MutateTransitiveConditionally': {
|
|
capturedOrMutated.add(effect.value.identifier.id);
|
|
break;
|
|
}
|
|
case 'Impure':
|
|
case 'Render':
|
|
case 'MutateFrozen':
|
|
case 'MutateGlobal':
|
|
case 'CreateFunction':
|
|
case 'Create':
|
|
case 'Freeze':
|
|
case 'ImmutableCapture': {
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(effect, `Unexpected effect kind ${effect.kind}`);
|
|
}
|
|
}
|
|
}
|
|
for (const operand of fn.context) {
|
|
if (capturedOrMutated.has(operand.identifier.id) ||
|
|
operand.effect === Effect.Capture) {
|
|
operand.effect = Effect.Capture;
|
|
}
|
|
else {
|
|
operand.effect = Effect.Read;
|
|
}
|
|
}
|
|
(_b = (_a = fn.env.logger) === null || _a === void 0 ? void 0 : _a.debugLogIRs) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
|
kind: 'hir',
|
|
name: 'AnalyseFunction (inner)',
|
|
value: fn,
|
|
});
|
|
}
|
|
|
|
function collectMaybeMemoDependencies(value, maybeDeps, optional) {
|
|
var _a;
|
|
switch (value.kind) {
|
|
case 'LoadGlobal': {
|
|
return {
|
|
root: {
|
|
kind: 'Global',
|
|
identifierName: value.binding.name,
|
|
},
|
|
path: [],
|
|
loc: value.loc,
|
|
};
|
|
}
|
|
case 'PropertyLoad': {
|
|
const object = maybeDeps.get(value.object.identifier.id);
|
|
if (object != null) {
|
|
return {
|
|
root: object.root,
|
|
path: [
|
|
...object.path,
|
|
{ property: value.property, optional, loc: value.loc },
|
|
],
|
|
loc: value.loc,
|
|
};
|
|
}
|
|
break;
|
|
}
|
|
case 'LoadLocal':
|
|
case 'LoadContext': {
|
|
const source = maybeDeps.get(value.place.identifier.id);
|
|
if (source != null) {
|
|
return source;
|
|
}
|
|
else if (value.place.identifier.name != null &&
|
|
value.place.identifier.name.kind === 'named') {
|
|
return {
|
|
root: {
|
|
kind: 'NamedLocal',
|
|
value: Object.assign({}, value.place),
|
|
constant: false,
|
|
},
|
|
path: [],
|
|
loc: value.place.loc,
|
|
};
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
const lvalue = value.lvalue.place.identifier;
|
|
const rvalue = value.value.identifier.id;
|
|
const aliased = maybeDeps.get(rvalue);
|
|
if (aliased != null && ((_a = lvalue.name) === null || _a === void 0 ? void 0 : _a.kind) !== 'named') {
|
|
maybeDeps.set(lvalue.id, aliased);
|
|
return aliased;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
function collectTemporaries(instr, env, sidemap) {
|
|
const { value, lvalue } = instr;
|
|
switch (value.kind) {
|
|
case 'FunctionExpression': {
|
|
sidemap.functions.set(instr.lvalue.identifier.id, instr);
|
|
break;
|
|
}
|
|
case 'LoadGlobal': {
|
|
const global = env.getGlobalDeclaration(value.binding, value.loc);
|
|
const hookKind = global !== null ? getHookKindForType(env, global) : null;
|
|
const lvalId = instr.lvalue.identifier.id;
|
|
if (hookKind === 'useMemo' || hookKind === 'useCallback') {
|
|
sidemap.manualMemos.set(lvalId, {
|
|
kind: hookKind,
|
|
loadInstr: instr,
|
|
});
|
|
}
|
|
else if (value.binding.name === 'React') {
|
|
sidemap.react.add(lvalId);
|
|
}
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
if (sidemap.react.has(value.object.identifier.id)) {
|
|
const property = value.property;
|
|
if (property === 'useMemo' || property === 'useCallback') {
|
|
sidemap.manualMemos.set(instr.lvalue.identifier.id, {
|
|
kind: property,
|
|
loadInstr: instr,
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'ArrayExpression': {
|
|
if (value.elements.every(e => e.kind === 'Identifier')) {
|
|
sidemap.maybeDepsLists.set(instr.lvalue.identifier.id, {
|
|
loc: value.loc,
|
|
deps: value.elements,
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
const maybeDep = collectMaybeMemoDependencies(value, sidemap.maybeDeps, sidemap.optionals.has(lvalue.identifier.id));
|
|
if (maybeDep != null) {
|
|
sidemap.maybeDeps.set(lvalue.identifier.id, maybeDep);
|
|
}
|
|
}
|
|
function makeManualMemoizationMarkers(fnExpr, env, depsList, depsLoc, memoDecl, manualMemoId) {
|
|
return [
|
|
{
|
|
id: makeInstructionId(0),
|
|
lvalue: createTemporaryPlace(env, fnExpr.loc),
|
|
value: {
|
|
kind: 'StartMemoize',
|
|
manualMemoId,
|
|
deps: depsList,
|
|
depsLoc,
|
|
loc: fnExpr.loc,
|
|
},
|
|
effects: null,
|
|
loc: fnExpr.loc,
|
|
},
|
|
{
|
|
id: makeInstructionId(0),
|
|
lvalue: createTemporaryPlace(env, fnExpr.loc),
|
|
value: {
|
|
kind: 'FinishMemoize',
|
|
manualMemoId,
|
|
decl: Object.assign({}, memoDecl),
|
|
loc: fnExpr.loc,
|
|
},
|
|
effects: null,
|
|
loc: fnExpr.loc,
|
|
},
|
|
];
|
|
}
|
|
function getManualMemoizationReplacement(fn, loc, kind) {
|
|
if (kind === 'useMemo') {
|
|
return {
|
|
kind: 'CallExpression',
|
|
callee: fn,
|
|
args: [],
|
|
loc,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
kind: 'LoadLocal',
|
|
place: {
|
|
kind: 'Identifier',
|
|
identifier: fn.identifier,
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc,
|
|
},
|
|
loc,
|
|
};
|
|
}
|
|
}
|
|
function extractManualMemoizationArgs(instr, kind, sidemap, env) {
|
|
const [fnPlace, depsListPlace] = instr.value.args;
|
|
if (fnPlace == null || fnPlace.kind !== 'Identifier') {
|
|
env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.UseMemo,
|
|
reason: `Expected a callback function to be passed to ${kind}`,
|
|
description: kind === 'useCallback'
|
|
? 'The first argument to useCallback() must be a function to cache'
|
|
: 'The first argument to useMemo() must be a function that calculates a result to cache',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: kind === 'useCallback'
|
|
? `Expected a callback function`
|
|
: `Expected a memoization function`,
|
|
}));
|
|
return null;
|
|
}
|
|
if (depsListPlace == null) {
|
|
return {
|
|
fnPlace,
|
|
depsList: null,
|
|
depsLoc: null,
|
|
};
|
|
}
|
|
const maybeDepsList = depsListPlace.kind === 'Identifier'
|
|
? sidemap.maybeDepsLists.get(depsListPlace.identifier.id)
|
|
: null;
|
|
if (maybeDepsList == null) {
|
|
env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.UseMemo,
|
|
reason: `Expected the dependency list for ${kind} to be an array literal`,
|
|
description: `Expected the dependency list for ${kind} to be an array literal`,
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: (depsListPlace === null || depsListPlace === void 0 ? void 0 : depsListPlace.kind) === 'Identifier' ? depsListPlace.loc : instr.loc,
|
|
message: `Expected the dependency list for ${kind} to be an array literal`,
|
|
}));
|
|
return null;
|
|
}
|
|
const depsList = [];
|
|
for (const dep of maybeDepsList.deps) {
|
|
const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
|
|
if (maybeDep == null) {
|
|
env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.UseMemo,
|
|
reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
|
description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: dep.loc,
|
|
message: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
|
}));
|
|
}
|
|
else {
|
|
depsList.push(maybeDep);
|
|
}
|
|
}
|
|
return {
|
|
fnPlace,
|
|
depsList,
|
|
depsLoc: maybeDepsList.loc,
|
|
};
|
|
}
|
|
function dropManualMemoization(func) {
|
|
const isValidationEnabled = func.env.config.validatePreserveExistingMemoizationGuarantees ||
|
|
func.env.config.validateNoSetStateInRender ||
|
|
func.env.config.enablePreserveExistingMemoizationGuarantees;
|
|
const optionals = findOptionalPlaces$1(func);
|
|
const sidemap = {
|
|
functions: new Map(),
|
|
manualMemos: new Map(),
|
|
react: new Set(),
|
|
maybeDeps: new Map(),
|
|
maybeDepsLists: new Map(),
|
|
optionals,
|
|
};
|
|
let nextManualMemoId = 0;
|
|
const queuedInserts = new Map();
|
|
for (const [_, block] of func.body.blocks) {
|
|
for (let i = 0; i < block.instructions.length; i++) {
|
|
const instr = block.instructions[i];
|
|
if (instr.value.kind === 'CallExpression' ||
|
|
instr.value.kind === 'MethodCall') {
|
|
const id = instr.value.kind === 'CallExpression'
|
|
? instr.value.callee.identifier.id
|
|
: instr.value.property.identifier.id;
|
|
const manualMemo = sidemap.manualMemos.get(id);
|
|
if (manualMemo != null) {
|
|
const memoDetails = extractManualMemoizationArgs(instr, manualMemo.kind, sidemap, func.env);
|
|
if (memoDetails == null) {
|
|
continue;
|
|
}
|
|
const { fnPlace, depsList, depsLoc } = memoDetails;
|
|
instr.value = getManualMemoizationReplacement(fnPlace, instr.value.loc, manualMemo.kind);
|
|
if (isValidationEnabled) {
|
|
if (!sidemap.functions.has(fnPlace.identifier.id)) {
|
|
func.env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.UseMemo,
|
|
reason: `Expected the first argument to be an inline function expression`,
|
|
description: `Expected the first argument to be an inline function expression`,
|
|
suggestions: [],
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: fnPlace.loc,
|
|
message: `Expected the first argument to be an inline function expression`,
|
|
}));
|
|
continue;
|
|
}
|
|
const memoDecl = manualMemo.kind === 'useMemo'
|
|
? instr.lvalue
|
|
: {
|
|
kind: 'Identifier',
|
|
identifier: fnPlace.identifier,
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc: fnPlace.loc,
|
|
};
|
|
const [startMarker, finishMarker] = makeManualMemoizationMarkers(fnPlace, func.env, depsList, depsLoc, memoDecl, nextManualMemoId++);
|
|
queuedInserts.set(manualMemo.loadInstr.id, startMarker);
|
|
queuedInserts.set(instr.id, finishMarker);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
collectTemporaries(instr, func.env, sidemap);
|
|
}
|
|
}
|
|
}
|
|
if (queuedInserts.size > 0) {
|
|
let hasChanges = false;
|
|
for (const [_, block] of func.body.blocks) {
|
|
let nextInstructions = null;
|
|
for (let i = 0; i < block.instructions.length; i++) {
|
|
const instr = block.instructions[i];
|
|
const insertInstr = queuedInserts.get(instr.id);
|
|
if (insertInstr != null) {
|
|
nextInstructions = nextInstructions !== null && nextInstructions !== void 0 ? nextInstructions : block.instructions.slice(0, i);
|
|
nextInstructions.push(instr);
|
|
nextInstructions.push(insertInstr);
|
|
}
|
|
else if (nextInstructions != null) {
|
|
nextInstructions.push(instr);
|
|
}
|
|
}
|
|
if (nextInstructions !== null) {
|
|
block.instructions = nextInstructions;
|
|
hasChanges = true;
|
|
}
|
|
}
|
|
if (hasChanges) {
|
|
markInstructionIds(func.body);
|
|
}
|
|
}
|
|
}
|
|
function findOptionalPlaces$1(fn) {
|
|
const optionals = new Set();
|
|
for (const [, block] of fn.body.blocks) {
|
|
if (block.terminal.kind === 'optional' && block.terminal.optional) {
|
|
const optionalTerminal = block.terminal;
|
|
let testBlock = fn.body.blocks.get(block.terminal.test);
|
|
loop: while (true) {
|
|
const terminal = testBlock.terminal;
|
|
switch (terminal.kind) {
|
|
case 'branch': {
|
|
if (terminal.fallthrough === optionalTerminal.fallthrough) {
|
|
const consequent = fn.body.blocks.get(terminal.consequent);
|
|
const last = consequent.instructions.at(-1);
|
|
if (last !== undefined && last.value.kind === 'StoreLocal') {
|
|
optionals.add(last.value.value.identifier.id);
|
|
}
|
|
break loop;
|
|
}
|
|
else {
|
|
testBlock = fn.body.blocks.get(terminal.fallthrough);
|
|
}
|
|
break;
|
|
}
|
|
case 'optional':
|
|
case 'logical':
|
|
case 'sequence':
|
|
case 'ternary': {
|
|
testBlock = fn.body.blocks.get(terminal.fallthrough);
|
|
break;
|
|
}
|
|
case 'maybe-throw': {
|
|
testBlock = fn.body.blocks.get(terminal.continuation);
|
|
break;
|
|
}
|
|
default: {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected terminal in optional`,
|
|
message: `Unexpected ${terminal.kind} in optional`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return optionals;
|
|
}
|
|
|
|
function createControlDominators(fn, isControlVariable) {
|
|
const postDominators = computePostDominatorTree(fn, {
|
|
includeThrowsAsExitNode: false,
|
|
});
|
|
const postDominatorFrontierCache = new Map();
|
|
function isControlledBlock(id) {
|
|
let controlBlocks = postDominatorFrontierCache.get(id);
|
|
if (controlBlocks === undefined) {
|
|
controlBlocks = postDominatorFrontier(fn, postDominators, id);
|
|
postDominatorFrontierCache.set(id, controlBlocks);
|
|
}
|
|
for (const blockId of controlBlocks) {
|
|
const controlBlock = fn.body.blocks.get(blockId);
|
|
switch (controlBlock.terminal.kind) {
|
|
case 'if':
|
|
case 'branch': {
|
|
if (isControlVariable(controlBlock.terminal.test)) {
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
case 'switch': {
|
|
if (isControlVariable(controlBlock.terminal.test)) {
|
|
return true;
|
|
}
|
|
for (const case_ of controlBlock.terminal.cases) {
|
|
if (case_.test !== null && isControlVariable(case_.test)) {
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
return isControlledBlock;
|
|
}
|
|
function postDominatorFrontier(fn, postDominators, targetId) {
|
|
const visited = new Set();
|
|
const frontier = new Set();
|
|
const targetPostDominators = postDominatorsOf(fn, postDominators, targetId);
|
|
for (const blockId of [...targetPostDominators, targetId]) {
|
|
if (visited.has(blockId)) {
|
|
continue;
|
|
}
|
|
visited.add(blockId);
|
|
const block = fn.body.blocks.get(blockId);
|
|
for (const pred of block.preds) {
|
|
if (!targetPostDominators.has(pred)) {
|
|
frontier.add(pred);
|
|
}
|
|
}
|
|
}
|
|
return frontier;
|
|
}
|
|
function postDominatorsOf(fn, postDominators, targetId) {
|
|
var _a;
|
|
const result = new Set();
|
|
const visited = new Set();
|
|
const queue = [targetId];
|
|
while (queue.length) {
|
|
const currentId = queue.shift();
|
|
if (visited.has(currentId)) {
|
|
continue;
|
|
}
|
|
visited.add(currentId);
|
|
const current = fn.body.blocks.get(currentId);
|
|
for (const pred of current.preds) {
|
|
const predPostDominator = (_a = postDominators.get(pred)) !== null && _a !== void 0 ? _a : pred;
|
|
if (predPostDominator === targetId || result.has(predPostDominator)) {
|
|
result.add(pred);
|
|
}
|
|
queue.push(pred);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
class StableSidemap {
|
|
constructor(env) {
|
|
this.map = new Map();
|
|
this.env = env;
|
|
}
|
|
handleInstruction(instr) {
|
|
const { value, lvalue } = instr;
|
|
switch (value.kind) {
|
|
case 'CallExpression':
|
|
case 'MethodCall': {
|
|
if (evaluatesToStableTypeOrContainer(this.env, instr)) {
|
|
if (isStableType(lvalue.identifier)) {
|
|
this.map.set(lvalue.identifier.id, {
|
|
isStable: true,
|
|
});
|
|
}
|
|
else {
|
|
this.map.set(lvalue.identifier.id, {
|
|
isStable: false,
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'Destructure':
|
|
case 'PropertyLoad': {
|
|
const source = value.kind === 'Destructure'
|
|
? value.value.identifier.id
|
|
: value.object.identifier.id;
|
|
const entry = this.map.get(source);
|
|
if (entry) {
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
if (isStableTypeContainer(lvalue.identifier)) {
|
|
this.map.set(lvalue.identifier.id, {
|
|
isStable: false,
|
|
});
|
|
}
|
|
else if (isStableType(lvalue.identifier)) {
|
|
this.map.set(lvalue.identifier.id, {
|
|
isStable: true,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
const entry = this.map.get(value.value.identifier.id);
|
|
if (entry) {
|
|
this.map.set(lvalue.identifier.id, entry);
|
|
this.map.set(value.lvalue.place.identifier.id, entry);
|
|
}
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
const entry = this.map.get(value.place.identifier.id);
|
|
if (entry) {
|
|
this.map.set(lvalue.identifier.id, entry);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
isStable(id) {
|
|
const entry = this.map.get(id);
|
|
return entry != null ? entry.isStable : false;
|
|
}
|
|
}
|
|
function inferReactivePlaces(fn) {
|
|
const reactiveIdentifiers = new ReactivityMap(findDisjointMutableValues(fn));
|
|
const stableIdentifierSources = new StableSidemap(fn.env);
|
|
for (const param of fn.params) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
reactiveIdentifiers.markReactive(place);
|
|
}
|
|
const isReactiveControlledBlock = createControlDominators(fn, place => reactiveIdentifiers.isReactive(place));
|
|
do {
|
|
for (const [, block] of fn.body.blocks) {
|
|
let hasReactiveControl = isReactiveControlledBlock(block.id);
|
|
for (const phi of block.phis) {
|
|
if (reactiveIdentifiers.isReactive(phi.place)) {
|
|
continue;
|
|
}
|
|
let isPhiReactive = false;
|
|
for (const [, operand] of phi.operands) {
|
|
if (reactiveIdentifiers.isReactive(operand)) {
|
|
isPhiReactive = true;
|
|
break;
|
|
}
|
|
}
|
|
if (isPhiReactive) {
|
|
reactiveIdentifiers.markReactive(phi.place);
|
|
}
|
|
else {
|
|
for (const [pred] of phi.operands) {
|
|
if (isReactiveControlledBlock(pred)) {
|
|
reactiveIdentifiers.markReactive(phi.place);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const instruction of block.instructions) {
|
|
stableIdentifierSources.handleInstruction(instruction);
|
|
const { value } = instruction;
|
|
let hasReactiveInput = false;
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
const reactive = reactiveIdentifiers.isReactive(operand);
|
|
hasReactiveInput || (hasReactiveInput = reactive);
|
|
}
|
|
if (value.kind === 'CallExpression' &&
|
|
(getHookKind(fn.env, value.callee.identifier) != null ||
|
|
isUseOperator(value.callee.identifier))) {
|
|
hasReactiveInput = true;
|
|
}
|
|
else if (value.kind === 'MethodCall' &&
|
|
(getHookKind(fn.env, value.property.identifier) != null ||
|
|
isUseOperator(value.property.identifier))) {
|
|
hasReactiveInput = true;
|
|
}
|
|
if (hasReactiveInput) {
|
|
for (const lvalue of eachInstructionLValue(instruction)) {
|
|
if (stableIdentifierSources.isStable(lvalue.identifier.id)) {
|
|
continue;
|
|
}
|
|
reactiveIdentifiers.markReactive(lvalue);
|
|
}
|
|
}
|
|
if (hasReactiveInput || hasReactiveControl) {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
switch (operand.effect) {
|
|
case Effect.Capture:
|
|
case Effect.Store:
|
|
case Effect.ConditionallyMutate:
|
|
case Effect.ConditionallyMutateIterator:
|
|
case Effect.Mutate: {
|
|
if (isMutable(instruction, operand)) {
|
|
reactiveIdentifiers.markReactive(operand);
|
|
}
|
|
break;
|
|
}
|
|
case Effect.Freeze:
|
|
case Effect.Read: {
|
|
break;
|
|
}
|
|
case Effect.Unknown: {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Unexpected unknown effect',
|
|
loc: operand.loc,
|
|
});
|
|
}
|
|
default: {
|
|
assertExhaustive$1(operand.effect, `Unexpected effect kind \`${operand.effect}\``);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
reactiveIdentifiers.isReactive(operand);
|
|
}
|
|
}
|
|
} while (reactiveIdentifiers.snapshot());
|
|
function propagateReactivityToInnerFunctions(fn, isOutermost) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
if (!isOutermost) {
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
reactiveIdentifiers.isReactive(operand);
|
|
}
|
|
}
|
|
if (instr.value.kind === 'ObjectMethod' ||
|
|
instr.value.kind === 'FunctionExpression') {
|
|
propagateReactivityToInnerFunctions(instr.value.loweredFunc.func, false);
|
|
}
|
|
}
|
|
if (!isOutermost) {
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
reactiveIdentifiers.isReactive(operand);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
propagateReactivityToInnerFunctions(fn, true);
|
|
}
|
|
class ReactivityMap {
|
|
constructor(aliasedIdentifiers) {
|
|
this.hasChanges = false;
|
|
this.reactive = new Set();
|
|
this.aliasedIdentifiers = aliasedIdentifiers;
|
|
}
|
|
isReactive(place) {
|
|
var _a;
|
|
const identifier = (_a = this.aliasedIdentifiers.find(place.identifier)) !== null && _a !== void 0 ? _a : place.identifier;
|
|
const reactive = this.reactive.has(identifier.id);
|
|
if (reactive) {
|
|
place.reactive = true;
|
|
}
|
|
return reactive;
|
|
}
|
|
markReactive(place) {
|
|
var _a;
|
|
place.reactive = true;
|
|
const identifier = (_a = this.aliasedIdentifiers.find(place.identifier)) !== null && _a !== void 0 ? _a : place.identifier;
|
|
if (!this.reactive.has(identifier.id)) {
|
|
this.hasChanges = true;
|
|
this.reactive.add(identifier.id);
|
|
}
|
|
}
|
|
snapshot() {
|
|
const hasChanges = this.hasChanges;
|
|
this.hasChanges = false;
|
|
return hasChanges;
|
|
}
|
|
}
|
|
|
|
function inlineImmediatelyInvokedFunctionExpressions(fn) {
|
|
const functions = new Map();
|
|
const inlinedFunctions = new Set();
|
|
const queue = Array.from(fn.body.blocks.values());
|
|
queue: for (const block of queue) {
|
|
if (isStatementBlockKind(block.kind)) {
|
|
for (let ii = 0; ii < block.instructions.length; ii++) {
|
|
const instr = block.instructions[ii];
|
|
switch (instr.value.kind) {
|
|
case 'FunctionExpression': {
|
|
if (instr.lvalue.identifier.name === null) {
|
|
functions.set(instr.lvalue.identifier.id, instr.value);
|
|
}
|
|
break;
|
|
}
|
|
case 'CallExpression': {
|
|
if (instr.value.args.length !== 0) {
|
|
continue;
|
|
}
|
|
const body = functions.get(instr.value.callee.identifier.id);
|
|
if (body === undefined) {
|
|
continue;
|
|
}
|
|
if (body.loweredFunc.func.params.length > 0 ||
|
|
body.loweredFunc.func.async ||
|
|
body.loweredFunc.func.generator) {
|
|
continue;
|
|
}
|
|
inlinedFunctions.add(instr.value.callee.identifier.id);
|
|
const continuationBlockId = fn.env.nextBlockId;
|
|
const continuationBlock = {
|
|
id: continuationBlockId,
|
|
instructions: block.instructions.slice(ii + 1),
|
|
kind: block.kind,
|
|
phis: new Set(),
|
|
preds: new Set(),
|
|
terminal: block.terminal,
|
|
};
|
|
fn.body.blocks.set(continuationBlockId, continuationBlock);
|
|
block.instructions.length = ii;
|
|
if (hasSingleExitReturnTerminal(body.loweredFunc.func)) {
|
|
block.terminal = {
|
|
kind: 'goto',
|
|
block: body.loweredFunc.func.body.entry,
|
|
id: block.terminal.id,
|
|
loc: block.terminal.loc,
|
|
variant: GotoVariant.Break,
|
|
};
|
|
for (const block of body.loweredFunc.func.body.blocks.values()) {
|
|
if (block.terminal.kind === 'return') {
|
|
block.instructions.push({
|
|
id: makeInstructionId(0),
|
|
loc: block.terminal.loc,
|
|
lvalue: instr.lvalue,
|
|
value: {
|
|
kind: 'LoadLocal',
|
|
loc: block.terminal.loc,
|
|
place: block.terminal.value,
|
|
},
|
|
effects: null,
|
|
});
|
|
block.terminal = {
|
|
kind: 'goto',
|
|
block: continuationBlockId,
|
|
id: block.terminal.id,
|
|
loc: block.terminal.loc,
|
|
variant: GotoVariant.Break,
|
|
};
|
|
}
|
|
}
|
|
for (const [id, block] of body.loweredFunc.func.body.blocks) {
|
|
block.preds.clear();
|
|
fn.body.blocks.set(id, block);
|
|
}
|
|
}
|
|
else {
|
|
const newTerminal = {
|
|
block: body.loweredFunc.func.body.entry,
|
|
id: makeInstructionId(0),
|
|
kind: 'label',
|
|
fallthrough: continuationBlockId,
|
|
loc: block.terminal.loc,
|
|
};
|
|
block.terminal = newTerminal;
|
|
const result = instr.lvalue;
|
|
declareTemporary(fn.env, block, result);
|
|
if (result.identifier.name == null) {
|
|
promoteTemporary(result.identifier);
|
|
}
|
|
for (const [id, block] of body.loweredFunc.func.body.blocks) {
|
|
block.preds.clear();
|
|
rewriteBlock(fn.env, block, continuationBlockId, result);
|
|
fn.body.blocks.set(id, block);
|
|
}
|
|
}
|
|
queue.push(continuationBlock);
|
|
continue queue;
|
|
}
|
|
default: {
|
|
for (const place of eachInstructionValueOperand(instr.value)) {
|
|
functions.delete(place.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (inlinedFunctions.size !== 0) {
|
|
for (const block of fn.body.blocks.values()) {
|
|
retainWhere(block.instructions, instr => !inlinedFunctions.has(instr.lvalue.identifier.id));
|
|
}
|
|
reversePostorderBlocks(fn.body);
|
|
markInstructionIds(fn.body);
|
|
markPredecessors(fn.body);
|
|
mergeConsecutiveBlocks(fn);
|
|
}
|
|
}
|
|
function hasSingleExitReturnTerminal(fn) {
|
|
let hasReturn = false;
|
|
let exitCount = 0;
|
|
for (const [, block] of fn.body.blocks) {
|
|
if (block.terminal.kind === 'return' || block.terminal.kind === 'throw') {
|
|
hasReturn || (hasReturn = block.terminal.kind === 'return');
|
|
exitCount++;
|
|
}
|
|
}
|
|
return exitCount === 1 && hasReturn;
|
|
}
|
|
function rewriteBlock(env, block, returnTarget, returnValue) {
|
|
const { terminal } = block;
|
|
if (terminal.kind !== 'return') {
|
|
return;
|
|
}
|
|
block.instructions.push({
|
|
id: makeInstructionId(0),
|
|
loc: terminal.loc,
|
|
lvalue: createTemporaryPlace(env, terminal.loc),
|
|
value: {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Reassign, place: Object.assign({}, returnValue) },
|
|
value: terminal.value,
|
|
type: null,
|
|
loc: terminal.loc,
|
|
},
|
|
effects: null,
|
|
});
|
|
block.terminal = {
|
|
kind: 'goto',
|
|
block: returnTarget,
|
|
id: makeInstructionId(0),
|
|
variant: GotoVariant.Break,
|
|
loc: block.terminal.loc,
|
|
};
|
|
}
|
|
function declareTemporary(env, block, result) {
|
|
block.instructions.push({
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
lvalue: createTemporaryPlace(env, result.loc),
|
|
value: {
|
|
kind: 'DeclareLocal',
|
|
lvalue: {
|
|
place: result,
|
|
kind: InstructionKind.Let,
|
|
},
|
|
type: null,
|
|
loc: result.loc,
|
|
},
|
|
effects: null,
|
|
});
|
|
}
|
|
|
|
function alignMethodCallScopes(fn) {
|
|
const scopeMapping = new Map();
|
|
const mergedScopes = new DisjointSet();
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
if (value.kind === 'MethodCall') {
|
|
const lvalueScope = lvalue.identifier.scope;
|
|
const propertyScope = value.property.identifier.scope;
|
|
if (lvalueScope !== null) {
|
|
if (propertyScope !== null) {
|
|
mergedScopes.union([lvalueScope, propertyScope]);
|
|
}
|
|
else {
|
|
scopeMapping.set(value.property.identifier.id, lvalueScope);
|
|
}
|
|
}
|
|
else if (propertyScope !== null) {
|
|
scopeMapping.set(value.property.identifier.id, null);
|
|
}
|
|
}
|
|
else if (value.kind === 'FunctionExpression' ||
|
|
value.kind === 'ObjectMethod') {
|
|
alignMethodCallScopes(value.loweredFunc.func);
|
|
}
|
|
}
|
|
}
|
|
mergedScopes.forEach((scope, root) => {
|
|
if (scope === root) {
|
|
return;
|
|
}
|
|
root.range.start = makeInstructionId(Math.min(scope.range.start, root.range.start));
|
|
root.range.end = makeInstructionId(Math.max(scope.range.end, root.range.end));
|
|
});
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
const mappedScope = scopeMapping.get(instr.lvalue.identifier.id);
|
|
if (mappedScope !== undefined) {
|
|
instr.lvalue.identifier.scope = mappedScope;
|
|
}
|
|
else if (instr.lvalue.identifier.scope !== null) {
|
|
const mergedScope = mergedScopes.find(instr.lvalue.identifier.scope);
|
|
if (mergedScope != null) {
|
|
instr.lvalue.identifier.scope = mergedScope;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function alignReactiveScopesToBlockScopesHIR(fn) {
|
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
const activeBlockFallthroughRanges = [];
|
|
const activeScopes = new Set();
|
|
const seen = new Set();
|
|
const valueBlockNodes = new Map();
|
|
const placeScopes = new Map();
|
|
function recordPlace(id, place, node) {
|
|
if (place.identifier.scope !== null) {
|
|
placeScopes.set(place, place.identifier.scope);
|
|
}
|
|
const scope = getPlaceScope(id, place);
|
|
if (scope == null) {
|
|
return;
|
|
}
|
|
activeScopes.add(scope);
|
|
node === null || node === void 0 ? void 0 : node.children.push({ kind: 'scope', scope, id });
|
|
if (seen.has(scope)) {
|
|
return;
|
|
}
|
|
seen.add(scope);
|
|
if (node != null && node.valueRange !== null) {
|
|
scope.range.start = makeInstructionId(Math.min(node.valueRange.start, scope.range.start));
|
|
scope.range.end = makeInstructionId(Math.max(node.valueRange.end, scope.range.end));
|
|
}
|
|
}
|
|
for (const [, block] of fn.body.blocks) {
|
|
const startingId = (_b = (_a = block.instructions[0]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : block.terminal.id;
|
|
retainWhere_Set(activeScopes, scope => scope.range.end > startingId);
|
|
const top = activeBlockFallthroughRanges.at(-1);
|
|
if ((top === null || top === void 0 ? void 0 : top.fallthrough) === block.id) {
|
|
activeBlockFallthroughRanges.pop();
|
|
for (const scope of activeScopes) {
|
|
scope.range.start = makeInstructionId(Math.min(scope.range.start, top.range.start));
|
|
}
|
|
}
|
|
const { instructions, terminal } = block;
|
|
const node = (_c = valueBlockNodes.get(block.id)) !== null && _c !== void 0 ? _c : null;
|
|
for (const instr of instructions) {
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
recordPlace(instr.id, lvalue, node);
|
|
}
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
recordPlace(instr.id, operand, node);
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(terminal)) {
|
|
recordPlace(terminal.id, operand, node);
|
|
}
|
|
const fallthrough = terminalFallthrough(terminal);
|
|
if (fallthrough !== null && terminal.kind !== 'branch') {
|
|
const fallthroughBlock = fn.body.blocks.get(fallthrough);
|
|
const nextId = (_e = (_d = fallthroughBlock.instructions[0]) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : fallthroughBlock.terminal.id;
|
|
for (const scope of activeScopes) {
|
|
if (scope.range.end > terminal.id) {
|
|
scope.range.end = makeInstructionId(Math.max(scope.range.end, nextId));
|
|
}
|
|
}
|
|
activeBlockFallthroughRanges.push({
|
|
fallthrough,
|
|
range: {
|
|
start: terminal.id,
|
|
end: nextId,
|
|
},
|
|
});
|
|
CompilerError.invariant(!valueBlockNodes.has(fallthrough), {
|
|
reason: 'Expect hir blocks to have unique fallthroughs',
|
|
loc: terminal.loc,
|
|
});
|
|
if (node != null) {
|
|
valueBlockNodes.set(fallthrough, node);
|
|
}
|
|
}
|
|
else if (terminal.kind === 'goto') {
|
|
const start = activeBlockFallthroughRanges.find(range => range.fallthrough === terminal.block);
|
|
if (start != null && start !== activeBlockFallthroughRanges.at(-1)) {
|
|
const fallthroughBlock = fn.body.blocks.get(start.fallthrough);
|
|
const firstId = (_g = (_f = fallthroughBlock.instructions[0]) === null || _f === void 0 ? void 0 : _f.id) !== null && _g !== void 0 ? _g : fallthroughBlock.terminal.id;
|
|
for (const scope of activeScopes) {
|
|
if (scope.range.end <= terminal.id) {
|
|
continue;
|
|
}
|
|
scope.range.start = makeInstructionId(Math.min(start.range.start, scope.range.start));
|
|
scope.range.end = makeInstructionId(Math.max(firstId, scope.range.end));
|
|
}
|
|
}
|
|
}
|
|
mapTerminalSuccessors(terminal, successor => {
|
|
var _a, _b;
|
|
if (valueBlockNodes.has(successor)) {
|
|
return successor;
|
|
}
|
|
const successorBlock = fn.body.blocks.get(successor);
|
|
if (successorBlock.kind === 'block' || successorBlock.kind === 'catch') ;
|
|
else if (node == null ||
|
|
terminal.kind === 'ternary' ||
|
|
terminal.kind === 'logical' ||
|
|
terminal.kind === 'optional') {
|
|
let valueRange;
|
|
if (node == null) {
|
|
CompilerError.invariant(fallthrough !== null, {
|
|
reason: `Expected a fallthrough for value block`,
|
|
loc: terminal.loc,
|
|
});
|
|
const fallthroughBlock = fn.body.blocks.get(fallthrough);
|
|
const nextId = (_b = (_a = fallthroughBlock.instructions[0]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : fallthroughBlock.terminal.id;
|
|
valueRange = {
|
|
start: terminal.id,
|
|
end: nextId,
|
|
};
|
|
}
|
|
else {
|
|
valueRange = node.valueRange;
|
|
}
|
|
const childNode = {
|
|
kind: 'node',
|
|
id: terminal.id,
|
|
children: [],
|
|
valueRange,
|
|
};
|
|
node === null || node === void 0 ? void 0 : node.children.push(childNode);
|
|
valueBlockNodes.set(successor, childNode);
|
|
}
|
|
else {
|
|
valueBlockNodes.set(successor, node);
|
|
}
|
|
return successor;
|
|
});
|
|
}
|
|
}
|
|
|
|
function flattenReactiveLoopsHIR(fn) {
|
|
const activeLoops = Array();
|
|
for (const [, block] of fn.body.blocks) {
|
|
retainWhere(activeLoops, id => id !== block.id);
|
|
const { terminal } = block;
|
|
switch (terminal.kind) {
|
|
case 'do-while':
|
|
case 'for':
|
|
case 'for-in':
|
|
case 'for-of':
|
|
case 'while': {
|
|
activeLoops.push(terminal.fallthrough);
|
|
break;
|
|
}
|
|
case 'scope': {
|
|
if (activeLoops.length !== 0) {
|
|
block.terminal = {
|
|
kind: 'pruned-scope',
|
|
block: terminal.block,
|
|
fallthrough: terminal.fallthrough,
|
|
id: terminal.id,
|
|
loc: terminal.loc,
|
|
scope: terminal.scope,
|
|
};
|
|
}
|
|
break;
|
|
}
|
|
case 'branch':
|
|
case 'goto':
|
|
case 'if':
|
|
case 'label':
|
|
case 'logical':
|
|
case 'maybe-throw':
|
|
case 'optional':
|
|
case 'pruned-scope':
|
|
case 'return':
|
|
case 'sequence':
|
|
case 'switch':
|
|
case 'ternary':
|
|
case 'throw':
|
|
case 'try':
|
|
case 'unreachable':
|
|
case 'unsupported': {
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, `Unexpected terminal kind \`${terminal.kind}\``);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function flattenScopesWithHooksOrUseHIR(fn) {
|
|
const activeScopes = [];
|
|
const prune = [];
|
|
for (const [, block] of fn.body.blocks) {
|
|
retainWhere(activeScopes, current => current.fallthrough !== block.id);
|
|
for (const instr of block.instructions) {
|
|
const { value } = instr;
|
|
switch (value.kind) {
|
|
case 'MethodCall':
|
|
case 'CallExpression': {
|
|
const callee = value.kind === 'MethodCall' ? value.property : value.callee;
|
|
if (getHookKind(fn.env, callee.identifier) != null ||
|
|
isUseOperator(callee.identifier)) {
|
|
prune.push(...activeScopes.map(entry => entry.block));
|
|
activeScopes.length = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (block.terminal.kind === 'scope') {
|
|
activeScopes.push({
|
|
block: block.id,
|
|
fallthrough: block.terminal.fallthrough,
|
|
});
|
|
}
|
|
}
|
|
for (const id of prune) {
|
|
const block = fn.body.blocks.get(id);
|
|
const terminal = block.terminal;
|
|
CompilerError.invariant(terminal.kind === 'scope', {
|
|
reason: `Expected block to have a scope terminal`,
|
|
description: `Expected block bb${block.id} to end in a scope terminal`,
|
|
loc: terminal.loc,
|
|
});
|
|
const body = fn.body.blocks.get(terminal.block);
|
|
if (body.instructions.length === 1 &&
|
|
body.terminal.kind === 'goto' &&
|
|
body.terminal.block === terminal.fallthrough) {
|
|
block.terminal = {
|
|
kind: 'label',
|
|
block: terminal.block,
|
|
fallthrough: terminal.fallthrough,
|
|
id: terminal.id,
|
|
loc: terminal.loc,
|
|
};
|
|
continue;
|
|
}
|
|
block.terminal = {
|
|
kind: 'pruned-scope',
|
|
block: terminal.block,
|
|
fallthrough: terminal.fallthrough,
|
|
id: terminal.id,
|
|
loc: terminal.loc,
|
|
scope: terminal.scope,
|
|
};
|
|
}
|
|
}
|
|
|
|
function pruneAlwaysInvalidatingScopes(fn) {
|
|
visitReactiveFunction(fn, new Transform(), false);
|
|
}
|
|
class Transform extends ReactiveFunctionTransform {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.alwaysInvalidatingValues = new Set();
|
|
this.unmemoizedValues = new Set();
|
|
}
|
|
transformInstruction(instruction, withinScope) {
|
|
this.visitInstruction(instruction, withinScope);
|
|
const { lvalue, value } = instruction;
|
|
switch (value.kind) {
|
|
case 'ArrayExpression':
|
|
case 'ObjectExpression':
|
|
case 'JsxExpression':
|
|
case 'JsxFragment':
|
|
case 'NewExpression': {
|
|
if (lvalue !== null) {
|
|
this.alwaysInvalidatingValues.add(lvalue.identifier);
|
|
if (!withinScope) {
|
|
this.unmemoizedValues.add(lvalue.identifier);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
if (this.alwaysInvalidatingValues.has(value.value.identifier)) {
|
|
this.alwaysInvalidatingValues.add(value.lvalue.place.identifier);
|
|
}
|
|
if (this.unmemoizedValues.has(value.value.identifier)) {
|
|
this.unmemoizedValues.add(value.lvalue.place.identifier);
|
|
}
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
if (lvalue !== null &&
|
|
this.alwaysInvalidatingValues.has(value.place.identifier)) {
|
|
this.alwaysInvalidatingValues.add(lvalue.identifier);
|
|
}
|
|
if (lvalue !== null &&
|
|
this.unmemoizedValues.has(value.place.identifier)) {
|
|
this.unmemoizedValues.add(lvalue.identifier);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return { kind: 'keep' };
|
|
}
|
|
transformScope(scopeBlock, _withinScope) {
|
|
this.visitScope(scopeBlock, true);
|
|
for (const dep of scopeBlock.scope.dependencies) {
|
|
if (this.unmemoizedValues.has(dep.identifier)) {
|
|
for (const [_, decl] of scopeBlock.scope.declarations) {
|
|
if (this.alwaysInvalidatingValues.has(decl.identifier)) {
|
|
this.unmemoizedValues.add(decl.identifier);
|
|
}
|
|
}
|
|
for (const identifier of scopeBlock.scope.reassignments) {
|
|
if (this.alwaysInvalidatingValues.has(identifier)) {
|
|
this.unmemoizedValues.add(identifier);
|
|
}
|
|
}
|
|
return {
|
|
kind: 'replace',
|
|
value: {
|
|
kind: 'pruned-scope',
|
|
scope: scopeBlock.scope,
|
|
instructions: scopeBlock.instructions,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
return { kind: 'keep' };
|
|
}
|
|
}
|
|
|
|
function isPrimitiveBinaryOp(op) {
|
|
switch (op) {
|
|
case '+':
|
|
case '-':
|
|
case '/':
|
|
case '%':
|
|
case '*':
|
|
case '**':
|
|
case '&':
|
|
case '|':
|
|
case '>>':
|
|
case '<<':
|
|
case '^':
|
|
case '>':
|
|
case '<':
|
|
case '>=':
|
|
case '<=':
|
|
case '|>':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
function inferTypes(func) {
|
|
const unifier = new Unifier(func.env);
|
|
for (const e of generate(func)) {
|
|
unifier.unify(e.left, e.right);
|
|
}
|
|
apply(func, unifier);
|
|
}
|
|
function apply(func, unifier) {
|
|
for (const [_, block] of func.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
phi.place.identifier.type = unifier.get(phi.place.identifier.type);
|
|
}
|
|
for (const instr of block.instructions) {
|
|
for (const operand of eachInstructionLValue(instr)) {
|
|
operand.identifier.type = unifier.get(operand.identifier.type);
|
|
}
|
|
for (const place of eachInstructionOperand(instr)) {
|
|
place.identifier.type = unifier.get(place.identifier.type);
|
|
}
|
|
const { lvalue, value } = instr;
|
|
lvalue.identifier.type = unifier.get(lvalue.identifier.type);
|
|
if (value.kind === 'FunctionExpression' ||
|
|
value.kind === 'ObjectMethod') {
|
|
apply(value.loweredFunc.func, unifier);
|
|
}
|
|
}
|
|
}
|
|
const returns = func.returns.identifier;
|
|
returns.type = unifier.get(returns.type);
|
|
}
|
|
function equation(left, right) {
|
|
return {
|
|
left,
|
|
right,
|
|
};
|
|
}
|
|
function* generate(func) {
|
|
if (func.fnType === 'Component') {
|
|
const [props, ref] = func.params;
|
|
if (props && props.kind === 'Identifier') {
|
|
yield equation(props.identifier.type, {
|
|
kind: 'Object',
|
|
shapeId: BuiltInPropsId,
|
|
});
|
|
}
|
|
if (ref && ref.kind === 'Identifier') {
|
|
yield equation(ref.identifier.type, {
|
|
kind: 'Object',
|
|
shapeId: BuiltInUseRefId,
|
|
});
|
|
}
|
|
}
|
|
const names = new Map();
|
|
const returnTypes = [];
|
|
for (const [_, block] of func.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
yield equation(phi.place.identifier.type, {
|
|
kind: 'Phi',
|
|
operands: [...phi.operands.values()].map(id => id.identifier.type),
|
|
});
|
|
}
|
|
for (const instr of block.instructions) {
|
|
yield* generateInstructionTypes(func.env, names, instr);
|
|
}
|
|
const terminal = block.terminal;
|
|
if (terminal.kind === 'return') {
|
|
returnTypes.push(terminal.value.identifier.type);
|
|
}
|
|
}
|
|
if (returnTypes.length > 1) {
|
|
yield equation(func.returns.identifier.type, {
|
|
kind: 'Phi',
|
|
operands: returnTypes,
|
|
});
|
|
}
|
|
else if (returnTypes.length === 1) {
|
|
yield equation(func.returns.identifier.type, returnTypes[0]);
|
|
}
|
|
}
|
|
function setName(names, id, name) {
|
|
var _a;
|
|
if (((_a = name.name) === null || _a === void 0 ? void 0 : _a.kind) === 'named') {
|
|
names.set(id, name.name.value);
|
|
}
|
|
}
|
|
function getName(names, id) {
|
|
var _a;
|
|
return (_a = names.get(id)) !== null && _a !== void 0 ? _a : '';
|
|
}
|
|
function* generateInstructionTypes(env, names, instr) {
|
|
const { lvalue, value } = instr;
|
|
const left = lvalue.identifier.type;
|
|
switch (value.kind) {
|
|
case 'TemplateLiteral':
|
|
case 'JSXText':
|
|
case 'Primitive': {
|
|
yield equation(left, { kind: 'Primitive' });
|
|
break;
|
|
}
|
|
case 'UnaryExpression': {
|
|
yield equation(left, { kind: 'Primitive' });
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
setName(names, lvalue.identifier.id, value.place.identifier);
|
|
yield equation(left, value.place.identifier.type);
|
|
break;
|
|
}
|
|
case 'DeclareContext':
|
|
case 'LoadContext': {
|
|
break;
|
|
}
|
|
case 'StoreContext': {
|
|
if (value.lvalue.kind === InstructionKind.Const) {
|
|
yield equation(value.lvalue.place.identifier.type, value.value.identifier.type);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
yield equation(left, value.value.identifier.type);
|
|
yield equation(value.lvalue.place.identifier.type, value.value.identifier.type);
|
|
break;
|
|
}
|
|
case 'StoreGlobal': {
|
|
yield equation(left, value.value.identifier.type);
|
|
break;
|
|
}
|
|
case 'BinaryExpression': {
|
|
if (isPrimitiveBinaryOp(value.operator)) {
|
|
yield equation(value.left.identifier.type, { kind: 'Primitive' });
|
|
yield equation(value.right.identifier.type, { kind: 'Primitive' });
|
|
}
|
|
yield equation(left, { kind: 'Primitive' });
|
|
break;
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
yield equation(value.value.identifier.type, { kind: 'Primitive' });
|
|
yield equation(value.lvalue.identifier.type, { kind: 'Primitive' });
|
|
yield equation(left, { kind: 'Primitive' });
|
|
break;
|
|
}
|
|
case 'LoadGlobal': {
|
|
const globalType = env.getGlobalDeclaration(value.binding, value.loc);
|
|
if (globalType) {
|
|
yield equation(left, globalType);
|
|
}
|
|
break;
|
|
}
|
|
case 'CallExpression': {
|
|
const returnType = makeType();
|
|
let shapeId = null;
|
|
if (env.config.enableTreatSetIdentifiersAsStateSetters) {
|
|
const name = getName(names, value.callee.identifier.id);
|
|
if (name.startsWith('set')) {
|
|
shapeId = BuiltInSetStateId;
|
|
}
|
|
}
|
|
yield equation(value.callee.identifier.type, {
|
|
kind: 'Function',
|
|
shapeId,
|
|
return: returnType,
|
|
isConstructor: false,
|
|
});
|
|
yield equation(left, returnType);
|
|
break;
|
|
}
|
|
case 'TaggedTemplateExpression': {
|
|
const returnType = makeType();
|
|
yield equation(value.tag.identifier.type, {
|
|
kind: 'Function',
|
|
shapeId: null,
|
|
return: returnType,
|
|
isConstructor: false,
|
|
});
|
|
yield equation(left, returnType);
|
|
break;
|
|
}
|
|
case 'ObjectExpression': {
|
|
for (const property of value.properties) {
|
|
if (property.kind === 'ObjectProperty' &&
|
|
property.key.kind === 'computed') {
|
|
yield equation(property.key.name.identifier.type, {
|
|
kind: 'Primitive',
|
|
});
|
|
}
|
|
}
|
|
yield equation(left, { kind: 'Object', shapeId: BuiltInObjectId });
|
|
break;
|
|
}
|
|
case 'ArrayExpression': {
|
|
yield equation(left, { kind: 'Object', shapeId: BuiltInArrayId });
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
yield equation(left, {
|
|
kind: 'Property',
|
|
objectType: value.object.identifier.type,
|
|
objectName: getName(names, value.object.identifier.id),
|
|
propertyName: {
|
|
kind: 'literal',
|
|
value: value.property,
|
|
},
|
|
});
|
|
break;
|
|
}
|
|
case 'ComputedLoad': {
|
|
yield equation(left, {
|
|
kind: 'Property',
|
|
objectType: value.object.identifier.type,
|
|
objectName: getName(names, value.object.identifier.id),
|
|
propertyName: {
|
|
kind: 'computed',
|
|
value: value.property.identifier.type,
|
|
},
|
|
});
|
|
break;
|
|
}
|
|
case 'MethodCall': {
|
|
const returnType = makeType();
|
|
yield equation(value.property.identifier.type, {
|
|
kind: 'Function',
|
|
return: returnType,
|
|
shapeId: null,
|
|
isConstructor: false,
|
|
});
|
|
yield equation(left, returnType);
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
const pattern = value.lvalue.pattern;
|
|
if (pattern.kind === 'ArrayPattern') {
|
|
for (let i = 0; i < pattern.items.length; i++) {
|
|
const item = pattern.items[i];
|
|
if (item.kind === 'Identifier') {
|
|
const propertyName = String(i);
|
|
yield equation(item.identifier.type, {
|
|
kind: 'Property',
|
|
objectType: value.value.identifier.type,
|
|
objectName: getName(names, value.value.identifier.id),
|
|
propertyName: {
|
|
kind: 'literal',
|
|
value: makePropertyLiteral(propertyName),
|
|
},
|
|
});
|
|
}
|
|
else if (item.kind === 'Spread') {
|
|
yield equation(item.place.identifier.type, {
|
|
kind: 'Object',
|
|
shapeId: BuiltInArrayId,
|
|
});
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (const property of pattern.properties) {
|
|
if (property.kind === 'ObjectProperty') {
|
|
if (property.key.kind === 'identifier' ||
|
|
property.key.kind === 'string') {
|
|
yield equation(property.place.identifier.type, {
|
|
kind: 'Property',
|
|
objectType: value.value.identifier.type,
|
|
objectName: getName(names, value.value.identifier.id),
|
|
propertyName: {
|
|
kind: 'literal',
|
|
value: makePropertyLiteral(property.key.name),
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'TypeCastExpression': {
|
|
yield equation(left, value.value.identifier.type);
|
|
break;
|
|
}
|
|
case 'PropertyDelete':
|
|
case 'ComputedDelete': {
|
|
yield equation(left, { kind: 'Primitive' });
|
|
break;
|
|
}
|
|
case 'FunctionExpression': {
|
|
yield* generate(value.loweredFunc.func);
|
|
yield equation(left, {
|
|
kind: 'Function',
|
|
shapeId: BuiltInFunctionId,
|
|
return: value.loweredFunc.func.returns.identifier.type,
|
|
isConstructor: false,
|
|
});
|
|
break;
|
|
}
|
|
case 'NextPropertyOf': {
|
|
yield equation(left, { kind: 'Primitive' });
|
|
break;
|
|
}
|
|
case 'ObjectMethod': {
|
|
yield* generate(value.loweredFunc.func);
|
|
yield equation(left, { kind: 'ObjectMethod' });
|
|
break;
|
|
}
|
|
case 'JsxExpression':
|
|
case 'JsxFragment': {
|
|
if (env.config.enableTreatRefLikeIdentifiersAsRefs) {
|
|
if (value.kind === 'JsxExpression') {
|
|
for (const prop of value.props) {
|
|
if (prop.kind === 'JsxAttribute' && prop.name === 'ref') {
|
|
yield equation(prop.place.identifier.type, {
|
|
kind: 'Object',
|
|
shapeId: BuiltInUseRefId,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
yield equation(left, { kind: 'Object', shapeId: BuiltInJsxId });
|
|
break;
|
|
}
|
|
case 'NewExpression': {
|
|
const returnType = makeType();
|
|
yield equation(value.callee.identifier.type, {
|
|
kind: 'Function',
|
|
return: returnType,
|
|
shapeId: null,
|
|
isConstructor: true,
|
|
});
|
|
yield equation(left, returnType);
|
|
break;
|
|
}
|
|
case 'PropertyStore': {
|
|
yield equation(makeType(), {
|
|
kind: 'Property',
|
|
objectType: value.object.identifier.type,
|
|
objectName: getName(names, value.object.identifier.id),
|
|
propertyName: {
|
|
kind: 'literal',
|
|
value: value.property,
|
|
},
|
|
});
|
|
break;
|
|
}
|
|
case 'DeclareLocal':
|
|
case 'RegExpLiteral':
|
|
case 'MetaProperty':
|
|
case 'ComputedStore':
|
|
case 'Await':
|
|
case 'GetIterator':
|
|
case 'IteratorNext':
|
|
case 'UnsupportedNode':
|
|
case 'Debugger':
|
|
case 'FinishMemoize':
|
|
case 'StartMemoize': {
|
|
break;
|
|
}
|
|
default:
|
|
assertExhaustive$1(value, `Unhandled instruction value kind: ${value.kind}`);
|
|
}
|
|
}
|
|
class Unifier {
|
|
constructor(env) {
|
|
this.substitutions = new Map();
|
|
this.env = env;
|
|
}
|
|
unify(tA, tB) {
|
|
if (tB.kind === 'Property') {
|
|
if (this.env.config.enableTreatRefLikeIdentifiersAsRefs &&
|
|
isRefLikeName(tB)) {
|
|
this.unify(tB.objectType, {
|
|
kind: 'Object',
|
|
shapeId: BuiltInUseRefId,
|
|
});
|
|
this.unify(tA, {
|
|
kind: 'Object',
|
|
shapeId: BuiltInRefValueId,
|
|
});
|
|
return;
|
|
}
|
|
const objectType = this.get(tB.objectType);
|
|
const propertyType = tB.propertyName.kind === 'literal'
|
|
? this.env.getPropertyType(objectType, tB.propertyName.value)
|
|
: this.env.getFallthroughPropertyType(objectType, tB.propertyName.value);
|
|
if (propertyType !== null) {
|
|
this.unify(tA, propertyType);
|
|
}
|
|
return;
|
|
}
|
|
if (typeEquals(tA, tB)) {
|
|
return;
|
|
}
|
|
if (tA.kind === 'Type') {
|
|
this.bindVariableTo(tA, tB);
|
|
return;
|
|
}
|
|
if (tB.kind === 'Type') {
|
|
this.bindVariableTo(tB, tA);
|
|
return;
|
|
}
|
|
if (tB.kind === 'Function' &&
|
|
tA.kind === 'Function' &&
|
|
tA.isConstructor === tB.isConstructor) {
|
|
this.unify(tA.return, tB.return);
|
|
return;
|
|
}
|
|
}
|
|
bindVariableTo(v, type) {
|
|
if (type.kind === 'Poly') {
|
|
return;
|
|
}
|
|
if (this.substitutions.has(v.id)) {
|
|
this.unify(this.substitutions.get(v.id), type);
|
|
return;
|
|
}
|
|
if (type.kind === 'Type' && this.substitutions.has(type.id)) {
|
|
this.unify(v, this.substitutions.get(type.id));
|
|
return;
|
|
}
|
|
if (type.kind === 'Phi') {
|
|
CompilerError.invariant(type.operands.length > 0, {
|
|
reason: 'there should be at least one operand',
|
|
loc: GeneratedSource,
|
|
});
|
|
let candidateType = null;
|
|
for (const operand of type.operands) {
|
|
const resolved = this.get(operand);
|
|
if (candidateType === null) {
|
|
candidateType = resolved;
|
|
}
|
|
else if (!typeEquals(resolved, candidateType)) {
|
|
const unionType = tryUnionTypes(resolved, candidateType);
|
|
if (unionType === null) {
|
|
candidateType = null;
|
|
break;
|
|
}
|
|
else {
|
|
candidateType = unionType;
|
|
}
|
|
}
|
|
}
|
|
if (candidateType !== null) {
|
|
this.unify(v, candidateType);
|
|
return;
|
|
}
|
|
}
|
|
if (this.occursCheck(v, type)) {
|
|
const resolvedType = this.tryResolveType(v, type);
|
|
if (resolvedType !== null) {
|
|
this.substitutions.set(v.id, resolvedType);
|
|
return;
|
|
}
|
|
throw new Error('cycle detected');
|
|
}
|
|
this.substitutions.set(v.id, type);
|
|
}
|
|
tryResolveType(v, type) {
|
|
switch (type.kind) {
|
|
case 'Phi': {
|
|
const operands = [];
|
|
for (const operand of type.operands) {
|
|
if (operand.kind === 'Type' && operand.id === v.id) {
|
|
continue;
|
|
}
|
|
const resolved = this.tryResolveType(v, operand);
|
|
if (resolved === null) {
|
|
return null;
|
|
}
|
|
operands.push(resolved);
|
|
}
|
|
return { kind: 'Phi', operands };
|
|
}
|
|
case 'Type': {
|
|
const substitution = this.get(type);
|
|
if (substitution !== type) {
|
|
const resolved = this.tryResolveType(v, substitution);
|
|
if (resolved !== null) {
|
|
this.substitutions.set(type.id, resolved);
|
|
}
|
|
return resolved;
|
|
}
|
|
return type;
|
|
}
|
|
case 'Property': {
|
|
const objectType = this.tryResolveType(v, this.get(type.objectType));
|
|
if (objectType === null) {
|
|
return null;
|
|
}
|
|
return {
|
|
kind: 'Property',
|
|
objectName: type.objectName,
|
|
objectType,
|
|
propertyName: type.propertyName,
|
|
};
|
|
}
|
|
case 'Function': {
|
|
const returnType = this.tryResolveType(v, this.get(type.return));
|
|
if (returnType === null) {
|
|
return null;
|
|
}
|
|
return {
|
|
kind: 'Function',
|
|
return: returnType,
|
|
shapeId: type.shapeId,
|
|
isConstructor: type.isConstructor,
|
|
};
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'Object':
|
|
case 'Primitive':
|
|
case 'Poly': {
|
|
return type;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(type, `Unexpected type kind '${type.kind}'`);
|
|
}
|
|
}
|
|
}
|
|
occursCheck(v, type) {
|
|
if (typeEquals(v, type))
|
|
return true;
|
|
if (type.kind === 'Type' && this.substitutions.has(type.id)) {
|
|
return this.occursCheck(v, this.substitutions.get(type.id));
|
|
}
|
|
if (type.kind === 'Phi') {
|
|
return type.operands.some(o => this.occursCheck(v, o));
|
|
}
|
|
if (type.kind === 'Function') {
|
|
return this.occursCheck(v, type.return);
|
|
}
|
|
return false;
|
|
}
|
|
get(type) {
|
|
if (type.kind === 'Type') {
|
|
if (this.substitutions.has(type.id)) {
|
|
return this.get(this.substitutions.get(type.id));
|
|
}
|
|
}
|
|
if (type.kind === 'Phi') {
|
|
return { kind: 'Phi', operands: type.operands.map(o => this.get(o)) };
|
|
}
|
|
if (type.kind === 'Function') {
|
|
return {
|
|
kind: 'Function',
|
|
isConstructor: type.isConstructor,
|
|
shapeId: type.shapeId,
|
|
return: this.get(type.return),
|
|
};
|
|
}
|
|
return type;
|
|
}
|
|
}
|
|
const RefLikeNameRE = /^(?:[a-zA-Z$_][a-zA-Z$_0-9]*)Ref$|^ref$/;
|
|
function isRefLikeName(t) {
|
|
return (t.propertyName.kind === 'literal' &&
|
|
RefLikeNameRE.test(t.objectName) &&
|
|
t.propertyName.value === 'current');
|
|
}
|
|
function tryUnionTypes(ty1, ty2) {
|
|
let readonlyType;
|
|
let otherType;
|
|
if (ty1.kind === 'Object' && ty1.shapeId === BuiltInMixedReadonlyId) {
|
|
readonlyType = ty1;
|
|
otherType = ty2;
|
|
}
|
|
else if (ty2.kind === 'Object' && ty2.shapeId === BuiltInMixedReadonlyId) {
|
|
readonlyType = ty2;
|
|
otherType = ty1;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
if (otherType.kind === 'Primitive') {
|
|
return readonlyType;
|
|
}
|
|
else if (otherType.kind === 'Object' &&
|
|
otherType.shapeId === BuiltInArrayId) {
|
|
return otherType;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function validateContextVariableLValues(fn) {
|
|
const identifierKinds = new Map();
|
|
validateContextVariableLValuesImpl(fn, identifierKinds, fn.env);
|
|
}
|
|
function validateContextVariableLValuesImpl(fn, identifierKinds, env) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
const { value } = instr;
|
|
switch (value.kind) {
|
|
case 'DeclareContext':
|
|
case 'StoreContext': {
|
|
visit(identifierKinds, value.lvalue.place, 'context', env);
|
|
break;
|
|
}
|
|
case 'LoadContext': {
|
|
visit(identifierKinds, value.place, 'context', env);
|
|
break;
|
|
}
|
|
case 'StoreLocal':
|
|
case 'DeclareLocal': {
|
|
visit(identifierKinds, value.lvalue.place, 'local', env);
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
visit(identifierKinds, value.place, 'local', env);
|
|
break;
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
visit(identifierKinds, value.lvalue, 'local', env);
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
for (const lvalue of eachPatternOperand(value.lvalue.pattern)) {
|
|
visit(identifierKinds, lvalue, 'destructure', env);
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
validateContextVariableLValuesImpl(value.loweredFunc.func, identifierKinds, env);
|
|
break;
|
|
}
|
|
default: {
|
|
for (const _ of eachInstructionValueLValue(value)) {
|
|
fn.env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'ValidateContextVariableLValues: unhandled instruction variant',
|
|
description: `Handle '${value.kind} lvalues`,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: value.loc,
|
|
message: null,
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function visit(identifiers, place, kind, env) {
|
|
const prev = identifiers.get(place.identifier.id);
|
|
if (prev !== undefined) {
|
|
const wasContext = prev.kind === 'context';
|
|
const isContext = kind === 'context';
|
|
if (wasContext !== isContext) {
|
|
if (prev.kind === 'destructure' || kind === 'destructure') {
|
|
env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Todo,
|
|
reason: `Support destructuring of context variables`,
|
|
description: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: kind === 'destructure' ? place.loc : prev.place.loc,
|
|
message: null,
|
|
}));
|
|
return;
|
|
}
|
|
CompilerError.invariant(false, {
|
|
reason: 'Expected all references to a variable to be consistently local or context references',
|
|
description: `Identifier ${printPlace(place)} is referenced as a ${kind} variable, but was previously referenced as a ${prev.kind} variable`,
|
|
message: `this is ${prev.kind}`,
|
|
loc: place.loc,
|
|
});
|
|
}
|
|
}
|
|
identifiers.set(place.identifier.id, { place, kind });
|
|
}
|
|
|
|
function computeUnconditionalBlocks(fn) {
|
|
const unconditionalBlocks = new Set();
|
|
const dominators = computePostDominatorTree(fn, {
|
|
includeThrowsAsExitNode: false,
|
|
});
|
|
const exit = dominators.exit;
|
|
let current = fn.body.entry;
|
|
while (current !== null && current !== exit) {
|
|
CompilerError.invariant(!unconditionalBlocks.has(current), {
|
|
reason: 'Internal error: non-terminating loop in ComputeUnconditionalBlocks',
|
|
loc: GeneratedSource,
|
|
});
|
|
unconditionalBlocks.add(current);
|
|
current = dominators.get(current);
|
|
}
|
|
return unconditionalBlocks;
|
|
}
|
|
|
|
var Kind;
|
|
(function (Kind) {
|
|
Kind["Error"] = "Error";
|
|
Kind["KnownHook"] = "KnownHook";
|
|
Kind["PotentialHook"] = "PotentialHook";
|
|
Kind["Global"] = "Global";
|
|
Kind["Local"] = "Local";
|
|
})(Kind || (Kind = {}));
|
|
function joinKinds(a, b) {
|
|
if (a === Kind.Error || b === Kind.Error) {
|
|
return Kind.Error;
|
|
}
|
|
else if (a === Kind.KnownHook || b === Kind.KnownHook) {
|
|
return Kind.KnownHook;
|
|
}
|
|
else if (a === Kind.PotentialHook || b === Kind.PotentialHook) {
|
|
return Kind.PotentialHook;
|
|
}
|
|
else if (a === Kind.Global || b === Kind.Global) {
|
|
return Kind.Global;
|
|
}
|
|
else {
|
|
return Kind.Local;
|
|
}
|
|
}
|
|
function validateHooksUsage(fn) {
|
|
const unconditionalBlocks = computeUnconditionalBlocks(fn);
|
|
const errorsByPlace = new Map();
|
|
function trackError(loc, errorDetail) {
|
|
if (typeof loc === 'symbol') {
|
|
fn.env.recordError(errorDetail);
|
|
}
|
|
else {
|
|
errorsByPlace.set(loc, errorDetail);
|
|
}
|
|
}
|
|
function recordConditionalHookError(place) {
|
|
setKind(place, Kind.Error);
|
|
const reason = 'Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning)';
|
|
const previousError = typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
|
if (previousError === undefined || previousError.reason !== reason) {
|
|
trackError(place.loc, new CompilerErrorDetail({
|
|
category: ErrorCategory.Hooks,
|
|
description: null,
|
|
reason,
|
|
loc: place.loc,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
}
|
|
function recordInvalidHookUsageError(place) {
|
|
const previousError = typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
|
if (previousError === undefined) {
|
|
trackError(place.loc, new CompilerErrorDetail({
|
|
category: ErrorCategory.Hooks,
|
|
description: null,
|
|
reason: 'Hooks may not be referenced as normal values, they must be called. See https://react.dev/reference/rules/react-calls-components-and-hooks#never-pass-around-hooks-as-regular-values',
|
|
loc: place.loc,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
}
|
|
function recordDynamicHookUsageError(place) {
|
|
const previousError = typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
|
if (previousError === undefined) {
|
|
trackError(place.loc, new CompilerErrorDetail({
|
|
category: ErrorCategory.Hooks,
|
|
description: null,
|
|
reason: 'Hooks must be the same function on every render, but this value may change over time to a different function. See https://react.dev/reference/rules/react-calls-components-and-hooks#dont-dynamically-use-hooks',
|
|
loc: place.loc,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
}
|
|
const valueKinds = new Map();
|
|
function getKindForPlace(place) {
|
|
const knownKind = valueKinds.get(place.identifier.id);
|
|
if (place.identifier.name !== null &&
|
|
isHookName$2(place.identifier.name.value)) {
|
|
return joinKinds(knownKind !== null && knownKind !== void 0 ? knownKind : Kind.Local, Kind.PotentialHook);
|
|
}
|
|
else {
|
|
return knownKind !== null && knownKind !== void 0 ? knownKind : Kind.Local;
|
|
}
|
|
}
|
|
function visitPlace(place) {
|
|
const kind = valueKinds.get(place.identifier.id);
|
|
if (kind === Kind.KnownHook) {
|
|
recordInvalidHookUsageError(place);
|
|
}
|
|
}
|
|
function setKind(place, kind) {
|
|
valueKinds.set(place.identifier.id, kind);
|
|
}
|
|
for (const param of fn.params) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
const kind = getKindForPlace(place);
|
|
setKind(place, kind);
|
|
}
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const phi of block.phis) {
|
|
let kind = phi.place.identifier.name !== null &&
|
|
isHookName$2(phi.place.identifier.name.value)
|
|
? Kind.PotentialHook
|
|
: Kind.Local;
|
|
for (const [, operand] of phi.operands) {
|
|
const operandKind = valueKinds.get(operand.identifier.id);
|
|
if (operandKind !== undefined) {
|
|
kind = joinKinds(kind, operandKind);
|
|
}
|
|
}
|
|
valueKinds.set(phi.place.identifier.id, kind);
|
|
}
|
|
for (const instr of block.instructions) {
|
|
switch (instr.value.kind) {
|
|
case 'LoadGlobal': {
|
|
if (getHookKind(fn.env, instr.lvalue.identifier) != null) {
|
|
setKind(instr.lvalue, Kind.KnownHook);
|
|
}
|
|
else {
|
|
setKind(instr.lvalue, Kind.Global);
|
|
}
|
|
break;
|
|
}
|
|
case 'LoadContext':
|
|
case 'LoadLocal': {
|
|
visitPlace(instr.value.place);
|
|
const kind = getKindForPlace(instr.value.place);
|
|
setKind(instr.lvalue, kind);
|
|
break;
|
|
}
|
|
case 'StoreLocal':
|
|
case 'StoreContext': {
|
|
visitPlace(instr.value.value);
|
|
const kind = joinKinds(getKindForPlace(instr.value.value), getKindForPlace(instr.value.lvalue.place));
|
|
setKind(instr.value.lvalue.place, kind);
|
|
setKind(instr.lvalue, kind);
|
|
break;
|
|
}
|
|
case 'ComputedLoad': {
|
|
visitPlace(instr.value.object);
|
|
const kind = getKindForPlace(instr.value.object);
|
|
setKind(instr.lvalue, joinKinds(getKindForPlace(instr.lvalue), kind));
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
const objectKind = getKindForPlace(instr.value.object);
|
|
const isHookProperty = typeof instr.value.property === 'string' &&
|
|
isHookName$2(instr.value.property);
|
|
let kind;
|
|
switch (objectKind) {
|
|
case Kind.Error: {
|
|
kind = Kind.Error;
|
|
break;
|
|
}
|
|
case Kind.KnownHook: {
|
|
kind = isHookProperty ? Kind.KnownHook : Kind.Local;
|
|
break;
|
|
}
|
|
case Kind.PotentialHook: {
|
|
kind = Kind.PotentialHook;
|
|
break;
|
|
}
|
|
case Kind.Global: {
|
|
kind = isHookProperty ? Kind.KnownHook : Kind.Global;
|
|
break;
|
|
}
|
|
case Kind.Local: {
|
|
kind = isHookProperty ? Kind.PotentialHook : Kind.Local;
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(objectKind, `Unexpected kind \`${objectKind}\``);
|
|
}
|
|
}
|
|
setKind(instr.lvalue, kind);
|
|
break;
|
|
}
|
|
case 'CallExpression': {
|
|
const calleeKind = getKindForPlace(instr.value.callee);
|
|
const isHookCallee = calleeKind === Kind.KnownHook || calleeKind === Kind.PotentialHook;
|
|
if (isHookCallee && !unconditionalBlocks.has(block.id)) {
|
|
recordConditionalHookError(instr.value.callee);
|
|
}
|
|
else if (calleeKind === Kind.PotentialHook) {
|
|
recordDynamicHookUsageError(instr.value.callee);
|
|
}
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
if (operand === instr.value.callee) {
|
|
continue;
|
|
}
|
|
visitPlace(operand);
|
|
}
|
|
break;
|
|
}
|
|
case 'MethodCall': {
|
|
const calleeKind = getKindForPlace(instr.value.property);
|
|
const isHookCallee = calleeKind === Kind.KnownHook || calleeKind === Kind.PotentialHook;
|
|
if (isHookCallee && !unconditionalBlocks.has(block.id)) {
|
|
recordConditionalHookError(instr.value.property);
|
|
}
|
|
else if (calleeKind === Kind.PotentialHook) {
|
|
recordDynamicHookUsageError(instr.value.property);
|
|
}
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
if (operand === instr.value.property) {
|
|
continue;
|
|
}
|
|
visitPlace(operand);
|
|
}
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
visitPlace(instr.value.value);
|
|
const objectKind = getKindForPlace(instr.value.value);
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
const isHookProperty = lvalue.identifier.name !== null &&
|
|
isHookName$2(lvalue.identifier.name.value);
|
|
let kind;
|
|
switch (objectKind) {
|
|
case Kind.Error: {
|
|
kind = Kind.Error;
|
|
break;
|
|
}
|
|
case Kind.KnownHook: {
|
|
kind = Kind.KnownHook;
|
|
break;
|
|
}
|
|
case Kind.PotentialHook: {
|
|
kind = Kind.PotentialHook;
|
|
break;
|
|
}
|
|
case Kind.Global: {
|
|
kind = isHookProperty ? Kind.KnownHook : Kind.Global;
|
|
break;
|
|
}
|
|
case Kind.Local: {
|
|
kind = isHookProperty ? Kind.PotentialHook : Kind.Local;
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(objectKind, `Unexpected kind \`${objectKind}\``);
|
|
}
|
|
}
|
|
setKind(lvalue, kind);
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
visitFunctionExpression(fn.env, instr.value.loweredFunc.func);
|
|
break;
|
|
}
|
|
default: {
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
visitPlace(operand);
|
|
}
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
const kind = getKindForPlace(lvalue);
|
|
setKind(lvalue, kind);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
visitPlace(operand);
|
|
}
|
|
}
|
|
for (const [, error] of errorsByPlace) {
|
|
fn.env.recordError(error);
|
|
}
|
|
}
|
|
function visitFunctionExpression(env, fn) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
switch (instr.value.kind) {
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
visitFunctionExpression(env, instr.value.loweredFunc.func);
|
|
break;
|
|
}
|
|
case 'MethodCall':
|
|
case 'CallExpression': {
|
|
const callee = instr.value.kind === 'CallExpression'
|
|
? instr.value.callee
|
|
: instr.value.property;
|
|
const hookKind = getHookKind(fn.env, callee.identifier);
|
|
if (hookKind != null) {
|
|
env.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.Hooks,
|
|
reason: 'Hooks must be called at the top level in the body of a function component or custom hook, and may not be called within function expressions. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning)',
|
|
loc: callee.loc,
|
|
description: `Cannot call ${hookKind === 'Custom' ? 'hook' : hookKind} within a function expression`,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function validateNoCapitalizedCalls(fn) {
|
|
var _a;
|
|
const envConfig = fn.env.config;
|
|
const ALLOW_LIST = new Set([
|
|
...DEFAULT_GLOBALS.keys(),
|
|
...((_a = envConfig.validateNoCapitalizedCalls) !== null && _a !== void 0 ? _a : []),
|
|
]);
|
|
const isAllowed = (name) => {
|
|
return ALLOW_LIST.has(name);
|
|
};
|
|
const capitalLoadGlobals = new Map();
|
|
const capitalizedProperties = new Map();
|
|
const reason = 'Capitalized functions are reserved for components, which must be invoked with JSX. If this is a component, render it with JSX. Otherwise, ensure that it has no hook calls and rename it to begin with a lowercase letter. Alternatively, if you know for a fact that this function is not a component, you can allowlist it via the compiler config';
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const { lvalue, value } of block.instructions) {
|
|
switch (value.kind) {
|
|
case 'LoadGlobal': {
|
|
if (value.binding.name != '' &&
|
|
/^[A-Z]/.test(value.binding.name) &&
|
|
!(value.binding.name.toUpperCase() === value.binding.name) &&
|
|
!isAllowed(value.binding.name)) {
|
|
capitalLoadGlobals.set(lvalue.identifier.id, value.binding.name);
|
|
}
|
|
break;
|
|
}
|
|
case 'CallExpression': {
|
|
const calleeIdentifier = value.callee.identifier.id;
|
|
const calleeName = capitalLoadGlobals.get(calleeIdentifier);
|
|
if (calleeName != null) {
|
|
fn.env.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.CapitalizedCalls,
|
|
reason,
|
|
description: `${calleeName} may be a component`,
|
|
loc: value.loc,
|
|
suggestions: null,
|
|
}));
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
if (typeof value.property === 'string' &&
|
|
/^[A-Z]/.test(value.property)) {
|
|
capitalizedProperties.set(lvalue.identifier.id, value.property);
|
|
}
|
|
break;
|
|
}
|
|
case 'MethodCall': {
|
|
const propertyIdentifier = value.property.identifier.id;
|
|
const propertyName = capitalizedProperties.get(propertyIdentifier);
|
|
if (propertyName != null) {
|
|
fn.env.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.CapitalizedCalls,
|
|
reason,
|
|
description: `${propertyName} may be a component`,
|
|
loc: value.loc,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var _Env_changed, _Env_data, _Env_temporaries;
|
|
function makeRefId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected identifier id to be a non-negative integer',
|
|
loc: GeneratedSource,
|
|
});
|
|
return id;
|
|
}
|
|
let _refId = 0;
|
|
function nextRefId() {
|
|
return makeRefId(_refId++);
|
|
}
|
|
class Env {
|
|
constructor() {
|
|
_Env_changed.set(this, false);
|
|
_Env_data.set(this, new Map());
|
|
_Env_temporaries.set(this, new Map());
|
|
}
|
|
lookup(place) {
|
|
var _a;
|
|
return (_a = __classPrivateFieldGet(this, _Env_temporaries, "f").get(place.identifier.id)) !== null && _a !== void 0 ? _a : place;
|
|
}
|
|
define(place, value) {
|
|
__classPrivateFieldGet(this, _Env_temporaries, "f").set(place.identifier.id, value);
|
|
}
|
|
resetChanged() {
|
|
__classPrivateFieldSet(this, _Env_changed, false, "f");
|
|
}
|
|
hasChanged() {
|
|
return __classPrivateFieldGet(this, _Env_changed, "f");
|
|
}
|
|
get(key) {
|
|
var _a, _b;
|
|
const operandId = (_b = (_a = __classPrivateFieldGet(this, _Env_temporaries, "f").get(key)) === null || _a === void 0 ? void 0 : _a.identifier.id) !== null && _b !== void 0 ? _b : key;
|
|
return __classPrivateFieldGet(this, _Env_data, "f").get(operandId);
|
|
}
|
|
set(key, value) {
|
|
var _a, _b;
|
|
const operandId = (_b = (_a = __classPrivateFieldGet(this, _Env_temporaries, "f").get(key)) === null || _a === void 0 ? void 0 : _a.identifier.id) !== null && _b !== void 0 ? _b : key;
|
|
const cur = __classPrivateFieldGet(this, _Env_data, "f").get(operandId);
|
|
const widenedValue = joinRefAccessTypes(value, cur !== null && cur !== void 0 ? cur : { kind: 'None' });
|
|
if (!(cur == null && widenedValue.kind === 'None') &&
|
|
(cur == null || !tyEqual(cur, widenedValue))) {
|
|
__classPrivateFieldSet(this, _Env_changed, true, "f");
|
|
}
|
|
__classPrivateFieldGet(this, _Env_data, "f").set(operandId, widenedValue);
|
|
return this;
|
|
}
|
|
}
|
|
_Env_changed = new WeakMap(), _Env_data = new WeakMap(), _Env_temporaries = new WeakMap();
|
|
function validateNoRefAccessInRender(fn) {
|
|
const env = new Env();
|
|
collectTemporariesSidemap$1(fn, env);
|
|
const errors = new CompilerError();
|
|
validateNoRefAccessInRenderImpl(fn, env, errors);
|
|
for (const detail of errors.details) {
|
|
fn.env.recordError(detail);
|
|
}
|
|
}
|
|
function collectTemporariesSidemap$1(fn, env) {
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
switch (value.kind) {
|
|
case 'LoadLocal': {
|
|
const temp = env.lookup(value.place);
|
|
if (temp != null) {
|
|
env.define(lvalue, temp);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
const temp = env.lookup(value.value);
|
|
if (temp != null) {
|
|
env.define(lvalue, temp);
|
|
env.define(value.lvalue.place, temp);
|
|
}
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
if (isUseRefType(value.object.identifier) &&
|
|
value.property === 'current') {
|
|
continue;
|
|
}
|
|
const temp = env.lookup(value.object);
|
|
if (temp != null) {
|
|
env.define(lvalue, temp);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function refTypeOfType(place) {
|
|
if (isRefValueType(place.identifier)) {
|
|
return { kind: 'RefValue' };
|
|
}
|
|
else if (isUseRefType(place.identifier)) {
|
|
return { kind: 'Ref', refId: nextRefId() };
|
|
}
|
|
else {
|
|
return { kind: 'None' };
|
|
}
|
|
}
|
|
function tyEqual(a, b) {
|
|
if (a.kind !== b.kind) {
|
|
return false;
|
|
}
|
|
switch (a.kind) {
|
|
case 'None':
|
|
return true;
|
|
case 'Ref':
|
|
return true;
|
|
case 'Nullable':
|
|
return true;
|
|
case 'Guard':
|
|
CompilerError.invariant(b.kind === 'Guard', {
|
|
reason: 'Expected ref value',
|
|
loc: GeneratedSource,
|
|
});
|
|
return a.refId === b.refId;
|
|
case 'RefValue':
|
|
CompilerError.invariant(b.kind === 'RefValue', {
|
|
reason: 'Expected ref value',
|
|
loc: GeneratedSource,
|
|
});
|
|
return a.loc == b.loc;
|
|
case 'Structure': {
|
|
CompilerError.invariant(b.kind === 'Structure', {
|
|
reason: 'Expected structure',
|
|
loc: GeneratedSource,
|
|
});
|
|
const fnTypesEqual = (a.fn === null && b.fn === null) ||
|
|
(a.fn !== null &&
|
|
b.fn !== null &&
|
|
a.fn.readRefEffect === b.fn.readRefEffect &&
|
|
tyEqual(a.fn.returnType, b.fn.returnType));
|
|
return (fnTypesEqual &&
|
|
(a.value === b.value ||
|
|
(a.value !== null && b.value !== null && tyEqual(a.value, b.value))));
|
|
}
|
|
}
|
|
}
|
|
function joinRefAccessTypes(...types) {
|
|
function joinRefAccessRefTypes(a, b) {
|
|
if (a.kind === 'RefValue') {
|
|
if (b.kind === 'RefValue' && a.refId === b.refId) {
|
|
return a;
|
|
}
|
|
return { kind: 'RefValue' };
|
|
}
|
|
else if (b.kind === 'RefValue') {
|
|
return b;
|
|
}
|
|
else if (a.kind === 'Ref' || b.kind === 'Ref') {
|
|
if (a.kind === 'Ref' && b.kind === 'Ref' && a.refId === b.refId) {
|
|
return a;
|
|
}
|
|
return { kind: 'Ref', refId: nextRefId() };
|
|
}
|
|
else {
|
|
CompilerError.invariant(a.kind === 'Structure' && b.kind === 'Structure', {
|
|
reason: 'Expected structure',
|
|
loc: GeneratedSource,
|
|
});
|
|
const fn = a.fn === null
|
|
? b.fn
|
|
: b.fn === null
|
|
? a.fn
|
|
: {
|
|
readRefEffect: a.fn.readRefEffect || b.fn.readRefEffect,
|
|
returnType: joinRefAccessTypes(a.fn.returnType, b.fn.returnType),
|
|
};
|
|
const value = a.value === null
|
|
? b.value
|
|
: b.value === null
|
|
? a.value
|
|
: joinRefAccessRefTypes(a.value, b.value);
|
|
return {
|
|
kind: 'Structure',
|
|
fn,
|
|
value,
|
|
};
|
|
}
|
|
}
|
|
return types.reduce((a, b) => {
|
|
if (a.kind === 'None') {
|
|
return b;
|
|
}
|
|
else if (b.kind === 'None') {
|
|
return a;
|
|
}
|
|
else if (a.kind === 'Guard') {
|
|
if (b.kind === 'Guard' && a.refId === b.refId) {
|
|
return a;
|
|
}
|
|
else if (b.kind === 'Nullable' || b.kind === 'Guard') {
|
|
return { kind: 'None' };
|
|
}
|
|
else {
|
|
return b;
|
|
}
|
|
}
|
|
else if (b.kind === 'Guard') {
|
|
if (a.kind === 'Nullable') {
|
|
return { kind: 'None' };
|
|
}
|
|
else {
|
|
return b;
|
|
}
|
|
}
|
|
else if (a.kind === 'Nullable') {
|
|
return b;
|
|
}
|
|
else if (b.kind === 'Nullable') {
|
|
return a;
|
|
}
|
|
else {
|
|
return joinRefAccessRefTypes(a, b);
|
|
}
|
|
}, { kind: 'None' });
|
|
}
|
|
function validateNoRefAccessInRenderImpl(fn, env, errors) {
|
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
let returnValues = [];
|
|
let place;
|
|
for (const param of fn.params) {
|
|
if (param.kind === 'Identifier') {
|
|
place = param;
|
|
}
|
|
else {
|
|
place = param.place;
|
|
}
|
|
const type = refTypeOfType(place);
|
|
env.set(place.identifier.id, type);
|
|
}
|
|
const interpolatedAsJsx = new Set();
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
const { value } = instr;
|
|
if (value.kind === 'JsxExpression' || value.kind === 'JsxFragment') {
|
|
if (value.children != null) {
|
|
for (const child of value.children) {
|
|
interpolatedAsJsx.add(child.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (let i = 0; (i == 0 || env.hasChanged()) && i < 10; i++) {
|
|
env.resetChanged();
|
|
returnValues = [];
|
|
const safeBlocks = [];
|
|
for (const [, block] of fn.body.blocks) {
|
|
retainWhere(safeBlocks, entry => entry.block !== block.id);
|
|
for (const phi of block.phis) {
|
|
env.set(phi.place.identifier.id, joinRefAccessTypes(...Array(...phi.operands.values()).map(operand => { var _a; return (_a = env.get(operand.identifier.id)) !== null && _a !== void 0 ? _a : { kind: 'None' }; })));
|
|
}
|
|
for (const instr of block.instructions) {
|
|
switch (instr.value.kind) {
|
|
case 'JsxExpression':
|
|
case 'JsxFragment': {
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
validateNoDirectRefValueAccess(errors, operand, env);
|
|
}
|
|
break;
|
|
}
|
|
case 'ComputedLoad':
|
|
case 'PropertyLoad': {
|
|
if (instr.value.kind === 'ComputedLoad') {
|
|
validateNoDirectRefValueAccess(errors, instr.value.property, env);
|
|
}
|
|
const objType = env.get(instr.value.object.identifier.id);
|
|
let lookupType = null;
|
|
if ((objType === null || objType === void 0 ? void 0 : objType.kind) === 'Structure') {
|
|
lookupType = objType.value;
|
|
}
|
|
else if ((objType === null || objType === void 0 ? void 0 : objType.kind) === 'Ref') {
|
|
lookupType = {
|
|
kind: 'RefValue',
|
|
loc: instr.loc,
|
|
refId: objType.refId,
|
|
};
|
|
}
|
|
env.set(instr.lvalue.identifier.id, lookupType !== null && lookupType !== void 0 ? lookupType : refTypeOfType(instr.lvalue));
|
|
break;
|
|
}
|
|
case 'TypeCastExpression': {
|
|
env.set(instr.lvalue.identifier.id, (_a = env.get(instr.value.value.identifier.id)) !== null && _a !== void 0 ? _a : refTypeOfType(instr.lvalue));
|
|
break;
|
|
}
|
|
case 'LoadContext':
|
|
case 'LoadLocal': {
|
|
env.set(instr.lvalue.identifier.id, (_b = env.get(instr.value.place.identifier.id)) !== null && _b !== void 0 ? _b : refTypeOfType(instr.lvalue));
|
|
break;
|
|
}
|
|
case 'StoreContext':
|
|
case 'StoreLocal': {
|
|
env.set(instr.value.lvalue.place.identifier.id, (_c = env.get(instr.value.value.identifier.id)) !== null && _c !== void 0 ? _c : refTypeOfType(instr.value.lvalue.place));
|
|
env.set(instr.lvalue.identifier.id, (_d = env.get(instr.value.value.identifier.id)) !== null && _d !== void 0 ? _d : refTypeOfType(instr.lvalue));
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
const objType = env.get(instr.value.value.identifier.id);
|
|
let lookupType = null;
|
|
if ((objType === null || objType === void 0 ? void 0 : objType.kind) === 'Structure') {
|
|
lookupType = objType.value;
|
|
}
|
|
env.set(instr.lvalue.identifier.id, lookupType !== null && lookupType !== void 0 ? lookupType : refTypeOfType(instr.lvalue));
|
|
for (const lval of eachPatternOperand(instr.value.lvalue.pattern)) {
|
|
env.set(lval.identifier.id, lookupType !== null && lookupType !== void 0 ? lookupType : refTypeOfType(lval));
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
let returnType = { kind: 'None' };
|
|
let readRefEffect = false;
|
|
const innerErrors = new CompilerError();
|
|
const result = validateNoRefAccessInRenderImpl(instr.value.loweredFunc.func, env, innerErrors);
|
|
if (!innerErrors.hasAnyErrors()) {
|
|
returnType = result;
|
|
}
|
|
else {
|
|
readRefEffect = true;
|
|
}
|
|
env.set(instr.lvalue.identifier.id, {
|
|
kind: 'Structure',
|
|
fn: {
|
|
readRefEffect,
|
|
returnType,
|
|
},
|
|
value: null,
|
|
});
|
|
break;
|
|
}
|
|
case 'MethodCall':
|
|
case 'CallExpression': {
|
|
const callee = instr.value.kind === 'CallExpression'
|
|
? instr.value.callee
|
|
: instr.value.property;
|
|
const hookKind = getHookKindForType(fn.env, callee.identifier.type);
|
|
let returnType = { kind: 'None' };
|
|
const fnType = env.get(callee.identifier.id);
|
|
let didError = false;
|
|
if ((fnType === null || fnType === void 0 ? void 0 : fnType.kind) === 'Structure' && fnType.fn !== null) {
|
|
returnType = fnType.fn.returnType;
|
|
if (fnType.fn.readRefEffect) {
|
|
didError = true;
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Refs,
|
|
reason: 'Cannot access refs during render',
|
|
description: ERROR_DESCRIPTION,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: callee.loc,
|
|
message: `This function accesses a ref value`,
|
|
}));
|
|
}
|
|
}
|
|
if (!didError) {
|
|
const isRefLValue = isUseRefType(instr.lvalue.identifier);
|
|
if (isRefLValue ||
|
|
(hookKind != null &&
|
|
hookKind !== 'useState' &&
|
|
hookKind !== 'useReducer')) {
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
validateNoDirectRefValueAccess(errors, operand, env);
|
|
}
|
|
}
|
|
else if (interpolatedAsJsx.has(instr.lvalue.identifier.id)) {
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
validateNoRefValueAccess(errors, env, operand);
|
|
}
|
|
}
|
|
else if (hookKind == null && instr.effects != null) {
|
|
const visitedEffects = new Set();
|
|
for (const effect of instr.effects) {
|
|
let place = null;
|
|
let validation = 'none';
|
|
switch (effect.kind) {
|
|
case 'Freeze': {
|
|
place = effect.value;
|
|
validation = 'direct-ref';
|
|
break;
|
|
}
|
|
case 'Mutate':
|
|
case 'MutateTransitive':
|
|
case 'MutateConditionally':
|
|
case 'MutateTransitiveConditionally': {
|
|
place = effect.value;
|
|
validation = 'ref-passed';
|
|
break;
|
|
}
|
|
case 'Render': {
|
|
place = effect.place;
|
|
validation = 'ref-passed';
|
|
break;
|
|
}
|
|
case 'Capture':
|
|
case 'Alias':
|
|
case 'MaybeAlias':
|
|
case 'Assign':
|
|
case 'CreateFrom': {
|
|
place = effect.from;
|
|
validation = 'ref-passed';
|
|
break;
|
|
}
|
|
case 'ImmutableCapture': {
|
|
place = effect.from;
|
|
const isFrozen = instr.effects.some(e => e.kind === 'Freeze' &&
|
|
e.value.identifier.id === effect.from.identifier.id);
|
|
validation = isFrozen ? 'direct-ref' : 'ref-passed';
|
|
break;
|
|
}
|
|
}
|
|
if (place !== null && validation !== 'none') {
|
|
const key = `${place.identifier.id}:${validation}`;
|
|
if (!visitedEffects.has(key)) {
|
|
visitedEffects.add(key);
|
|
if (validation === 'direct-ref') {
|
|
validateNoDirectRefValueAccess(errors, place, env);
|
|
}
|
|
else {
|
|
validateNoRefPassedToFunction(errors, env, place, place.loc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
validateNoRefPassedToFunction(errors, env, operand, operand.loc);
|
|
}
|
|
}
|
|
}
|
|
env.set(instr.lvalue.identifier.id, returnType);
|
|
break;
|
|
}
|
|
case 'ObjectExpression':
|
|
case 'ArrayExpression': {
|
|
const types = [];
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
validateNoDirectRefValueAccess(errors, operand, env);
|
|
types.push((_e = env.get(operand.identifier.id)) !== null && _e !== void 0 ? _e : { kind: 'None' });
|
|
}
|
|
const value = joinRefAccessTypes(...types);
|
|
if (value.kind === 'None' ||
|
|
value.kind === 'Guard' ||
|
|
value.kind === 'Nullable') {
|
|
env.set(instr.lvalue.identifier.id, { kind: 'None' });
|
|
}
|
|
else {
|
|
env.set(instr.lvalue.identifier.id, {
|
|
kind: 'Structure',
|
|
value,
|
|
fn: null,
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case 'PropertyDelete':
|
|
case 'PropertyStore':
|
|
case 'ComputedDelete':
|
|
case 'ComputedStore': {
|
|
const target = env.get(instr.value.object.identifier.id);
|
|
let safe = null;
|
|
if (instr.value.kind === 'PropertyStore' &&
|
|
target != null &&
|
|
target.kind === 'Ref') {
|
|
safe = safeBlocks.find(entry => entry.ref === target.refId);
|
|
}
|
|
if (safe != null) {
|
|
retainWhere(safeBlocks, entry => entry !== safe);
|
|
}
|
|
else {
|
|
validateNoRefUpdate(errors, env, instr.value.object, instr.loc);
|
|
}
|
|
if (instr.value.kind === 'ComputedDelete' ||
|
|
instr.value.kind === 'ComputedStore') {
|
|
validateNoRefValueAccess(errors, env, instr.value.property);
|
|
}
|
|
if (instr.value.kind === 'ComputedStore' ||
|
|
instr.value.kind === 'PropertyStore') {
|
|
validateNoDirectRefValueAccess(errors, instr.value.value, env);
|
|
const type = env.get(instr.value.value.identifier.id);
|
|
if (type != null && type.kind === 'Structure') {
|
|
let objectType = type;
|
|
if (target != null) {
|
|
objectType = joinRefAccessTypes(objectType, target);
|
|
}
|
|
env.set(instr.value.object.identifier.id, objectType);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'StartMemoize':
|
|
case 'FinishMemoize':
|
|
break;
|
|
case 'LoadGlobal': {
|
|
if (instr.value.binding.name === 'undefined') {
|
|
env.set(instr.lvalue.identifier.id, { kind: 'Nullable' });
|
|
}
|
|
break;
|
|
}
|
|
case 'Primitive': {
|
|
if (instr.value.value == null) {
|
|
env.set(instr.lvalue.identifier.id, { kind: 'Nullable' });
|
|
}
|
|
break;
|
|
}
|
|
case 'UnaryExpression': {
|
|
if (instr.value.operator === '!') {
|
|
const value = env.get(instr.value.value.identifier.id);
|
|
const refId = (value === null || value === void 0 ? void 0 : value.kind) === 'RefValue' && value.refId != null
|
|
? value.refId
|
|
: null;
|
|
if (refId !== null) {
|
|
env.set(instr.lvalue.identifier.id, { kind: 'Guard', refId });
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Refs,
|
|
reason: 'Cannot access refs during render',
|
|
description: ERROR_DESCRIPTION,
|
|
})
|
|
.withDetails({
|
|
kind: 'error',
|
|
loc: instr.value.value.loc,
|
|
message: `Cannot access ref value during render`,
|
|
})
|
|
.withDetails({
|
|
kind: 'hint',
|
|
message: 'To initialize a ref only once, check that the ref is null with the pattern `if (ref.current == null) { ref.current = ... }`',
|
|
}));
|
|
break;
|
|
}
|
|
}
|
|
validateNoRefValueAccess(errors, env, instr.value.value);
|
|
break;
|
|
}
|
|
case 'BinaryExpression': {
|
|
const left = env.get(instr.value.left.identifier.id);
|
|
const right = env.get(instr.value.right.identifier.id);
|
|
let nullish = false;
|
|
let refId = null;
|
|
if ((left === null || left === void 0 ? void 0 : left.kind) === 'RefValue' && left.refId != null) {
|
|
refId = left.refId;
|
|
}
|
|
else if ((right === null || right === void 0 ? void 0 : right.kind) === 'RefValue' && right.refId != null) {
|
|
refId = right.refId;
|
|
}
|
|
if ((left === null || left === void 0 ? void 0 : left.kind) === 'Nullable') {
|
|
nullish = true;
|
|
}
|
|
else if ((right === null || right === void 0 ? void 0 : right.kind) === 'Nullable') {
|
|
nullish = true;
|
|
}
|
|
if (refId !== null && nullish) {
|
|
env.set(instr.lvalue.identifier.id, { kind: 'Guard', refId });
|
|
}
|
|
else {
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
validateNoRefValueAccess(errors, env, operand);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
validateNoRefValueAccess(errors, env, operand);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
guardCheck(errors, operand, env);
|
|
}
|
|
if (isUseRefType(instr.lvalue.identifier) &&
|
|
((_f = env.get(instr.lvalue.identifier.id)) === null || _f === void 0 ? void 0 : _f.kind) !== 'Ref') {
|
|
env.set(instr.lvalue.identifier.id, joinRefAccessTypes((_g = env.get(instr.lvalue.identifier.id)) !== null && _g !== void 0 ? _g : { kind: 'None' }, { kind: 'Ref', refId: nextRefId() }));
|
|
}
|
|
if (isRefValueType(instr.lvalue.identifier) &&
|
|
((_h = env.get(instr.lvalue.identifier.id)) === null || _h === void 0 ? void 0 : _h.kind) !== 'RefValue') {
|
|
env.set(instr.lvalue.identifier.id, joinRefAccessTypes((_j = env.get(instr.lvalue.identifier.id)) !== null && _j !== void 0 ? _j : { kind: 'None' }, { kind: 'RefValue', loc: instr.loc }));
|
|
}
|
|
}
|
|
if (block.terminal.kind === 'if') {
|
|
const test = env.get(block.terminal.test.identifier.id);
|
|
if ((test === null || test === void 0 ? void 0 : test.kind) === 'Guard' &&
|
|
safeBlocks.find(entry => entry.ref === test.refId) == null) {
|
|
safeBlocks.push({ block: block.terminal.fallthrough, ref: test.refId });
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
if (block.terminal.kind !== 'return') {
|
|
validateNoRefValueAccess(errors, env, operand);
|
|
if (block.terminal.kind !== 'if') {
|
|
guardCheck(errors, operand, env);
|
|
}
|
|
}
|
|
else {
|
|
validateNoDirectRefValueAccess(errors, operand, env);
|
|
guardCheck(errors, operand, env);
|
|
returnValues.push(env.get(operand.identifier.id));
|
|
}
|
|
}
|
|
}
|
|
if (errors.hasAnyErrors()) {
|
|
return { kind: 'None' };
|
|
}
|
|
}
|
|
CompilerError.invariant(!env.hasChanged(), {
|
|
reason: 'Ref type environment did not converge',
|
|
loc: GeneratedSource,
|
|
});
|
|
return joinRefAccessTypes(...returnValues.filter((env) => env !== undefined));
|
|
}
|
|
function destructure(type) {
|
|
if ((type === null || type === void 0 ? void 0 : type.kind) === 'Structure' && type.value !== null) {
|
|
return destructure(type.value);
|
|
}
|
|
return type;
|
|
}
|
|
function guardCheck(errors, operand, env) {
|
|
var _a;
|
|
if (((_a = env.get(operand.identifier.id)) === null || _a === void 0 ? void 0 : _a.kind) === 'Guard') {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Refs,
|
|
reason: 'Cannot access refs during render',
|
|
description: ERROR_DESCRIPTION,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: operand.loc,
|
|
message: `Cannot access ref value during render`,
|
|
}));
|
|
}
|
|
}
|
|
function validateNoRefValueAccess(errors, env, operand) {
|
|
var _a;
|
|
const type = destructure(env.get(operand.identifier.id));
|
|
if ((type === null || type === void 0 ? void 0 : type.kind) === 'RefValue' ||
|
|
((type === null || type === void 0 ? void 0 : type.kind) === 'Structure' && ((_a = type.fn) === null || _a === void 0 ? void 0 : _a.readRefEffect))) {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Refs,
|
|
reason: 'Cannot access refs during render',
|
|
description: ERROR_DESCRIPTION,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: (type.kind === 'RefValue' && type.loc) || operand.loc,
|
|
message: `Cannot access ref value during render`,
|
|
}));
|
|
}
|
|
}
|
|
function validateNoRefPassedToFunction(errors, env, operand, loc) {
|
|
var _a;
|
|
const type = destructure(env.get(operand.identifier.id));
|
|
if ((type === null || type === void 0 ? void 0 : type.kind) === 'Ref' ||
|
|
(type === null || type === void 0 ? void 0 : type.kind) === 'RefValue' ||
|
|
((type === null || type === void 0 ? void 0 : type.kind) === 'Structure' && ((_a = type.fn) === null || _a === void 0 ? void 0 : _a.readRefEffect))) {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Refs,
|
|
reason: 'Cannot access refs during render',
|
|
description: ERROR_DESCRIPTION,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: (type.kind === 'RefValue' && type.loc) || loc,
|
|
message: `Passing a ref to a function may read its value during render`,
|
|
}));
|
|
}
|
|
}
|
|
function validateNoRefUpdate(errors, env, operand, loc) {
|
|
const type = destructure(env.get(operand.identifier.id));
|
|
if ((type === null || type === void 0 ? void 0 : type.kind) === 'Ref' || (type === null || type === void 0 ? void 0 : type.kind) === 'RefValue') {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Refs,
|
|
reason: 'Cannot access refs during render',
|
|
description: ERROR_DESCRIPTION,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: (type.kind === 'RefValue' && type.loc) || loc,
|
|
message: `Cannot update ref during render`,
|
|
}));
|
|
}
|
|
}
|
|
function validateNoDirectRefValueAccess(errors, operand, env) {
|
|
var _a;
|
|
const type = destructure(env.get(operand.identifier.id));
|
|
if ((type === null || type === void 0 ? void 0 : type.kind) === 'RefValue') {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Refs,
|
|
reason: 'Cannot access refs during render',
|
|
description: ERROR_DESCRIPTION,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: (_a = type.loc) !== null && _a !== void 0 ? _a : operand.loc,
|
|
message: `Cannot access ref value during render`,
|
|
}));
|
|
}
|
|
}
|
|
const ERROR_DESCRIPTION = 'React refs are values that are not needed for rendering. Refs should only be accessed ' +
|
|
'outside of render, such as in event handlers or effects. ' +
|
|
'Accessing a ref value (the `current` property) during render can cause your component ' +
|
|
'not to update as expected (https://react.dev/reference/react/useRef)';
|
|
|
|
function validateNoSetStateInRender(fn) {
|
|
const unconditionalSetStateFunctions = new Set();
|
|
const errors = validateNoSetStateInRenderImpl(fn, unconditionalSetStateFunctions);
|
|
for (const detail of errors.details) {
|
|
fn.env.recordError(detail);
|
|
}
|
|
}
|
|
function validateNoSetStateInRenderImpl(fn, unconditionalSetStateFunctions) {
|
|
const unconditionalBlocks = computeUnconditionalBlocks(fn);
|
|
let activeManualMemoId = null;
|
|
const errors = new CompilerError();
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
switch (instr.value.kind) {
|
|
case 'LoadLocal': {
|
|
if (unconditionalSetStateFunctions.has(instr.value.place.identifier.id)) {
|
|
unconditionalSetStateFunctions.add(instr.lvalue.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
if (unconditionalSetStateFunctions.has(instr.value.value.identifier.id)) {
|
|
unconditionalSetStateFunctions.add(instr.value.lvalue.place.identifier.id);
|
|
unconditionalSetStateFunctions.add(instr.lvalue.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
if ([...eachInstructionValueOperand(instr.value)].some(operand => isSetStateType(operand.identifier) ||
|
|
unconditionalSetStateFunctions.has(operand.identifier.id)) &&
|
|
validateNoSetStateInRenderImpl(instr.value.loweredFunc.func, unconditionalSetStateFunctions).hasAnyErrors()) {
|
|
unconditionalSetStateFunctions.add(instr.lvalue.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'StartMemoize': {
|
|
CompilerError.invariant(activeManualMemoId === null, {
|
|
reason: 'Unexpected nested StartMemoize instructions',
|
|
loc: instr.value.loc,
|
|
});
|
|
activeManualMemoId = instr.value.manualMemoId;
|
|
break;
|
|
}
|
|
case 'FinishMemoize': {
|
|
CompilerError.invariant(activeManualMemoId === instr.value.manualMemoId, {
|
|
reason: 'Expected FinishMemoize to align with previous StartMemoize instruction',
|
|
loc: instr.value.loc,
|
|
});
|
|
activeManualMemoId = null;
|
|
break;
|
|
}
|
|
case 'CallExpression': {
|
|
const callee = instr.value.callee;
|
|
if (isSetStateType(callee.identifier) ||
|
|
unconditionalSetStateFunctions.has(callee.identifier.id)) {
|
|
if (activeManualMemoId !== null) {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.RenderSetState,
|
|
reason: 'Calling setState from useMemo may trigger an infinite loop',
|
|
description: 'Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState)',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: callee.loc,
|
|
message: 'Found setState() within useMemo()',
|
|
}));
|
|
}
|
|
else if (unconditionalBlocks.has(block.id)) {
|
|
const enableUseKeyedState = fn.env.config.enableUseKeyedState;
|
|
if (enableUseKeyedState) {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.RenderSetState,
|
|
reason: 'Cannot call setState during render',
|
|
description: 'Calling setState during render may trigger an infinite loop.\n' +
|
|
'* To reset state when other state/props change, use `const [state, setState] = useKeyedState(initialState, key)` to reset `state` when `key` changes.\n' +
|
|
'* To derive data from other state/props, compute the derived data during render without using state',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: callee.loc,
|
|
message: 'Found setState() in render',
|
|
}));
|
|
}
|
|
else {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.RenderSetState,
|
|
reason: 'Cannot call setState during render',
|
|
description: 'Calling setState during render may trigger an infinite loop.\n' +
|
|
'* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders\n' +
|
|
'* To derive data from other state/props, compute the derived data during render without using state',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: callee.loc,
|
|
message: 'Found setState() in render',
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
function validatePreservedManualMemoization(fn) {
|
|
const state = {
|
|
env: fn.env,
|
|
manualMemoState: null,
|
|
};
|
|
visitReactiveFunction(fn, new Visitor(), state);
|
|
}
|
|
function prettyPrintScopeDependency(val) {
|
|
var _a;
|
|
let rootStr;
|
|
if (((_a = val.identifier.name) === null || _a === void 0 ? void 0 : _a.kind) === 'named') {
|
|
rootStr = val.identifier.name.value;
|
|
}
|
|
else {
|
|
rootStr = '[unnamed]';
|
|
}
|
|
return `${rootStr}${val.path.map(v => `${v.optional ? '?.' : '.'}${v.property}`).join('')}`;
|
|
}
|
|
var CompareDependencyResult;
|
|
(function (CompareDependencyResult) {
|
|
CompareDependencyResult[CompareDependencyResult["Ok"] = 0] = "Ok";
|
|
CompareDependencyResult[CompareDependencyResult["RootDifference"] = 1] = "RootDifference";
|
|
CompareDependencyResult[CompareDependencyResult["PathDifference"] = 2] = "PathDifference";
|
|
CompareDependencyResult[CompareDependencyResult["Subpath"] = 3] = "Subpath";
|
|
CompareDependencyResult[CompareDependencyResult["RefAccessDifference"] = 4] = "RefAccessDifference";
|
|
})(CompareDependencyResult || (CompareDependencyResult = {}));
|
|
function merge$1(a, b) {
|
|
return Math.max(a, b);
|
|
}
|
|
function getCompareDependencyResultDescription(result) {
|
|
switch (result) {
|
|
case CompareDependencyResult.Ok:
|
|
return 'Dependencies equal';
|
|
case CompareDependencyResult.RootDifference:
|
|
case CompareDependencyResult.PathDifference:
|
|
return 'Inferred different dependency than source';
|
|
case CompareDependencyResult.RefAccessDifference:
|
|
return 'Differences in ref.current access';
|
|
case CompareDependencyResult.Subpath:
|
|
return 'Inferred less specific property than source';
|
|
}
|
|
}
|
|
function compareDeps(inferred, source) {
|
|
const rootsEqual = (inferred.root.kind === 'Global' &&
|
|
source.root.kind === 'Global' &&
|
|
inferred.root.identifierName === source.root.identifierName) ||
|
|
(inferred.root.kind === 'NamedLocal' &&
|
|
source.root.kind === 'NamedLocal' &&
|
|
inferred.root.value.identifier.id === source.root.value.identifier.id);
|
|
if (!rootsEqual) {
|
|
return CompareDependencyResult.RootDifference;
|
|
}
|
|
let isSubpath = true;
|
|
for (let i = 0; i < Math.min(inferred.path.length, source.path.length); i++) {
|
|
if (inferred.path[i].property !== source.path[i].property) {
|
|
isSubpath = false;
|
|
break;
|
|
}
|
|
else if (inferred.path[i].optional !== source.path[i].optional) {
|
|
return CompareDependencyResult.PathDifference;
|
|
}
|
|
}
|
|
if (isSubpath &&
|
|
(source.path.length === inferred.path.length ||
|
|
(inferred.path.length >= source.path.length &&
|
|
!inferred.path.some(token => token.property === 'current')))) {
|
|
return CompareDependencyResult.Ok;
|
|
}
|
|
else {
|
|
if (isSubpath) {
|
|
if (source.path.some(token => token.property === 'current') ||
|
|
inferred.path.some(token => token.property === 'current')) {
|
|
return CompareDependencyResult.RefAccessDifference;
|
|
}
|
|
else {
|
|
return CompareDependencyResult.Subpath;
|
|
}
|
|
}
|
|
else {
|
|
return CompareDependencyResult.PathDifference;
|
|
}
|
|
}
|
|
}
|
|
function validateInferredDep(dep, temporaries, declsWithinMemoBlock, validDepsInMemoBlock, env, memoLocation) {
|
|
var _a;
|
|
let normalizedDep;
|
|
const maybeNormalizedRoot = temporaries.get(dep.identifier.id);
|
|
if (maybeNormalizedRoot != null) {
|
|
normalizedDep = {
|
|
root: maybeNormalizedRoot.root,
|
|
path: [...maybeNormalizedRoot.path, ...dep.path],
|
|
loc: maybeNormalizedRoot.loc,
|
|
};
|
|
}
|
|
else {
|
|
CompilerError.invariant(((_a = dep.identifier.name) === null || _a === void 0 ? void 0 : _a.kind) === 'named', {
|
|
reason: 'ValidatePreservedManualMemoization: expected scope dependency to be named',
|
|
loc: GeneratedSource,
|
|
});
|
|
normalizedDep = {
|
|
root: {
|
|
kind: 'NamedLocal',
|
|
value: {
|
|
kind: 'Identifier',
|
|
identifier: dep.identifier,
|
|
loc: GeneratedSource,
|
|
effect: Effect.Read,
|
|
reactive: false,
|
|
},
|
|
constant: false,
|
|
},
|
|
path: [...dep.path],
|
|
loc: GeneratedSource,
|
|
};
|
|
}
|
|
for (const decl of declsWithinMemoBlock) {
|
|
if (normalizedDep.root.kind === 'NamedLocal' &&
|
|
decl === normalizedDep.root.value.identifier.declarationId) {
|
|
return;
|
|
}
|
|
}
|
|
let errorDiagnostic = null;
|
|
for (const originalDep of validDepsInMemoBlock) {
|
|
const compareResult = compareDeps(normalizedDep, originalDep);
|
|
if (compareResult === CompareDependencyResult.Ok) {
|
|
return;
|
|
}
|
|
else {
|
|
errorDiagnostic = merge$1(errorDiagnostic !== null && errorDiagnostic !== void 0 ? errorDiagnostic : compareResult, compareResult);
|
|
}
|
|
}
|
|
env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.PreserveManualMemo,
|
|
reason: 'Existing memoization could not be preserved',
|
|
description: [
|
|
'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. ',
|
|
'The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. ',
|
|
(dep.identifier.name != null && dep.identifier.name.kind === 'named')
|
|
? `The inferred dependency was \`${prettyPrintScopeDependency(dep)}\`, but the source dependencies were [${validDepsInMemoBlock
|
|
.map(dep => printManualMemoDependency$1(dep, true))
|
|
.join(', ')}]. ${errorDiagnostic
|
|
? getCompareDependencyResultDescription(errorDiagnostic)
|
|
: 'Inferred dependency not present in source'}`
|
|
: '',
|
|
]
|
|
.join('')
|
|
.trim(),
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: memoLocation,
|
|
message: 'Could not preserve existing manual memoization',
|
|
}));
|
|
}
|
|
class Visitor extends ReactiveFunctionVisitor {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.scopes = new Set();
|
|
this.prunedScopes = new Set();
|
|
this.temporaries = new Map();
|
|
}
|
|
recordDepsInValue(value, state) {
|
|
var _a, _b;
|
|
switch (value.kind) {
|
|
case 'SequenceExpression': {
|
|
for (const instr of value.instructions) {
|
|
this.visitInstruction(instr, state);
|
|
}
|
|
this.recordDepsInValue(value.value, state);
|
|
break;
|
|
}
|
|
case 'OptionalExpression': {
|
|
this.recordDepsInValue(value.value, state);
|
|
break;
|
|
}
|
|
case 'ConditionalExpression': {
|
|
this.recordDepsInValue(value.test, state);
|
|
this.recordDepsInValue(value.consequent, state);
|
|
this.recordDepsInValue(value.alternate, state);
|
|
break;
|
|
}
|
|
case 'LogicalExpression': {
|
|
this.recordDepsInValue(value.left, state);
|
|
this.recordDepsInValue(value.right, state);
|
|
break;
|
|
}
|
|
default: {
|
|
collectMaybeMemoDependencies(value, this.temporaries, false);
|
|
if (value.kind === 'StoreLocal' ||
|
|
value.kind === 'StoreContext' ||
|
|
value.kind === 'Destructure') {
|
|
for (const storeTarget of eachInstructionValueLValue(value)) {
|
|
(_a = state.manualMemoState) === null || _a === void 0 ? void 0 : _a.decls.add(storeTarget.identifier.declarationId);
|
|
if (((_b = storeTarget.identifier.name) === null || _b === void 0 ? void 0 : _b.kind) === 'named') {
|
|
this.temporaries.set(storeTarget.identifier.id, {
|
|
root: {
|
|
kind: 'NamedLocal',
|
|
value: storeTarget,
|
|
constant: false,
|
|
},
|
|
path: [],
|
|
loc: storeTarget.loc,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
recordTemporaries(instr, state) {
|
|
var _a;
|
|
const temporaries = this.temporaries;
|
|
const { lvalue, value } = instr;
|
|
const lvalId = lvalue === null || lvalue === void 0 ? void 0 : lvalue.identifier.id;
|
|
if (lvalId != null && temporaries.has(lvalId)) {
|
|
return;
|
|
}
|
|
const isNamedLocal = ((_a = lvalue === null || lvalue === void 0 ? void 0 : lvalue.identifier.name) === null || _a === void 0 ? void 0 : _a.kind) === 'named';
|
|
if (lvalue !== null && isNamedLocal && state.manualMemoState != null) {
|
|
state.manualMemoState.decls.add(lvalue.identifier.declarationId);
|
|
}
|
|
this.recordDepsInValue(value, state);
|
|
if (lvalue != null) {
|
|
temporaries.set(lvalue.identifier.id, {
|
|
root: {
|
|
kind: 'NamedLocal',
|
|
value: Object.assign({}, lvalue),
|
|
constant: false,
|
|
},
|
|
path: [],
|
|
loc: lvalue.loc,
|
|
});
|
|
}
|
|
}
|
|
visitScope(scopeBlock, state) {
|
|
this.traverseScope(scopeBlock, state);
|
|
if (state.manualMemoState != null &&
|
|
state.manualMemoState.depsFromSource != null) {
|
|
for (const dep of scopeBlock.scope.dependencies) {
|
|
validateInferredDep(dep, this.temporaries, state.manualMemoState.decls, state.manualMemoState.depsFromSource, state.env, state.manualMemoState.loc);
|
|
}
|
|
}
|
|
this.scopes.add(scopeBlock.scope.id);
|
|
for (const id of scopeBlock.scope.merged) {
|
|
this.scopes.add(id);
|
|
}
|
|
}
|
|
visitPrunedScope(scopeBlock, state) {
|
|
this.traversePrunedScope(scopeBlock, state);
|
|
this.prunedScopes.add(scopeBlock.scope.id);
|
|
}
|
|
visitInstruction(instruction, state) {
|
|
var _a, _b;
|
|
this.recordTemporaries(instruction, state);
|
|
const value = instruction.value;
|
|
if (value.kind === 'StoreLocal' &&
|
|
value.lvalue.kind === 'Reassign' &&
|
|
state.manualMemoState != null) {
|
|
const ids = getOrInsertDefault(state.manualMemoState.reassignments, value.lvalue.place.identifier.declarationId, new Set());
|
|
ids.add(value.value.identifier);
|
|
}
|
|
if (value.kind === 'LoadLocal' &&
|
|
value.place.identifier.scope != null &&
|
|
instruction.lvalue != null &&
|
|
instruction.lvalue.identifier.scope == null &&
|
|
state.manualMemoState != null) {
|
|
const ids = getOrInsertDefault(state.manualMemoState.reassignments, instruction.lvalue.identifier.declarationId, new Set());
|
|
ids.add(value.place.identifier);
|
|
}
|
|
if (value.kind === 'StartMemoize') {
|
|
CompilerError.invariant(state.manualMemoState == null, {
|
|
reason: 'Unexpected nested StartMemoize instructions',
|
|
description: `Bad manual memoization ids: ${(_a = state.manualMemoState) === null || _a === void 0 ? void 0 : _a.manualMemoId}, ${value.manualMemoId}`,
|
|
loc: value.loc,
|
|
});
|
|
if (value.hasInvalidDeps === true) {
|
|
return;
|
|
}
|
|
let depsFromSource = null;
|
|
if (value.deps != null) {
|
|
depsFromSource = value.deps;
|
|
}
|
|
state.manualMemoState = {
|
|
loc: instruction.loc,
|
|
decls: new Set(),
|
|
depsFromSource,
|
|
manualMemoId: value.manualMemoId,
|
|
reassignments: new Map(),
|
|
};
|
|
for (const { identifier, loc } of eachInstructionValueOperand(value)) {
|
|
if (identifier.scope != null &&
|
|
!this.scopes.has(identifier.scope.id) &&
|
|
!this.prunedScopes.has(identifier.scope.id)) {
|
|
state.env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.PreserveManualMemo,
|
|
reason: 'Existing memoization could not be preserved',
|
|
description: [
|
|
'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. ',
|
|
'This dependency may be mutated later, which could cause the value to change unexpectedly',
|
|
].join(''),
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc,
|
|
message: 'This dependency may be modified later',
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
if (value.kind === 'FinishMemoize') {
|
|
if (state.manualMemoState == null) {
|
|
return;
|
|
}
|
|
CompilerError.invariant(state.manualMemoState.manualMemoId === value.manualMemoId, {
|
|
reason: 'Unexpected mismatch between StartMemoize and FinishMemoize',
|
|
description: `Encountered StartMemoize id=${state.manualMemoState.manualMemoId} followed by FinishMemoize id=${value.manualMemoId}`,
|
|
loc: value.loc,
|
|
});
|
|
const reassignments = state.manualMemoState.reassignments;
|
|
state.manualMemoState = null;
|
|
if (!value.pruned) {
|
|
for (const { identifier, loc } of eachInstructionValueOperand(value)) {
|
|
let decls;
|
|
if (identifier.scope == null) {
|
|
decls = (_b = reassignments.get(identifier.declarationId)) !== null && _b !== void 0 ? _b : [identifier];
|
|
}
|
|
else {
|
|
decls = [identifier];
|
|
}
|
|
for (const identifier of decls) {
|
|
if (isUnmemoized(identifier, this.scopes)) {
|
|
state.env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.PreserveManualMemo,
|
|
reason: 'Existing memoization could not be preserved',
|
|
description: [
|
|
'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output',
|
|
'',
|
|
]
|
|
.join('')
|
|
.trim(),
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc,
|
|
message: 'Could not preserve existing memoization',
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function isUnmemoized(operand, scopes) {
|
|
return operand.scope != null && !scopes.has(operand.scope.id);
|
|
}
|
|
|
|
const IMPORTANT_INSTRUMENTED_TYPES = new Set([
|
|
'ArrowFunctionExpression',
|
|
'AssignmentPattern',
|
|
'ObjectMethod',
|
|
'ExpressionStatement',
|
|
'BreakStatement',
|
|
'ContinueStatement',
|
|
'ReturnStatement',
|
|
'ThrowStatement',
|
|
'TryStatement',
|
|
'VariableDeclarator',
|
|
'IfStatement',
|
|
'ForStatement',
|
|
'ForInStatement',
|
|
'ForOfStatement',
|
|
'WhileStatement',
|
|
'DoWhileStatement',
|
|
'SwitchStatement',
|
|
'SwitchCase',
|
|
'WithStatement',
|
|
'FunctionDeclaration',
|
|
'FunctionExpression',
|
|
'LabeledStatement',
|
|
'ConditionalExpression',
|
|
'LogicalExpression',
|
|
'VariableDeclaration',
|
|
'Identifier',
|
|
]);
|
|
function isManualMemoization(node) {
|
|
if (libExports$1.isCallExpression(node)) {
|
|
const callee = node.callee;
|
|
if (libExports$1.isIdentifier(callee)) {
|
|
return callee.name === 'useMemo' || callee.name === 'useCallback';
|
|
}
|
|
if (libExports$1.isMemberExpression(callee) &&
|
|
libExports$1.isIdentifier(callee.property) &&
|
|
libExports$1.isIdentifier(callee.object)) {
|
|
return (callee.object.name === 'React' &&
|
|
(callee.property.name === 'useMemo' ||
|
|
callee.property.name === 'useCallback'));
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function locationKey(loc) {
|
|
return `${loc.start.line}:${loc.start.column}-${loc.end.line}:${loc.end.column}`;
|
|
}
|
|
function validateSourceLocations(func, generatedAst, env) {
|
|
const importantOriginalLocations = new Map();
|
|
func.traverse({
|
|
enter(path) {
|
|
const node = path.node;
|
|
if (!IMPORTANT_INSTRUMENTED_TYPES.has(node.type)) {
|
|
return;
|
|
}
|
|
if (isManualMemoization(node)) {
|
|
return;
|
|
}
|
|
if (libExports$1.isReturnStatement(node) && node.argument != null) {
|
|
const parentBody = path.parentPath;
|
|
const parentFunc = parentBody === null || parentBody === void 0 ? void 0 : parentBody.parentPath;
|
|
if ((parentBody === null || parentBody === void 0 ? void 0 : parentBody.isBlockStatement()) &&
|
|
(parentFunc === null || parentFunc === void 0 ? void 0 : parentFunc.isArrowFunctionExpression()) &&
|
|
parentBody.node.body.length === 1 &&
|
|
parentBody.node.directives.length === 0) {
|
|
return;
|
|
}
|
|
}
|
|
if (node.loc) {
|
|
const key = locationKey(node.loc);
|
|
const existing = importantOriginalLocations.get(key);
|
|
if (existing) {
|
|
existing.nodeTypes.add(node.type);
|
|
}
|
|
else {
|
|
importantOriginalLocations.set(key, {
|
|
loc: node.loc,
|
|
nodeTypes: new Set([node.type]),
|
|
});
|
|
}
|
|
}
|
|
},
|
|
});
|
|
const generatedLocations = new Map();
|
|
function collectGeneratedLocations(node) {
|
|
if (node.loc) {
|
|
const key = locationKey(node.loc);
|
|
const nodeTypes = generatedLocations.get(key);
|
|
if (nodeTypes) {
|
|
nodeTypes.add(node.type);
|
|
}
|
|
else {
|
|
generatedLocations.set(key, new Set([node.type]));
|
|
}
|
|
}
|
|
const keys = libExports$1.VISITOR_KEYS[node.type];
|
|
if (!keys) {
|
|
return;
|
|
}
|
|
for (const key of keys) {
|
|
const value = node[key];
|
|
if (Array.isArray(value)) {
|
|
for (const item of value) {
|
|
if (libExports$1.isNode(item)) {
|
|
collectGeneratedLocations(item);
|
|
}
|
|
}
|
|
}
|
|
else if (libExports$1.isNode(value)) {
|
|
collectGeneratedLocations(value);
|
|
}
|
|
}
|
|
}
|
|
collectGeneratedLocations(generatedAst.body);
|
|
for (const outlined of generatedAst.outlined) {
|
|
collectGeneratedLocations(outlined.fn.body);
|
|
}
|
|
const strictNodeTypes = new Set([
|
|
'VariableDeclaration',
|
|
'VariableDeclarator',
|
|
'Identifier',
|
|
]);
|
|
const reportMissingLocation = (loc, nodeType) => {
|
|
env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Important source location missing in generated code',
|
|
description: `Source location for ${nodeType} is missing in the generated output. This can cause coverage instrumentation ` +
|
|
`to fail to track this code properly, resulting in inaccurate coverage reports.`,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc,
|
|
message: null,
|
|
}));
|
|
};
|
|
const reportWrongNodeType = (loc, expectedType, actualTypes) => {
|
|
env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Important source location has wrong node type in generated code',
|
|
description: `Source location for ${expectedType} exists in the generated output but with wrong node type(s): ${Array.from(actualTypes).join(', ')}. ` +
|
|
`This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports.`,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc,
|
|
message: null,
|
|
}));
|
|
};
|
|
for (const [key, { loc, nodeTypes }] of importantOriginalLocations) {
|
|
const generatedNodeTypes = generatedLocations.get(key);
|
|
if (!generatedNodeTypes) {
|
|
reportMissingLocation(loc, Array.from(nodeTypes).join(', '));
|
|
}
|
|
else {
|
|
for (const nodeType of nodeTypes) {
|
|
if (strictNodeTypes.has(nodeType) &&
|
|
!generatedNodeTypes.has(nodeType)) {
|
|
const hasValidNodeType = Array.from(generatedNodeTypes).some(genType => nodeTypes.has(genType));
|
|
if (hasValidNodeType) {
|
|
reportMissingLocation(loc, nodeType);
|
|
}
|
|
else {
|
|
reportWrongNodeType(loc, nodeType, generatedNodeTypes);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function validateUseMemo(fn) {
|
|
const voidMemoErrors = new CompilerError();
|
|
const useMemos = new Set();
|
|
const react = new Set();
|
|
const functions = new Map();
|
|
const unusedUseMemos = new Map();
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const { lvalue, value } of block.instructions) {
|
|
if (unusedUseMemos.size !== 0) {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
unusedUseMemos.delete(operand.identifier.id);
|
|
}
|
|
}
|
|
switch (value.kind) {
|
|
case 'LoadGlobal': {
|
|
if (value.binding.name === 'useMemo') {
|
|
useMemos.add(lvalue.identifier.id);
|
|
}
|
|
else if (value.binding.name === 'React') {
|
|
react.add(lvalue.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
if (react.has(value.object.identifier.id)) {
|
|
if (value.property === 'useMemo') {
|
|
useMemos.add(lvalue.identifier.id);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'FunctionExpression': {
|
|
functions.set(lvalue.identifier.id, value);
|
|
break;
|
|
}
|
|
case 'MethodCall':
|
|
case 'CallExpression': {
|
|
const callee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
const isUseMemo = useMemos.has(callee.identifier.id);
|
|
if (!isUseMemo || value.args.length === 0) {
|
|
continue;
|
|
}
|
|
const [arg] = value.args;
|
|
if (arg.kind !== 'Identifier') {
|
|
continue;
|
|
}
|
|
const body = functions.get(arg.identifier.id);
|
|
if (body === undefined) {
|
|
continue;
|
|
}
|
|
if (body.loweredFunc.func.params.length > 0) {
|
|
const firstParam = body.loweredFunc.func.params[0];
|
|
const loc = firstParam.kind === 'Identifier'
|
|
? firstParam.loc
|
|
: firstParam.place.loc;
|
|
fn.env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.UseMemo,
|
|
reason: 'useMemo() callbacks may not accept parameters',
|
|
description: 'useMemo() callbacks are called by React to cache calculations across re-renders. They should not take parameters. Instead, directly reference the props, state, or local variables needed for the computation',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc,
|
|
message: 'Callbacks with parameters are not supported',
|
|
}));
|
|
}
|
|
if (body.loweredFunc.func.async || body.loweredFunc.func.generator) {
|
|
fn.env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.UseMemo,
|
|
reason: 'useMemo() callbacks may not be async or generator functions',
|
|
description: 'useMemo() callbacks are called once and must synchronously return a value',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: body.loc,
|
|
message: 'Async and generator functions are not supported',
|
|
}));
|
|
}
|
|
validateNoContextVariableAssignment(body.loweredFunc.func, fn.env);
|
|
if (fn.env.config.validateNoVoidUseMemo) {
|
|
if (!hasNonVoidReturn(body.loweredFunc.func)) {
|
|
voidMemoErrors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.VoidUseMemo,
|
|
reason: 'useMemo() callbacks must return a value',
|
|
description: `This useMemo() callback doesn't return a value. useMemo() is for computing and caching values, not for arbitrary side effects`,
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: body.loc,
|
|
message: 'useMemo() callbacks must return a value',
|
|
}));
|
|
}
|
|
else {
|
|
unusedUseMemos.set(lvalue.identifier.id, callee.loc);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (unusedUseMemos.size !== 0) {
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
unusedUseMemos.delete(operand.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
if (unusedUseMemos.size !== 0) {
|
|
for (const loc of unusedUseMemos.values()) {
|
|
voidMemoErrors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.VoidUseMemo,
|
|
reason: 'useMemo() result is unused',
|
|
description: `This useMemo() value is unused. useMemo() is for computing and caching values, not for arbitrary side effects`,
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc,
|
|
message: 'useMemo() result is unused',
|
|
}));
|
|
}
|
|
}
|
|
fn.env.logErrors(voidMemoErrors.asResult());
|
|
}
|
|
function validateNoContextVariableAssignment(fn, env) {
|
|
const context = new Set(fn.context.map(place => place.identifier.id));
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
const value = instr.value;
|
|
switch (value.kind) {
|
|
case 'StoreContext': {
|
|
if (context.has(value.lvalue.place.identifier.id)) {
|
|
env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.UseMemo,
|
|
reason: 'useMemo() callbacks may not reassign variables declared outside of the callback',
|
|
description: 'useMemo() callbacks must be pure functions and cannot reassign variables defined outside of the callback function',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: value.lvalue.place.loc,
|
|
message: 'Cannot reassign variable',
|
|
}));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function hasNonVoidReturn(func) {
|
|
for (const [, block] of func.body.blocks) {
|
|
if (block.terminal.kind === 'return') {
|
|
if (block.terminal.returnVariant === 'Explicit' ||
|
|
block.terminal.returnVariant === 'Implicit') {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function validateLocalsNotReassignedAfterRender(fn) {
|
|
const contextVariables = new Set();
|
|
const reassignment = getContextReassignment(fn, contextVariables, false, false, fn.env);
|
|
if (reassignment !== null) {
|
|
const variable = reassignment.identifier.name != null &&
|
|
reassignment.identifier.name.kind === 'named'
|
|
? `\`${reassignment.identifier.name.value}\``
|
|
: 'variable';
|
|
fn.env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Immutability,
|
|
reason: 'Cannot reassign variable after render completes',
|
|
description: `Reassigning ${variable} after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead`,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: reassignment.loc,
|
|
message: `Cannot reassign ${variable} after render completes`,
|
|
}));
|
|
}
|
|
}
|
|
function getContextReassignment(fn, contextVariables, isFunctionExpression, isAsync, env) {
|
|
const reassigningFunctions = new Map();
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
switch (value.kind) {
|
|
case 'FunctionExpression':
|
|
case 'ObjectMethod': {
|
|
let reassignment = getContextReassignment(value.loweredFunc.func, contextVariables, true, isAsync || value.loweredFunc.func.async, env);
|
|
if (reassignment === null) {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
const reassignmentFromOperand = reassigningFunctions.get(operand.identifier.id);
|
|
if (reassignmentFromOperand !== undefined) {
|
|
reassignment = reassignmentFromOperand;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (reassignment !== null) {
|
|
if (isAsync || value.loweredFunc.func.async) {
|
|
const variable = reassignment.identifier.name !== null &&
|
|
reassignment.identifier.name.kind === 'named'
|
|
? `\`${reassignment.identifier.name.value}\``
|
|
: 'variable';
|
|
env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Immutability,
|
|
reason: 'Cannot reassign variable in async function',
|
|
description: 'Reassigning a variable in an async function can cause inconsistent behavior on subsequent renders. Consider using state instead',
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: reassignment.loc,
|
|
message: `Cannot reassign ${variable}`,
|
|
}));
|
|
return null;
|
|
}
|
|
reassigningFunctions.set(lvalue.identifier.id, reassignment);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
const reassignment = reassigningFunctions.get(value.value.identifier.id);
|
|
if (reassignment !== undefined) {
|
|
reassigningFunctions.set(value.lvalue.place.identifier.id, reassignment);
|
|
reassigningFunctions.set(lvalue.identifier.id, reassignment);
|
|
}
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
const reassignment = reassigningFunctions.get(value.place.identifier.id);
|
|
if (reassignment !== undefined) {
|
|
reassigningFunctions.set(lvalue.identifier.id, reassignment);
|
|
}
|
|
break;
|
|
}
|
|
case 'DeclareContext': {
|
|
if (!isFunctionExpression) {
|
|
contextVariables.add(value.lvalue.place.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreContext': {
|
|
if (isFunctionExpression) {
|
|
if (contextVariables.has(value.lvalue.place.identifier.id)) {
|
|
return value.lvalue.place;
|
|
}
|
|
}
|
|
else {
|
|
contextVariables.add(value.lvalue.place.identifier.id);
|
|
}
|
|
const reassignment = reassigningFunctions.get(value.value.identifier.id);
|
|
if (reassignment !== undefined) {
|
|
reassigningFunctions.set(value.lvalue.place.identifier.id, reassignment);
|
|
reassigningFunctions.set(lvalue.identifier.id, reassignment);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
let operands = eachInstructionValueOperand(value);
|
|
if (value.kind === 'CallExpression') {
|
|
const signature = getFunctionCallSignature(fn.env, value.callee.identifier.type);
|
|
if (signature === null || signature === void 0 ? void 0 : signature.noAlias) {
|
|
operands = [value.callee];
|
|
}
|
|
}
|
|
else if (value.kind === 'MethodCall') {
|
|
const signature = getFunctionCallSignature(fn.env, value.property.identifier.type);
|
|
if (signature === null || signature === void 0 ? void 0 : signature.noAlias) {
|
|
operands = [value.receiver, value.property];
|
|
}
|
|
}
|
|
else if (value.kind === 'TaggedTemplateExpression') {
|
|
const signature = getFunctionCallSignature(fn.env, value.tag.identifier.type);
|
|
if (signature === null || signature === void 0 ? void 0 : signature.noAlias) {
|
|
operands = [value.tag];
|
|
}
|
|
}
|
|
for (const operand of operands) {
|
|
CompilerError.invariant(operand.effect !== Effect.Unknown, {
|
|
reason: `Expected effects to be inferred prior to ValidateLocalsNotReassignedAfterRender`,
|
|
loc: operand.loc,
|
|
});
|
|
const reassignment = reassigningFunctions.get(operand.identifier.id);
|
|
if (reassignment !== undefined) {
|
|
if (operand.effect === Effect.Freeze) {
|
|
return reassignment;
|
|
}
|
|
else {
|
|
for (const lval of eachInstructionLValue(instr)) {
|
|
reassigningFunctions.set(lval.identifier.id, reassignment);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
const reassignment = reassigningFunctions.get(operand.identifier.id);
|
|
if (reassignment !== undefined) {
|
|
return reassignment;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function outlineFunctions(fn, fbtOperands) {
|
|
var _a;
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
const { value, lvalue } = instr;
|
|
if (value.kind === 'FunctionExpression' ||
|
|
value.kind === 'ObjectMethod') {
|
|
outlineFunctions(value.loweredFunc.func, fbtOperands);
|
|
}
|
|
if (value.kind === 'FunctionExpression' &&
|
|
value.loweredFunc.func.context.length === 0 &&
|
|
value.loweredFunc.func.id === null &&
|
|
!fbtOperands.has(lvalue.identifier.id)) {
|
|
const loweredFunc = value.loweredFunc.func;
|
|
const id = fn.env.generateGloballyUniqueIdentifierName((_a = loweredFunc.id) !== null && _a !== void 0 ? _a : loweredFunc.nameHint);
|
|
loweredFunc.id = id.value;
|
|
fn.env.outlineFunction(loweredFunc, null);
|
|
instr.value = {
|
|
kind: 'LoadGlobal',
|
|
binding: {
|
|
kind: 'Global',
|
|
name: id.value,
|
|
},
|
|
loc: value.loc,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function validateNoSetStateInEffects(fn, env) {
|
|
const setStateFunctions = new Map();
|
|
const errors = new CompilerError();
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
switch (instr.value.kind) {
|
|
case 'LoadLocal': {
|
|
if (setStateFunctions.has(instr.value.place.identifier.id)) {
|
|
setStateFunctions.set(instr.lvalue.identifier.id, instr.value.place);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
if (setStateFunctions.has(instr.value.value.identifier.id)) {
|
|
setStateFunctions.set(instr.value.lvalue.place.identifier.id, instr.value.value);
|
|
setStateFunctions.set(instr.lvalue.identifier.id, instr.value.value);
|
|
}
|
|
break;
|
|
}
|
|
case 'FunctionExpression': {
|
|
if ([...eachInstructionValueOperand(instr.value)].some(operand => isSetStateType(operand.identifier) ||
|
|
setStateFunctions.has(operand.identifier.id))) {
|
|
const callee = getSetStateCall(instr.value.loweredFunc.func, setStateFunctions, env);
|
|
if (callee !== null) {
|
|
setStateFunctions.set(instr.lvalue.identifier.id, callee);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'MethodCall':
|
|
case 'CallExpression': {
|
|
const callee = instr.value.kind === 'MethodCall'
|
|
? instr.value.property
|
|
: instr.value.callee;
|
|
if (isUseEffectEventType(callee.identifier)) {
|
|
const arg = instr.value.args[0];
|
|
if (arg !== undefined && arg.kind === 'Identifier') {
|
|
const setState = setStateFunctions.get(arg.identifier.id);
|
|
if (setState !== undefined) {
|
|
setStateFunctions.set(instr.lvalue.identifier.id, setState);
|
|
}
|
|
}
|
|
}
|
|
else if (isUseEffectHookType(callee.identifier) ||
|
|
isUseLayoutEffectHookType(callee.identifier) ||
|
|
isUseInsertionEffectHookType(callee.identifier)) {
|
|
const arg = instr.value.args[0];
|
|
if (arg !== undefined && arg.kind === 'Identifier') {
|
|
const setState = setStateFunctions.get(arg.identifier.id);
|
|
if (setState !== undefined) {
|
|
const enableVerbose = env.config.enableVerboseNoSetStateInEffect;
|
|
if (enableVerbose) {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.EffectSetState,
|
|
reason: 'Calling setState synchronously within an effect can trigger cascading renders',
|
|
description: 'Effects are intended to synchronize state between React and external systems. ' +
|
|
'Calling setState synchronously causes cascading renders that hurt performance.\n\n' +
|
|
'This pattern may indicate one of several issues:\n\n' +
|
|
'**1. Non-local derived data**: If the value being set could be computed from props/state ' +
|
|
'but requires data from a parent component, consider restructuring state ownership so the ' +
|
|
'derivation can happen during render in the component that owns the relevant state.\n\n' +
|
|
"**2. Derived event pattern**: If you're detecting when a prop changes (e.g., `isPlaying` " +
|
|
'transitioning from false to true), this often indicates the parent should provide an event ' +
|
|
'callback (like `onPlay`) instead of just the current state. Request access to the original event.\n\n' +
|
|
"**3. Force update / external sync**: If you're forcing a re-render to sync with an external " +
|
|
'data source (mutable values outside React), use `useSyncExternalStore` to properly subscribe ' +
|
|
'to external state changes.\n\n' +
|
|
'See: https://react.dev/learn/you-might-not-need-an-effect',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: setState.loc,
|
|
message: 'Avoid calling setState() directly within an effect',
|
|
}));
|
|
}
|
|
else {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.EffectSetState,
|
|
reason: 'Calling setState synchronously within an effect can trigger cascading renders',
|
|
description: 'Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. ' +
|
|
'In general, the body of an effect should do one or both of the following:\n' +
|
|
'* Update external systems with the latest state from React.\n' +
|
|
'* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\n' +
|
|
'Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. ' +
|
|
'(https://react.dev/learn/you-might-not-need-an-effect)',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: setState.loc,
|
|
message: 'Avoid calling setState() directly within an effect',
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return errors.asResult();
|
|
}
|
|
function getSetStateCall(fn, setStateFunctions, env) {
|
|
const enableAllowSetStateFromRefsInEffects = env.config.enableAllowSetStateFromRefsInEffects;
|
|
const refDerivedValues = new Set();
|
|
const isDerivedFromRef = (place) => {
|
|
return (refDerivedValues.has(place.identifier.id) ||
|
|
isUseRefType(place.identifier) ||
|
|
isRefValueType(place.identifier));
|
|
};
|
|
const isRefControlledBlock = enableAllowSetStateFromRefsInEffects
|
|
? createControlDominators(fn, place => isDerivedFromRef(place))
|
|
: () => false;
|
|
for (const [, block] of fn.body.blocks) {
|
|
if (enableAllowSetStateFromRefsInEffects) {
|
|
for (const phi of block.phis) {
|
|
if (isDerivedFromRef(phi.place)) {
|
|
continue;
|
|
}
|
|
let isPhiDerivedFromRef = false;
|
|
for (const [, operand] of phi.operands) {
|
|
if (isDerivedFromRef(operand)) {
|
|
isPhiDerivedFromRef = true;
|
|
break;
|
|
}
|
|
}
|
|
if (isPhiDerivedFromRef) {
|
|
refDerivedValues.add(phi.place.identifier.id);
|
|
}
|
|
else {
|
|
for (const [pred] of phi.operands) {
|
|
if (isRefControlledBlock(pred)) {
|
|
refDerivedValues.add(phi.place.identifier.id);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
if (enableAllowSetStateFromRefsInEffects) {
|
|
const hasRefOperand = Iterable_some(eachInstructionValueOperand(instr.value), isDerivedFromRef);
|
|
if (hasRefOperand) {
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
refDerivedValues.add(lvalue.identifier.id);
|
|
}
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
switch (operand.effect) {
|
|
case Effect.Capture:
|
|
case Effect.Store:
|
|
case Effect.ConditionallyMutate:
|
|
case Effect.ConditionallyMutateIterator:
|
|
case Effect.Mutate: {
|
|
if (isMutable(instr, operand)) {
|
|
refDerivedValues.add(operand.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case Effect.Freeze:
|
|
case Effect.Read: {
|
|
break;
|
|
}
|
|
case Effect.Unknown: {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Unexpected unknown effect',
|
|
loc: operand.loc,
|
|
});
|
|
}
|
|
default: {
|
|
assertExhaustive$1(operand.effect, `Unexpected effect kind \`${operand.effect}\``);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (instr.value.kind === 'PropertyLoad' &&
|
|
instr.value.property === 'current' &&
|
|
(isUseRefType(instr.value.object.identifier) ||
|
|
isRefValueType(instr.value.object.identifier))) {
|
|
refDerivedValues.add(instr.lvalue.identifier.id);
|
|
}
|
|
}
|
|
switch (instr.value.kind) {
|
|
case 'LoadLocal': {
|
|
if (setStateFunctions.has(instr.value.place.identifier.id)) {
|
|
setStateFunctions.set(instr.lvalue.identifier.id, instr.value.place);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
if (setStateFunctions.has(instr.value.value.identifier.id)) {
|
|
setStateFunctions.set(instr.value.lvalue.place.identifier.id, instr.value.value);
|
|
setStateFunctions.set(instr.lvalue.identifier.id, instr.value.value);
|
|
}
|
|
break;
|
|
}
|
|
case 'CallExpression': {
|
|
const callee = instr.value.callee;
|
|
if (isSetStateType(callee.identifier) ||
|
|
setStateFunctions.has(callee.identifier.id)) {
|
|
if (enableAllowSetStateFromRefsInEffects) {
|
|
const arg = instr.value.args.at(0);
|
|
if (arg !== undefined &&
|
|
arg.kind === 'Identifier' &&
|
|
refDerivedValues.has(arg.identifier.id)) {
|
|
return null;
|
|
}
|
|
else if (isRefControlledBlock(block.id)) {
|
|
continue;
|
|
}
|
|
}
|
|
return callee;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function validateNoJSXInTryStatement(fn) {
|
|
const activeTryBlocks = [];
|
|
const errors = new CompilerError();
|
|
for (const [, block] of fn.body.blocks) {
|
|
retainWhere(activeTryBlocks, id => id !== block.id);
|
|
if (activeTryBlocks.length !== 0) {
|
|
for (const instr of block.instructions) {
|
|
const { value } = instr;
|
|
switch (value.kind) {
|
|
case 'JsxExpression':
|
|
case 'JsxFragment': {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.ErrorBoundaries,
|
|
reason: 'Avoid constructing JSX within try/catch',
|
|
description: `React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)`,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: value.loc,
|
|
message: 'Avoid constructing JSX within try/catch',
|
|
}));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (block.terminal.kind === 'try') {
|
|
activeTryBlocks.push(block.terminal.handler);
|
|
}
|
|
}
|
|
return errors.asResult();
|
|
}
|
|
|
|
function collectHoistablePropertyLoads(fn, temporaries, hoistableFromOptionals) {
|
|
const registry = new PropertyPathRegistry();
|
|
const knownImmutableIdentifiers = new Set();
|
|
if (fn.fnType === 'Component' || fn.fnType === 'Hook') {
|
|
for (const p of fn.params) {
|
|
if (p.kind === 'Identifier') {
|
|
knownImmutableIdentifiers.add(p.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
return collectHoistablePropertyLoadsImpl(fn, {
|
|
temporaries,
|
|
knownImmutableIdentifiers,
|
|
hoistableFromOptionals,
|
|
registry,
|
|
nestedFnImmutableContext: null,
|
|
assumedInvokedFns: getAssumedInvokedFunctions(fn),
|
|
});
|
|
}
|
|
function collectHoistablePropertyLoadsImpl(fn, context) {
|
|
const nodes = collectNonNullsInBlocks(fn, context);
|
|
propagateNonNull(fn, nodes, context.registry);
|
|
return nodes;
|
|
}
|
|
function keyByScopeId(fn, source) {
|
|
const keyedByScopeId = new Map();
|
|
for (const [_, block] of fn.body.blocks) {
|
|
if (block.terminal.kind === 'scope') {
|
|
keyedByScopeId.set(block.terminal.scope.id, source.get(block.terminal.block));
|
|
}
|
|
}
|
|
return keyedByScopeId;
|
|
}
|
|
class PropertyPathRegistry {
|
|
constructor() {
|
|
this.roots = new Map();
|
|
}
|
|
getOrCreateIdentifier(identifier, reactive, loc) {
|
|
let rootNode = this.roots.get(identifier.id);
|
|
if (rootNode === undefined) {
|
|
rootNode = {
|
|
root: identifier.id,
|
|
properties: new Map(),
|
|
optionalProperties: new Map(),
|
|
fullPath: {
|
|
identifier,
|
|
reactive,
|
|
path: [],
|
|
loc,
|
|
},
|
|
hasOptional: false,
|
|
parent: null,
|
|
};
|
|
this.roots.set(identifier.id, rootNode);
|
|
}
|
|
else {
|
|
CompilerError.invariant(reactive === rootNode.fullPath.reactive, {
|
|
reason: '[HoistablePropertyLoads] Found inconsistencies in `reactive` flag when deduping identifier reads within the same scope',
|
|
loc: identifier.loc,
|
|
});
|
|
}
|
|
return rootNode;
|
|
}
|
|
static getOrCreatePropertyEntry(parent, entry) {
|
|
const map = entry.optional ? parent.optionalProperties : parent.properties;
|
|
let child = map.get(entry.property);
|
|
if (child == null) {
|
|
child = {
|
|
properties: new Map(),
|
|
optionalProperties: new Map(),
|
|
parent: parent,
|
|
fullPath: {
|
|
identifier: parent.fullPath.identifier,
|
|
reactive: parent.fullPath.reactive,
|
|
path: parent.fullPath.path.concat(entry),
|
|
loc: entry.loc,
|
|
},
|
|
hasOptional: parent.hasOptional || entry.optional,
|
|
};
|
|
map.set(entry.property, child);
|
|
}
|
|
return child;
|
|
}
|
|
getOrCreateProperty(n) {
|
|
let currNode = this.getOrCreateIdentifier(n.identifier, n.reactive, n.loc);
|
|
if (n.path.length === 0) {
|
|
return currNode;
|
|
}
|
|
for (let i = 0; i < n.path.length - 1; i++) {
|
|
currNode = PropertyPathRegistry.getOrCreatePropertyEntry(currNode, n.path[i]);
|
|
}
|
|
return PropertyPathRegistry.getOrCreatePropertyEntry(currNode, n.path.at(-1));
|
|
}
|
|
}
|
|
function getMaybeNonNullInInstruction(value, context) {
|
|
var _a, _b, _c;
|
|
let path = null;
|
|
if (value.kind === 'PropertyLoad') {
|
|
path = (_a = context.temporaries.get(value.object.identifier.id)) !== null && _a !== void 0 ? _a : {
|
|
identifier: value.object.identifier,
|
|
reactive: value.object.reactive,
|
|
path: [],
|
|
loc: value.loc,
|
|
};
|
|
}
|
|
else if (value.kind === 'Destructure') {
|
|
path = (_b = context.temporaries.get(value.value.identifier.id)) !== null && _b !== void 0 ? _b : null;
|
|
}
|
|
else if (value.kind === 'ComputedLoad') {
|
|
path = (_c = context.temporaries.get(value.object.identifier.id)) !== null && _c !== void 0 ? _c : null;
|
|
}
|
|
return path != null ? context.registry.getOrCreateProperty(path) : null;
|
|
}
|
|
function isImmutableAtInstr(identifier, instr, context) {
|
|
if (context.nestedFnImmutableContext != null) {
|
|
return context.nestedFnImmutableContext.has(identifier.id);
|
|
}
|
|
else {
|
|
const mutableAtInstr = identifier.mutableRange.end > identifier.mutableRange.start + 1 &&
|
|
identifier.scope != null &&
|
|
inRange({
|
|
id: instr,
|
|
}, identifier.scope.range);
|
|
return (!mutableAtInstr || context.knownImmutableIdentifiers.has(identifier.id));
|
|
}
|
|
}
|
|
function collectNonNullsInBlocks(fn, context) {
|
|
var _a;
|
|
const knownNonNullIdentifiers = new Set();
|
|
if (fn.fnType === 'Component' &&
|
|
fn.params.length > 0 &&
|
|
fn.params[0].kind === 'Identifier') {
|
|
const identifier = fn.params[0].identifier;
|
|
knownNonNullIdentifiers.add(context.registry.getOrCreateIdentifier(identifier, true, fn.params[0].loc));
|
|
}
|
|
const nodes = new Map();
|
|
for (const [_, block] of fn.body.blocks) {
|
|
const assumedNonNullObjects = new Set(knownNonNullIdentifiers);
|
|
const maybeOptionalChain = context.hoistableFromOptionals.get(block.id);
|
|
if (maybeOptionalChain != null) {
|
|
assumedNonNullObjects.add(context.registry.getOrCreateProperty(maybeOptionalChain));
|
|
}
|
|
for (const instr of block.instructions) {
|
|
const maybeNonNull = getMaybeNonNullInInstruction(instr.value, context);
|
|
if (maybeNonNull != null &&
|
|
isImmutableAtInstr(maybeNonNull.fullPath.identifier, instr.id, context)) {
|
|
assumedNonNullObjects.add(maybeNonNull);
|
|
}
|
|
if (instr.value.kind === 'FunctionExpression') {
|
|
const innerFn = instr.value.loweredFunc;
|
|
if (context.assumedInvokedFns.has(innerFn)) {
|
|
const innerHoistableMap = collectHoistablePropertyLoadsImpl(innerFn.func, Object.assign(Object.assign({}, context), { nestedFnImmutableContext: (_a = context.nestedFnImmutableContext) !== null && _a !== void 0 ? _a : new Set(innerFn.func.context
|
|
.filter(place => isImmutableAtInstr(place.identifier, instr.id, context))
|
|
.map(place => place.identifier.id)) }));
|
|
const innerHoistables = assertNonNull(innerHoistableMap.get(innerFn.func.body.entry));
|
|
for (const entry of innerHoistables.assumedNonNullObjects) {
|
|
assumedNonNullObjects.add(entry);
|
|
}
|
|
}
|
|
}
|
|
else if (fn.env.config.enablePreserveExistingMemoizationGuarantees &&
|
|
instr.value.kind === 'StartMemoize' &&
|
|
instr.value.deps != null) {
|
|
for (const dep of instr.value.deps) {
|
|
if (dep.root.kind === 'NamedLocal') {
|
|
if (!isImmutableAtInstr(dep.root.value.identifier, instr.id, context)) {
|
|
continue;
|
|
}
|
|
for (let i = 0; i < dep.path.length; i++) {
|
|
const pathEntry = dep.path[i];
|
|
if (pathEntry.optional) {
|
|
break;
|
|
}
|
|
const depNode = context.registry.getOrCreateProperty({
|
|
identifier: dep.root.value.identifier,
|
|
path: dep.path.slice(0, i),
|
|
reactive: dep.root.value.reactive,
|
|
loc: dep.loc,
|
|
});
|
|
assumedNonNullObjects.add(depNode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
nodes.set(block.id, {
|
|
block,
|
|
assumedNonNullObjects,
|
|
});
|
|
}
|
|
return nodes;
|
|
}
|
|
function propagateNonNull(fn, nodes, registry) {
|
|
const blockSuccessors = new Map();
|
|
const terminalPreds = new Set();
|
|
for (const [blockId, block] of fn.body.blocks) {
|
|
for (const pred of block.preds) {
|
|
getOrInsertDefault(blockSuccessors, pred, new Set()).add(blockId);
|
|
}
|
|
if (block.terminal.kind === 'throw' || block.terminal.kind === 'return') {
|
|
terminalPreds.add(blockId);
|
|
}
|
|
}
|
|
function recursivelyPropagateNonNull(nodeId, direction, traversalState) {
|
|
var _a;
|
|
if (traversalState.has(nodeId)) {
|
|
return false;
|
|
}
|
|
traversalState.set(nodeId, 'active');
|
|
const node = nodes.get(nodeId);
|
|
if (node == null) {
|
|
CompilerError.invariant(false, {
|
|
reason: `Bad node ${nodeId}, kind: ${direction}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
const neighbors = Array.from(direction === 'backward'
|
|
? ((_a = blockSuccessors.get(nodeId)) !== null && _a !== void 0 ? _a : [])
|
|
: node.block.preds);
|
|
let changed = false;
|
|
for (const pred of neighbors) {
|
|
if (!traversalState.has(pred)) {
|
|
const neighborChanged = recursivelyPropagateNonNull(pred, direction, traversalState);
|
|
changed || (changed = neighborChanged);
|
|
}
|
|
}
|
|
const neighborAccesses = Set_intersect(Array.from(neighbors)
|
|
.filter(n => traversalState.get(n) === 'done')
|
|
.map(n => assertNonNull(nodes.get(n)).assumedNonNullObjects));
|
|
const prevObjects = assertNonNull(nodes.get(nodeId)).assumedNonNullObjects;
|
|
const mergedObjects = Set_union(prevObjects, neighborAccesses);
|
|
reduceMaybeOptionalChains(mergedObjects, registry);
|
|
assertNonNull(nodes.get(nodeId)).assumedNonNullObjects = mergedObjects;
|
|
traversalState.set(nodeId, 'done');
|
|
changed || (changed = !Set_equal(prevObjects, mergedObjects));
|
|
return changed;
|
|
}
|
|
const traversalState = new Map();
|
|
const reversedBlocks = [...fn.body.blocks];
|
|
reversedBlocks.reverse();
|
|
let changed;
|
|
let i = 0;
|
|
do {
|
|
CompilerError.invariant(i++ < 100, {
|
|
reason: '[CollectHoistablePropertyLoads] fixed point iteration did not terminate after 100 loops',
|
|
loc: GeneratedSource,
|
|
});
|
|
changed = false;
|
|
for (const [blockId] of fn.body.blocks) {
|
|
const forwardChanged = recursivelyPropagateNonNull(blockId, 'forward', traversalState);
|
|
changed || (changed = forwardChanged);
|
|
}
|
|
traversalState.clear();
|
|
for (const [blockId] of reversedBlocks) {
|
|
const backwardChanged = recursivelyPropagateNonNull(blockId, 'backward', traversalState);
|
|
changed || (changed = backwardChanged);
|
|
}
|
|
traversalState.clear();
|
|
} while (changed);
|
|
}
|
|
function assertNonNull(value, source) {
|
|
CompilerError.invariant(value != null, {
|
|
reason: 'Unexpected null',
|
|
description: source != null ? `(from ${source})` : null,
|
|
loc: GeneratedSource,
|
|
});
|
|
return value;
|
|
}
|
|
function reduceMaybeOptionalChains(nodes, registry) {
|
|
let optionalChainNodes = Set_filter(nodes, n => n.hasOptional);
|
|
if (optionalChainNodes.size === 0) {
|
|
return;
|
|
}
|
|
let changed;
|
|
do {
|
|
changed = false;
|
|
for (const original of optionalChainNodes) {
|
|
let { identifier, path: origPath, reactive, loc: origLoc, } = original.fullPath;
|
|
let currNode = registry.getOrCreateIdentifier(identifier, reactive, origLoc);
|
|
for (let i = 0; i < origPath.length; i++) {
|
|
const entry = origPath[i];
|
|
const nextEntry = entry.optional && nodes.has(currNode)
|
|
? { property: entry.property, optional: false, loc: entry.loc }
|
|
: entry;
|
|
currNode = PropertyPathRegistry.getOrCreatePropertyEntry(currNode, nextEntry);
|
|
}
|
|
if (currNode !== original) {
|
|
changed = true;
|
|
optionalChainNodes.delete(original);
|
|
optionalChainNodes.add(currNode);
|
|
nodes.delete(original);
|
|
nodes.add(currNode);
|
|
}
|
|
}
|
|
} while (changed);
|
|
}
|
|
function getAssumedInvokedFunctions(fn, temporaries = new Map()) {
|
|
var _a;
|
|
const hoistableFunctions = new Set();
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const { lvalue, value } of block.instructions) {
|
|
if (value.kind === 'FunctionExpression') {
|
|
temporaries.set(lvalue.identifier.id, {
|
|
fn: value.loweredFunc,
|
|
mayInvoke: new Set(),
|
|
});
|
|
}
|
|
else if (value.kind === 'StoreLocal') {
|
|
const lvalue = value.lvalue.place.identifier;
|
|
const maybeLoweredFunc = temporaries.get(value.value.identifier.id);
|
|
if (maybeLoweredFunc != null) {
|
|
temporaries.set(lvalue.id, maybeLoweredFunc);
|
|
}
|
|
}
|
|
else if (value.kind === 'LoadLocal') {
|
|
const maybeLoweredFunc = temporaries.get(value.place.identifier.id);
|
|
if (maybeLoweredFunc != null) {
|
|
temporaries.set(lvalue.identifier.id, maybeLoweredFunc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const { lvalue, value } of block.instructions) {
|
|
if (value.kind === 'CallExpression') {
|
|
const callee = value.callee;
|
|
const maybeHook = getHookKind(fn.env, callee.identifier);
|
|
const maybeLoweredFunc = temporaries.get(callee.identifier.id);
|
|
if (maybeLoweredFunc != null) {
|
|
hoistableFunctions.add(maybeLoweredFunc.fn);
|
|
}
|
|
else if (maybeHook != null) {
|
|
for (const arg of value.args) {
|
|
if (arg.kind === 'Identifier') {
|
|
const maybeLoweredFunc = temporaries.get(arg.identifier.id);
|
|
if (maybeLoweredFunc != null) {
|
|
hoistableFunctions.add(maybeLoweredFunc.fn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (value.kind === 'JsxExpression') {
|
|
for (const attr of value.props) {
|
|
if (attr.kind === 'JsxSpreadAttribute') {
|
|
continue;
|
|
}
|
|
const maybeLoweredFunc = temporaries.get(attr.place.identifier.id);
|
|
if (maybeLoweredFunc != null) {
|
|
hoistableFunctions.add(maybeLoweredFunc.fn);
|
|
}
|
|
}
|
|
for (const child of (_a = value.children) !== null && _a !== void 0 ? _a : []) {
|
|
const maybeLoweredFunc = temporaries.get(child.identifier.id);
|
|
if (maybeLoweredFunc != null) {
|
|
hoistableFunctions.add(maybeLoweredFunc.fn);
|
|
}
|
|
}
|
|
}
|
|
else if (value.kind === 'FunctionExpression') {
|
|
const loweredFunc = value.loweredFunc.func;
|
|
const lambdasCalled = getAssumedInvokedFunctions(loweredFunc, temporaries);
|
|
const maybeLoweredFunc = temporaries.get(lvalue.identifier.id);
|
|
if (maybeLoweredFunc != null) {
|
|
for (const called of lambdasCalled) {
|
|
maybeLoweredFunc.mayInvoke.add(called);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (block.terminal.kind === 'return') {
|
|
const maybeLoweredFunc = temporaries.get(block.terminal.value.identifier.id);
|
|
if (maybeLoweredFunc != null) {
|
|
hoistableFunctions.add(maybeLoweredFunc.fn);
|
|
}
|
|
}
|
|
}
|
|
for (const [_, { fn, mayInvoke }] of temporaries) {
|
|
if (hoistableFunctions.has(fn)) {
|
|
for (const called of mayInvoke) {
|
|
hoistableFunctions.add(called);
|
|
}
|
|
}
|
|
}
|
|
return hoistableFunctions;
|
|
}
|
|
|
|
var _a, _ReactiveScopeDependencyTreeHIR_hoistableObjects, _ReactiveScopeDependencyTreeHIR_deps, _ReactiveScopeDependencyTreeHIR_getOrCreateRoot, _ReactiveScopeDependencyTreeHIR_debugImpl;
|
|
class ReactiveScopeDependencyTreeHIR {
|
|
constructor(hoistableObjects) {
|
|
var _b;
|
|
_ReactiveScopeDependencyTreeHIR_hoistableObjects.set(this, new Map());
|
|
_ReactiveScopeDependencyTreeHIR_deps.set(this, new Map());
|
|
for (const { path, identifier, reactive, loc } of hoistableObjects) {
|
|
let currNode = __classPrivateFieldGet(_a, _a, "m", _ReactiveScopeDependencyTreeHIR_getOrCreateRoot).call(_a, identifier, reactive, __classPrivateFieldGet(this, _ReactiveScopeDependencyTreeHIR_hoistableObjects, "f"), path.length > 0 && path[0].optional ? 'Optional' : 'NonNull', loc);
|
|
for (let i = 0; i < path.length; i++) {
|
|
const prevAccessType = (_b = currNode.properties.get(path[i].property)) === null || _b === void 0 ? void 0 : _b.accessType;
|
|
const accessType = i + 1 < path.length && path[i + 1].optional ? 'Optional' : 'NonNull';
|
|
CompilerError.invariant(prevAccessType == null || prevAccessType === accessType, {
|
|
reason: 'Conflicting access types',
|
|
loc: GeneratedSource,
|
|
});
|
|
let nextNode = currNode.properties.get(path[i].property);
|
|
if (nextNode == null) {
|
|
nextNode = {
|
|
properties: new Map(),
|
|
accessType,
|
|
loc: path[i].loc,
|
|
};
|
|
currNode.properties.set(path[i].property, nextNode);
|
|
}
|
|
currNode = nextNode;
|
|
}
|
|
}
|
|
}
|
|
addDependency(dep) {
|
|
const { identifier, reactive, path, loc } = dep;
|
|
let depCursor = __classPrivateFieldGet(_a, _a, "m", _ReactiveScopeDependencyTreeHIR_getOrCreateRoot).call(_a, identifier, reactive, __classPrivateFieldGet(this, _ReactiveScopeDependencyTreeHIR_deps, "f"), PropertyAccessType.UnconditionalAccess, loc);
|
|
let hoistableCursor = __classPrivateFieldGet(this, _ReactiveScopeDependencyTreeHIR_hoistableObjects, "f").get(identifier);
|
|
for (const entry of path) {
|
|
let nextHoistableCursor;
|
|
let nextDepCursor;
|
|
if (entry.optional) {
|
|
if (hoistableCursor != null) {
|
|
nextHoistableCursor = hoistableCursor === null || hoistableCursor === void 0 ? void 0 : hoistableCursor.properties.get(entry.property);
|
|
}
|
|
let accessType;
|
|
if (hoistableCursor != null &&
|
|
hoistableCursor.accessType === 'NonNull') {
|
|
accessType = PropertyAccessType.UnconditionalAccess;
|
|
}
|
|
else {
|
|
accessType = PropertyAccessType.OptionalAccess;
|
|
}
|
|
nextDepCursor = makeOrMergeProperty(depCursor, entry.property, accessType, entry.loc);
|
|
}
|
|
else if (hoistableCursor != null &&
|
|
hoistableCursor.accessType === 'NonNull') {
|
|
nextHoistableCursor = hoistableCursor.properties.get(entry.property);
|
|
nextDepCursor = makeOrMergeProperty(depCursor, entry.property, PropertyAccessType.UnconditionalAccess, entry.loc);
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
depCursor = nextDepCursor;
|
|
hoistableCursor = nextHoistableCursor;
|
|
}
|
|
depCursor.accessType = merge(depCursor.accessType, PropertyAccessType.OptionalDependency);
|
|
}
|
|
deriveMinimalDependencies() {
|
|
const results = new Set();
|
|
for (const [rootId, rootNode] of __classPrivateFieldGet(this, _ReactiveScopeDependencyTreeHIR_deps, "f").entries()) {
|
|
collectMinimalDependenciesInSubtree(rootNode, rootNode.reactive, rootId, [], results);
|
|
}
|
|
return results;
|
|
}
|
|
printDeps(includeAccesses) {
|
|
let res = [];
|
|
for (const [rootId, rootNode] of __classPrivateFieldGet(this, _ReactiveScopeDependencyTreeHIR_deps, "f").entries()) {
|
|
const rootResults = printSubtree(rootNode, includeAccesses).map(result => `${printIdentifier(rootId)}.${result}`);
|
|
res.push(rootResults);
|
|
}
|
|
return res.flat().join('\n');
|
|
}
|
|
static debug(roots) {
|
|
const buf = [`tree() [`];
|
|
for (const [rootId, rootNode] of roots) {
|
|
buf.push(`${printIdentifier(rootId)} (${rootNode.accessType}):`);
|
|
__classPrivateFieldGet(this, _a, "m", _ReactiveScopeDependencyTreeHIR_debugImpl).call(this, buf, rootNode, 1);
|
|
}
|
|
buf.push(']');
|
|
return buf.length > 2 ? buf.join('\n') : buf.join('');
|
|
}
|
|
}
|
|
_a = ReactiveScopeDependencyTreeHIR, _ReactiveScopeDependencyTreeHIR_hoistableObjects = new WeakMap(), _ReactiveScopeDependencyTreeHIR_deps = new WeakMap(), _ReactiveScopeDependencyTreeHIR_getOrCreateRoot = function _ReactiveScopeDependencyTreeHIR_getOrCreateRoot(identifier, reactive, roots, defaultAccessType, loc) {
|
|
let rootNode = roots.get(identifier);
|
|
if (rootNode === undefined) {
|
|
rootNode = {
|
|
properties: new Map(),
|
|
reactive,
|
|
accessType: defaultAccessType,
|
|
loc,
|
|
};
|
|
roots.set(identifier, rootNode);
|
|
}
|
|
else {
|
|
CompilerError.invariant(reactive === rootNode.reactive, {
|
|
reason: '[DeriveMinimalDependenciesHIR] Conflicting reactive root flag',
|
|
description: `Identifier ${printIdentifier(identifier)}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
return rootNode;
|
|
}, _ReactiveScopeDependencyTreeHIR_debugImpl = function _ReactiveScopeDependencyTreeHIR_debugImpl(buf, node, depth = 0) {
|
|
for (const [property, childNode] of node.properties) {
|
|
buf.push(`${' '.repeat(depth)}.${property} (${childNode.accessType}):`);
|
|
__classPrivateFieldGet(this, _a, "m", _ReactiveScopeDependencyTreeHIR_debugImpl).call(this, buf, childNode, depth + 1);
|
|
}
|
|
};
|
|
var PropertyAccessType;
|
|
(function (PropertyAccessType) {
|
|
PropertyAccessType["OptionalAccess"] = "OptionalAccess";
|
|
PropertyAccessType["UnconditionalAccess"] = "UnconditionalAccess";
|
|
PropertyAccessType["OptionalDependency"] = "OptionalDependency";
|
|
PropertyAccessType["UnconditionalDependency"] = "UnconditionalDependency";
|
|
})(PropertyAccessType || (PropertyAccessType = {}));
|
|
function isOptional(access) {
|
|
return (access === PropertyAccessType.OptionalAccess ||
|
|
access === PropertyAccessType.OptionalDependency);
|
|
}
|
|
function isDependency(access) {
|
|
return (access === PropertyAccessType.OptionalDependency ||
|
|
access === PropertyAccessType.UnconditionalDependency);
|
|
}
|
|
function merge(access1, access2) {
|
|
const resultIsUnconditional = !(isOptional(access1) && isOptional(access2));
|
|
const resultIsDependency = isDependency(access1) || isDependency(access2);
|
|
if (resultIsUnconditional) {
|
|
if (resultIsDependency) {
|
|
return PropertyAccessType.UnconditionalDependency;
|
|
}
|
|
else {
|
|
return PropertyAccessType.UnconditionalAccess;
|
|
}
|
|
}
|
|
else {
|
|
if (resultIsDependency) {
|
|
return PropertyAccessType.OptionalDependency;
|
|
}
|
|
else {
|
|
return PropertyAccessType.OptionalAccess;
|
|
}
|
|
}
|
|
}
|
|
function collectMinimalDependenciesInSubtree(node, reactive, rootIdentifier, path, results) {
|
|
if (isDependency(node.accessType)) {
|
|
results.add({ identifier: rootIdentifier, reactive, path, loc: node.loc });
|
|
}
|
|
else {
|
|
for (const [childName, childNode] of node.properties) {
|
|
collectMinimalDependenciesInSubtree(childNode, reactive, rootIdentifier, [
|
|
...path,
|
|
{
|
|
property: childName,
|
|
optional: isOptional(childNode.accessType),
|
|
loc: childNode.loc,
|
|
},
|
|
], results);
|
|
}
|
|
}
|
|
}
|
|
function printSubtree(node, includeAccesses) {
|
|
const results = [];
|
|
for (const [propertyName, propertyNode] of node.properties) {
|
|
if (includeAccesses || isDependency(propertyNode.accessType)) {
|
|
results.push(`${propertyName} (${propertyNode.accessType})`);
|
|
}
|
|
const propertyResults = printSubtree(propertyNode, includeAccesses);
|
|
results.push(...propertyResults.map(result => `${propertyName}.${result}`));
|
|
}
|
|
return results;
|
|
}
|
|
function makeOrMergeProperty(node, property, accessType, loc) {
|
|
let child = node.properties.get(property);
|
|
if (child == null) {
|
|
child = {
|
|
properties: new Map(),
|
|
accessType,
|
|
loc,
|
|
};
|
|
node.properties.set(property, child);
|
|
}
|
|
else {
|
|
child.accessType = merge(child.accessType, accessType);
|
|
}
|
|
return child;
|
|
}
|
|
|
|
function collectOptionalChainSidemap(fn) {
|
|
const context = {
|
|
currFn: fn,
|
|
blocks: fn.body.blocks,
|
|
seenOptionals: new Set(),
|
|
processedInstrsInOptional: new Set(),
|
|
temporariesReadInOptional: new Map(),
|
|
hoistableObjects: new Map(),
|
|
};
|
|
traverseFunction(fn, context);
|
|
return {
|
|
temporariesReadInOptional: context.temporariesReadInOptional,
|
|
processedInstrsInOptional: context.processedInstrsInOptional,
|
|
hoistableObjects: context.hoistableObjects,
|
|
};
|
|
}
|
|
function traverseFunction(fn, context) {
|
|
for (const [_, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
if (instr.value.kind === 'FunctionExpression' ||
|
|
instr.value.kind === 'ObjectMethod') {
|
|
traverseFunction(instr.value.loweredFunc.func, Object.assign(Object.assign({}, context), { currFn: instr.value.loweredFunc.func, blocks: instr.value.loweredFunc.func.body.blocks }));
|
|
}
|
|
}
|
|
if (block.terminal.kind === 'optional' &&
|
|
!context.seenOptionals.has(block.id)) {
|
|
traverseOptionalBlock(block, context, null);
|
|
}
|
|
}
|
|
}
|
|
function matchOptionalTestBlock(terminal, blocks) {
|
|
const consequentBlock = assertNonNull(blocks.get(terminal.consequent));
|
|
if (consequentBlock.instructions.length === 2 &&
|
|
consequentBlock.instructions[0].value.kind === 'PropertyLoad' &&
|
|
consequentBlock.instructions[1].value.kind === 'StoreLocal') {
|
|
const propertyLoad = consequentBlock
|
|
.instructions[0];
|
|
const storeLocal = consequentBlock.instructions[1].value;
|
|
const storeLocalInstr = consequentBlock.instructions[1];
|
|
CompilerError.invariant(propertyLoad.value.object.identifier.id === terminal.test.identifier.id, {
|
|
reason: '[OptionalChainDeps] Inconsistent optional chaining property load',
|
|
description: `Test=${printIdentifier(terminal.test.identifier)} PropertyLoad base=${printIdentifier(propertyLoad.value.object.identifier)}`,
|
|
loc: propertyLoad.loc,
|
|
});
|
|
CompilerError.invariant(storeLocal.value.identifier.id === propertyLoad.lvalue.identifier.id, {
|
|
reason: '[OptionalChainDeps] Unexpected storeLocal',
|
|
loc: propertyLoad.loc,
|
|
});
|
|
if (consequentBlock.terminal.kind !== 'goto' ||
|
|
consequentBlock.terminal.variant !== GotoVariant.Break) {
|
|
return null;
|
|
}
|
|
const alternate = assertNonNull(blocks.get(terminal.alternate));
|
|
CompilerError.invariant(alternate.instructions.length === 2 &&
|
|
alternate.instructions[0].value.kind === 'Primitive' &&
|
|
alternate.instructions[1].value.kind === 'StoreLocal', {
|
|
reason: 'Unexpected alternate structure',
|
|
loc: terminal.loc,
|
|
});
|
|
return {
|
|
consequentId: storeLocal.lvalue.place.identifier.id,
|
|
property: propertyLoad.value.property,
|
|
propertyId: propertyLoad.lvalue.identifier.id,
|
|
storeLocalInstr,
|
|
consequentGoto: consequentBlock.terminal.block,
|
|
propertyLoadLoc: propertyLoad.loc,
|
|
};
|
|
}
|
|
return null;
|
|
}
|
|
function traverseOptionalBlock(optional, context, outerAlternate) {
|
|
context.seenOptionals.add(optional.id);
|
|
const maybeTest = context.blocks.get(optional.terminal.test);
|
|
let test;
|
|
let baseObject;
|
|
if (maybeTest.terminal.kind === 'branch') {
|
|
CompilerError.invariant(optional.terminal.optional, {
|
|
reason: '[OptionalChainDeps] Expect base case to be always optional',
|
|
loc: optional.terminal.loc,
|
|
});
|
|
if (maybeTest.instructions.length === 0 ||
|
|
maybeTest.instructions[0].value.kind !== 'LoadLocal') {
|
|
return null;
|
|
}
|
|
const path = [];
|
|
for (let i = 1; i < maybeTest.instructions.length; i++) {
|
|
const instrVal = maybeTest.instructions[i].value;
|
|
const prevInstr = maybeTest.instructions[i - 1];
|
|
if (instrVal.kind === 'PropertyLoad' &&
|
|
instrVal.object.identifier.id === prevInstr.lvalue.identifier.id) {
|
|
path.push({
|
|
property: instrVal.property,
|
|
optional: false,
|
|
loc: instrVal.loc,
|
|
});
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
CompilerError.invariant(maybeTest.terminal.test.identifier.id ===
|
|
maybeTest.instructions.at(-1).lvalue.identifier.id, {
|
|
reason: '[OptionalChainDeps] Unexpected test expression',
|
|
loc: maybeTest.terminal.loc,
|
|
});
|
|
baseObject = {
|
|
identifier: maybeTest.instructions[0].value.place.identifier,
|
|
reactive: maybeTest.instructions[0].value.place.reactive,
|
|
path,
|
|
loc: maybeTest.instructions[0].value.place.loc,
|
|
};
|
|
test = maybeTest.terminal;
|
|
}
|
|
else if (maybeTest.terminal.kind === 'optional') {
|
|
const testBlock = context.blocks.get(maybeTest.terminal.fallthrough);
|
|
if (testBlock.terminal.kind !== 'branch') {
|
|
return null;
|
|
}
|
|
const innerOptional = traverseOptionalBlock(maybeTest, context, testBlock.terminal.alternate);
|
|
if (innerOptional == null) {
|
|
return null;
|
|
}
|
|
if (testBlock.terminal.test.identifier.id !== innerOptional) {
|
|
return null;
|
|
}
|
|
if (!optional.terminal.optional) {
|
|
context.hoistableObjects.set(optional.id, assertNonNull(context.temporariesReadInOptional.get(innerOptional)));
|
|
}
|
|
baseObject = assertNonNull(context.temporariesReadInOptional.get(innerOptional));
|
|
test = testBlock.terminal;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
if (test.alternate === outerAlternate) {
|
|
CompilerError.invariant(optional.instructions.length === 0, {
|
|
reason: '[OptionalChainDeps] Unexpected instructions an inner optional block. ' +
|
|
'This indicates that the compiler may be incorrectly concatenating two unrelated optional chains',
|
|
loc: optional.terminal.loc,
|
|
});
|
|
}
|
|
const matchConsequentResult = matchOptionalTestBlock(test, context.blocks);
|
|
if (!matchConsequentResult) {
|
|
return null;
|
|
}
|
|
CompilerError.invariant(matchConsequentResult.consequentGoto === optional.terminal.fallthrough, {
|
|
reason: '[OptionalChainDeps] Unexpected optional goto-fallthrough',
|
|
description: `${matchConsequentResult.consequentGoto} != ${optional.terminal.fallthrough}`,
|
|
loc: optional.terminal.loc,
|
|
});
|
|
const load = {
|
|
identifier: baseObject.identifier,
|
|
reactive: baseObject.reactive,
|
|
path: [
|
|
...baseObject.path,
|
|
{
|
|
property: matchConsequentResult.property,
|
|
optional: optional.terminal.optional,
|
|
loc: matchConsequentResult.propertyLoadLoc,
|
|
},
|
|
],
|
|
loc: matchConsequentResult.propertyLoadLoc,
|
|
};
|
|
context.processedInstrsInOptional.add(matchConsequentResult.storeLocalInstr);
|
|
context.processedInstrsInOptional.add(test);
|
|
context.temporariesReadInOptional.set(matchConsequentResult.consequentId, load);
|
|
context.temporariesReadInOptional.set(matchConsequentResult.propertyId, load);
|
|
return matchConsequentResult.consequentId;
|
|
}
|
|
|
|
var _DependencyCollectionContext_instances, _DependencyCollectionContext_declarations, _DependencyCollectionContext_reassignments, _DependencyCollectionContext_scopes, _DependencyCollectionContext_dependencies, _DependencyCollectionContext_temporaries, _DependencyCollectionContext_temporariesUsedOutsideScope, _DependencyCollectionContext_processedInstrsInOptional, _DependencyCollectionContext_innerFnContext, _DependencyCollectionContext_checkValidDependency, _DependencyCollectionContext_isScopeActive;
|
|
function propagateScopeDependenciesHIR(fn) {
|
|
const usedOutsideDeclaringScope = findTemporariesUsedOutsideDeclaringScope(fn);
|
|
const temporaries = collectTemporariesSidemap(fn, usedOutsideDeclaringScope);
|
|
const { temporariesReadInOptional, processedInstrsInOptional, hoistableObjects, } = collectOptionalChainSidemap(fn);
|
|
const hoistablePropertyLoads = keyByScopeId(fn, collectHoistablePropertyLoads(fn, temporaries, hoistableObjects));
|
|
const scopeDeps = collectDependencies$1(fn, usedOutsideDeclaringScope, new Map([...temporaries, ...temporariesReadInOptional]), processedInstrsInOptional);
|
|
for (const [scope, deps] of scopeDeps) {
|
|
if (deps.length === 0) {
|
|
continue;
|
|
}
|
|
const hoistables = hoistablePropertyLoads.get(scope.id);
|
|
CompilerError.invariant(hoistables != null, {
|
|
reason: '[PropagateScopeDependencies] Scope not found in tracked blocks',
|
|
loc: GeneratedSource,
|
|
});
|
|
const tree = new ReactiveScopeDependencyTreeHIR([...hoistables.assumedNonNullObjects].map(o => o.fullPath));
|
|
for (const dep of deps) {
|
|
tree.addDependency(Object.assign({}, dep));
|
|
}
|
|
const candidates = tree.deriveMinimalDependencies();
|
|
for (const candidateDep of candidates) {
|
|
if (!Iterable_some(scope.dependencies, existingDep => existingDep.identifier.declarationId ===
|
|
candidateDep.identifier.declarationId &&
|
|
areEqualPaths(existingDep.path, candidateDep.path)))
|
|
scope.dependencies.add(candidateDep);
|
|
}
|
|
}
|
|
}
|
|
function findTemporariesUsedOutsideDeclaringScope(fn) {
|
|
const declarations = new Map();
|
|
const prunedScopes = new Set();
|
|
const scopeTraversal = new ScopeBlockTraversal();
|
|
const usedOutsideDeclaringScope = new Set();
|
|
function handlePlace(place) {
|
|
const declaringScope = declarations.get(place.identifier.declarationId);
|
|
if (declaringScope != null &&
|
|
!scopeTraversal.isScopeActive(declaringScope) &&
|
|
!prunedScopes.has(declaringScope)) {
|
|
usedOutsideDeclaringScope.add(place.identifier.declarationId);
|
|
}
|
|
}
|
|
function handleInstruction(instr) {
|
|
const scope = scopeTraversal.currentScope;
|
|
if (scope == null || prunedScopes.has(scope)) {
|
|
return;
|
|
}
|
|
switch (instr.value.kind) {
|
|
case 'LoadLocal':
|
|
case 'LoadContext':
|
|
case 'PropertyLoad': {
|
|
declarations.set(instr.lvalue.identifier.declarationId, scope);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for (const [blockId, block] of fn.body.blocks) {
|
|
scopeTraversal.recordScopes(block);
|
|
const scopeStartInfo = scopeTraversal.blockInfos.get(blockId);
|
|
if ((scopeStartInfo === null || scopeStartInfo === void 0 ? void 0 : scopeStartInfo.kind) === 'begin' && scopeStartInfo.pruned) {
|
|
prunedScopes.add(scopeStartInfo.scope.id);
|
|
}
|
|
for (const instr of block.instructions) {
|
|
for (const place of eachInstructionOperand(instr)) {
|
|
handlePlace(place);
|
|
}
|
|
handleInstruction(instr);
|
|
}
|
|
for (const place of eachTerminalOperand(block.terminal)) {
|
|
handlePlace(place);
|
|
}
|
|
}
|
|
return usedOutsideDeclaringScope;
|
|
}
|
|
function collectTemporariesSidemap(fn, usedOutsideDeclaringScope) {
|
|
const temporaries = new Map();
|
|
collectTemporariesSidemapImpl(fn, usedOutsideDeclaringScope, temporaries, null);
|
|
return temporaries;
|
|
}
|
|
function isLoadContextMutable(instrValue, id) {
|
|
if (instrValue.kind === 'LoadContext') {
|
|
return (instrValue.place.identifier.scope != null &&
|
|
id >= instrValue.place.identifier.scope.range.end);
|
|
}
|
|
return false;
|
|
}
|
|
function collectTemporariesSidemapImpl(fn, usedOutsideDeclaringScope, temporaries, innerFnContext) {
|
|
for (const [_, block] of fn.body.blocks) {
|
|
for (const { value, lvalue, id: origInstrId } of block.instructions) {
|
|
const instrId = innerFnContext != null ? innerFnContext.instrId : origInstrId;
|
|
const usedOutside = usedOutsideDeclaringScope.has(lvalue.identifier.declarationId);
|
|
if (value.kind === 'PropertyLoad' && !usedOutside) {
|
|
if (innerFnContext == null ||
|
|
temporaries.has(value.object.identifier.id)) {
|
|
const property = getProperty(value.object, value.property, false, value.loc, temporaries);
|
|
temporaries.set(lvalue.identifier.id, property);
|
|
}
|
|
}
|
|
else if ((value.kind === 'LoadLocal' || isLoadContextMutable(value, instrId)) &&
|
|
lvalue.identifier.name == null &&
|
|
value.place.identifier.name !== null &&
|
|
!usedOutside) {
|
|
if (innerFnContext == null ||
|
|
fn.context.some(context => context.identifier.id === value.place.identifier.id)) {
|
|
temporaries.set(lvalue.identifier.id, {
|
|
identifier: value.place.identifier,
|
|
reactive: value.place.reactive,
|
|
path: [],
|
|
loc: value.loc,
|
|
});
|
|
}
|
|
}
|
|
else if (value.kind === 'FunctionExpression' ||
|
|
value.kind === 'ObjectMethod') {
|
|
collectTemporariesSidemapImpl(value.loweredFunc.func, usedOutsideDeclaringScope, temporaries, innerFnContext !== null && innerFnContext !== void 0 ? innerFnContext : { instrId });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function getProperty(object, propertyName, optional, loc, temporaries) {
|
|
const resolvedDependency = temporaries.get(object.identifier.id);
|
|
let property;
|
|
if (resolvedDependency == null) {
|
|
property = {
|
|
identifier: object.identifier,
|
|
reactive: object.reactive,
|
|
path: [{ property: propertyName, optional, loc }],
|
|
loc,
|
|
};
|
|
}
|
|
else {
|
|
property = {
|
|
identifier: resolvedDependency.identifier,
|
|
reactive: resolvedDependency.reactive,
|
|
path: [
|
|
...resolvedDependency.path,
|
|
{ property: propertyName, optional, loc },
|
|
],
|
|
loc,
|
|
};
|
|
}
|
|
return property;
|
|
}
|
|
class DependencyCollectionContext {
|
|
constructor(temporariesUsedOutsideScope, temporaries, processedInstrsInOptional) {
|
|
_DependencyCollectionContext_instances.add(this);
|
|
_DependencyCollectionContext_declarations.set(this, new Map());
|
|
_DependencyCollectionContext_reassignments.set(this, new Map());
|
|
_DependencyCollectionContext_scopes.set(this, empty());
|
|
_DependencyCollectionContext_dependencies.set(this, empty());
|
|
this.deps = new Map();
|
|
_DependencyCollectionContext_temporaries.set(this, void 0);
|
|
_DependencyCollectionContext_temporariesUsedOutsideScope.set(this, void 0);
|
|
_DependencyCollectionContext_processedInstrsInOptional.set(this, void 0);
|
|
_DependencyCollectionContext_innerFnContext.set(this, null);
|
|
__classPrivateFieldSet(this, _DependencyCollectionContext_temporariesUsedOutsideScope, temporariesUsedOutsideScope, "f");
|
|
__classPrivateFieldSet(this, _DependencyCollectionContext_temporaries, temporaries, "f");
|
|
__classPrivateFieldSet(this, _DependencyCollectionContext_processedInstrsInOptional, processedInstrsInOptional, "f");
|
|
}
|
|
enterScope(scope) {
|
|
__classPrivateFieldSet(this, _DependencyCollectionContext_dependencies, __classPrivateFieldGet(this, _DependencyCollectionContext_dependencies, "f").push([]), "f");
|
|
__classPrivateFieldSet(this, _DependencyCollectionContext_scopes, __classPrivateFieldGet(this, _DependencyCollectionContext_scopes, "f").push(scope), "f");
|
|
}
|
|
exitScope(scope, pruned) {
|
|
var _a;
|
|
const scopedDependencies = __classPrivateFieldGet(this, _DependencyCollectionContext_dependencies, "f").value;
|
|
CompilerError.invariant(scopedDependencies != null, {
|
|
reason: '[PropagateScopeDeps]: Unexpected scope mismatch',
|
|
loc: scope.loc,
|
|
});
|
|
__classPrivateFieldSet(this, _DependencyCollectionContext_scopes, __classPrivateFieldGet(this, _DependencyCollectionContext_scopes, "f").pop(), "f");
|
|
__classPrivateFieldSet(this, _DependencyCollectionContext_dependencies, __classPrivateFieldGet(this, _DependencyCollectionContext_dependencies, "f").pop(), "f");
|
|
for (const dep of scopedDependencies) {
|
|
if (__classPrivateFieldGet(this, _DependencyCollectionContext_instances, "m", _DependencyCollectionContext_checkValidDependency).call(this, dep)) {
|
|
(_a = __classPrivateFieldGet(this, _DependencyCollectionContext_dependencies, "f").value) === null || _a === void 0 ? void 0 : _a.push(dep);
|
|
}
|
|
}
|
|
if (!pruned) {
|
|
this.deps.set(scope, scopedDependencies);
|
|
}
|
|
}
|
|
isUsedOutsideDeclaringScope(place) {
|
|
return __classPrivateFieldGet(this, _DependencyCollectionContext_temporariesUsedOutsideScope, "f").has(place.identifier.declarationId);
|
|
}
|
|
declare(identifier, decl) {
|
|
if (__classPrivateFieldGet(this, _DependencyCollectionContext_innerFnContext, "f") != null)
|
|
return;
|
|
if (!__classPrivateFieldGet(this, _DependencyCollectionContext_declarations, "f").has(identifier.declarationId)) {
|
|
__classPrivateFieldGet(this, _DependencyCollectionContext_declarations, "f").set(identifier.declarationId, decl);
|
|
}
|
|
__classPrivateFieldGet(this, _DependencyCollectionContext_reassignments, "f").set(identifier, decl);
|
|
}
|
|
hasDeclared(identifier) {
|
|
return __classPrivateFieldGet(this, _DependencyCollectionContext_declarations, "f").has(identifier.declarationId);
|
|
}
|
|
get currentScope() {
|
|
return __classPrivateFieldGet(this, _DependencyCollectionContext_scopes, "f");
|
|
}
|
|
visitOperand(place) {
|
|
var _a;
|
|
this.visitDependency((_a = __classPrivateFieldGet(this, _DependencyCollectionContext_temporaries, "f").get(place.identifier.id)) !== null && _a !== void 0 ? _a : {
|
|
identifier: place.identifier,
|
|
reactive: place.reactive,
|
|
path: [],
|
|
loc: place.loc,
|
|
});
|
|
}
|
|
visitProperty(object, property, optional, loc) {
|
|
const nextDependency = getProperty(object, property, optional, loc, __classPrivateFieldGet(this, _DependencyCollectionContext_temporaries, "f"));
|
|
this.visitDependency(nextDependency);
|
|
}
|
|
visitDependency(maybeDependency) {
|
|
var _a;
|
|
const originalDeclaration = __classPrivateFieldGet(this, _DependencyCollectionContext_declarations, "f").get(maybeDependency.identifier.declarationId);
|
|
if (originalDeclaration !== undefined &&
|
|
originalDeclaration.scope.value !== null) {
|
|
originalDeclaration.scope.each(scope => {
|
|
if (!__classPrivateFieldGet(this, _DependencyCollectionContext_instances, "m", _DependencyCollectionContext_isScopeActive).call(this, scope) &&
|
|
!Iterable_some(scope.declarations.values(), decl => decl.identifier.declarationId ===
|
|
maybeDependency.identifier.declarationId)) {
|
|
scope.declarations.set(maybeDependency.identifier.id, {
|
|
identifier: maybeDependency.identifier,
|
|
scope: originalDeclaration.scope.value,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
if (isUseRefType(maybeDependency.identifier) &&
|
|
((_a = maybeDependency.path.at(0)) === null || _a === void 0 ? void 0 : _a.property) === 'current') {
|
|
maybeDependency = {
|
|
identifier: maybeDependency.identifier,
|
|
reactive: maybeDependency.reactive,
|
|
path: [],
|
|
loc: maybeDependency.loc,
|
|
};
|
|
}
|
|
if (__classPrivateFieldGet(this, _DependencyCollectionContext_instances, "m", _DependencyCollectionContext_checkValidDependency).call(this, maybeDependency)) {
|
|
__classPrivateFieldGet(this, _DependencyCollectionContext_dependencies, "f").value.push(maybeDependency);
|
|
}
|
|
}
|
|
visitReassignment(place) {
|
|
const currentScope = this.currentScope.value;
|
|
if (currentScope != null &&
|
|
!Iterable_some(currentScope.reassignments, identifier => identifier.declarationId === place.identifier.declarationId) &&
|
|
__classPrivateFieldGet(this, _DependencyCollectionContext_instances, "m", _DependencyCollectionContext_checkValidDependency).call(this, {
|
|
identifier: place.identifier,
|
|
reactive: place.reactive,
|
|
path: [],
|
|
loc: place.loc,
|
|
})) {
|
|
currentScope.reassignments.add(place.identifier);
|
|
}
|
|
}
|
|
enterInnerFn(innerFn, cb) {
|
|
var _a;
|
|
const prevContext = __classPrivateFieldGet(this, _DependencyCollectionContext_innerFnContext, "f");
|
|
__classPrivateFieldSet(this, _DependencyCollectionContext_innerFnContext, (_a = __classPrivateFieldGet(this, _DependencyCollectionContext_innerFnContext, "f")) !== null && _a !== void 0 ? _a : { outerInstrId: innerFn.id }, "f");
|
|
const result = cb();
|
|
__classPrivateFieldSet(this, _DependencyCollectionContext_innerFnContext, prevContext, "f");
|
|
return result;
|
|
}
|
|
isDeferredDependency(instr) {
|
|
return (__classPrivateFieldGet(this, _DependencyCollectionContext_processedInstrsInOptional, "f").has(instr.value) ||
|
|
(instr.kind === HIRValue.Instruction &&
|
|
__classPrivateFieldGet(this, _DependencyCollectionContext_temporaries, "f").has(instr.value.lvalue.identifier.id)));
|
|
}
|
|
}
|
|
_DependencyCollectionContext_declarations = new WeakMap(), _DependencyCollectionContext_reassignments = new WeakMap(), _DependencyCollectionContext_scopes = new WeakMap(), _DependencyCollectionContext_dependencies = new WeakMap(), _DependencyCollectionContext_temporaries = new WeakMap(), _DependencyCollectionContext_temporariesUsedOutsideScope = new WeakMap(), _DependencyCollectionContext_processedInstrsInOptional = new WeakMap(), _DependencyCollectionContext_innerFnContext = new WeakMap(), _DependencyCollectionContext_instances = new WeakSet(), _DependencyCollectionContext_checkValidDependency = function _DependencyCollectionContext_checkValidDependency(maybeDependency) {
|
|
var _a;
|
|
if (isRefValueType(maybeDependency.identifier)) {
|
|
return false;
|
|
}
|
|
if (isObjectMethodType(maybeDependency.identifier)) {
|
|
return false;
|
|
}
|
|
const identifier = maybeDependency.identifier;
|
|
const currentDeclaration = (_a = __classPrivateFieldGet(this, _DependencyCollectionContext_reassignments, "f").get(identifier)) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _DependencyCollectionContext_declarations, "f").get(identifier.declarationId);
|
|
const currentScope = this.currentScope.value;
|
|
return (currentScope != null &&
|
|
currentDeclaration !== undefined &&
|
|
currentDeclaration.id < currentScope.range.start);
|
|
}, _DependencyCollectionContext_isScopeActive = function _DependencyCollectionContext_isScopeActive(scope) {
|
|
if (__classPrivateFieldGet(this, _DependencyCollectionContext_scopes, "f") === null) {
|
|
return false;
|
|
}
|
|
return __classPrivateFieldGet(this, _DependencyCollectionContext_scopes, "f").find(state => state === scope);
|
|
};
|
|
var HIRValue;
|
|
(function (HIRValue) {
|
|
HIRValue[HIRValue["Instruction"] = 1] = "Instruction";
|
|
HIRValue[HIRValue["Terminal"] = 2] = "Terminal";
|
|
})(HIRValue || (HIRValue = {}));
|
|
function handleInstruction(instr, context) {
|
|
const { id, value, lvalue } = instr;
|
|
context.declare(lvalue.identifier, {
|
|
id,
|
|
scope: context.currentScope,
|
|
});
|
|
if (context.isDeferredDependency({ kind: HIRValue.Instruction, value: instr })) {
|
|
return;
|
|
}
|
|
if (value.kind === 'PropertyLoad') {
|
|
context.visitProperty(value.object, value.property, false, value.loc);
|
|
}
|
|
else if (value.kind === 'StoreLocal') {
|
|
context.visitOperand(value.value);
|
|
if (value.lvalue.kind === InstructionKind.Reassign) {
|
|
context.visitReassignment(value.lvalue.place);
|
|
}
|
|
context.declare(value.lvalue.place.identifier, {
|
|
id,
|
|
scope: context.currentScope,
|
|
});
|
|
}
|
|
else if (value.kind === 'DeclareLocal' || value.kind === 'DeclareContext') {
|
|
if (convertHoistedLValueKind(value.lvalue.kind) === null) {
|
|
context.declare(value.lvalue.place.identifier, {
|
|
id,
|
|
scope: context.currentScope,
|
|
});
|
|
}
|
|
}
|
|
else if (value.kind === 'Destructure') {
|
|
context.visitOperand(value.value);
|
|
for (const place of eachPatternOperand(value.lvalue.pattern)) {
|
|
if (value.lvalue.kind === InstructionKind.Reassign) {
|
|
context.visitReassignment(place);
|
|
}
|
|
context.declare(place.identifier, {
|
|
id,
|
|
scope: context.currentScope,
|
|
});
|
|
}
|
|
}
|
|
else if (value.kind === 'StoreContext') {
|
|
if (!context.hasDeclared(value.lvalue.place.identifier) ||
|
|
value.lvalue.kind !== InstructionKind.Reassign) {
|
|
context.declare(value.lvalue.place.identifier, {
|
|
id,
|
|
scope: context.currentScope,
|
|
});
|
|
}
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
context.visitOperand(operand);
|
|
}
|
|
}
|
|
else {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
context.visitOperand(operand);
|
|
}
|
|
}
|
|
}
|
|
function collectDependencies$1(fn, usedOutsideDeclaringScope, temporaries, processedInstrsInOptional) {
|
|
const context = new DependencyCollectionContext(usedOutsideDeclaringScope, temporaries, processedInstrsInOptional);
|
|
for (const param of fn.params) {
|
|
if (param.kind === 'Identifier') {
|
|
context.declare(param.identifier, {
|
|
id: makeInstructionId(0),
|
|
scope: empty(),
|
|
});
|
|
}
|
|
else {
|
|
context.declare(param.place.identifier, {
|
|
id: makeInstructionId(0),
|
|
scope: empty(),
|
|
});
|
|
}
|
|
}
|
|
const scopeTraversal = new ScopeBlockTraversal();
|
|
const handleFunction = (fn) => {
|
|
for (const [blockId, block] of fn.body.blocks) {
|
|
scopeTraversal.recordScopes(block);
|
|
const scopeBlockInfo = scopeTraversal.blockInfos.get(blockId);
|
|
if ((scopeBlockInfo === null || scopeBlockInfo === void 0 ? void 0 : scopeBlockInfo.kind) === 'begin') {
|
|
context.enterScope(scopeBlockInfo.scope);
|
|
}
|
|
else if ((scopeBlockInfo === null || scopeBlockInfo === void 0 ? void 0 : scopeBlockInfo.kind) === 'end') {
|
|
context.exitScope(scopeBlockInfo.scope, scopeBlockInfo.pruned);
|
|
}
|
|
for (const phi of block.phis) {
|
|
for (const operand of phi.operands) {
|
|
const maybeOptionalChain = temporaries.get(operand[1].identifier.id);
|
|
if (maybeOptionalChain) {
|
|
context.visitDependency(maybeOptionalChain);
|
|
}
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
if (instr.value.kind === 'FunctionExpression' ||
|
|
instr.value.kind === 'ObjectMethod') {
|
|
context.declare(instr.lvalue.identifier, {
|
|
id: instr.id,
|
|
scope: context.currentScope,
|
|
});
|
|
const innerFn = instr.value.loweredFunc.func;
|
|
context.enterInnerFn(instr, () => {
|
|
handleFunction(innerFn);
|
|
});
|
|
}
|
|
else {
|
|
handleInstruction(instr, context);
|
|
}
|
|
}
|
|
if (!context.isDeferredDependency({
|
|
kind: HIRValue.Terminal,
|
|
value: block.terminal,
|
|
})) {
|
|
for (const place of eachTerminalOperand(block.terminal)) {
|
|
context.visitOperand(place);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
handleFunction(fn);
|
|
return context.deps;
|
|
}
|
|
|
|
function outlineJSX(fn) {
|
|
const outlinedFns = [];
|
|
outlineJsxImpl(fn, outlinedFns);
|
|
for (const outlinedFn of outlinedFns) {
|
|
fn.env.outlineFunction(outlinedFn, 'Component');
|
|
}
|
|
}
|
|
function outlineJsxImpl(fn, outlinedFns) {
|
|
const globals = new Map();
|
|
function processAndOutlineJSX(state, rewriteInstr) {
|
|
if (state.jsx.length <= 1) {
|
|
return;
|
|
}
|
|
const result = process$1(fn, [...state.jsx].sort((a, b) => a.id - b.id), globals);
|
|
if (result) {
|
|
outlinedFns.push(result.fn);
|
|
rewriteInstr.set(state.jsx.at(0).id, result.instrs);
|
|
}
|
|
}
|
|
for (const [, block] of fn.body.blocks) {
|
|
const rewriteInstr = new Map();
|
|
let state = {
|
|
jsx: [],
|
|
children: new Set(),
|
|
};
|
|
for (let i = block.instructions.length - 1; i >= 0; i--) {
|
|
const instr = block.instructions[i];
|
|
const { value, lvalue } = instr;
|
|
switch (value.kind) {
|
|
case 'LoadGlobal': {
|
|
globals.set(lvalue.identifier.id, instr);
|
|
break;
|
|
}
|
|
case 'FunctionExpression': {
|
|
outlineJsxImpl(value.loweredFunc.func, outlinedFns);
|
|
break;
|
|
}
|
|
case 'JsxExpression': {
|
|
if (!state.children.has(lvalue.identifier.id)) {
|
|
processAndOutlineJSX(state, rewriteInstr);
|
|
state = {
|
|
jsx: [],
|
|
children: new Set(),
|
|
};
|
|
}
|
|
state.jsx.push(instr);
|
|
if (value.children) {
|
|
for (const child of value.children) {
|
|
state.children.add(child.identifier.id);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'ArrayExpression':
|
|
case 'Await':
|
|
case 'BinaryExpression':
|
|
case 'CallExpression':
|
|
case 'ComputedDelete':
|
|
case 'ComputedLoad':
|
|
case 'ComputedStore':
|
|
case 'Debugger':
|
|
case 'DeclareContext':
|
|
case 'DeclareLocal':
|
|
case 'Destructure':
|
|
case 'FinishMemoize':
|
|
case 'GetIterator':
|
|
case 'IteratorNext':
|
|
case 'JSXText':
|
|
case 'JsxFragment':
|
|
case 'LoadContext':
|
|
case 'LoadLocal':
|
|
case 'MetaProperty':
|
|
case 'MethodCall':
|
|
case 'NewExpression':
|
|
case 'NextPropertyOf':
|
|
case 'ObjectExpression':
|
|
case 'ObjectMethod':
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate':
|
|
case 'Primitive':
|
|
case 'PropertyDelete':
|
|
case 'PropertyLoad':
|
|
case 'PropertyStore':
|
|
case 'RegExpLiteral':
|
|
case 'StartMemoize':
|
|
case 'StoreContext':
|
|
case 'StoreGlobal':
|
|
case 'StoreLocal':
|
|
case 'TaggedTemplateExpression':
|
|
case 'TemplateLiteral':
|
|
case 'TypeCastExpression':
|
|
case 'UnsupportedNode':
|
|
case 'UnaryExpression': {
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(value, `Unexpected instruction: ${value}`);
|
|
}
|
|
}
|
|
}
|
|
processAndOutlineJSX(state, rewriteInstr);
|
|
if (rewriteInstr.size > 0) {
|
|
const newInstrs = [];
|
|
for (let i = 0; i < block.instructions.length; i++) {
|
|
const id = i + 1;
|
|
if (rewriteInstr.has(id)) {
|
|
const instrs = rewriteInstr.get(id);
|
|
newInstrs.push(...instrs);
|
|
}
|
|
else {
|
|
newInstrs.push(block.instructions[i]);
|
|
}
|
|
}
|
|
block.instructions = newInstrs;
|
|
}
|
|
deadCodeElimination(fn);
|
|
}
|
|
}
|
|
function process$1(fn, jsx, globals) {
|
|
if (fn.fnType === 'Component') {
|
|
return null;
|
|
}
|
|
const props = collectProps(fn.env, jsx);
|
|
if (!props)
|
|
return null;
|
|
const outlinedTag = fn.env.generateGloballyUniqueIdentifierName(null).value;
|
|
const newInstrs = emitOutlinedJsx(fn.env, jsx, props, outlinedTag);
|
|
if (!newInstrs)
|
|
return null;
|
|
const outlinedFn = emitOutlinedFn(fn.env, jsx, props, globals);
|
|
if (!outlinedFn)
|
|
return null;
|
|
outlinedFn.id = outlinedTag;
|
|
return { instrs: newInstrs, fn: outlinedFn };
|
|
}
|
|
function collectProps(env, instructions) {
|
|
let id = 1;
|
|
function generateName(oldName) {
|
|
let newName = oldName;
|
|
while (seen.has(newName)) {
|
|
newName = `${oldName}${id++}`;
|
|
}
|
|
seen.add(newName);
|
|
env.programContext.addNewReference(newName);
|
|
return newName;
|
|
}
|
|
const attributes = [];
|
|
const jsxIds = new Set(instructions.map(i => i.lvalue.identifier.id));
|
|
const seen = new Set();
|
|
for (const instr of instructions) {
|
|
const { value } = instr;
|
|
for (const at of value.props) {
|
|
if (at.kind === 'JsxSpreadAttribute') {
|
|
return null;
|
|
}
|
|
if (at.kind === 'JsxAttribute') {
|
|
const newName = generateName(at.name);
|
|
attributes.push({
|
|
originalName: at.name,
|
|
newName,
|
|
place: at.place,
|
|
});
|
|
}
|
|
}
|
|
if (value.children) {
|
|
for (const child of value.children) {
|
|
if (jsxIds.has(child.identifier.id)) {
|
|
continue;
|
|
}
|
|
promoteTemporary(child.identifier);
|
|
const newName = generateName('t');
|
|
attributes.push({
|
|
originalName: child.identifier.name.value,
|
|
newName: newName,
|
|
place: child,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return attributes;
|
|
}
|
|
function emitOutlinedJsx(env, instructions, outlinedProps, outlinedTag) {
|
|
const props = outlinedProps.map(p => ({
|
|
kind: 'JsxAttribute',
|
|
name: p.newName,
|
|
place: p.place,
|
|
}));
|
|
const loadJsx = {
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
lvalue: createTemporaryPlace(env, GeneratedSource),
|
|
value: {
|
|
kind: 'LoadGlobal',
|
|
binding: {
|
|
kind: 'ModuleLocal',
|
|
name: outlinedTag,
|
|
},
|
|
loc: GeneratedSource,
|
|
},
|
|
effects: null,
|
|
};
|
|
promoteTemporaryJsxTag(loadJsx.lvalue.identifier);
|
|
const jsxExpr = {
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
lvalue: instructions.at(-1).lvalue,
|
|
value: {
|
|
kind: 'JsxExpression',
|
|
tag: Object.assign({}, loadJsx.lvalue),
|
|
props,
|
|
children: null,
|
|
loc: GeneratedSource,
|
|
openingLoc: GeneratedSource,
|
|
closingLoc: GeneratedSource,
|
|
},
|
|
effects: null,
|
|
};
|
|
return [loadJsx, jsxExpr];
|
|
}
|
|
function emitOutlinedFn(env, jsx, oldProps, globals) {
|
|
const instructions = [];
|
|
const oldToNewProps = createOldToNewPropsMapping(env, oldProps);
|
|
const propsObj = createTemporaryPlace(env, GeneratedSource);
|
|
promoteTemporary(propsObj.identifier);
|
|
const destructurePropsInstr = emitDestructureProps(env, propsObj, oldToNewProps);
|
|
instructions.push(destructurePropsInstr);
|
|
const updatedJsxInstructions = emitUpdatedJsx(jsx, oldToNewProps);
|
|
const loadGlobalInstrs = emitLoadGlobals(jsx, globals);
|
|
if (!loadGlobalInstrs) {
|
|
return null;
|
|
}
|
|
instructions.push(...loadGlobalInstrs);
|
|
instructions.push(...updatedJsxInstructions);
|
|
const block = {
|
|
kind: 'block',
|
|
id: makeBlockId(0),
|
|
instructions,
|
|
terminal: {
|
|
id: makeInstructionId(0),
|
|
kind: 'return',
|
|
returnVariant: 'Explicit',
|
|
loc: GeneratedSource,
|
|
value: instructions.at(-1).lvalue,
|
|
effects: null,
|
|
},
|
|
preds: new Set(),
|
|
phis: new Set(),
|
|
};
|
|
const fn = {
|
|
loc: GeneratedSource,
|
|
id: null,
|
|
nameHint: null,
|
|
fnType: 'Other',
|
|
env,
|
|
params: [propsObj],
|
|
returnTypeAnnotation: null,
|
|
returns: createTemporaryPlace(env, GeneratedSource),
|
|
context: [],
|
|
body: {
|
|
entry: block.id,
|
|
blocks: new Map([[block.id, block]]),
|
|
},
|
|
generator: false,
|
|
async: false,
|
|
directives: [],
|
|
aliasingEffects: [],
|
|
};
|
|
return fn;
|
|
}
|
|
function emitLoadGlobals(jsx, globals) {
|
|
const instructions = [];
|
|
for (const { value } of jsx) {
|
|
if (value.tag.kind === 'Identifier') {
|
|
const loadGlobalInstr = globals.get(value.tag.identifier.id);
|
|
if (!loadGlobalInstr) {
|
|
return null;
|
|
}
|
|
instructions.push(loadGlobalInstr);
|
|
}
|
|
}
|
|
return instructions;
|
|
}
|
|
function emitUpdatedJsx(jsx, oldToNewProps) {
|
|
const newInstrs = [];
|
|
const jsxIds = new Set(jsx.map(i => i.lvalue.identifier.id));
|
|
for (const instr of jsx) {
|
|
const { value } = instr;
|
|
const newProps = [];
|
|
for (const prop of value.props) {
|
|
invariant(prop.kind === 'JsxAttribute', `Expected only attributes but found ${prop.kind}`);
|
|
if (prop.name === 'key') {
|
|
continue;
|
|
}
|
|
const newProp = oldToNewProps.get(prop.place.identifier.id);
|
|
invariant(newProp !== undefined, `Expected a new property for ${printIdentifier(prop.place.identifier)}`);
|
|
newProps.push({
|
|
kind: 'JsxAttribute',
|
|
name: newProp.originalName,
|
|
place: newProp.place,
|
|
});
|
|
}
|
|
let newChildren = null;
|
|
if (value.children) {
|
|
newChildren = [];
|
|
for (const child of value.children) {
|
|
if (jsxIds.has(child.identifier.id)) {
|
|
newChildren.push(Object.assign({}, child));
|
|
continue;
|
|
}
|
|
const newChild = oldToNewProps.get(child.identifier.id);
|
|
invariant(newChild !== undefined, `Expected a new prop for ${printIdentifier(child.identifier)}`);
|
|
newChildren.push(Object.assign({}, newChild.place));
|
|
}
|
|
}
|
|
newInstrs.push(Object.assign(Object.assign({}, instr), { value: Object.assign(Object.assign({}, value), { props: newProps, children: newChildren }) }));
|
|
}
|
|
return newInstrs;
|
|
}
|
|
function createOldToNewPropsMapping(env, oldProps) {
|
|
const oldToNewProps = new Map();
|
|
for (const oldProp of oldProps) {
|
|
if (oldProp.originalName === 'key') {
|
|
continue;
|
|
}
|
|
const newProp = Object.assign(Object.assign({}, oldProp), { place: createTemporaryPlace(env, GeneratedSource) });
|
|
newProp.place.identifier.name = makeIdentifierName(oldProp.newName);
|
|
oldToNewProps.set(oldProp.place.identifier.id, newProp);
|
|
}
|
|
return oldToNewProps;
|
|
}
|
|
function emitDestructureProps(env, propsObj, oldToNewProps) {
|
|
const properties = [];
|
|
for (const [_, prop] of oldToNewProps) {
|
|
properties.push({
|
|
kind: 'ObjectProperty',
|
|
key: {
|
|
kind: 'string',
|
|
name: prop.newName,
|
|
},
|
|
type: 'property',
|
|
place: prop.place,
|
|
});
|
|
}
|
|
const destructurePropsInstr = {
|
|
id: makeInstructionId(0),
|
|
lvalue: createTemporaryPlace(env, GeneratedSource),
|
|
loc: GeneratedSource,
|
|
value: {
|
|
kind: 'Destructure',
|
|
lvalue: {
|
|
pattern: {
|
|
kind: 'ObjectPattern',
|
|
properties,
|
|
loc: GeneratedSource,
|
|
},
|
|
kind: InstructionKind.Let,
|
|
},
|
|
loc: GeneratedSource,
|
|
value: propsObj,
|
|
},
|
|
effects: null,
|
|
};
|
|
return destructurePropsInstr;
|
|
}
|
|
|
|
function optimizePropsMethodCalls(fn) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (let i = 0; i < block.instructions.length; i++) {
|
|
const instr = block.instructions[i];
|
|
if (instr.value.kind === 'MethodCall' &&
|
|
isPropsType(instr.value.receiver.identifier)) {
|
|
instr.value = {
|
|
kind: 'CallExpression',
|
|
callee: instr.value.property,
|
|
args: instr.value.args,
|
|
loc: instr.value.loc,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function validateStaticComponents(fn) {
|
|
const error = new CompilerError();
|
|
const knownDynamicComponents = new Map();
|
|
for (const block of fn.body.blocks.values()) {
|
|
phis: for (const phi of block.phis) {
|
|
for (const operand of phi.operands.values()) {
|
|
const loc = knownDynamicComponents.get(operand.identifier.id);
|
|
if (loc != null) {
|
|
knownDynamicComponents.set(phi.place.identifier.id, loc);
|
|
continue phis;
|
|
}
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
switch (value.kind) {
|
|
case 'FunctionExpression':
|
|
case 'NewExpression':
|
|
case 'MethodCall':
|
|
case 'CallExpression': {
|
|
knownDynamicComponents.set(lvalue.identifier.id, value.loc);
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
const loc = knownDynamicComponents.get(value.place.identifier.id);
|
|
if (loc != null) {
|
|
knownDynamicComponents.set(lvalue.identifier.id, loc);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
const loc = knownDynamicComponents.get(value.value.identifier.id);
|
|
if (loc != null) {
|
|
knownDynamicComponents.set(lvalue.identifier.id, loc);
|
|
knownDynamicComponents.set(value.lvalue.place.identifier.id, loc);
|
|
}
|
|
break;
|
|
}
|
|
case 'JsxExpression': {
|
|
if (value.tag.kind === 'Identifier') {
|
|
const location = knownDynamicComponents.get(value.tag.identifier.id);
|
|
if (location != null) {
|
|
error.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.StaticComponents,
|
|
reason: 'Cannot create components during render',
|
|
description: `Components created during render will reset their state each time they are created. Declare components outside of render`,
|
|
})
|
|
.withDetails({
|
|
kind: 'error',
|
|
loc: value.tag.loc,
|
|
message: 'This component is created during render',
|
|
})
|
|
.withDetails({
|
|
kind: 'error',
|
|
loc: location,
|
|
message: 'The component is created during render here',
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return error.asResult();
|
|
}
|
|
|
|
function validateNoFreezingKnownMutableFunctions(fn) {
|
|
const contextMutationEffects = new Map();
|
|
function visitOperand(operand) {
|
|
if (operand.effect === Effect.Freeze) {
|
|
const effect = contextMutationEffects.get(operand.identifier.id);
|
|
if (effect != null) {
|
|
const place = effect.value;
|
|
const variable = place != null &&
|
|
place.identifier.name != null &&
|
|
place.identifier.name.kind === 'named'
|
|
? `\`${place.identifier.name.value}\``
|
|
: 'a local variable';
|
|
fn.env.recordError(CompilerDiagnostic.create({
|
|
category: ErrorCategory.Immutability,
|
|
reason: 'Cannot modify local variables after render completes',
|
|
description: `This argument is a function which may reassign or mutate ${variable} after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead`,
|
|
})
|
|
.withDetails({
|
|
kind: 'error',
|
|
loc: operand.loc,
|
|
message: `This function may (indirectly) reassign or modify ${variable} after render`,
|
|
})
|
|
.withDetails({
|
|
kind: 'error',
|
|
loc: effect.value.loc,
|
|
message: `This modifies ${variable}`,
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
switch (value.kind) {
|
|
case 'LoadLocal': {
|
|
const effect = contextMutationEffects.get(value.place.identifier.id);
|
|
if (effect != null) {
|
|
contextMutationEffects.set(lvalue.identifier.id, effect);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
const effect = contextMutationEffects.get(value.value.identifier.id);
|
|
if (effect != null) {
|
|
contextMutationEffects.set(lvalue.identifier.id, effect);
|
|
contextMutationEffects.set(value.lvalue.place.identifier.id, effect);
|
|
}
|
|
break;
|
|
}
|
|
case 'FunctionExpression': {
|
|
if (value.loweredFunc.func.aliasingEffects != null) {
|
|
const context = new Set(value.loweredFunc.func.context.map(p => p.identifier.id));
|
|
effects: for (const effect of value.loweredFunc.func
|
|
.aliasingEffects) {
|
|
switch (effect.kind) {
|
|
case 'Mutate':
|
|
case 'MutateTransitive': {
|
|
const knownMutation = contextMutationEffects.get(effect.value.identifier.id);
|
|
if (knownMutation != null) {
|
|
contextMutationEffects.set(lvalue.identifier.id, knownMutation);
|
|
}
|
|
else if (context.has(effect.value.identifier.id) &&
|
|
!isRefOrRefLikeMutableType(effect.value.identifier.type)) {
|
|
contextMutationEffects.set(lvalue.identifier.id, effect);
|
|
break effects;
|
|
}
|
|
break;
|
|
}
|
|
case 'MutateConditionally':
|
|
case 'MutateTransitiveConditionally': {
|
|
const knownMutation = contextMutationEffects.get(effect.value.identifier.id);
|
|
if (knownMutation != null) {
|
|
contextMutationEffects.set(lvalue.identifier.id, knownMutation);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
visitOperand(operand);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
visitOperand(operand);
|
|
}
|
|
}
|
|
}
|
|
|
|
function validateNoDerivedComputationsInEffects(fn) {
|
|
const candidateDependencies = new Map();
|
|
const functions = new Map();
|
|
const locals = new Map();
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
if (value.kind === 'LoadLocal') {
|
|
locals.set(lvalue.identifier.id, value.place.identifier.id);
|
|
}
|
|
else if (value.kind === 'ArrayExpression') {
|
|
candidateDependencies.set(lvalue.identifier.id, value);
|
|
}
|
|
else if (value.kind === 'FunctionExpression') {
|
|
functions.set(lvalue.identifier.id, value);
|
|
}
|
|
else if (value.kind === 'CallExpression' ||
|
|
value.kind === 'MethodCall') {
|
|
const callee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
if (isUseEffectHookType(callee.identifier) &&
|
|
value.args.length === 2 &&
|
|
value.args[0].kind === 'Identifier' &&
|
|
value.args[1].kind === 'Identifier') {
|
|
const effectFunction = functions.get(value.args[0].identifier.id);
|
|
const deps = candidateDependencies.get(value.args[1].identifier.id);
|
|
if (effectFunction != null &&
|
|
deps != null &&
|
|
deps.elements.length !== 0 &&
|
|
deps.elements.every(element => element.kind === 'Identifier')) {
|
|
const dependencies = deps.elements.map(dep => {
|
|
var _a;
|
|
CompilerError.invariant(dep.kind === 'Identifier', {
|
|
reason: `Dependency is checked as a place above`,
|
|
loc: value.loc,
|
|
});
|
|
return (_a = locals.get(dep.identifier.id)) !== null && _a !== void 0 ? _a : dep.identifier.id;
|
|
});
|
|
validateEffect$1(effectFunction.loweredFunc.func, dependencies, fn.env);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function validateEffect$1(effectFunction, effectDeps, env) {
|
|
for (const operand of effectFunction.context) {
|
|
if (isSetStateType(operand.identifier)) {
|
|
continue;
|
|
}
|
|
else if (effectDeps.find(dep => dep === operand.identifier.id) != null) {
|
|
continue;
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
}
|
|
for (const dep of effectDeps) {
|
|
if (effectFunction.context.find(operand => operand.identifier.id === dep) ==
|
|
null) {
|
|
return;
|
|
}
|
|
}
|
|
const seenBlocks = new Set();
|
|
const values = new Map();
|
|
for (const dep of effectDeps) {
|
|
values.set(dep, [dep]);
|
|
}
|
|
const setStateLocations = [];
|
|
for (const block of effectFunction.body.blocks.values()) {
|
|
for (const pred of block.preds) {
|
|
if (!seenBlocks.has(pred)) {
|
|
return;
|
|
}
|
|
}
|
|
for (const phi of block.phis) {
|
|
const aggregateDeps = new Set();
|
|
for (const operand of phi.operands.values()) {
|
|
const deps = values.get(operand.identifier.id);
|
|
if (deps != null) {
|
|
for (const dep of deps) {
|
|
aggregateDeps.add(dep);
|
|
}
|
|
}
|
|
}
|
|
if (aggregateDeps.size !== 0) {
|
|
values.set(phi.place.identifier.id, Array.from(aggregateDeps));
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
switch (instr.value.kind) {
|
|
case 'Primitive':
|
|
case 'JSXText':
|
|
case 'LoadGlobal': {
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
const deps = values.get(instr.value.place.identifier.id);
|
|
if (deps != null) {
|
|
values.set(instr.lvalue.identifier.id, deps);
|
|
}
|
|
break;
|
|
}
|
|
case 'ComputedLoad':
|
|
case 'PropertyLoad':
|
|
case 'BinaryExpression':
|
|
case 'TemplateLiteral':
|
|
case 'CallExpression':
|
|
case 'MethodCall': {
|
|
const aggregateDeps = new Set();
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
const deps = values.get(operand.identifier.id);
|
|
if (deps != null) {
|
|
for (const dep of deps) {
|
|
aggregateDeps.add(dep);
|
|
}
|
|
}
|
|
}
|
|
if (aggregateDeps.size !== 0) {
|
|
values.set(instr.lvalue.identifier.id, Array.from(aggregateDeps));
|
|
}
|
|
if (instr.value.kind === 'CallExpression' &&
|
|
isSetStateType(instr.value.callee.identifier) &&
|
|
instr.value.args.length === 1 &&
|
|
instr.value.args[0].kind === 'Identifier') {
|
|
const deps = values.get(instr.value.args[0].identifier.id);
|
|
if (deps != null && new Set(deps).size === effectDeps.length) {
|
|
setStateLocations.push(instr.value.callee.loc);
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
if (values.has(operand.identifier.id)) {
|
|
return;
|
|
}
|
|
}
|
|
seenBlocks.add(block.id);
|
|
}
|
|
for (const loc of setStateLocations) {
|
|
env.recordError(new CompilerErrorDetail({
|
|
category: ErrorCategory.EffectDerivationsOfState,
|
|
reason: 'Values derived from props and state should be calculated during render, not in an effect. (https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)',
|
|
description: null,
|
|
loc,
|
|
suggestions: null,
|
|
}));
|
|
}
|
|
}
|
|
|
|
const MAX_FIXPOINT_ITERATIONS = 100;
|
|
class DerivationCache {
|
|
constructor() {
|
|
this.hasChanges = false;
|
|
this.cache = new Map();
|
|
this.previousCache = null;
|
|
}
|
|
takeSnapshot() {
|
|
this.previousCache = new Map();
|
|
for (const [key, value] of this.cache.entries()) {
|
|
this.previousCache.set(key, {
|
|
place: value.place,
|
|
sourcesIds: new Set(value.sourcesIds),
|
|
typeOfValue: value.typeOfValue,
|
|
isStateSource: value.isStateSource,
|
|
});
|
|
}
|
|
}
|
|
checkForChanges() {
|
|
if (this.previousCache === null) {
|
|
this.hasChanges = true;
|
|
return;
|
|
}
|
|
for (const [key, value] of this.cache.entries()) {
|
|
const previousValue = this.previousCache.get(key);
|
|
if (previousValue === undefined ||
|
|
!this.isDerivationEqual(previousValue, value)) {
|
|
this.hasChanges = true;
|
|
return;
|
|
}
|
|
}
|
|
if (this.cache.size !== this.previousCache.size) {
|
|
this.hasChanges = true;
|
|
return;
|
|
}
|
|
this.hasChanges = false;
|
|
}
|
|
snapshot() {
|
|
const hasChanges = this.hasChanges;
|
|
this.hasChanges = false;
|
|
return hasChanges;
|
|
}
|
|
addDerivationEntry(derivedVar, sourcesIds, typeOfValue, isStateSource) {
|
|
var _a;
|
|
let finalIsSource = isStateSource;
|
|
if (!finalIsSource) {
|
|
for (const sourceId of sourcesIds) {
|
|
const sourceMetadata = this.cache.get(sourceId);
|
|
if ((sourceMetadata === null || sourceMetadata === void 0 ? void 0 : sourceMetadata.isStateSource) &&
|
|
((_a = sourceMetadata.place.identifier.name) === null || _a === void 0 ? void 0 : _a.kind) !== 'named') {
|
|
finalIsSource = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
this.cache.set(derivedVar.identifier.id, {
|
|
place: derivedVar,
|
|
sourcesIds: sourcesIds,
|
|
typeOfValue: typeOfValue !== null && typeOfValue !== void 0 ? typeOfValue : 'ignored',
|
|
isStateSource: finalIsSource,
|
|
});
|
|
}
|
|
isDerivationEqual(a, b) {
|
|
if (a.typeOfValue !== b.typeOfValue) {
|
|
return false;
|
|
}
|
|
if (a.sourcesIds.size !== b.sourcesIds.size) {
|
|
return false;
|
|
}
|
|
for (const id of a.sourcesIds) {
|
|
if (!b.sourcesIds.has(id)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
function isNamedIdentifier(place) {
|
|
return (place.identifier.name !== null && place.identifier.name.kind === 'named');
|
|
}
|
|
function validateNoDerivedComputationsInEffects_exp(fn) {
|
|
const functions = new Map();
|
|
const candidateDependencies = new Map();
|
|
const derivationCache = new DerivationCache();
|
|
const errors = new CompilerError();
|
|
const effectsCache = new Map();
|
|
const setStateLoads = new Map();
|
|
const setStateUsages = new Map();
|
|
const context = {
|
|
functions,
|
|
candidateDependencies,
|
|
errors,
|
|
derivationCache,
|
|
effectsCache,
|
|
setStateLoads,
|
|
setStateUsages,
|
|
};
|
|
if (fn.fnType === 'Hook') {
|
|
for (const param of fn.params) {
|
|
if (param.kind === 'Identifier') {
|
|
context.derivationCache.cache.set(param.identifier.id, {
|
|
place: param,
|
|
sourcesIds: new Set(),
|
|
typeOfValue: 'fromProps',
|
|
isStateSource: true,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
else if (fn.fnType === 'Component') {
|
|
const props = fn.params[0];
|
|
if (props != null && props.kind === 'Identifier') {
|
|
context.derivationCache.cache.set(props.identifier.id, {
|
|
place: props,
|
|
sourcesIds: new Set(),
|
|
typeOfValue: 'fromProps',
|
|
isStateSource: true,
|
|
});
|
|
}
|
|
}
|
|
let iterationCount = 0;
|
|
do {
|
|
context.derivationCache.takeSnapshot();
|
|
for (const block of fn.body.blocks.values()) {
|
|
recordPhiDerivations(block, context);
|
|
for (const instr of block.instructions) {
|
|
recordInstructionDerivations(instr, context);
|
|
}
|
|
}
|
|
context.derivationCache.checkForChanges();
|
|
iterationCount++;
|
|
CompilerError.invariant(iterationCount < MAX_FIXPOINT_ITERATIONS, {
|
|
reason: '[ValidateNoDerivedComputationsInEffects] Fixpoint iteration failed to converge.',
|
|
description: `Fixpoint iteration exceeded ${MAX_FIXPOINT_ITERATIONS} iterations while tracking derivations. This suggests a cyclic dependency in the derivation cache.`,
|
|
loc: fn.loc,
|
|
});
|
|
} while (context.derivationCache.snapshot());
|
|
for (const [, effect] of effectsCache) {
|
|
validateEffect(effect.effect, effect.dependencies, context);
|
|
}
|
|
return errors.asResult();
|
|
}
|
|
function recordPhiDerivations(block, context) {
|
|
for (const phi of block.phis) {
|
|
let typeOfValue = 'ignored';
|
|
let sourcesIds = new Set();
|
|
for (const operand of phi.operands.values()) {
|
|
const operandMetadata = context.derivationCache.cache.get(operand.identifier.id);
|
|
if (operandMetadata === undefined) {
|
|
continue;
|
|
}
|
|
typeOfValue = joinValue(typeOfValue, operandMetadata.typeOfValue);
|
|
sourcesIds.add(operand.identifier.id);
|
|
}
|
|
if (typeOfValue !== 'ignored') {
|
|
context.derivationCache.addDerivationEntry(phi.place, sourcesIds, typeOfValue, false);
|
|
}
|
|
}
|
|
}
|
|
function joinValue(lvalueType, valueType) {
|
|
if (lvalueType === 'ignored')
|
|
return valueType;
|
|
if (valueType === 'ignored')
|
|
return lvalueType;
|
|
if (lvalueType === valueType)
|
|
return lvalueType;
|
|
return 'fromPropsAndState';
|
|
}
|
|
function getRootSetState(key, loads, visited = new Set()) {
|
|
if (visited.has(key)) {
|
|
return null;
|
|
}
|
|
visited.add(key);
|
|
const parentId = loads.get(key);
|
|
if (parentId === undefined) {
|
|
return null;
|
|
}
|
|
if (parentId === null) {
|
|
return key;
|
|
}
|
|
return getRootSetState(parentId, loads, visited);
|
|
}
|
|
function maybeRecordSetState(instr, loads, usages) {
|
|
for (const operand of eachInstructionLValue(instr)) {
|
|
if (instr.value.kind === 'LoadLocal' &&
|
|
loads.has(instr.value.place.identifier.id)) {
|
|
loads.set(operand.identifier.id, instr.value.place.identifier.id);
|
|
}
|
|
else {
|
|
if (isSetStateType(operand.identifier)) {
|
|
loads.set(operand.identifier.id, null);
|
|
}
|
|
}
|
|
const rootSetState = getRootSetState(operand.identifier.id, loads);
|
|
if (rootSetState !== null && usages.get(rootSetState) === undefined) {
|
|
usages.set(rootSetState, new Set([operand.loc]));
|
|
}
|
|
}
|
|
}
|
|
function recordInstructionDerivations(instr, context, isFirstPass) {
|
|
var _a;
|
|
maybeRecordSetState(instr, context.setStateLoads, context.setStateUsages);
|
|
let typeOfValue = 'ignored';
|
|
let isSource = false;
|
|
const sources = new Set();
|
|
const { lvalue, value } = instr;
|
|
if (value.kind === 'FunctionExpression') {
|
|
context.functions.set(lvalue.identifier.id, value);
|
|
for (const [, block] of value.loweredFunc.func.body.blocks) {
|
|
recordPhiDerivations(block, context);
|
|
for (const instr of block.instructions) {
|
|
recordInstructionDerivations(instr, context);
|
|
}
|
|
}
|
|
}
|
|
else if (value.kind === 'CallExpression' || value.kind === 'MethodCall') {
|
|
const callee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
if (isUseEffectHookType(callee.identifier) &&
|
|
value.args.length === 2 &&
|
|
value.args[0].kind === 'Identifier' &&
|
|
value.args[1].kind === 'Identifier') {
|
|
const effectFunction = context.functions.get(value.args[0].identifier.id);
|
|
const deps = context.candidateDependencies.get(value.args[1].identifier.id);
|
|
if (effectFunction != null && deps != null) {
|
|
context.effectsCache.set(value.args[0].identifier.id, {
|
|
effect: effectFunction.loweredFunc.func,
|
|
dependencies: deps,
|
|
});
|
|
}
|
|
}
|
|
else if (isUseStateType(lvalue.identifier)) {
|
|
typeOfValue = 'fromState';
|
|
context.derivationCache.addDerivationEntry(lvalue, new Set(), typeOfValue, true);
|
|
return;
|
|
}
|
|
}
|
|
else if (value.kind === 'ArrayExpression') {
|
|
context.candidateDependencies.set(lvalue.identifier.id, value);
|
|
}
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
if (context.setStateLoads.has(operand.identifier.id)) {
|
|
const rootSetStateId = getRootSetState(operand.identifier.id, context.setStateLoads);
|
|
if (rootSetStateId !== null) {
|
|
(_a = context.setStateUsages.get(rootSetStateId)) === null || _a === void 0 ? void 0 : _a.add(operand.loc);
|
|
}
|
|
}
|
|
const operandMetadata = context.derivationCache.cache.get(operand.identifier.id);
|
|
if (operandMetadata === undefined) {
|
|
continue;
|
|
}
|
|
typeOfValue = joinValue(typeOfValue, operandMetadata.typeOfValue);
|
|
sources.add(operand.identifier.id);
|
|
}
|
|
if (typeOfValue === 'ignored') {
|
|
return;
|
|
}
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
context.derivationCache.addDerivationEntry(lvalue, sources, typeOfValue, isSource);
|
|
}
|
|
if (value.kind === 'FunctionExpression') {
|
|
return;
|
|
}
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
switch (operand.effect) {
|
|
case Effect.Capture:
|
|
case Effect.Store:
|
|
case Effect.ConditionallyMutate:
|
|
case Effect.ConditionallyMutateIterator:
|
|
case Effect.Mutate: {
|
|
if (isMutable(instr, operand)) {
|
|
if (context.derivationCache.cache.has(operand.identifier.id)) {
|
|
const operandMetadata = context.derivationCache.cache.get(operand.identifier.id);
|
|
if (operandMetadata !== undefined) {
|
|
operandMetadata.typeOfValue = joinValue(typeOfValue, operandMetadata.typeOfValue);
|
|
}
|
|
}
|
|
else {
|
|
context.derivationCache.addDerivationEntry(operand, sources, typeOfValue, false);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case Effect.Freeze:
|
|
case Effect.Read: {
|
|
break;
|
|
}
|
|
case Effect.Unknown: {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Unexpected unknown effect',
|
|
loc: operand.loc,
|
|
});
|
|
}
|
|
default: {
|
|
assertExhaustive$1(operand.effect, `Unexpected effect kind \`${operand.effect}\``);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function buildTreeNode(sourceId, context, visited = new Set()) {
|
|
const sourceMetadata = context.derivationCache.cache.get(sourceId);
|
|
if (!sourceMetadata) {
|
|
return [];
|
|
}
|
|
if (sourceMetadata.isStateSource && isNamedIdentifier(sourceMetadata.place)) {
|
|
return [
|
|
{
|
|
name: sourceMetadata.place.identifier.name.value,
|
|
typeOfValue: sourceMetadata.typeOfValue,
|
|
isSource: sourceMetadata.isStateSource,
|
|
children: [],
|
|
},
|
|
];
|
|
}
|
|
const children = [];
|
|
const namedSiblings = new Set();
|
|
for (const childId of sourceMetadata.sourcesIds) {
|
|
CompilerError.invariant(childId !== sourceId, {
|
|
reason: 'Unexpected self-reference: a value should not have itself as a source',
|
|
loc: sourceMetadata.place.loc,
|
|
});
|
|
const childNodes = buildTreeNode(childId, context, new Set([
|
|
...visited,
|
|
...(isNamedIdentifier(sourceMetadata.place)
|
|
? [sourceMetadata.place.identifier.name.value]
|
|
: []),
|
|
]));
|
|
if (childNodes) {
|
|
for (const childNode of childNodes) {
|
|
if (!namedSiblings.has(childNode.name)) {
|
|
children.push(childNode);
|
|
namedSiblings.add(childNode.name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (isNamedIdentifier(sourceMetadata.place) &&
|
|
!visited.has(sourceMetadata.place.identifier.name.value)) {
|
|
return [
|
|
{
|
|
name: sourceMetadata.place.identifier.name.value,
|
|
typeOfValue: sourceMetadata.typeOfValue,
|
|
isSource: sourceMetadata.isStateSource,
|
|
children: children,
|
|
},
|
|
];
|
|
}
|
|
return children;
|
|
}
|
|
function renderTree(node, indent = '', isLast = true, propsSet, stateSet) {
|
|
const prefix = indent + (isLast ? '└── ' : '├── ');
|
|
const childIndent = indent + (isLast ? ' ' : '│ ');
|
|
let result = `${prefix}${node.name}`;
|
|
if (node.isSource) {
|
|
let typeLabel;
|
|
if (node.typeOfValue === 'fromProps') {
|
|
propsSet.add(node.name);
|
|
typeLabel = 'Prop';
|
|
}
|
|
else if (node.typeOfValue === 'fromState') {
|
|
stateSet.add(node.name);
|
|
typeLabel = 'State';
|
|
}
|
|
else {
|
|
propsSet.add(node.name);
|
|
stateSet.add(node.name);
|
|
typeLabel = 'Prop and State';
|
|
}
|
|
result += ` (${typeLabel})`;
|
|
}
|
|
if (node.children.length > 0) {
|
|
result += '\n';
|
|
node.children.forEach((child, index) => {
|
|
const isLastChild = index === node.children.length - 1;
|
|
result += renderTree(child, childIndent, isLastChild, propsSet, stateSet);
|
|
if (index < node.children.length - 1) {
|
|
result += '\n';
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
function getFnLocalDeps(fn) {
|
|
if (!fn) {
|
|
return undefined;
|
|
}
|
|
const deps = new Set();
|
|
for (const [, block] of fn.loweredFunc.func.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
if (instr.value.kind === 'LoadLocal') {
|
|
deps.add(instr.value.place.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
return deps;
|
|
}
|
|
function validateEffect(effectFunction, dependencies, context) {
|
|
var _a;
|
|
const seenBlocks = new Set();
|
|
const effectDerivedSetStateCalls = [];
|
|
const effectSetStateUsages = new Map();
|
|
for (const dep of dependencies.elements) {
|
|
if (dep.kind === 'Identifier') {
|
|
const root = getRootSetState(dep.identifier.id, context.setStateLoads);
|
|
if (root !== null) {
|
|
effectSetStateUsages.set(root, new Set([dep.loc]));
|
|
}
|
|
}
|
|
}
|
|
let cleanUpFunctionDeps;
|
|
const globals = new Set();
|
|
for (const block of effectFunction.body.blocks.values()) {
|
|
if (block.terminal.kind === 'return' &&
|
|
block.terminal.returnVariant === 'Explicit') {
|
|
cleanUpFunctionDeps = getFnLocalDeps(context.functions.get(block.terminal.value.identifier.id));
|
|
}
|
|
for (const pred of block.preds) {
|
|
if (!seenBlocks.has(pred)) {
|
|
return;
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
if (isUseRefType(instr.lvalue.identifier)) {
|
|
return;
|
|
}
|
|
maybeRecordSetState(instr, context.setStateLoads, effectSetStateUsages);
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
if (context.setStateLoads.has(operand.identifier.id)) {
|
|
const rootSetStateId = getRootSetState(operand.identifier.id, context.setStateLoads);
|
|
if (rootSetStateId !== null) {
|
|
(_a = effectSetStateUsages.get(rootSetStateId)) === null || _a === void 0 ? void 0 : _a.add(operand.loc);
|
|
}
|
|
}
|
|
}
|
|
if (instr.value.kind === 'CallExpression' &&
|
|
isSetStateType(instr.value.callee.identifier) &&
|
|
instr.value.args.length === 1 &&
|
|
instr.value.args[0].kind === 'Identifier') {
|
|
const calleeMetadata = context.derivationCache.cache.get(instr.value.callee.identifier.id);
|
|
if ((calleeMetadata === null || calleeMetadata === void 0 ? void 0 : calleeMetadata.typeOfValue) != 'fromState') {
|
|
continue;
|
|
}
|
|
const argMetadata = context.derivationCache.cache.get(instr.value.args[0].identifier.id);
|
|
if (argMetadata !== undefined) {
|
|
effectDerivedSetStateCalls.push({
|
|
value: instr.value,
|
|
id: instr.value.callee.identifier.id,
|
|
sourceIds: argMetadata.sourcesIds,
|
|
typeOfValue: argMetadata.typeOfValue,
|
|
});
|
|
}
|
|
}
|
|
else if (instr.value.kind === 'CallExpression') {
|
|
const calleeMetadata = context.derivationCache.cache.get(instr.value.callee.identifier.id);
|
|
if (calleeMetadata !== undefined &&
|
|
(calleeMetadata.typeOfValue === 'fromProps' ||
|
|
calleeMetadata.typeOfValue === 'fromPropsAndState')) {
|
|
return;
|
|
}
|
|
if (globals.has(instr.value.callee.identifier.id)) {
|
|
return;
|
|
}
|
|
}
|
|
else if (instr.value.kind === 'LoadGlobal') {
|
|
globals.add(instr.lvalue.identifier.id);
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
globals.add(operand.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
seenBlocks.add(block.id);
|
|
}
|
|
for (const derivedSetStateCall of effectDerivedSetStateCalls) {
|
|
const rootSetStateCall = getRootSetState(derivedSetStateCall.id, context.setStateLoads);
|
|
if (rootSetStateCall !== null &&
|
|
effectSetStateUsages.has(rootSetStateCall) &&
|
|
context.setStateUsages.has(rootSetStateCall) &&
|
|
effectSetStateUsages.get(rootSetStateCall).size ===
|
|
context.setStateUsages.get(rootSetStateCall).size - 1) {
|
|
const propsSet = new Set();
|
|
const stateSet = new Set();
|
|
const rootNodesMap = new Map();
|
|
for (const id of derivedSetStateCall.sourceIds) {
|
|
const nodes = buildTreeNode(id, context);
|
|
for (const node of nodes) {
|
|
if (!rootNodesMap.has(node.name)) {
|
|
rootNodesMap.set(node.name, node);
|
|
}
|
|
}
|
|
}
|
|
const rootNodes = Array.from(rootNodesMap.values());
|
|
const trees = rootNodes.map((node, index) => renderTree(node, '', index === rootNodes.length - 1, propsSet, stateSet));
|
|
for (const dep of derivedSetStateCall.sourceIds) {
|
|
if (cleanUpFunctionDeps !== undefined && cleanUpFunctionDeps.has(dep)) {
|
|
return;
|
|
}
|
|
}
|
|
const propsArr = Array.from(propsSet);
|
|
const stateArr = Array.from(stateSet);
|
|
let rootSources = '';
|
|
if (propsArr.length > 0) {
|
|
rootSources += `Props: [${propsArr.join(', ')}]`;
|
|
}
|
|
if (stateArr.length > 0) {
|
|
if (rootSources)
|
|
rootSources += '\n';
|
|
rootSources += `State: [${stateArr.join(', ')}]`;
|
|
}
|
|
const description = `Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
|
|
|
|
This setState call is setting a derived value that depends on the following reactive sources:
|
|
|
|
${rootSources}
|
|
|
|
Data Flow Tree:
|
|
${trees.join('\n')}
|
|
|
|
See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state`;
|
|
context.errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
description: description,
|
|
category: ErrorCategory.EffectDerivationsOfState,
|
|
reason: 'You might not need an effect. Derive values in render, not effects.',
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: derivedSetStateCall.value.callee.loc,
|
|
message: 'This should be computed during render, not in an effect',
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
function nameAnonymousFunctions(fn) {
|
|
if (fn.id == null) {
|
|
return;
|
|
}
|
|
const parentName = fn.id;
|
|
const functions = nameAnonymousFunctionsImpl(fn);
|
|
function visit(node, prefix) {
|
|
var _a, _b;
|
|
if (node.generatedName != null && node.fn.nameHint == null) {
|
|
const name = `${prefix}${node.generatedName}]`;
|
|
node.fn.nameHint = name;
|
|
node.fn.loweredFunc.func.nameHint = name;
|
|
}
|
|
const nextPrefix = `${prefix}${(_b = (_a = node.generatedName) !== null && _a !== void 0 ? _a : node.fn.name) !== null && _b !== void 0 ? _b : '<anonymous>'} > `;
|
|
for (const inner of node.inner) {
|
|
visit(inner, nextPrefix);
|
|
}
|
|
}
|
|
for (const node of functions) {
|
|
visit(node, `${parentName}[`);
|
|
}
|
|
}
|
|
function nameAnonymousFunctionsImpl(fn) {
|
|
var _a, _b;
|
|
const functions = new Map();
|
|
const names = new Map();
|
|
const nodes = [];
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
switch (value.kind) {
|
|
case 'LoadGlobal': {
|
|
names.set(lvalue.identifier.id, value.binding.name);
|
|
break;
|
|
}
|
|
case 'LoadContext':
|
|
case 'LoadLocal': {
|
|
const name = value.place.identifier.name;
|
|
if (name != null && name.kind === 'named') {
|
|
names.set(lvalue.identifier.id, name.value);
|
|
}
|
|
const func = functions.get(value.place.identifier.id);
|
|
if (func != null) {
|
|
functions.set(lvalue.identifier.id, func);
|
|
}
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
const objectName = names.get(value.object.identifier.id);
|
|
if (objectName != null) {
|
|
names.set(lvalue.identifier.id, `${objectName}.${String(value.property)}`);
|
|
}
|
|
break;
|
|
}
|
|
case 'FunctionExpression': {
|
|
const inner = nameAnonymousFunctionsImpl(value.loweredFunc.func);
|
|
const node = {
|
|
fn: value,
|
|
generatedName: null,
|
|
inner,
|
|
};
|
|
nodes.push(node);
|
|
if (value.name == null) {
|
|
functions.set(lvalue.identifier.id, node);
|
|
}
|
|
break;
|
|
}
|
|
case 'StoreContext':
|
|
case 'StoreLocal': {
|
|
const node = functions.get(value.value.identifier.id);
|
|
const variableName = value.lvalue.place.identifier.name;
|
|
if (node != null &&
|
|
node.generatedName == null &&
|
|
variableName != null &&
|
|
variableName.kind === 'named') {
|
|
node.generatedName = variableName.value;
|
|
functions.delete(value.value.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'CallExpression':
|
|
case 'MethodCall': {
|
|
const callee = value.kind === 'MethodCall' ? value.property : value.callee;
|
|
const hookKind = getHookKind(fn.env, callee.identifier);
|
|
let calleeName = null;
|
|
if (hookKind != null && hookKind !== 'Custom') {
|
|
calleeName = hookKind;
|
|
}
|
|
else {
|
|
calleeName = (_a = names.get(callee.identifier.id)) !== null && _a !== void 0 ? _a : '(anonymous)';
|
|
}
|
|
let fnArgCount = 0;
|
|
for (const arg of value.args) {
|
|
if (arg.kind === 'Identifier' && functions.has(arg.identifier.id)) {
|
|
fnArgCount++;
|
|
}
|
|
}
|
|
for (let i = 0; i < value.args.length; i++) {
|
|
const arg = value.args[i];
|
|
if (arg.kind === 'Spread') {
|
|
continue;
|
|
}
|
|
const node = functions.get(arg.identifier.id);
|
|
if (node != null && node.generatedName == null) {
|
|
const generatedName = fnArgCount > 1 ? `${calleeName}(arg${i})` : `${calleeName}()`;
|
|
node.generatedName = generatedName;
|
|
functions.delete(arg.identifier.id);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'JsxExpression': {
|
|
for (const attr of value.props) {
|
|
if (attr.kind === 'JsxSpreadAttribute') {
|
|
continue;
|
|
}
|
|
const node = functions.get(attr.place.identifier.id);
|
|
if (node != null && node.generatedName == null) {
|
|
const elementName = value.tag.kind === 'BuiltinTag'
|
|
? value.tag.name
|
|
: ((_b = names.get(value.tag.identifier.id)) !== null && _b !== void 0 ? _b : null);
|
|
const propName = elementName == null
|
|
? attr.name
|
|
: `<${elementName}>.${attr.name}`;
|
|
node.generatedName = `${propName}`;
|
|
functions.delete(attr.place.identifier.id);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nodes;
|
|
}
|
|
|
|
function optimizeForSSR(fn) {
|
|
const inlinedState = new Map();
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
const { value } = instr;
|
|
switch (value.kind) {
|
|
case 'Destructure': {
|
|
if (inlinedState.has(value.value.identifier.id) &&
|
|
value.lvalue.pattern.kind === 'ArrayPattern' &&
|
|
value.lvalue.pattern.items.length >= 1 &&
|
|
value.lvalue.pattern.items[0].kind === 'Identifier') {
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case 'MethodCall':
|
|
case 'CallExpression': {
|
|
const calleee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
const hookKind = getHookKind(fn.env, calleee.identifier);
|
|
switch (hookKind) {
|
|
case 'useReducer': {
|
|
if (value.args.length === 2 &&
|
|
value.args[1].kind === 'Identifier') {
|
|
const arg = value.args[1];
|
|
const replace = {
|
|
kind: 'LoadLocal',
|
|
place: arg,
|
|
loc: arg.loc,
|
|
};
|
|
inlinedState.set(instr.lvalue.identifier.id, replace);
|
|
}
|
|
else if (value.args.length === 3 &&
|
|
value.args[1].kind === 'Identifier' &&
|
|
value.args[2].kind === 'Identifier') {
|
|
const arg = value.args[1];
|
|
const initializer = value.args[2];
|
|
const replace = {
|
|
kind: 'CallExpression',
|
|
callee: initializer,
|
|
args: [arg],
|
|
loc: value.loc,
|
|
};
|
|
inlinedState.set(instr.lvalue.identifier.id, replace);
|
|
}
|
|
break;
|
|
}
|
|
case 'useState': {
|
|
if (value.args.length === 1 &&
|
|
value.args[0].kind === 'Identifier') {
|
|
const arg = value.args[0];
|
|
if (isPrimitiveType(arg.identifier) ||
|
|
isPlainObjectType(arg.identifier) ||
|
|
isArrayType(arg.identifier)) {
|
|
const replace = {
|
|
kind: 'LoadLocal',
|
|
place: arg,
|
|
loc: arg.loc,
|
|
};
|
|
inlinedState.set(instr.lvalue.identifier.id, replace);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (inlinedState.size !== 0) {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
inlinedState.delete(operand.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
if (inlinedState.size !== 0) {
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
inlinedState.delete(operand.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
const { value } = instr;
|
|
switch (value.kind) {
|
|
case 'FunctionExpression': {
|
|
if (hasKnownNonRenderCall(value.loweredFunc.func)) {
|
|
instr.value = {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: value.loc,
|
|
};
|
|
}
|
|
break;
|
|
}
|
|
case 'JsxExpression': {
|
|
if (value.tag.kind === 'BuiltinTag' &&
|
|
value.tag.name.indexOf('-') === -1) {
|
|
const tag = value.tag.name;
|
|
retainWhere(value.props, prop => {
|
|
return (prop.kind === 'JsxSpreadAttribute' ||
|
|
(!isKnownEventHandler(tag, prop.name) && prop.name !== 'ref'));
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
if (inlinedState.has(value.value.identifier.id)) {
|
|
CompilerError.invariant(value.lvalue.pattern.kind === 'ArrayPattern' &&
|
|
value.lvalue.pattern.items.length >= 1 &&
|
|
value.lvalue.pattern.items[0].kind === 'Identifier', {
|
|
reason: 'Expected a valid destructuring pattern for inlined state',
|
|
message: 'Expected a valid destructuring pattern',
|
|
loc: value.loc,
|
|
});
|
|
const store = {
|
|
kind: 'StoreLocal',
|
|
loc: value.loc,
|
|
type: null,
|
|
lvalue: {
|
|
kind: value.lvalue.kind,
|
|
place: value.lvalue.pattern.items[0],
|
|
},
|
|
value: value.value,
|
|
};
|
|
instr.value = store;
|
|
}
|
|
break;
|
|
}
|
|
case 'MethodCall':
|
|
case 'CallExpression': {
|
|
const calleee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
const hookKind = getHookKind(fn.env, calleee.identifier);
|
|
switch (hookKind) {
|
|
case 'useEffectEvent': {
|
|
if (value.args.length === 1 &&
|
|
value.args[0].kind === 'Identifier') {
|
|
const load = {
|
|
kind: 'LoadLocal',
|
|
place: value.args[0],
|
|
loc: value.loc,
|
|
};
|
|
instr.value = load;
|
|
}
|
|
break;
|
|
}
|
|
case 'useEffect':
|
|
case 'useLayoutEffect':
|
|
case 'useInsertionEffect': {
|
|
instr.value = {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: value.loc,
|
|
};
|
|
break;
|
|
}
|
|
case 'useReducer':
|
|
case 'useState': {
|
|
const replace = inlinedState.get(instr.lvalue.identifier.id);
|
|
if (replace != null) {
|
|
instr.value = replace;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function hasKnownNonRenderCall(fn) {
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
if (instr.value.kind === 'CallExpression' &&
|
|
(isSetStateType(instr.value.callee.identifier) ||
|
|
isStartTransitionType(instr.value.callee.identifier))) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
const EVENT_HANDLER_PATTERN = /^on[A-Z]/;
|
|
function isKnownEventHandler(_tag, prop) {
|
|
return EVENT_HANDLER_PATTERN.test(prop);
|
|
}
|
|
|
|
function validateExhaustiveDependencies(fn) {
|
|
const env = fn.env;
|
|
const reactive = collectReactiveIdentifiersHIR(fn);
|
|
const temporaries = new Map();
|
|
for (const param of fn.params) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
temporaries.set(place.identifier.id, {
|
|
kind: 'Local',
|
|
identifier: place.identifier,
|
|
path: [],
|
|
context: false,
|
|
loc: place.loc,
|
|
});
|
|
}
|
|
let startMemo = null;
|
|
function onStartMemoize(value, dependencies, locals) {
|
|
CompilerError.invariant(startMemo == null, {
|
|
reason: 'Unexpected nested memo calls',
|
|
loc: value.loc,
|
|
});
|
|
startMemo = value;
|
|
dependencies.clear();
|
|
locals.clear();
|
|
}
|
|
function onFinishMemoize(value, dependencies, locals) {
|
|
var _a;
|
|
CompilerError.invariant(startMemo != null && startMemo.manualMemoId === value.manualMemoId, {
|
|
reason: 'Found FinishMemoize without corresponding StartMemoize',
|
|
loc: value.loc,
|
|
});
|
|
if (env.config.validateExhaustiveMemoizationDependencies) {
|
|
visitCandidateDependency(value.decl, temporaries, dependencies, locals);
|
|
const inferred = Array.from(dependencies);
|
|
const diagnostic = validateDependencies(inferred, (_a = startMemo.deps) !== null && _a !== void 0 ? _a : [], reactive, startMemo.depsLoc, ErrorCategory.MemoDependencies, 'all');
|
|
if (diagnostic != null) {
|
|
fn.env.recordError(diagnostic);
|
|
startMemo.hasInvalidDeps = true;
|
|
}
|
|
}
|
|
dependencies.clear();
|
|
locals.clear();
|
|
startMemo = null;
|
|
}
|
|
collectDependencies(fn, temporaries, {
|
|
onStartMemoize,
|
|
onFinishMemoize,
|
|
onEffect: (inferred, manual, manualMemoLoc) => {
|
|
if (env.config.validateExhaustiveEffectDependencies === 'off') {
|
|
return;
|
|
}
|
|
const manualDeps = [];
|
|
for (const dep of manual) {
|
|
if (dep.kind === 'Local') {
|
|
manualDeps.push({
|
|
root: {
|
|
kind: 'NamedLocal',
|
|
constant: false,
|
|
value: {
|
|
effect: Effect.Read,
|
|
identifier: dep.identifier,
|
|
kind: 'Identifier',
|
|
loc: dep.loc,
|
|
reactive: reactive.has(dep.identifier.id),
|
|
},
|
|
},
|
|
path: dep.path,
|
|
loc: dep.loc,
|
|
});
|
|
}
|
|
else {
|
|
manualDeps.push({
|
|
root: {
|
|
kind: 'Global',
|
|
identifierName: dep.binding.name,
|
|
},
|
|
path: [],
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
const effectReportMode = typeof env.config.validateExhaustiveEffectDependencies === 'string'
|
|
? env.config.validateExhaustiveEffectDependencies
|
|
: 'all';
|
|
const diagnostic = validateDependencies(Array.from(inferred), manualDeps, reactive, manualMemoLoc, ErrorCategory.EffectExhaustiveDependencies, effectReportMode);
|
|
if (diagnostic != null) {
|
|
fn.env.recordError(diagnostic);
|
|
}
|
|
},
|
|
}, false);
|
|
}
|
|
function validateDependencies(inferred, manualDependencies, reactive, manualMemoLoc, category, exhaustiveDepsReportMode) {
|
|
var _a, _b, _c, _d;
|
|
inferred.sort((a, b) => {
|
|
var _a, _b;
|
|
if (a.kind === 'Global' && b.kind == 'Global') {
|
|
return a.binding.name.localeCompare(b.binding.name);
|
|
}
|
|
else if (a.kind == 'Local' && b.kind == 'Local') {
|
|
CompilerError.invariant(a.identifier.name != null &&
|
|
a.identifier.name.kind === 'named' &&
|
|
b.identifier.name != null &&
|
|
b.identifier.name.kind === 'named', {
|
|
reason: 'Expected dependencies to be named variables',
|
|
loc: a.loc,
|
|
});
|
|
if (a.identifier.id !== b.identifier.id) {
|
|
return a.identifier.name.value.localeCompare(b.identifier.name.value);
|
|
}
|
|
if (a.path.length !== b.path.length) {
|
|
return a.path.length - b.path.length;
|
|
}
|
|
for (let i = 0; i < a.path.length; i++) {
|
|
const aProperty = a.path[i];
|
|
const bProperty = b.path[i];
|
|
const aOptional = aProperty.optional ? 0 : 1;
|
|
const bOptional = bProperty.optional ? 0 : 1;
|
|
if (aOptional !== bOptional) {
|
|
return aOptional - bOptional;
|
|
}
|
|
else if (aProperty.property !== bProperty.property) {
|
|
return String(aProperty.property).localeCompare(String(bProperty.property));
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
else {
|
|
const aName = a.kind === 'Global' ? a.binding.name : (_a = a.identifier.name) === null || _a === void 0 ? void 0 : _a.value;
|
|
const bName = b.kind === 'Global' ? b.binding.name : (_b = b.identifier.name) === null || _b === void 0 ? void 0 : _b.value;
|
|
if (aName != null && bName != null) {
|
|
return aName.localeCompare(bName);
|
|
}
|
|
return 0;
|
|
}
|
|
});
|
|
retainWhere(inferred, (dep, ix) => {
|
|
const match = inferred.findIndex(prevDep => {
|
|
return (isEqualTemporary(prevDep, dep) ||
|
|
(prevDep.kind === 'Local' &&
|
|
dep.kind === 'Local' &&
|
|
prevDep.identifier.id === dep.identifier.id &&
|
|
isSubPath(prevDep.path, dep.path)));
|
|
});
|
|
return match === -1 || match >= ix;
|
|
});
|
|
const matched = new Set();
|
|
const missing = [];
|
|
const extra = [];
|
|
for (const inferredDependency of inferred) {
|
|
if (inferredDependency.kind === 'Global') {
|
|
for (const manualDependency of manualDependencies) {
|
|
if (manualDependency.root.kind === 'Global' &&
|
|
manualDependency.root.identifierName ===
|
|
inferredDependency.binding.name) {
|
|
matched.add(manualDependency);
|
|
extra.push(manualDependency);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
CompilerError.invariant(inferredDependency.kind === 'Local', {
|
|
reason: 'Unexpected function dependency',
|
|
loc: inferredDependency.loc,
|
|
});
|
|
if (isEffectEventFunctionType(inferredDependency.identifier)) {
|
|
continue;
|
|
}
|
|
let hasMatchingManualDependency = false;
|
|
for (const manualDependency of manualDependencies) {
|
|
if (manualDependency.root.kind === 'NamedLocal' &&
|
|
manualDependency.root.value.identifier.id ===
|
|
inferredDependency.identifier.id &&
|
|
(areEqualPaths(manualDependency.path, inferredDependency.path) ||
|
|
isSubPathIgnoringOptionals(manualDependency.path, inferredDependency.path))) {
|
|
hasMatchingManualDependency = true;
|
|
matched.add(manualDependency);
|
|
}
|
|
}
|
|
if (hasMatchingManualDependency ||
|
|
isOptionalDependency(inferredDependency, reactive)) {
|
|
continue;
|
|
}
|
|
missing.push(inferredDependency);
|
|
}
|
|
for (const dep of manualDependencies) {
|
|
if (matched.has(dep)) {
|
|
continue;
|
|
}
|
|
if (dep.root.kind === 'NamedLocal' && dep.root.constant) {
|
|
CompilerError.invariant(!dep.root.value.reactive && isPrimitiveType(dep.root.value.identifier), {
|
|
reason: 'Expected constant-folded dependency to be non-reactive',
|
|
loc: dep.root.value.loc,
|
|
});
|
|
continue;
|
|
}
|
|
extra.push(dep);
|
|
}
|
|
const filteredMissing = exhaustiveDepsReportMode === 'extra-only' ? [] : missing;
|
|
const filteredExtra = exhaustiveDepsReportMode === 'missing-only' ? [] : extra;
|
|
if (filteredMissing.length !== 0 || filteredExtra.length !== 0) {
|
|
let suggestion = null;
|
|
if (manualMemoLoc != null &&
|
|
typeof manualMemoLoc !== 'symbol' &&
|
|
manualMemoLoc.start.index != null &&
|
|
manualMemoLoc.end.index != null) {
|
|
suggestion = {
|
|
description: 'Update dependencies',
|
|
range: [manualMemoLoc.start.index, manualMemoLoc.end.index],
|
|
op: CompilerSuggestionOperation.Replace,
|
|
text: `[${inferred
|
|
.filter(dep => dep.kind === 'Local' &&
|
|
!isOptionalDependency(dep, reactive) &&
|
|
!isEffectEventFunctionType(dep.identifier))
|
|
.map(printInferredDependency)
|
|
.join(', ')}]`,
|
|
};
|
|
}
|
|
const diagnostic = createDiagnostic(category, filteredMissing, filteredExtra, suggestion);
|
|
for (const dep of filteredMissing) {
|
|
let reactiveStableValueHint = '';
|
|
if (isStableType(dep.identifier)) {
|
|
reactiveStableValueHint =
|
|
'. Refs, setState functions, and other "stable" values generally do not need to be added ' +
|
|
'as dependencies, but this variable may change over time to point to different values';
|
|
}
|
|
diagnostic.withDetails({
|
|
kind: 'error',
|
|
message: `Missing dependency \`${printInferredDependency(dep)}\`${reactiveStableValueHint}`,
|
|
loc: dep.loc,
|
|
});
|
|
}
|
|
for (const dep of filteredExtra) {
|
|
if (dep.root.kind === 'Global') {
|
|
diagnostic.withDetails({
|
|
kind: 'error',
|
|
message: `Unnecessary dependency \`${printManualMemoDependency(dep)}\`. ` +
|
|
'Values declared outside of a component/hook should not be listed as ' +
|
|
'dependencies as the component will not re-render if they change',
|
|
loc: (_a = dep.loc) !== null && _a !== void 0 ? _a : manualMemoLoc,
|
|
});
|
|
}
|
|
else {
|
|
const root = dep.root.value;
|
|
const matchingInferred = inferred.find((inferredDep) => {
|
|
return (inferredDep.kind === 'Local' &&
|
|
inferredDep.identifier.id === root.identifier.id &&
|
|
isSubPathIgnoringOptionals(inferredDep.path, dep.path));
|
|
});
|
|
if (matchingInferred != null &&
|
|
isEffectEventFunctionType(matchingInferred.identifier)) {
|
|
diagnostic.withDetails({
|
|
kind: 'error',
|
|
message: `Functions returned from \`useEffectEvent\` must not be included in the dependency array. ` +
|
|
`Remove \`${printManualMemoDependency(dep)}\` from the dependencies.`,
|
|
loc: (_b = dep.loc) !== null && _b !== void 0 ? _b : manualMemoLoc,
|
|
});
|
|
}
|
|
else if (matchingInferred != null &&
|
|
!isOptionalDependency(matchingInferred, reactive)) {
|
|
diagnostic.withDetails({
|
|
kind: 'error',
|
|
message: `Overly precise dependency \`${printManualMemoDependency(dep)}\`, ` +
|
|
`use \`${printInferredDependency(matchingInferred)}\` instead`,
|
|
loc: (_c = dep.loc) !== null && _c !== void 0 ? _c : manualMemoLoc,
|
|
});
|
|
}
|
|
else {
|
|
diagnostic.withDetails({
|
|
kind: 'error',
|
|
message: `Unnecessary dependency \`${printManualMemoDependency(dep)}\``,
|
|
loc: (_d = dep.loc) !== null && _d !== void 0 ? _d : manualMemoLoc,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (suggestion != null) {
|
|
diagnostic.withDetails({
|
|
kind: 'hint',
|
|
message: `Inferred dependencies: \`${suggestion.text}\``,
|
|
});
|
|
}
|
|
return diagnostic;
|
|
}
|
|
return null;
|
|
}
|
|
function addDependency(dep, dependencies, locals) {
|
|
if (dep.kind === 'Aggregate') {
|
|
for (const x of dep.dependencies) {
|
|
addDependency(x, dependencies, locals);
|
|
}
|
|
}
|
|
else if (dep.kind === 'Global') {
|
|
dependencies.add(dep);
|
|
}
|
|
else if (!locals.has(dep.identifier.id)) {
|
|
dependencies.add(dep);
|
|
}
|
|
}
|
|
function visitCandidateDependency(place, temporaries, dependencies, locals) {
|
|
const dep = temporaries.get(place.identifier.id);
|
|
if (dep != null) {
|
|
addDependency(dep, dependencies, locals);
|
|
}
|
|
}
|
|
function collectDependencies(fn, temporaries, callbacks, isFunctionExpression) {
|
|
var _a, _b;
|
|
const optionals = findOptionalPlaces(fn);
|
|
const locals = new Set();
|
|
if (isFunctionExpression) {
|
|
for (const param of fn.params) {
|
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
locals.add(place.identifier.id);
|
|
}
|
|
}
|
|
const dependencies = new Set();
|
|
function visit(place) {
|
|
visitCandidateDependency(place, temporaries, dependencies, locals);
|
|
}
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const phi of block.phis) {
|
|
const deps = [];
|
|
for (const operand of phi.operands.values()) {
|
|
const dep = temporaries.get(operand.identifier.id);
|
|
if (dep == null) {
|
|
continue;
|
|
}
|
|
if (dep.kind === 'Aggregate') {
|
|
deps.push(...dep.dependencies);
|
|
}
|
|
else {
|
|
deps.push(dep);
|
|
}
|
|
}
|
|
if (deps.length === 0) {
|
|
continue;
|
|
}
|
|
else if (deps.length === 1) {
|
|
temporaries.set(phi.place.identifier.id, deps[0]);
|
|
}
|
|
else {
|
|
temporaries.set(phi.place.identifier.id, {
|
|
kind: 'Aggregate',
|
|
dependencies: new Set(deps),
|
|
});
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
switch (value.kind) {
|
|
case 'LoadGlobal': {
|
|
temporaries.set(lvalue.identifier.id, {
|
|
kind: 'Global',
|
|
binding: value.binding,
|
|
});
|
|
break;
|
|
}
|
|
case 'LoadContext':
|
|
case 'LoadLocal': {
|
|
const temp = temporaries.get(value.place.identifier.id);
|
|
if (temp != null) {
|
|
if (temp.kind === 'Local') {
|
|
const local = Object.assign(Object.assign({}, temp), { loc: value.place.loc });
|
|
temporaries.set(lvalue.identifier.id, local);
|
|
}
|
|
else {
|
|
temporaries.set(lvalue.identifier.id, temp);
|
|
}
|
|
if (locals.has(value.place.identifier.id)) {
|
|
locals.add(lvalue.identifier.id);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'DeclareLocal': {
|
|
const local = {
|
|
kind: 'Local',
|
|
identifier: value.lvalue.place.identifier,
|
|
path: [],
|
|
context: false,
|
|
loc: value.lvalue.place.loc,
|
|
};
|
|
temporaries.set(value.lvalue.place.identifier.id, local);
|
|
locals.add(value.lvalue.place.identifier.id);
|
|
break;
|
|
}
|
|
case 'StoreLocal': {
|
|
if (value.lvalue.place.identifier.name == null) {
|
|
const temp = temporaries.get(value.value.identifier.id);
|
|
if (temp != null) {
|
|
temporaries.set(value.lvalue.place.identifier.id, temp);
|
|
}
|
|
break;
|
|
}
|
|
visit(value.value);
|
|
if (value.lvalue.kind !== InstructionKind.Reassign) {
|
|
const local = {
|
|
kind: 'Local',
|
|
identifier: value.lvalue.place.identifier,
|
|
path: [],
|
|
context: false,
|
|
loc: value.lvalue.place.loc,
|
|
};
|
|
temporaries.set(value.lvalue.place.identifier.id, local);
|
|
locals.add(value.lvalue.place.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'DeclareContext': {
|
|
const local = {
|
|
kind: 'Local',
|
|
identifier: value.lvalue.place.identifier,
|
|
path: [],
|
|
context: true,
|
|
loc: value.lvalue.place.loc,
|
|
};
|
|
temporaries.set(value.lvalue.place.identifier.id, local);
|
|
break;
|
|
}
|
|
case 'StoreContext': {
|
|
visit(value.value);
|
|
if (value.lvalue.kind !== InstructionKind.Reassign) {
|
|
const local = {
|
|
kind: 'Local',
|
|
identifier: value.lvalue.place.identifier,
|
|
path: [],
|
|
context: true,
|
|
loc: value.lvalue.place.loc,
|
|
};
|
|
temporaries.set(value.lvalue.place.identifier.id, local);
|
|
locals.add(value.lvalue.place.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
visit(value.value);
|
|
if (value.lvalue.kind !== InstructionKind.Reassign) {
|
|
for (const lvalue of eachInstructionValueLValue(value)) {
|
|
const local = {
|
|
kind: 'Local',
|
|
identifier: lvalue.identifier,
|
|
path: [],
|
|
context: false,
|
|
loc: lvalue.loc,
|
|
};
|
|
temporaries.set(lvalue.identifier.id, local);
|
|
locals.add(lvalue.identifier.id);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'PropertyLoad': {
|
|
if (typeof value.property === 'number' ||
|
|
(isUseRefType(value.object.identifier) &&
|
|
value.property === 'current')) {
|
|
visit(value.object);
|
|
break;
|
|
}
|
|
const object = temporaries.get(value.object.identifier.id);
|
|
if (object != null && object.kind === 'Local') {
|
|
const optional = (_a = optionals.get(value.object.identifier.id)) !== null && _a !== void 0 ? _a : false;
|
|
const local = {
|
|
kind: 'Local',
|
|
identifier: object.identifier,
|
|
context: object.context,
|
|
path: [
|
|
...object.path,
|
|
{
|
|
optional,
|
|
property: value.property,
|
|
loc: value.loc,
|
|
},
|
|
],
|
|
loc: value.loc,
|
|
};
|
|
temporaries.set(lvalue.identifier.id, local);
|
|
}
|
|
break;
|
|
}
|
|
case 'FunctionExpression':
|
|
case 'ObjectMethod': {
|
|
const functionDeps = collectDependencies(value.loweredFunc.func, temporaries, null, true);
|
|
temporaries.set(lvalue.identifier.id, functionDeps);
|
|
addDependency(functionDeps, dependencies, locals);
|
|
break;
|
|
}
|
|
case 'StartMemoize': {
|
|
const onStartMemoize = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onStartMemoize;
|
|
if (onStartMemoize != null) {
|
|
onStartMemoize(value, dependencies, locals);
|
|
}
|
|
break;
|
|
}
|
|
case 'FinishMemoize': {
|
|
const onFinishMemoize = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onFinishMemoize;
|
|
if (onFinishMemoize != null) {
|
|
onFinishMemoize(value, dependencies, locals);
|
|
}
|
|
break;
|
|
}
|
|
case 'ArrayExpression': {
|
|
const arrayDeps = new Set();
|
|
for (const item of value.elements) {
|
|
if (item.kind === 'Hole') {
|
|
continue;
|
|
}
|
|
const place = item.kind === 'Identifier' ? item : item.place;
|
|
visitCandidateDependency(place, temporaries, arrayDeps, new Set());
|
|
visit(place);
|
|
}
|
|
temporaries.set(lvalue.identifier.id, {
|
|
kind: 'Aggregate',
|
|
dependencies: arrayDeps,
|
|
loc: value.loc,
|
|
});
|
|
break;
|
|
}
|
|
case 'CallExpression':
|
|
case 'MethodCall': {
|
|
const receiver = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
const onEffect = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onEffect;
|
|
if (onEffect != null && isEffectHook(receiver.identifier)) {
|
|
const [fn, deps] = value.args;
|
|
if ((fn === null || fn === void 0 ? void 0 : fn.kind) === 'Identifier' && (deps === null || deps === void 0 ? void 0 : deps.kind) === 'Identifier') {
|
|
const fnDeps = temporaries.get(fn.identifier.id);
|
|
const manualDeps = temporaries.get(deps.identifier.id);
|
|
if ((fnDeps === null || fnDeps === void 0 ? void 0 : fnDeps.kind) === 'Aggregate' &&
|
|
(manualDeps === null || manualDeps === void 0 ? void 0 : manualDeps.kind) === 'Aggregate') {
|
|
onEffect(fnDeps.dependencies, manualDeps.dependencies, (_b = manualDeps.loc) !== null && _b !== void 0 ? _b : null);
|
|
}
|
|
}
|
|
}
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
if (value.kind === 'MethodCall' &&
|
|
operand.identifier.id === value.property.identifier.id) {
|
|
continue;
|
|
}
|
|
visit(operand);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
visit(operand);
|
|
}
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
locals.add(lvalue.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
if (optionals.has(operand.identifier.id)) {
|
|
continue;
|
|
}
|
|
visit(operand);
|
|
}
|
|
}
|
|
return { kind: 'Aggregate', dependencies };
|
|
}
|
|
function printInferredDependency(dep) {
|
|
switch (dep.kind) {
|
|
case 'Global': {
|
|
return dep.binding.name;
|
|
}
|
|
case 'Local': {
|
|
CompilerError.invariant(dep.identifier.name != null && dep.identifier.name.kind === 'named', {
|
|
reason: 'Expected dependencies to be named variables',
|
|
loc: dep.loc,
|
|
});
|
|
return `${dep.identifier.name.value}${dep.path.map(p => (p.optional ? '?' : '') + '.' + p.property).join('')}`;
|
|
}
|
|
}
|
|
}
|
|
function printManualMemoDependency(dep) {
|
|
let identifierName;
|
|
if (dep.root.kind === 'Global') {
|
|
identifierName = dep.root.identifierName;
|
|
}
|
|
else {
|
|
const name = dep.root.value.identifier.name;
|
|
CompilerError.invariant(name != null && name.kind === 'named', {
|
|
reason: 'Expected manual dependencies to be named variables',
|
|
loc: dep.root.value.loc,
|
|
});
|
|
identifierName = name.value;
|
|
}
|
|
return `${identifierName}${dep.path.map(p => (p.optional ? '?' : '') + '.' + p.property).join('')}`;
|
|
}
|
|
function isEqualTemporary(a, b) {
|
|
switch (a.kind) {
|
|
case 'Aggregate': {
|
|
return false;
|
|
}
|
|
case 'Global': {
|
|
return b.kind === 'Global' && a.binding.name === b.binding.name;
|
|
}
|
|
case 'Local': {
|
|
return (b.kind === 'Local' &&
|
|
a.identifier.id === b.identifier.id &&
|
|
areEqualPaths(a.path, b.path));
|
|
}
|
|
}
|
|
}
|
|
function collectReactiveIdentifiersHIR(fn) {
|
|
const reactive = new Set();
|
|
for (const block of fn.body.blocks.values()) {
|
|
for (const instr of block.instructions) {
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
if (lvalue.reactive) {
|
|
reactive.add(lvalue.identifier.id);
|
|
}
|
|
}
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
if (operand.reactive) {
|
|
reactive.add(operand.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
if (operand.reactive) {
|
|
reactive.add(operand.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
return reactive;
|
|
}
|
|
function findOptionalPlaces(fn) {
|
|
const optionals = new Map();
|
|
const visited = new Set();
|
|
for (const [, block] of fn.body.blocks) {
|
|
if (visited.has(block.id)) {
|
|
continue;
|
|
}
|
|
if (block.terminal.kind === 'optional') {
|
|
visited.add(block.id);
|
|
const optionalTerminal = block.terminal;
|
|
let testBlock = fn.body.blocks.get(block.terminal.test);
|
|
const queue = [block.terminal.optional];
|
|
loop: while (true) {
|
|
visited.add(testBlock.id);
|
|
const terminal = testBlock.terminal;
|
|
switch (terminal.kind) {
|
|
case 'branch': {
|
|
const isOptional = queue.pop();
|
|
CompilerError.invariant(isOptional !== undefined, {
|
|
reason: 'Expected an optional value for each optional test condition',
|
|
loc: terminal.test.loc,
|
|
});
|
|
if (isOptional != null) {
|
|
optionals.set(terminal.test.identifier.id, isOptional);
|
|
}
|
|
if (terminal.fallthrough === optionalTerminal.fallthrough) {
|
|
const consequent = fn.body.blocks.get(terminal.consequent);
|
|
const last = consequent.instructions.at(-1);
|
|
if (last !== undefined && last.value.kind === 'StoreLocal') {
|
|
if (isOptional != null) {
|
|
optionals.set(last.value.value.identifier.id, isOptional);
|
|
}
|
|
}
|
|
break loop;
|
|
}
|
|
else {
|
|
testBlock = fn.body.blocks.get(terminal.fallthrough);
|
|
}
|
|
break;
|
|
}
|
|
case 'optional': {
|
|
queue.push(terminal.optional);
|
|
testBlock = fn.body.blocks.get(terminal.test);
|
|
break;
|
|
}
|
|
case 'logical':
|
|
case 'ternary': {
|
|
queue.push(null);
|
|
testBlock = fn.body.blocks.get(terminal.test);
|
|
break;
|
|
}
|
|
case 'sequence': {
|
|
testBlock = fn.body.blocks.get(terminal.block);
|
|
break;
|
|
}
|
|
case 'maybe-throw': {
|
|
testBlock = fn.body.blocks.get(terminal.continuation);
|
|
break;
|
|
}
|
|
default: {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected terminal in optional`,
|
|
message: `Unexpected ${terminal.kind} in optional`,
|
|
loc: terminal.loc,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
CompilerError.invariant(queue.length === 0, {
|
|
reason: 'Expected a matching number of conditional blocks and branch points',
|
|
loc: block.terminal.loc,
|
|
});
|
|
}
|
|
}
|
|
return optionals;
|
|
}
|
|
function isOptionalDependency(inferredDependency, reactive) {
|
|
return (!reactive.has(inferredDependency.identifier.id) &&
|
|
(isStableType(inferredDependency.identifier) ||
|
|
isPrimitiveType(inferredDependency.identifier)));
|
|
}
|
|
function createDiagnostic(category, missing, extra, suggestion) {
|
|
let reason;
|
|
let description;
|
|
function joinMissingExtraDetail(missingString, extraString, joinStr) {
|
|
return [
|
|
missing.length !== 0 ? missingString : null,
|
|
extra.length !== 0 ? extraString : null,
|
|
]
|
|
.filter(Boolean)
|
|
.join(joinStr);
|
|
}
|
|
switch (category) {
|
|
case ErrorCategory.MemoDependencies: {
|
|
reason = `Found ${joinMissingExtraDetail('missing', 'extra', '/')} memoization dependencies`;
|
|
description = joinMissingExtraDetail('Missing dependencies can cause a value to update less often than it should, resulting in stale UI', 'Extra dependencies can cause a value to update more often than it should, resulting in performance' +
|
|
' problems such as excessive renders or effects firing too often', '. ');
|
|
break;
|
|
}
|
|
case ErrorCategory.EffectExhaustiveDependencies: {
|
|
reason = `Found ${joinMissingExtraDetail('missing', 'extra', '/')} effect dependencies`;
|
|
description = joinMissingExtraDetail('Missing dependencies can cause an effect to fire less often than it should', 'Extra dependencies can cause an effect to fire more often than it should, resulting' +
|
|
' in performance problems such as excessive renders and side effects', '. ');
|
|
break;
|
|
}
|
|
default: {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected error category: ${category}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
return CompilerDiagnostic.create({
|
|
category,
|
|
reason,
|
|
description,
|
|
suggestions: suggestion != null ? [suggestion] : null,
|
|
});
|
|
}
|
|
function isEffectHook(identifier) {
|
|
return (isUseEffectHookType(identifier) ||
|
|
isUseLayoutEffectHookType(identifier) ||
|
|
isUseInsertionEffectHookType(identifier));
|
|
}
|
|
|
|
function run(func, config, fnType, mode, programContext, logger, filename, code) {
|
|
var _a, _b;
|
|
const contextIdentifiers = findContextIdentifiers(func);
|
|
const env = new Environment(func.scope, fnType, mode, config, contextIdentifiers, func, logger, filename, code, programContext);
|
|
(_b = (_a = env.logger) === null || _a === void 0 ? void 0 : _a.debugLogIRs) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
|
kind: 'debug',
|
|
name: 'EnvironmentConfig',
|
|
value: prettyFormat(env.config),
|
|
});
|
|
return runWithEnvironment(func, env);
|
|
}
|
|
function runWithEnvironment(func, env) {
|
|
const log = (value) => {
|
|
var _a, _b;
|
|
(_b = (_a = env.logger) === null || _a === void 0 ? void 0 : _a.debugLogIRs) === null || _b === void 0 ? void 0 : _b.call(_a, value);
|
|
};
|
|
const hir = lower(func, env);
|
|
log({ kind: 'hir', name: 'HIR', value: hir });
|
|
pruneMaybeThrows(hir);
|
|
log({ kind: 'hir', name: 'PruneMaybeThrows', value: hir });
|
|
validateContextVariableLValues(hir);
|
|
validateUseMemo(hir);
|
|
if (env.enableDropManualMemoization) {
|
|
dropManualMemoization(hir);
|
|
log({ kind: 'hir', name: 'DropManualMemoization', value: hir });
|
|
}
|
|
inlineImmediatelyInvokedFunctionExpressions(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'InlineImmediatelyInvokedFunctionExpressions',
|
|
value: hir,
|
|
});
|
|
mergeConsecutiveBlocks(hir);
|
|
log({ kind: 'hir', name: 'MergeConsecutiveBlocks', value: hir });
|
|
assertConsistentIdentifiers(hir);
|
|
assertTerminalSuccessorsExist(hir);
|
|
enterSSA(hir);
|
|
log({ kind: 'hir', name: 'SSA', value: hir });
|
|
eliminateRedundantPhi(hir);
|
|
log({ kind: 'hir', name: 'EliminateRedundantPhi', value: hir });
|
|
assertConsistentIdentifiers(hir);
|
|
constantPropagation(hir);
|
|
log({ kind: 'hir', name: 'ConstantPropagation', value: hir });
|
|
inferTypes(hir);
|
|
log({ kind: 'hir', name: 'InferTypes', value: hir });
|
|
if (env.enableValidations) {
|
|
if (env.config.validateHooksUsage) {
|
|
validateHooksUsage(hir);
|
|
}
|
|
if (env.config.validateNoCapitalizedCalls) {
|
|
validateNoCapitalizedCalls(hir);
|
|
}
|
|
}
|
|
optimizePropsMethodCalls(hir);
|
|
log({ kind: 'hir', name: 'OptimizePropsMethodCalls', value: hir });
|
|
analyseFunctions(hir);
|
|
log({ kind: 'hir', name: 'AnalyseFunctions', value: hir });
|
|
inferMutationAliasingEffects(hir);
|
|
log({ kind: 'hir', name: 'InferMutationAliasingEffects', value: hir });
|
|
if (env.outputMode === 'ssr') {
|
|
optimizeForSSR(hir);
|
|
log({ kind: 'hir', name: 'OptimizeForSSR', value: hir });
|
|
}
|
|
deadCodeElimination(hir);
|
|
log({ kind: 'hir', name: 'DeadCodeElimination', value: hir });
|
|
pruneMaybeThrows(hir);
|
|
log({ kind: 'hir', name: 'PruneMaybeThrows', value: hir });
|
|
inferMutationAliasingRanges(hir, {
|
|
isFunctionExpression: false,
|
|
});
|
|
log({ kind: 'hir', name: 'InferMutationAliasingRanges', value: hir });
|
|
if (env.enableValidations) {
|
|
validateLocalsNotReassignedAfterRender(hir);
|
|
if (env.config.assertValidMutableRanges) {
|
|
assertValidMutableRanges(hir);
|
|
}
|
|
if (env.config.validateRefAccessDuringRender) {
|
|
validateNoRefAccessInRender(hir);
|
|
}
|
|
if (env.config.validateNoSetStateInRender) {
|
|
validateNoSetStateInRender(hir);
|
|
}
|
|
if (env.config.validateNoDerivedComputationsInEffects_exp &&
|
|
env.outputMode === 'lint') {
|
|
env.logErrors(validateNoDerivedComputationsInEffects_exp(hir));
|
|
}
|
|
else if (env.config.validateNoDerivedComputationsInEffects) {
|
|
validateNoDerivedComputationsInEffects(hir);
|
|
}
|
|
if (env.config.validateNoSetStateInEffects && env.outputMode === 'lint') {
|
|
env.logErrors(validateNoSetStateInEffects(hir, env));
|
|
}
|
|
if (env.config.validateNoJSXInTryStatements && env.outputMode === 'lint') {
|
|
env.logErrors(validateNoJSXInTryStatement(hir));
|
|
}
|
|
validateNoFreezingKnownMutableFunctions(hir);
|
|
}
|
|
inferReactivePlaces(hir);
|
|
log({ kind: 'hir', name: 'InferReactivePlaces', value: hir });
|
|
if (env.enableValidations) {
|
|
if (env.config.validateExhaustiveMemoizationDependencies ||
|
|
env.config.validateExhaustiveEffectDependencies) {
|
|
validateExhaustiveDependencies(hir);
|
|
}
|
|
}
|
|
rewriteInstructionKindsBasedOnReassignment(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'RewriteInstructionKindsBasedOnReassignment',
|
|
value: hir,
|
|
});
|
|
if (env.enableValidations &&
|
|
env.config.validateStaticComponents &&
|
|
env.outputMode === 'lint') {
|
|
env.logErrors(validateStaticComponents(hir));
|
|
}
|
|
if (env.enableMemoization) {
|
|
inferReactiveScopeVariables(hir);
|
|
log({ kind: 'hir', name: 'InferReactiveScopeVariables', value: hir });
|
|
}
|
|
const fbtOperands = memoizeFbtAndMacroOperandsInSameScope(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'MemoizeFbtAndMacroOperandsInSameScope',
|
|
value: hir,
|
|
});
|
|
if (env.config.enableJsxOutlining) {
|
|
outlineJSX(hir);
|
|
}
|
|
if (env.config.enableNameAnonymousFunctions) {
|
|
nameAnonymousFunctions(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'NameAnonymousFunctions',
|
|
value: hir,
|
|
});
|
|
}
|
|
if (env.config.enableFunctionOutlining) {
|
|
outlineFunctions(hir, fbtOperands);
|
|
log({ kind: 'hir', name: 'OutlineFunctions', value: hir });
|
|
}
|
|
alignMethodCallScopes(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'AlignMethodCallScopes',
|
|
value: hir,
|
|
});
|
|
alignObjectMethodScopes(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'AlignObjectMethodScopes',
|
|
value: hir,
|
|
});
|
|
pruneUnusedLabelsHIR(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'PruneUnusedLabelsHIR',
|
|
value: hir,
|
|
});
|
|
alignReactiveScopesToBlockScopesHIR(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'AlignReactiveScopesToBlockScopesHIR',
|
|
value: hir,
|
|
});
|
|
mergeOverlappingReactiveScopesHIR(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'MergeOverlappingReactiveScopesHIR',
|
|
value: hir,
|
|
});
|
|
assertValidBlockNesting(hir);
|
|
buildReactiveScopeTerminalsHIR(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'BuildReactiveScopeTerminalsHIR',
|
|
value: hir,
|
|
});
|
|
assertValidBlockNesting(hir);
|
|
flattenReactiveLoopsHIR(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'FlattenReactiveLoopsHIR',
|
|
value: hir,
|
|
});
|
|
flattenScopesWithHooksOrUseHIR(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'FlattenScopesWithHooksOrUseHIR',
|
|
value: hir,
|
|
});
|
|
assertTerminalSuccessorsExist(hir);
|
|
assertTerminalPredsExist(hir);
|
|
propagateScopeDependenciesHIR(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'PropagateScopeDependenciesHIR',
|
|
value: hir,
|
|
});
|
|
const reactiveFunction = buildReactiveFunction(hir);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'BuildReactiveFunction',
|
|
value: reactiveFunction,
|
|
});
|
|
assertWellFormedBreakTargets(reactiveFunction);
|
|
pruneUnusedLabels(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'PruneUnusedLabels',
|
|
value: reactiveFunction,
|
|
});
|
|
assertScopeInstructionsWithinScopes(reactiveFunction);
|
|
pruneNonEscapingScopes(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'PruneNonEscapingScopes',
|
|
value: reactiveFunction,
|
|
});
|
|
pruneNonReactiveDependencies(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'PruneNonReactiveDependencies',
|
|
value: reactiveFunction,
|
|
});
|
|
pruneUnusedScopes(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'PruneUnusedScopes',
|
|
value: reactiveFunction,
|
|
});
|
|
mergeReactiveScopesThatInvalidateTogether(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'MergeReactiveScopesThatInvalidateTogether',
|
|
value: reactiveFunction,
|
|
});
|
|
pruneAlwaysInvalidatingScopes(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'PruneAlwaysInvalidatingScopes',
|
|
value: reactiveFunction,
|
|
});
|
|
propagateEarlyReturns(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'PropagateEarlyReturns',
|
|
value: reactiveFunction,
|
|
});
|
|
pruneUnusedLValues(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'PruneUnusedLValues',
|
|
value: reactiveFunction,
|
|
});
|
|
promoteUsedTemporaries(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'PromoteUsedTemporaries',
|
|
value: reactiveFunction,
|
|
});
|
|
extractScopeDeclarationsFromDestructuring(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'ExtractScopeDeclarationsFromDestructuring',
|
|
value: reactiveFunction,
|
|
});
|
|
stabilizeBlockIds(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'StabilizeBlockIds',
|
|
value: reactiveFunction,
|
|
});
|
|
const uniqueIdentifiers = renameVariables(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'RenameVariables',
|
|
value: reactiveFunction,
|
|
});
|
|
pruneHoistedContexts(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'PruneHoistedContexts',
|
|
value: reactiveFunction,
|
|
});
|
|
if (env.config.enablePreserveExistingMemoizationGuarantees ||
|
|
env.config.validatePreserveExistingMemoizationGuarantees) {
|
|
validatePreservedManualMemoization(reactiveFunction);
|
|
}
|
|
const ast = codegenFunction(reactiveFunction, {
|
|
uniqueIdentifiers,
|
|
fbtOperands,
|
|
});
|
|
log({ kind: 'ast', name: 'Codegen', value: ast });
|
|
for (const outlined of ast.outlined) {
|
|
log({ kind: 'ast', name: 'Codegen (outlined)', value: outlined.fn });
|
|
}
|
|
if (env.config.validateSourceLocations) {
|
|
validateSourceLocations(func, ast, env);
|
|
}
|
|
if (env.config.throwUnknownException__testonly) {
|
|
throw new Error('unexpected error');
|
|
}
|
|
if (env.hasErrors()) {
|
|
return Err(env.aggregateErrors());
|
|
}
|
|
return Ok(ast);
|
|
}
|
|
function compileFn(func, config, fnType, mode, programContext, logger, filename, code) {
|
|
return run(func, config, fnType, mode, programContext, logger, filename, code);
|
|
}
|
|
|
|
function filterSuppressionsThatAffectFunction(suppressionRanges, fn) {
|
|
const suppressionsInScope = [];
|
|
const fnNode = fn.node;
|
|
for (const suppressionRange of suppressionRanges) {
|
|
if (suppressionRange.disableComment.start == null ||
|
|
fnNode.start == null ||
|
|
fnNode.end == null) {
|
|
continue;
|
|
}
|
|
if (suppressionRange.disableComment.start > fnNode.start &&
|
|
(suppressionRange.enableComment === null ||
|
|
(suppressionRange.enableComment.end != null &&
|
|
suppressionRange.enableComment.end < fnNode.end))) {
|
|
suppressionsInScope.push(suppressionRange);
|
|
}
|
|
if (suppressionRange.disableComment.start < fnNode.start &&
|
|
(suppressionRange.enableComment === null ||
|
|
(suppressionRange.enableComment.end != null &&
|
|
suppressionRange.enableComment.end > fnNode.end))) {
|
|
suppressionsInScope.push(suppressionRange);
|
|
}
|
|
}
|
|
return suppressionsInScope;
|
|
}
|
|
function findProgramSuppressions(programComments, ruleNames, flowSuppressions) {
|
|
const suppressionRanges = [];
|
|
let disableComment = null;
|
|
let enableComment = null;
|
|
let source = null;
|
|
let disableNextLinePattern = null;
|
|
let disablePattern = null;
|
|
let enablePattern = null;
|
|
if (ruleNames != null && ruleNames.length !== 0) {
|
|
const rulePattern = `(${ruleNames.join('|')})`;
|
|
disableNextLinePattern = new RegExp(`eslint-disable-next-line ${rulePattern}`);
|
|
disablePattern = new RegExp(`eslint-disable ${rulePattern}`);
|
|
enablePattern = new RegExp(`eslint-enable ${rulePattern}`);
|
|
}
|
|
const flowSuppressionPattern = new RegExp('\\$(FlowFixMe\\w*|FlowExpectedError|FlowIssue)\\[react\\-rule');
|
|
for (const comment of programComments) {
|
|
if (comment.start == null || comment.end == null) {
|
|
continue;
|
|
}
|
|
if (disableComment == null &&
|
|
disableNextLinePattern != null &&
|
|
disableNextLinePattern.test(comment.value)) {
|
|
disableComment = comment;
|
|
enableComment = comment;
|
|
source = 'Eslint';
|
|
}
|
|
if (flowSuppressions &&
|
|
disableComment == null &&
|
|
flowSuppressionPattern.test(comment.value)) {
|
|
disableComment = comment;
|
|
enableComment = comment;
|
|
source = 'Flow';
|
|
}
|
|
if (disablePattern != null && disablePattern.test(comment.value)) {
|
|
disableComment = comment;
|
|
source = 'Eslint';
|
|
}
|
|
if (enablePattern != null &&
|
|
enablePattern.test(comment.value) &&
|
|
source === 'Eslint') {
|
|
enableComment = comment;
|
|
}
|
|
if (disableComment != null && source != null) {
|
|
suppressionRanges.push({
|
|
disableComment: disableComment,
|
|
enableComment: enableComment,
|
|
source,
|
|
});
|
|
disableComment = null;
|
|
enableComment = null;
|
|
source = null;
|
|
}
|
|
}
|
|
return suppressionRanges;
|
|
}
|
|
function suppressionsToCompilerError(suppressionRanges) {
|
|
var _a;
|
|
CompilerError.invariant(suppressionRanges.length !== 0, {
|
|
reason: `Expected at least suppression comment source range`,
|
|
loc: GeneratedSource,
|
|
});
|
|
const error = new CompilerError();
|
|
for (const suppressionRange of suppressionRanges) {
|
|
if (suppressionRange.disableComment.start == null ||
|
|
suppressionRange.disableComment.end == null) {
|
|
continue;
|
|
}
|
|
let reason, suggestion;
|
|
switch (suppressionRange.source) {
|
|
case 'Eslint':
|
|
reason =
|
|
'React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled';
|
|
suggestion =
|
|
'Remove the ESLint suppression and address the React error';
|
|
break;
|
|
case 'Flow':
|
|
reason =
|
|
'React Compiler has skipped optimizing this component because one or more React rule violations were reported by Flow';
|
|
suggestion = 'Remove the Flow suppression and address the React error';
|
|
break;
|
|
default:
|
|
assertExhaustive$1(suppressionRange.source, 'Unhandled suppression source');
|
|
}
|
|
error.pushDiagnostic(CompilerDiagnostic.create({
|
|
reason: reason,
|
|
description: `React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression \`${suppressionRange.disableComment.value.trim()}\``,
|
|
category: ErrorCategory.Suppression,
|
|
suggestions: [
|
|
{
|
|
description: suggestion,
|
|
range: [
|
|
suppressionRange.disableComment.start,
|
|
suppressionRange.disableComment.end,
|
|
],
|
|
op: CompilerSuggestionOperation.Remove,
|
|
},
|
|
],
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: (_a = suppressionRange.disableComment.loc) !== null && _a !== void 0 ? _a : null,
|
|
message: 'Found React rule suppression',
|
|
}));
|
|
}
|
|
return error;
|
|
}
|
|
|
|
const OPT_IN_DIRECTIVES = new Set(['use forget', 'use memo']);
|
|
const OPT_OUT_DIRECTIVES = new Set(['use no forget', 'use no memo']);
|
|
const DYNAMIC_GATING_DIRECTIVE = new RegExp('^use memo if\\(([^\\)]*)\\)$');
|
|
function tryFindDirectiveEnablingMemoization(directives, opts) {
|
|
var _a, _b;
|
|
const optIn = directives.find(directive => OPT_IN_DIRECTIVES.has(directive.value.value));
|
|
if (optIn != null) {
|
|
return Ok(optIn);
|
|
}
|
|
const dynamicGating = findDirectivesDynamicGating(directives, opts);
|
|
if (dynamicGating.isOk()) {
|
|
return Ok((_b = (_a = dynamicGating.unwrap()) === null || _a === void 0 ? void 0 : _a.directive) !== null && _b !== void 0 ? _b : null);
|
|
}
|
|
else {
|
|
return Err(dynamicGating.unwrapErr());
|
|
}
|
|
}
|
|
function findDirectiveDisablingMemoization(directives, { customOptOutDirectives }) {
|
|
var _a, _b;
|
|
if (customOptOutDirectives != null) {
|
|
return ((_a = directives.find(directive => customOptOutDirectives.indexOf(directive.value.value) !== -1)) !== null && _a !== void 0 ? _a : null);
|
|
}
|
|
return ((_b = directives.find(directive => OPT_OUT_DIRECTIVES.has(directive.value.value))) !== null && _b !== void 0 ? _b : null);
|
|
}
|
|
function findDirectivesDynamicGating(directives, opts) {
|
|
var _a, _b;
|
|
if (opts.dynamicGating === null) {
|
|
return Ok(null);
|
|
}
|
|
const errors = new CompilerError();
|
|
const result = [];
|
|
for (const directive of directives) {
|
|
const maybeMatch = DYNAMIC_GATING_DIRECTIVE.exec(directive.value.value);
|
|
if (maybeMatch != null && maybeMatch[1] != null) {
|
|
if (libExports$1.isValidIdentifier(maybeMatch[1])) {
|
|
result.push({ directive, match: maybeMatch[1] });
|
|
}
|
|
else {
|
|
errors.push({
|
|
reason: `Dynamic gating directive is not a valid JavaScript identifier`,
|
|
description: `Found '${directive.value.value}'`,
|
|
category: ErrorCategory.Gating,
|
|
loc: (_a = directive.loc) !== null && _a !== void 0 ? _a : null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (errors.hasAnyErrors()) {
|
|
return Err(errors);
|
|
}
|
|
else if (result.length > 1) {
|
|
const error = new CompilerError();
|
|
error.push({
|
|
reason: `Multiple dynamic gating directives found`,
|
|
description: `Expected a single directive but found [${result
|
|
.map(r => r.directive.value.value)
|
|
.join(', ')}]`,
|
|
category: ErrorCategory.Gating,
|
|
loc: (_b = result[0].directive.loc) !== null && _b !== void 0 ? _b : null,
|
|
suggestions: null,
|
|
});
|
|
return Err(error);
|
|
}
|
|
else if (result.length === 1) {
|
|
return Ok({
|
|
gating: {
|
|
source: opts.dynamicGating.source,
|
|
importSpecifierName: result[0].match,
|
|
},
|
|
directive: result[0].directive,
|
|
});
|
|
}
|
|
else {
|
|
return Ok(null);
|
|
}
|
|
}
|
|
function isError(err) {
|
|
return !(err instanceof CompilerError) || err.hasErrors();
|
|
}
|
|
function isConfigError(err) {
|
|
if (err instanceof CompilerError) {
|
|
return err.details.some(detail => detail.category === ErrorCategory.Config);
|
|
}
|
|
return false;
|
|
}
|
|
function logError(err, context, fnLoc) {
|
|
var _a, _b;
|
|
if (context.opts.logger) {
|
|
if (err instanceof CompilerError) {
|
|
for (const detail of err.details) {
|
|
context.opts.logger.logEvent(context.filename, {
|
|
kind: 'CompileError',
|
|
fnLoc,
|
|
detail,
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
let stringifiedError;
|
|
if (err instanceof Error) {
|
|
stringifiedError = (_a = err.stack) !== null && _a !== void 0 ? _a : err.message;
|
|
}
|
|
else {
|
|
stringifiedError = (_b = err === null || err === void 0 ? void 0 : err.toString()) !== null && _b !== void 0 ? _b : '[ null ]';
|
|
}
|
|
context.opts.logger.logEvent(context.filename, {
|
|
kind: 'PipelineError',
|
|
fnLoc,
|
|
data: stringifiedError,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
function handleError(err, context, fnLoc) {
|
|
logError(err, context, fnLoc);
|
|
if (context.opts.panicThreshold === 'all_errors' ||
|
|
(context.opts.panicThreshold === 'critical_errors' && isError(err)) ||
|
|
isConfigError(err)) {
|
|
throw err;
|
|
}
|
|
}
|
|
function createNewFunctionNode(originalFn, compiledFn) {
|
|
var _a, _b, _c;
|
|
let transformedFn;
|
|
switch (originalFn.node.type) {
|
|
case 'FunctionDeclaration': {
|
|
const fn = {
|
|
type: 'FunctionDeclaration',
|
|
id: compiledFn.id,
|
|
loc: (_a = originalFn.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
async: compiledFn.async,
|
|
generator: compiledFn.generator,
|
|
params: compiledFn.params,
|
|
body: compiledFn.body,
|
|
};
|
|
transformedFn = fn;
|
|
break;
|
|
}
|
|
case 'ArrowFunctionExpression': {
|
|
const fn = {
|
|
type: 'ArrowFunctionExpression',
|
|
loc: (_b = originalFn.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
async: compiledFn.async,
|
|
generator: compiledFn.generator,
|
|
params: compiledFn.params,
|
|
expression: originalFn.node.expression,
|
|
body: compiledFn.body,
|
|
};
|
|
transformedFn = fn;
|
|
break;
|
|
}
|
|
case 'FunctionExpression': {
|
|
const fn = {
|
|
type: 'FunctionExpression',
|
|
id: compiledFn.id,
|
|
loc: (_c = originalFn.node.loc) !== null && _c !== void 0 ? _c : null,
|
|
async: compiledFn.async,
|
|
generator: compiledFn.generator,
|
|
params: compiledFn.params,
|
|
body: compiledFn.body,
|
|
};
|
|
transformedFn = fn;
|
|
break;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(originalFn.node, `Creating unhandled function: ${originalFn.node}`);
|
|
}
|
|
}
|
|
return transformedFn;
|
|
}
|
|
function insertNewOutlinedFunctionNode(program, originalFn, compiledFn) {
|
|
var _a, _b, _c;
|
|
switch (originalFn.type) {
|
|
case 'FunctionDeclaration': {
|
|
return originalFn.insertAfter(createNewFunctionNode(originalFn, compiledFn))[0];
|
|
}
|
|
case 'ArrowFunctionExpression':
|
|
case 'FunctionExpression': {
|
|
const fn = {
|
|
type: 'FunctionDeclaration',
|
|
id: compiledFn.id,
|
|
loc: (_a = originalFn.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
async: compiledFn.async,
|
|
generator: compiledFn.generator,
|
|
params: compiledFn.params,
|
|
body: compiledFn.body,
|
|
};
|
|
const insertedFuncDecl = program.pushContainer('body', [fn])[0];
|
|
CompilerError.invariant(insertedFuncDecl.isFunctionDeclaration(), {
|
|
reason: 'Expected inserted function declaration',
|
|
description: `Got: ${insertedFuncDecl}`,
|
|
loc: (_c = (_b = insertedFuncDecl.node) === null || _b === void 0 ? void 0 : _b.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
});
|
|
return insertedFuncDecl;
|
|
}
|
|
default: {
|
|
assertExhaustive$1(originalFn, `Inserting unhandled function: ${originalFn}`);
|
|
}
|
|
}
|
|
}
|
|
const DEFAULT_ESLINT_SUPPRESSIONS = [
|
|
'react-hooks/exhaustive-deps',
|
|
'react-hooks/rules-of-hooks',
|
|
];
|
|
function isFilePartOfSources(sources, filename) {
|
|
if (typeof sources === 'function') {
|
|
return sources(filename);
|
|
}
|
|
for (const prefix of sources) {
|
|
if (filename.indexOf(prefix) !== -1) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function compileProgram(program, pass) {
|
|
var _a, _b;
|
|
if (shouldSkipCompilation(program, pass)) {
|
|
return;
|
|
}
|
|
const restrictedImportsErr = validateRestrictedImports(program, pass.opts.environment);
|
|
if (restrictedImportsErr) {
|
|
handleError(restrictedImportsErr, pass, null);
|
|
return;
|
|
}
|
|
const suppressions = findProgramSuppressions(pass.comments, pass.opts.environment.validateExhaustiveMemoizationDependencies &&
|
|
pass.opts.environment.validateHooksUsage
|
|
? null
|
|
: ((_a = pass.opts.eslintSuppressionRules) !== null && _a !== void 0 ? _a : DEFAULT_ESLINT_SUPPRESSIONS), pass.opts.flowSuppressions);
|
|
const programContext = new ProgramContext({
|
|
program: program,
|
|
opts: pass.opts,
|
|
filename: pass.filename,
|
|
code: pass.code,
|
|
suppressions,
|
|
hasModuleScopeOptOut: findDirectiveDisablingMemoization(program.node.directives, pass.opts) !=
|
|
null,
|
|
});
|
|
const queue = findFunctionsToCompile(program, pass, programContext);
|
|
const compiledFns = [];
|
|
const outputMode = (_b = pass.opts.outputMode) !== null && _b !== void 0 ? _b : (pass.opts.noEmit ? 'lint' : 'client');
|
|
while (queue.length !== 0) {
|
|
const current = queue.shift();
|
|
const compiled = processFn(current.fn, current.fnType, programContext, outputMode);
|
|
if (compiled != null) {
|
|
for (const outlined of compiled.outlined) {
|
|
CompilerError.invariant(outlined.fn.outlined.length === 0, {
|
|
reason: 'Unexpected nested outlined functions',
|
|
loc: outlined.fn.loc,
|
|
});
|
|
const fn = insertNewOutlinedFunctionNode(program, current.fn, outlined.fn);
|
|
fn.skip();
|
|
programContext.alreadyCompiled.add(fn.node);
|
|
if (outlined.type !== null) {
|
|
queue.push({
|
|
kind: 'outlined',
|
|
fn,
|
|
fnType: outlined.type,
|
|
});
|
|
}
|
|
}
|
|
compiledFns.push({
|
|
kind: current.kind,
|
|
originalFn: current.fn,
|
|
compiledFn: compiled,
|
|
});
|
|
}
|
|
}
|
|
if (programContext.hasModuleScopeOptOut) {
|
|
if (compiledFns.length > 0) {
|
|
const error = new CompilerError();
|
|
error.pushErrorDetail(new CompilerErrorDetail({
|
|
reason: 'Unexpected compiled functions when module scope opt-out is present',
|
|
category: ErrorCategory.Invariant,
|
|
loc: null,
|
|
}));
|
|
handleError(error, programContext, null);
|
|
}
|
|
return;
|
|
}
|
|
applyCompiledFunctions(program, compiledFns, pass, programContext);
|
|
}
|
|
function findFunctionsToCompile(program, pass, programContext) {
|
|
var _a;
|
|
const queue = [];
|
|
const traverseFunction = (fn, pass) => {
|
|
if (pass.opts.compilationMode === 'all' &&
|
|
fn.scope.getProgramParent() !== fn.scope.parent) {
|
|
return;
|
|
}
|
|
const fnType = getReactFunctionType(fn, pass);
|
|
if (fnType === null || programContext.alreadyCompiled.has(fn.node)) {
|
|
return;
|
|
}
|
|
programContext.alreadyCompiled.add(fn.node);
|
|
fn.skip();
|
|
queue.push({ kind: 'original', fn, fnType });
|
|
};
|
|
program.traverse({
|
|
ClassDeclaration(node) {
|
|
node.skip();
|
|
},
|
|
ClassExpression(node) {
|
|
node.skip();
|
|
},
|
|
FunctionDeclaration: traverseFunction,
|
|
FunctionExpression: traverseFunction,
|
|
ArrowFunctionExpression: traverseFunction,
|
|
}, Object.assign(Object.assign({}, pass), { opts: Object.assign(Object.assign({}, pass.opts), pass.opts), filename: (_a = pass.filename) !== null && _a !== void 0 ? _a : null }));
|
|
return queue;
|
|
}
|
|
function processFn(fn, fnType, programContext, outputMode) {
|
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
let directives;
|
|
if (fn.node.body.type !== 'BlockStatement') {
|
|
directives = {
|
|
optIn: null,
|
|
optOut: null,
|
|
};
|
|
}
|
|
else {
|
|
const optIn = tryFindDirectiveEnablingMemoization(fn.node.body.directives, programContext.opts);
|
|
if (optIn.isErr()) {
|
|
handleError(optIn.unwrapErr(), programContext, (_a = fn.node.loc) !== null && _a !== void 0 ? _a : null);
|
|
return null;
|
|
}
|
|
directives = {
|
|
optIn: optIn.unwrapOr(null),
|
|
optOut: findDirectiveDisablingMemoization(fn.node.body.directives, programContext.opts),
|
|
};
|
|
}
|
|
let compiledFn;
|
|
const compileResult = tryCompileFunction(fn, fnType, programContext, outputMode);
|
|
if (compileResult.kind === 'error') {
|
|
if (directives.optOut != null) {
|
|
logError(compileResult.error, programContext, (_b = fn.node.loc) !== null && _b !== void 0 ? _b : null);
|
|
}
|
|
else {
|
|
handleError(compileResult.error, programContext, (_c = fn.node.loc) !== null && _c !== void 0 ? _c : null);
|
|
}
|
|
return null;
|
|
}
|
|
else {
|
|
compiledFn = compileResult.compiledFn;
|
|
}
|
|
if (programContext.opts.ignoreUseNoForget === false &&
|
|
directives.optOut != null) {
|
|
programContext.logEvent({
|
|
kind: 'CompileSkip',
|
|
fnLoc: (_d = fn.node.body.loc) !== null && _d !== void 0 ? _d : null,
|
|
reason: `Skipped due to '${directives.optOut.value}' directive.`,
|
|
loc: (_e = directives.optOut.loc) !== null && _e !== void 0 ? _e : null,
|
|
});
|
|
return null;
|
|
}
|
|
programContext.logEvent({
|
|
kind: 'CompileSuccess',
|
|
fnLoc: (_f = fn.node.loc) !== null && _f !== void 0 ? _f : null,
|
|
fnName: (_h = (_g = compiledFn.id) === null || _g === void 0 ? void 0 : _g.name) !== null && _h !== void 0 ? _h : null,
|
|
memoSlots: compiledFn.memoSlotsUsed,
|
|
memoBlocks: compiledFn.memoBlocks,
|
|
memoValues: compiledFn.memoValues,
|
|
prunedMemoBlocks: compiledFn.prunedMemoBlocks,
|
|
prunedMemoValues: compiledFn.prunedMemoValues,
|
|
});
|
|
if (programContext.hasModuleScopeOptOut) {
|
|
return null;
|
|
}
|
|
else if (programContext.opts.outputMode === 'lint') {
|
|
return null;
|
|
}
|
|
else if (programContext.opts.compilationMode === 'annotation' &&
|
|
directives.optIn == null) {
|
|
return null;
|
|
}
|
|
else {
|
|
return compiledFn;
|
|
}
|
|
}
|
|
function tryCompileFunction(fn, fnType, programContext, outputMode) {
|
|
var _a;
|
|
const suppressionsInFunction = filterSuppressionsThatAffectFunction(programContext.suppressions, fn);
|
|
if (suppressionsInFunction.length > 0) {
|
|
return {
|
|
kind: 'error',
|
|
error: suppressionsToCompilerError(suppressionsInFunction),
|
|
};
|
|
}
|
|
try {
|
|
const result = compileFn(fn, programContext.opts.environment, fnType, outputMode, programContext, programContext.opts.logger, programContext.filename, programContext.code);
|
|
if (result.isOk()) {
|
|
return { kind: 'compile', compiledFn: result.unwrap() };
|
|
}
|
|
else {
|
|
return { kind: 'error', error: result.unwrapErr() };
|
|
}
|
|
}
|
|
catch (err) {
|
|
if (err instanceof CompilerError &&
|
|
err.details.every(detail => detail.category !== ErrorCategory.Invariant)) {
|
|
programContext.logEvent({
|
|
kind: 'CompileUnexpectedThrow',
|
|
fnLoc: (_a = fn.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
data: err.toString(),
|
|
});
|
|
}
|
|
return { kind: 'error', error: err };
|
|
}
|
|
}
|
|
function applyCompiledFunctions(program, compiledFns, pass, programContext) {
|
|
var _a, _b;
|
|
let referencedBeforeDeclared = null;
|
|
for (const result of compiledFns) {
|
|
const { kind, originalFn, compiledFn } = result;
|
|
const transformedFn = createNewFunctionNode(originalFn, compiledFn);
|
|
programContext.alreadyCompiled.add(transformedFn);
|
|
let dynamicGating = null;
|
|
if (originalFn.node.body.type === 'BlockStatement') {
|
|
const result = findDirectivesDynamicGating(originalFn.node.body.directives, pass.opts);
|
|
if (result.isOk()) {
|
|
dynamicGating = (_b = (_a = result.unwrap()) === null || _a === void 0 ? void 0 : _a.gating) !== null && _b !== void 0 ? _b : null;
|
|
}
|
|
}
|
|
const functionGating = dynamicGating !== null && dynamicGating !== void 0 ? dynamicGating : pass.opts.gating;
|
|
if (kind === 'original' && functionGating != null) {
|
|
referencedBeforeDeclared !== null && referencedBeforeDeclared !== void 0 ? referencedBeforeDeclared : (referencedBeforeDeclared = getFunctionReferencedBeforeDeclarationAtTopLevel(program, compiledFns));
|
|
insertGatedFunctionDeclaration(originalFn, transformedFn, programContext, functionGating, referencedBeforeDeclared.has(result));
|
|
}
|
|
else {
|
|
originalFn.replaceWith(transformedFn);
|
|
}
|
|
}
|
|
if (compiledFns.length > 0) {
|
|
addImportsToProgram(program, programContext);
|
|
}
|
|
}
|
|
function shouldSkipCompilation(program, pass) {
|
|
if (pass.opts.sources) {
|
|
if (pass.filename === null) {
|
|
const error = new CompilerError();
|
|
error.pushErrorDetail(new CompilerErrorDetail({
|
|
reason: `Expected a filename but found none.`,
|
|
description: "When the 'sources' config options is specified, the React compiler will only compile files with a name",
|
|
category: ErrorCategory.Config,
|
|
loc: null,
|
|
}));
|
|
handleError(error, pass, null);
|
|
return true;
|
|
}
|
|
if (!isFilePartOfSources(pass.opts.sources, pass.filename)) {
|
|
return true;
|
|
}
|
|
}
|
|
if (hasMemoCacheFunctionImport(program, getReactCompilerRuntimeModule(pass.opts.target))) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function getReactFunctionType(fn, pass) {
|
|
var _a, _b;
|
|
if (fn.node.body.type === 'BlockStatement') {
|
|
const optInDirectives = tryFindDirectiveEnablingMemoization(fn.node.body.directives, pass.opts);
|
|
if (optInDirectives.unwrapOr(null) != null) {
|
|
return (_a = getComponentOrHookLike(fn)) !== null && _a !== void 0 ? _a : 'Other';
|
|
}
|
|
}
|
|
let componentSyntaxType = null;
|
|
if (fn.isFunctionDeclaration()) {
|
|
if (isComponentDeclaration(fn.node)) {
|
|
componentSyntaxType = 'Component';
|
|
}
|
|
else if (isHookDeclaration(fn.node)) {
|
|
componentSyntaxType = 'Hook';
|
|
}
|
|
}
|
|
switch (pass.opts.compilationMode) {
|
|
case 'annotation': {
|
|
return null;
|
|
}
|
|
case 'infer': {
|
|
return componentSyntaxType !== null && componentSyntaxType !== void 0 ? componentSyntaxType : getComponentOrHookLike(fn);
|
|
}
|
|
case 'syntax': {
|
|
return componentSyntaxType;
|
|
}
|
|
case 'all': {
|
|
return (_b = getComponentOrHookLike(fn)) !== null && _b !== void 0 ? _b : 'Other';
|
|
}
|
|
default: {
|
|
assertExhaustive$1(pass.opts.compilationMode, `Unexpected compilationMode \`${pass.opts.compilationMode}\``);
|
|
}
|
|
}
|
|
}
|
|
function hasMemoCacheFunctionImport(program, moduleName) {
|
|
let hasUseMemoCache = false;
|
|
program.traverse({
|
|
ImportSpecifier(path) {
|
|
const imported = path.get('imported');
|
|
let importedName = null;
|
|
if (imported.isIdentifier()) {
|
|
importedName = imported.node.name;
|
|
}
|
|
else if (imported.isStringLiteral()) {
|
|
importedName = imported.node.value;
|
|
}
|
|
if (importedName === 'c' &&
|
|
path.parentPath.isImportDeclaration() &&
|
|
path.parentPath.get('source').node.value === moduleName) {
|
|
hasUseMemoCache = true;
|
|
}
|
|
},
|
|
});
|
|
return hasUseMemoCache;
|
|
}
|
|
function isHookName$1(s) {
|
|
return /^use[A-Z0-9]/.test(s);
|
|
}
|
|
function isHook$1(path) {
|
|
if (path.isIdentifier()) {
|
|
return isHookName$1(path.node.name);
|
|
}
|
|
else if (path.isMemberExpression() &&
|
|
!path.node.computed &&
|
|
isHook$1(path.get('property'))) {
|
|
const obj = path.get('object').node;
|
|
const isPascalCaseNameSpace = /^[A-Z].*/;
|
|
return obj.type === 'Identifier' && isPascalCaseNameSpace.test(obj.name);
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
function isComponentName$1(path) {
|
|
return path.isIdentifier() && /^[A-Z]/.test(path.node.name);
|
|
}
|
|
function isReactAPI(path, functionName) {
|
|
const node = path.node;
|
|
return ((node.type === 'Identifier' && node.name === functionName) ||
|
|
(node.type === 'MemberExpression' &&
|
|
node.object.type === 'Identifier' &&
|
|
node.object.name === 'React' &&
|
|
node.property.type === 'Identifier' &&
|
|
node.property.name === functionName));
|
|
}
|
|
function isForwardRefCallback$1(path) {
|
|
return !!(path.parentPath.isCallExpression() &&
|
|
path.parentPath.get('callee').isExpression() &&
|
|
isReactAPI(path.parentPath.get('callee'), 'forwardRef'));
|
|
}
|
|
function isMemoCallback$1(path) {
|
|
return (path.parentPath.isCallExpression() &&
|
|
path.parentPath.get('callee').isExpression() &&
|
|
isReactAPI(path.parentPath.get('callee'), 'memo'));
|
|
}
|
|
function isValidPropsAnnotation(annot) {
|
|
if (annot == null) {
|
|
return true;
|
|
}
|
|
else if (annot.type === 'TSTypeAnnotation') {
|
|
switch (annot.typeAnnotation.type) {
|
|
case 'TSArrayType':
|
|
case 'TSBigIntKeyword':
|
|
case 'TSBooleanKeyword':
|
|
case 'TSConstructorType':
|
|
case 'TSFunctionType':
|
|
case 'TSLiteralType':
|
|
case 'TSNeverKeyword':
|
|
case 'TSNumberKeyword':
|
|
case 'TSStringKeyword':
|
|
case 'TSSymbolKeyword':
|
|
case 'TSTupleType':
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
else if (annot.type === 'TypeAnnotation') {
|
|
switch (annot.typeAnnotation.type) {
|
|
case 'ArrayTypeAnnotation':
|
|
case 'BooleanLiteralTypeAnnotation':
|
|
case 'BooleanTypeAnnotation':
|
|
case 'EmptyTypeAnnotation':
|
|
case 'FunctionTypeAnnotation':
|
|
case 'NumberLiteralTypeAnnotation':
|
|
case 'NumberTypeAnnotation':
|
|
case 'StringLiteralTypeAnnotation':
|
|
case 'StringTypeAnnotation':
|
|
case 'SymbolTypeAnnotation':
|
|
case 'ThisTypeAnnotation':
|
|
case 'TupleTypeAnnotation':
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
else if (annot.type === 'Noop') {
|
|
return true;
|
|
}
|
|
else {
|
|
assertExhaustive$1(annot, `Unexpected annotation node \`${annot}\``);
|
|
}
|
|
}
|
|
function isValidComponentParams(params) {
|
|
if (params.length === 0) {
|
|
return true;
|
|
}
|
|
else if (params.length > 0 && params.length <= 2) {
|
|
if (!isValidPropsAnnotation(params[0].node.typeAnnotation)) {
|
|
return false;
|
|
}
|
|
if (params.length === 1) {
|
|
return !params[0].isRestElement();
|
|
}
|
|
else if (params[1].isIdentifier()) {
|
|
const { name } = params[1].node;
|
|
return name.includes('ref') || name.includes('Ref');
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function getComponentOrHookLike(node) {
|
|
const functionName = getFunctionName$1(node);
|
|
if (functionName !== null && isComponentName$1(functionName)) {
|
|
let isComponent = callsHooksOrCreatesJsx(node) &&
|
|
isValidComponentParams(node.get('params')) &&
|
|
!returnsNonNode(node);
|
|
return isComponent ? 'Component' : null;
|
|
}
|
|
else if (functionName !== null && isHook$1(functionName)) {
|
|
return callsHooksOrCreatesJsx(node) ? 'Hook' : null;
|
|
}
|
|
if (node.isFunctionExpression() || node.isArrowFunctionExpression()) {
|
|
if (isForwardRefCallback$1(node) || isMemoCallback$1(node)) {
|
|
return callsHooksOrCreatesJsx(node) ? 'Component' : null;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
function skipNestedFunctions(node) {
|
|
return (fn) => {
|
|
if (fn.node !== node.node) {
|
|
fn.skip();
|
|
}
|
|
};
|
|
}
|
|
function callsHooksOrCreatesJsx(node) {
|
|
let invokesHooks = false;
|
|
let createsJsx = false;
|
|
node.traverse({
|
|
JSX() {
|
|
createsJsx = true;
|
|
},
|
|
CallExpression(call) {
|
|
const callee = call.get('callee');
|
|
if (callee.isExpression() && isHook$1(callee)) {
|
|
invokesHooks = true;
|
|
}
|
|
},
|
|
ArrowFunctionExpression: skipNestedFunctions(node),
|
|
FunctionExpression: skipNestedFunctions(node),
|
|
FunctionDeclaration: skipNestedFunctions(node),
|
|
});
|
|
return invokesHooks || createsJsx;
|
|
}
|
|
function isNonNode(node) {
|
|
if (!node) {
|
|
return true;
|
|
}
|
|
switch (node.type) {
|
|
case 'ObjectExpression':
|
|
case 'ArrowFunctionExpression':
|
|
case 'FunctionExpression':
|
|
case 'BigIntLiteral':
|
|
case 'ClassExpression':
|
|
case 'NewExpression':
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function returnsNonNode(node) {
|
|
let returnsNonNode = false;
|
|
if (node.type === 'ArrowFunctionExpression' &&
|
|
node.node.body.type !== 'BlockStatement') {
|
|
returnsNonNode = isNonNode(node.node.body);
|
|
}
|
|
node.traverse({
|
|
ReturnStatement(ret) {
|
|
returnsNonNode = isNonNode(ret.node.argument);
|
|
},
|
|
ArrowFunctionExpression: skipNestedFunctions(node),
|
|
FunctionExpression: skipNestedFunctions(node),
|
|
FunctionDeclaration: skipNestedFunctions(node),
|
|
ObjectMethod: node => node.skip(),
|
|
});
|
|
return returnsNonNode;
|
|
}
|
|
function getFunctionName$1(path) {
|
|
if (path.isFunctionDeclaration()) {
|
|
const id = path.get('id');
|
|
if (id.isIdentifier()) {
|
|
return id;
|
|
}
|
|
return null;
|
|
}
|
|
let id = null;
|
|
const parent = path.parentPath;
|
|
if (parent.isVariableDeclarator() && parent.get('init').node === path.node) {
|
|
id = parent.get('id');
|
|
}
|
|
else if (parent.isAssignmentExpression() &&
|
|
parent.get('right').node === path.node &&
|
|
parent.get('operator') === '=') {
|
|
id = parent.get('left');
|
|
}
|
|
else if (parent.isProperty() &&
|
|
parent.get('value').node === path.node &&
|
|
!parent.get('computed') &&
|
|
parent.get('key').isLVal()) {
|
|
id = parent.get('key');
|
|
}
|
|
else if (parent.isAssignmentPattern() &&
|
|
parent.get('right').node === path.node &&
|
|
!parent.get('computed')) {
|
|
id = parent.get('left');
|
|
}
|
|
if (id !== null && (id.isIdentifier() || id.isMemberExpression())) {
|
|
return id;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
function getFunctionReferencedBeforeDeclarationAtTopLevel(program, fns) {
|
|
const fnNames = new Map(fns
|
|
.map(fn => [
|
|
getFunctionName$1(fn.originalFn),
|
|
fn,
|
|
])
|
|
.filter((entry) => !!entry[0] && entry[0].isIdentifier())
|
|
.map(entry => [entry[0].node.name, { id: entry[0].node, fn: entry[1] }]));
|
|
const referencedBeforeDeclaration = new Set();
|
|
program.traverse({
|
|
TypeAnnotation(path) {
|
|
path.skip();
|
|
},
|
|
TSTypeAnnotation(path) {
|
|
path.skip();
|
|
},
|
|
TypeAlias(path) {
|
|
path.skip();
|
|
},
|
|
TSTypeAliasDeclaration(path) {
|
|
path.skip();
|
|
},
|
|
Identifier(id) {
|
|
const fn = fnNames.get(id.node.name);
|
|
if (!fn) {
|
|
return;
|
|
}
|
|
if (id.node === fn.id) {
|
|
fnNames.delete(id.node.name);
|
|
return;
|
|
}
|
|
const scope = id.scope.getFunctionParent();
|
|
if (scope === null && id.isReferencedIdentifier()) {
|
|
referencedBeforeDeclaration.add(fn.fn);
|
|
}
|
|
},
|
|
});
|
|
return referencedBeforeDeclaration;
|
|
}
|
|
function getReactCompilerRuntimeModule(target) {
|
|
if (target === '19') {
|
|
return 'react/compiler-runtime';
|
|
}
|
|
else if (target === '17' || target === '18') {
|
|
return 'react-compiler-runtime';
|
|
}
|
|
else {
|
|
CompilerError.invariant(target != null &&
|
|
target.kind === 'donotuse_meta_internal' &&
|
|
typeof target.runtimeModule === 'string', {
|
|
reason: 'Expected target to already be validated',
|
|
loc: GeneratedSource,
|
|
});
|
|
return target.runtimeModule;
|
|
}
|
|
}
|
|
|
|
function validateRestrictedImports(path, { validateBlocklistedImports }) {
|
|
if (validateBlocklistedImports == null ||
|
|
validateBlocklistedImports.length === 0) {
|
|
return null;
|
|
}
|
|
const error = new CompilerError();
|
|
const restrictedImports = new Set(validateBlocklistedImports);
|
|
path.traverse({
|
|
ImportDeclaration(importDeclPath) {
|
|
var _a;
|
|
if (restrictedImports.has(importDeclPath.node.source.value)) {
|
|
error.push({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Bailing out due to blocklisted import',
|
|
description: `Import from module ${importDeclPath.node.source.value}`,
|
|
loc: (_a = importDeclPath.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
});
|
|
}
|
|
},
|
|
});
|
|
if (error.hasAnyErrors()) {
|
|
return error;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
class ProgramContext {
|
|
constructor({ program, suppressions, opts, filename, code, hasModuleScopeOptOut, }) {
|
|
this.alreadyCompiled = new (WeakSet !== null && WeakSet !== void 0 ? WeakSet : Set)();
|
|
this.knownReferencedNames = new Set();
|
|
this.imports = new Map();
|
|
this.scope = program.scope;
|
|
this.opts = opts;
|
|
this.filename = filename;
|
|
this.code = code;
|
|
this.reactRuntimeModule = getReactCompilerRuntimeModule(opts.target);
|
|
this.suppressions = suppressions;
|
|
this.hasModuleScopeOptOut = hasModuleScopeOptOut;
|
|
}
|
|
isHookName(name) {
|
|
return isHookName$2(name);
|
|
}
|
|
hasReference(name) {
|
|
return (this.knownReferencedNames.has(name) ||
|
|
this.scope.hasBinding(name) ||
|
|
this.scope.hasGlobal(name) ||
|
|
this.scope.hasReference(name));
|
|
}
|
|
newUid(name) {
|
|
let uid;
|
|
if (this.isHookName(name)) {
|
|
uid = name;
|
|
let i = 0;
|
|
while (this.hasReference(uid)) {
|
|
this.knownReferencedNames.add(uid);
|
|
uid = `${name}_${i++}`;
|
|
}
|
|
}
|
|
else if (!this.hasReference(name)) {
|
|
uid = name;
|
|
}
|
|
else {
|
|
uid = this.scope.generateUid(name);
|
|
}
|
|
this.knownReferencedNames.add(uid);
|
|
return uid;
|
|
}
|
|
addMemoCacheImport() {
|
|
return this.addImportSpecifier({
|
|
source: this.reactRuntimeModule,
|
|
importSpecifierName: 'c',
|
|
}, '_c');
|
|
}
|
|
addImportSpecifier({ source: module, importSpecifierName: specifier }, nameHint) {
|
|
var _a;
|
|
const maybeBinding = (_a = this.imports.get(module)) === null || _a === void 0 ? void 0 : _a.get(specifier);
|
|
if (maybeBinding != null) {
|
|
return Object.assign({}, maybeBinding);
|
|
}
|
|
const binding = {
|
|
kind: 'ImportSpecifier',
|
|
name: this.newUid(nameHint !== null && nameHint !== void 0 ? nameHint : specifier),
|
|
module,
|
|
imported: specifier,
|
|
};
|
|
getOrInsertWith(this.imports, module, () => new Map()).set(specifier, Object.assign({}, binding));
|
|
return binding;
|
|
}
|
|
addNewReference(name) {
|
|
this.knownReferencedNames.add(name);
|
|
}
|
|
assertGlobalBinding(name, localScope) {
|
|
var _a, _b;
|
|
const scope = localScope !== null && localScope !== void 0 ? localScope : this.scope;
|
|
if (!scope.hasReference(name) && !scope.hasBinding(name)) {
|
|
return Ok(undefined);
|
|
}
|
|
const error = new CompilerError();
|
|
error.push({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Encountered conflicting global in generated program',
|
|
description: `Conflict from local binding ${name}`,
|
|
loc: (_b = (_a = scope.getBinding(name)) === null || _a === void 0 ? void 0 : _a.path.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
suggestions: null,
|
|
});
|
|
return Err(error);
|
|
}
|
|
logEvent(event) {
|
|
if (this.opts.logger != null) {
|
|
this.opts.logger.logEvent(this.filename, event);
|
|
}
|
|
}
|
|
}
|
|
function getExistingImports(program) {
|
|
const existingImports = new Map();
|
|
program.traverse({
|
|
ImportDeclaration(path) {
|
|
if (isNonNamespacedImport(path)) {
|
|
existingImports.set(path.node.source.value, path);
|
|
}
|
|
},
|
|
});
|
|
return existingImports;
|
|
}
|
|
function addImportsToProgram(path, programContext) {
|
|
const existingImports = getExistingImports(path);
|
|
const stmts = [];
|
|
const sortedModules = [...programContext.imports.entries()].sort(([a], [b]) => a.localeCompare(b));
|
|
for (const [moduleName, importsMap] of sortedModules) {
|
|
for (const [specifierName, loweredImport] of importsMap) {
|
|
CompilerError.invariant(path.scope.getBinding(loweredImport.name) == null, {
|
|
reason: 'Encountered conflicting import specifiers in generated program',
|
|
description: `Conflict from import ${loweredImport.module}:(${loweredImport.imported} as ${loweredImport.name})`,
|
|
loc: GeneratedSource,
|
|
});
|
|
CompilerError.invariant(loweredImport.module === moduleName &&
|
|
loweredImport.imported === specifierName, {
|
|
reason: 'Found inconsistent import specifier. This is an internal bug.',
|
|
description: `Expected import ${moduleName}:${specifierName} but found ${loweredImport.module}:${loweredImport.imported}`,
|
|
loc: GeneratedSource,
|
|
});
|
|
}
|
|
const sortedImport = [
|
|
...importsMap.values(),
|
|
].sort(({ imported: a }, { imported: b }) => a.localeCompare(b));
|
|
const importSpecifiers = sortedImport.map(specifier => {
|
|
return libExports$1.importSpecifier(libExports$1.identifier(specifier.name), libExports$1.identifier(specifier.imported));
|
|
});
|
|
const maybeExistingImports = existingImports.get(moduleName);
|
|
if (maybeExistingImports != null) {
|
|
maybeExistingImports.pushContainer('specifiers', importSpecifiers);
|
|
}
|
|
else {
|
|
if (path.node.sourceType === 'module') {
|
|
stmts.push(libExports$1.importDeclaration(importSpecifiers, libExports$1.stringLiteral(moduleName)));
|
|
}
|
|
else {
|
|
stmts.push(libExports$1.variableDeclaration('const', [
|
|
libExports$1.variableDeclarator(libExports$1.objectPattern(sortedImport.map(specifier => {
|
|
return libExports$1.objectProperty(libExports$1.identifier(specifier.imported), libExports$1.identifier(specifier.name));
|
|
})), libExports$1.callExpression(libExports$1.identifier('require'), [
|
|
libExports$1.stringLiteral(moduleName),
|
|
])),
|
|
]));
|
|
}
|
|
}
|
|
}
|
|
path.unshiftContainer('body', stmts);
|
|
}
|
|
function isNonNamespacedImport(importDeclPath) {
|
|
return (importDeclPath
|
|
.get('specifiers')
|
|
.every(specifier => specifier.isImportSpecifier()) &&
|
|
importDeclPath.node.importKind !== 'type' &&
|
|
importDeclPath.node.importKind !== 'typeof');
|
|
}
|
|
|
|
v4.z.enum([
|
|
'all_errors',
|
|
'critical_errors',
|
|
'none',
|
|
]);
|
|
const DynamicGatingOptionsSchema = v4.z.object({
|
|
source: v4.z.string(),
|
|
});
|
|
const CustomOptOutDirectiveSchema = v4.z
|
|
.nullable(v4.z.array(v4.z.string()))
|
|
.default(null);
|
|
const CompilerReactTargetSchema = v4.z.union([
|
|
v4.z.literal('17'),
|
|
v4.z.literal('18'),
|
|
v4.z.literal('19'),
|
|
v4.z.object({
|
|
kind: v4.z.literal('donotuse_meta_internal'),
|
|
runtimeModule: v4.z.string().default('react'),
|
|
}),
|
|
]);
|
|
v4.z.enum([
|
|
'infer',
|
|
'syntax',
|
|
'annotation',
|
|
'all',
|
|
]);
|
|
v4.z.enum([
|
|
'ssr',
|
|
'client',
|
|
'lint',
|
|
]);
|
|
const defaultOptions = {
|
|
compilationMode: 'infer',
|
|
panicThreshold: 'none',
|
|
environment: parseEnvironmentConfig({}).unwrap(),
|
|
logger: null,
|
|
gating: null,
|
|
noEmit: false,
|
|
outputMode: null,
|
|
dynamicGating: null,
|
|
eslintSuppressionRules: null,
|
|
flowSuppressions: true,
|
|
ignoreUseNoForget: false,
|
|
sources: filename => {
|
|
return filename.indexOf('node_modules') === -1;
|
|
},
|
|
enableReanimatedCheck: true,
|
|
customOptOutDirectives: null,
|
|
target: '19',
|
|
};
|
|
function parsePluginOptions(obj) {
|
|
if (obj == null || typeof obj !== 'object') {
|
|
return defaultOptions;
|
|
}
|
|
const parsedOptions = Object.create(null);
|
|
for (let [key, value] of Object.entries(obj)) {
|
|
if (typeof value === 'string') {
|
|
value = value.toLowerCase();
|
|
}
|
|
if (isCompilerFlag(key)) {
|
|
switch (key) {
|
|
case 'environment': {
|
|
const environmentResult = parseEnvironmentConfig(value);
|
|
if (environmentResult.isErr()) {
|
|
CompilerError.throwInvalidConfig({
|
|
reason: 'Error in validating environment config. This is an advanced setting and not meant to be used directly',
|
|
description: environmentResult.unwrapErr().toString(),
|
|
suggestions: null,
|
|
loc: null,
|
|
});
|
|
}
|
|
parsedOptions[key] = environmentResult.unwrap();
|
|
break;
|
|
}
|
|
case 'target': {
|
|
parsedOptions[key] = parseTargetConfig(value);
|
|
break;
|
|
}
|
|
case 'gating': {
|
|
if (value == null) {
|
|
parsedOptions[key] = null;
|
|
}
|
|
else {
|
|
parsedOptions[key] = tryParseExternalFunction(value);
|
|
}
|
|
break;
|
|
}
|
|
case 'dynamicGating': {
|
|
if (value == null) {
|
|
parsedOptions[key] = null;
|
|
}
|
|
else {
|
|
const result = DynamicGatingOptionsSchema.safeParse(value);
|
|
if (result.success) {
|
|
parsedOptions[key] = result.data;
|
|
}
|
|
else {
|
|
CompilerError.throwInvalidConfig({
|
|
reason: 'Could not parse dynamic gating. Update React Compiler config to fix the error',
|
|
description: `${v4$1.fromZodError(result.error)}`,
|
|
loc: null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'customOptOutDirectives': {
|
|
const result = CustomOptOutDirectiveSchema.safeParse(value);
|
|
if (result.success) {
|
|
parsedOptions[key] = result.data;
|
|
}
|
|
else {
|
|
CompilerError.throwInvalidConfig({
|
|
reason: 'Could not parse custom opt out directives. Update React Compiler config to fix the error',
|
|
description: `${v4$1.fromZodError(result.error)}`,
|
|
loc: null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
parsedOptions[key] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Object.assign(Object.assign({}, defaultOptions), parsedOptions);
|
|
}
|
|
function parseTargetConfig(value) {
|
|
const parsed = CompilerReactTargetSchema.safeParse(value);
|
|
if (parsed.success) {
|
|
return parsed.data;
|
|
}
|
|
else {
|
|
CompilerError.throwInvalidConfig({
|
|
reason: 'Not a valid target',
|
|
description: `${v4$1.fromZodError(parsed.error)}`,
|
|
suggestions: null,
|
|
loc: null,
|
|
});
|
|
}
|
|
}
|
|
function isCompilerFlag(s) {
|
|
return hasOwnProperty$1(defaultOptions, s);
|
|
}
|
|
|
|
function hasModule(name) {
|
|
if (typeof require === 'undefined') {
|
|
return false;
|
|
}
|
|
try {
|
|
return !!require.resolve(name);
|
|
}
|
|
catch (error) {
|
|
if (error.code === 'MODULE_NOT_FOUND' &&
|
|
error.message.indexOf(name) !== -1) {
|
|
return false;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
function pipelineUsesReanimatedPlugin(plugins) {
|
|
if (Array.isArray(plugins)) {
|
|
for (const plugin of plugins) {
|
|
if (hasOwnProperty$1(plugin, 'key')) {
|
|
const key = plugin.key;
|
|
if (typeof key === 'string' &&
|
|
key.indexOf('react-native-reanimated') !== -1) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return hasModule('react-native-reanimated');
|
|
}
|
|
function injectReanimatedFlag(options) {
|
|
return Object.assign(Object.assign({}, options), { environment: Object.assign(Object.assign({}, options.environment), { enableCustomTypeDefinitionForReanimated: true }) });
|
|
}
|
|
|
|
const ENABLE_REACT_COMPILER_TIMINGS = process.env['ENABLE_REACT_COMPILER_TIMINGS'] === '1';
|
|
function BabelPluginReactCompiler(_babel) {
|
|
return {
|
|
name: 'react-forget',
|
|
visitor: {
|
|
Program: {
|
|
enter(prog, pass) {
|
|
var _a, _b, _c;
|
|
try {
|
|
const filename = (_a = pass.filename) !== null && _a !== void 0 ? _a : 'unknown';
|
|
if (ENABLE_REACT_COMPILER_TIMINGS === true) {
|
|
performance.mark(`${filename}:start`, {
|
|
detail: 'BabelPlugin:Program:start',
|
|
});
|
|
}
|
|
let opts = parsePluginOptions(pass.opts);
|
|
const isDev = (typeof true !== 'undefined' && true === true) ||
|
|
process.env['NODE_ENV'] === 'development';
|
|
if (opts.enableReanimatedCheck === true &&
|
|
pipelineUsesReanimatedPlugin(pass.file.opts.plugins)) {
|
|
opts = injectReanimatedFlag(opts);
|
|
}
|
|
if (opts.environment.enableResetCacheOnSourceFileChanges !== false &&
|
|
isDev) {
|
|
opts = Object.assign(Object.assign({}, opts), { environment: Object.assign(Object.assign({}, opts.environment), { enableResetCacheOnSourceFileChanges: true }) });
|
|
}
|
|
compileProgram(prog, {
|
|
opts,
|
|
filename: (_b = pass.filename) !== null && _b !== void 0 ? _b : null,
|
|
comments: (_c = pass.file.ast.comments) !== null && _c !== void 0 ? _c : [],
|
|
code: pass.file.code,
|
|
});
|
|
if (ENABLE_REACT_COMPILER_TIMINGS === true) {
|
|
performance.mark(`${filename}:end`, {
|
|
detail: 'BabelPlugin:Program:end',
|
|
});
|
|
}
|
|
}
|
|
catch (e) {
|
|
if (e instanceof CompilerError) {
|
|
throw e.withPrintedMessage(pass.file.code, { eslint: false });
|
|
}
|
|
throw e;
|
|
}
|
|
},
|
|
exit(_, pass) {
|
|
var _a;
|
|
if (ENABLE_REACT_COMPILER_TIMINGS === true) {
|
|
const filename = (_a = pass.filename) !== null && _a !== void 0 ? _a : 'unknown';
|
|
const measurement = performance.measure(filename, {
|
|
start: `${filename}:start`,
|
|
end: `${filename}:end`,
|
|
detail: 'BabelPlugin:Program',
|
|
});
|
|
if ('logger' in pass.opts && pass.opts.logger != null) {
|
|
const logger = pass.opts.logger;
|
|
logger.logEvent(filename, {
|
|
kind: 'Timing',
|
|
measurement,
|
|
});
|
|
}
|
|
}
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Land or remove (zero effort)
|
|
//
|
|
// Flags that can likely be deleted or landed without consequences
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// eslint-plugin-react-hooks
|
|
// -----------------------------------------------------------------------------
|
|
var eprh_enableUseKeyedStateCompilerLint = false;
|
|
var eprh_enableVerboseNoSetStateInEffectCompilerLint = false;
|
|
var eprh_enableExhaustiveEffectDependenciesCompilerLint = 'off';
|
|
|
|
var _LRUCache_values, _LRUCache_headIdx;
|
|
const COMPONENT_NAME_PATTERN = /^[A-Z]/;
|
|
const HOOK_NAME_PATTERN = /^use[A-Z0-9]/;
|
|
function mayContainReactCode(sourceCode) {
|
|
const ast = sourceCode.ast;
|
|
for (const node of ast.body) {
|
|
if (checkTopLevelNode(node)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function checkTopLevelNode(node) {
|
|
if (node.type === 'ComponentDeclaration' || node.type === 'HookDeclaration') {
|
|
return true;
|
|
}
|
|
if (node.type === 'ExportNamedDeclaration') {
|
|
const decl = node.declaration;
|
|
if (decl != null) {
|
|
return checkTopLevelNode(decl);
|
|
}
|
|
return false;
|
|
}
|
|
if (node.type === 'ExportDefaultDeclaration') {
|
|
const decl = node.declaration;
|
|
if (decl.type === 'FunctionExpression' ||
|
|
decl.type === 'ArrowFunctionExpression' ||
|
|
(decl.type === 'FunctionDeclaration' &&
|
|
decl.id == null)) {
|
|
return true;
|
|
}
|
|
return checkTopLevelNode(decl);
|
|
}
|
|
if (node.type === 'FunctionDeclaration') {
|
|
if ('__componentDeclaration' in node || '__hookDeclaration' in node) {
|
|
return true;
|
|
}
|
|
const id = node.id;
|
|
if (id != null) {
|
|
const name = id.name;
|
|
if (COMPONENT_NAME_PATTERN.test(name) || HOOK_NAME_PATTERN.test(name)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
if (node.type === 'VariableDeclaration') {
|
|
for (const decl of node.declarations) {
|
|
if (decl.id.type === 'Identifier') {
|
|
const init = decl.init;
|
|
if (init != null &&
|
|
(init.type === 'ArrowFunctionExpression' ||
|
|
init.type === 'FunctionExpression')) {
|
|
const name = decl.id.name;
|
|
if (COMPONENT_NAME_PATTERN.test(name) ||
|
|
HOOK_NAME_PATTERN.test(name)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
const COMPILER_OPTIONS = {
|
|
outputMode: 'lint',
|
|
panicThreshold: 'none',
|
|
flowSuppressions: false,
|
|
environment: {
|
|
validateRefAccessDuringRender: true,
|
|
validateNoSetStateInRender: true,
|
|
validateNoSetStateInEffects: true,
|
|
validateNoJSXInTryStatements: true,
|
|
validateNoImpureFunctionsInRender: true,
|
|
validateStaticComponents: true,
|
|
validateNoFreezingKnownMutableFunctions: true,
|
|
validateNoVoidUseMemo: true,
|
|
validateNoCapitalizedCalls: [],
|
|
validateHooksUsage: true,
|
|
validateNoDerivedComputationsInEffects: true,
|
|
enableUseKeyedState: eprh_enableUseKeyedStateCompilerLint,
|
|
enableVerboseNoSetStateInEffect: eprh_enableVerboseNoSetStateInEffectCompilerLint,
|
|
validateExhaustiveEffectDependencies: eprh_enableExhaustiveEffectDependenciesCompilerLint,
|
|
},
|
|
};
|
|
const FLOW_SUPPRESSION_REGEX = /\$FlowFixMe\[([^\]]*)\]/g;
|
|
function getFlowSuppressions(sourceCode) {
|
|
const comments = sourceCode.getAllComments();
|
|
const results = [];
|
|
for (const commentNode of comments) {
|
|
const matches = commentNode.value.matchAll(FLOW_SUPPRESSION_REGEX);
|
|
for (const match of matches) {
|
|
if (match.index != null && commentNode.loc != null) {
|
|
const code = match[1];
|
|
results.push({
|
|
line: commentNode.loc.end.line,
|
|
code,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
function runReactCompilerImpl({ sourceCode, filename, userOpts, }) {
|
|
var _a, _b;
|
|
const options = parsePluginOptions(Object.assign(Object.assign(Object.assign({}, COMPILER_OPTIONS), userOpts), { environment: Object.assign(Object.assign({}, COMPILER_OPTIONS.environment), userOpts.environment) }));
|
|
const results = {
|
|
sourceCode: sourceCode.text,
|
|
filename,
|
|
userOpts,
|
|
flowSuppressions: [],
|
|
events: [],
|
|
};
|
|
const userLogger = options.logger;
|
|
options.logger = {
|
|
logEvent: (eventFilename, event) => {
|
|
userLogger === null || userLogger === void 0 ? void 0 : userLogger.logEvent(eventFilename, event);
|
|
results.events.push(event);
|
|
},
|
|
};
|
|
try {
|
|
options.environment = validateEnvironmentConfig((_a = options.environment) !== null && _a !== void 0 ? _a : {});
|
|
}
|
|
catch (err) {
|
|
(_b = options.logger) === null || _b === void 0 ? void 0 : _b.logEvent(filename, err);
|
|
}
|
|
let babelAST = null;
|
|
if (filename.endsWith('.tsx') || filename.endsWith('.ts')) {
|
|
try {
|
|
babelAST = BabelParser.parse(sourceCode.text, {
|
|
sourceFilename: filename,
|
|
sourceType: 'unambiguous',
|
|
plugins: ['typescript', 'jsx'],
|
|
});
|
|
}
|
|
catch (_c) {
|
|
}
|
|
}
|
|
else {
|
|
try {
|
|
babelAST = HermesParser.parse(sourceCode.text, {
|
|
babel: true,
|
|
enableExperimentalComponentSyntax: true,
|
|
sourceFilename: filename,
|
|
sourceType: 'module',
|
|
});
|
|
}
|
|
catch (_d) {
|
|
}
|
|
}
|
|
if (babelAST != null) {
|
|
results.flowSuppressions = getFlowSuppressions(sourceCode);
|
|
try {
|
|
core$1.transformFromAstSync(babelAST, sourceCode.text, {
|
|
filename,
|
|
highlightCode: false,
|
|
retainLines: true,
|
|
plugins: [[BabelPluginReactCompiler, options]],
|
|
sourceType: 'module',
|
|
configFile: false,
|
|
babelrc: false,
|
|
});
|
|
}
|
|
catch (err) {
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
const SENTINEL = Symbol();
|
|
class LRUCache {
|
|
constructor(size) {
|
|
_LRUCache_values.set(this, void 0);
|
|
_LRUCache_headIdx.set(this, 0);
|
|
__classPrivateFieldSet(this, _LRUCache_values, new Array(size).fill(SENTINEL), "f");
|
|
}
|
|
get(key) {
|
|
const idx = __classPrivateFieldGet(this, _LRUCache_values, "f").findIndex(entry => entry[0] === key);
|
|
if (idx === __classPrivateFieldGet(this, _LRUCache_headIdx, "f")) {
|
|
return __classPrivateFieldGet(this, _LRUCache_values, "f")[__classPrivateFieldGet(this, _LRUCache_headIdx, "f")][1];
|
|
}
|
|
else if (idx < 0) {
|
|
return null;
|
|
}
|
|
const entry = __classPrivateFieldGet(this, _LRUCache_values, "f")[idx];
|
|
const len = __classPrivateFieldGet(this, _LRUCache_values, "f").length;
|
|
for (let i = 0; i < Math.min(idx, len - 1); i++) {
|
|
__classPrivateFieldGet(this, _LRUCache_values, "f")[(__classPrivateFieldGet(this, _LRUCache_headIdx, "f") + i + 1) % len] =
|
|
__classPrivateFieldGet(this, _LRUCache_values, "f")[(__classPrivateFieldGet(this, _LRUCache_headIdx, "f") + i) % len];
|
|
}
|
|
__classPrivateFieldGet(this, _LRUCache_values, "f")[__classPrivateFieldGet(this, _LRUCache_headIdx, "f")] = entry;
|
|
return entry[1];
|
|
}
|
|
push(key, value) {
|
|
__classPrivateFieldSet(this, _LRUCache_headIdx, (__classPrivateFieldGet(this, _LRUCache_headIdx, "f") - 1 + __classPrivateFieldGet(this, _LRUCache_values, "f").length) % __classPrivateFieldGet(this, _LRUCache_values, "f").length, "f");
|
|
__classPrivateFieldGet(this, _LRUCache_values, "f")[__classPrivateFieldGet(this, _LRUCache_headIdx, "f")] = [key, value];
|
|
}
|
|
}
|
|
_LRUCache_values = new WeakMap(), _LRUCache_headIdx = new WeakMap();
|
|
const cache = new LRUCache(10);
|
|
function runReactCompiler({ sourceCode, filename, userOpts, }) {
|
|
const entry = cache.get(filename);
|
|
if (entry != null &&
|
|
entry.sourceCode === sourceCode.text &&
|
|
util.isDeepStrictEqual(entry.userOpts, userOpts)) {
|
|
return entry;
|
|
}
|
|
if (!mayContainReactCode(sourceCode)) {
|
|
const emptyResult = {
|
|
sourceCode: sourceCode.text,
|
|
filename,
|
|
userOpts,
|
|
flowSuppressions: [],
|
|
events: [],
|
|
};
|
|
if (entry != null) {
|
|
Object.assign(entry, emptyResult);
|
|
}
|
|
else {
|
|
cache.push(filename, emptyResult);
|
|
}
|
|
return Object.assign({}, emptyResult);
|
|
}
|
|
const runEntry = runReactCompilerImpl({
|
|
sourceCode,
|
|
filename,
|
|
userOpts,
|
|
});
|
|
if (entry != null) {
|
|
Object.assign(entry, runEntry);
|
|
}
|
|
else {
|
|
cache.push(filename, runEntry);
|
|
}
|
|
return Object.assign({}, runEntry);
|
|
}
|
|
|
|
function assertExhaustive(_, errorMsg) {
|
|
throw new Error(errorMsg);
|
|
}
|
|
function makeSuggestions(detail) {
|
|
const suggest = [];
|
|
if (Array.isArray(detail.suggestions)) {
|
|
for (const suggestion of detail.suggestions) {
|
|
switch (suggestion.op) {
|
|
case CompilerSuggestionOperation.InsertBefore:
|
|
suggest.push({
|
|
desc: suggestion.description,
|
|
fix(fixer) {
|
|
return fixer.insertTextBeforeRange(suggestion.range, suggestion.text);
|
|
},
|
|
});
|
|
break;
|
|
case CompilerSuggestionOperation.InsertAfter:
|
|
suggest.push({
|
|
desc: suggestion.description,
|
|
fix(fixer) {
|
|
return fixer.insertTextAfterRange(suggestion.range, suggestion.text);
|
|
},
|
|
});
|
|
break;
|
|
case CompilerSuggestionOperation.Replace:
|
|
suggest.push({
|
|
desc: suggestion.description,
|
|
fix(fixer) {
|
|
return fixer.replaceTextRange(suggestion.range, suggestion.text);
|
|
},
|
|
});
|
|
break;
|
|
case CompilerSuggestionOperation.Remove:
|
|
suggest.push({
|
|
desc: suggestion.description,
|
|
fix(fixer) {
|
|
return fixer.removeRange(suggestion.range);
|
|
},
|
|
});
|
|
break;
|
|
default:
|
|
assertExhaustive(suggestion, 'Unhandled suggestion operation');
|
|
}
|
|
}
|
|
}
|
|
return suggest;
|
|
}
|
|
function getReactCompilerResult(context) {
|
|
var _a, _b, _c;
|
|
const sourceCode = (_a = context.sourceCode) !== null && _a !== void 0 ? _a : context.getSourceCode();
|
|
const filename = (_b = context.filename) !== null && _b !== void 0 ? _b : context.getFilename();
|
|
const userOpts = (_c = context.options[0]) !== null && _c !== void 0 ? _c : {};
|
|
const results = runReactCompiler({
|
|
sourceCode,
|
|
filename,
|
|
userOpts,
|
|
});
|
|
return results;
|
|
}
|
|
function hasFlowSuppression(program, nodeLoc, suppressions) {
|
|
for (const commentNode of program.flowSuppressions) {
|
|
if (suppressions.includes(commentNode.code) &&
|
|
commentNode.line === nodeLoc.start.line - 1) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function makeRule(rule) {
|
|
const create = (context) => {
|
|
const result = getReactCompilerResult(context);
|
|
for (const event of result.events) {
|
|
if (event.kind === 'CompileError') {
|
|
const detail = event.detail;
|
|
if (detail.category === rule.category) {
|
|
const loc = detail.primaryLocation();
|
|
if (loc == null || typeof loc === 'symbol') {
|
|
continue;
|
|
}
|
|
if (hasFlowSuppression(result, loc, [
|
|
'react-rule-hook',
|
|
'react-rule-unsafe-ref',
|
|
])) {
|
|
continue;
|
|
}
|
|
context.report({
|
|
message: detail.printErrorMessage(result.sourceCode, {
|
|
eslint: true,
|
|
}),
|
|
loc,
|
|
suggest: makeSuggestions(detail.options),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return {};
|
|
};
|
|
return {
|
|
meta: {
|
|
type: 'problem',
|
|
docs: {
|
|
description: rule.description,
|
|
recommended: rule.preset === LintRulePreset.Recommended,
|
|
url: `https://react.dev/reference/eslint-plugin-react-hooks/lints/${rule.name}`,
|
|
},
|
|
fixable: 'code',
|
|
hasSuggestions: true,
|
|
schema: [{ type: 'object', additionalProperties: true }],
|
|
},
|
|
create,
|
|
};
|
|
}
|
|
const allRules = LintRules.reduce((acc, rule) => {
|
|
acc[rule.name] = { rule: makeRule(rule), severity: rule.severity };
|
|
return acc;
|
|
}, {});
|
|
const recommendedRules = LintRules.filter(rule => rule.preset === LintRulePreset.Recommended).reduce((acc, rule) => {
|
|
acc[rule.name] = { rule: makeRule(rule), severity: rule.severity };
|
|
return acc;
|
|
}, {});
|
|
const recommendedLatestRules = LintRules.filter(rule => rule.preset === LintRulePreset.Recommended ||
|
|
rule.preset === LintRulePreset.RecommendedLatest).reduce((acc, rule) => {
|
|
acc[rule.name] = { rule: makeRule(rule), severity: rule.severity };
|
|
return acc;
|
|
}, {});
|
|
function mapErrorSeverityToESlint(severity) {
|
|
switch (severity) {
|
|
case ErrorSeverity.Error: {
|
|
return 'error';
|
|
}
|
|
case ErrorSeverity.Warning: {
|
|
return 'warn';
|
|
}
|
|
case ErrorSeverity.Hint:
|
|
case ErrorSeverity.Off: {
|
|
return 'off';
|
|
}
|
|
default: {
|
|
assertExhaustive(severity, `Unhandled severity: ${severity}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
var assert_1;
|
|
var hasRequiredAssert;
|
|
function requireAssert() {
|
|
if (hasRequiredAssert) return assert_1;
|
|
hasRequiredAssert = 1;
|
|
function assert(cond) {
|
|
if (!cond) {
|
|
throw new Error('Assertion violated.');
|
|
}
|
|
}
|
|
assert_1 = assert;
|
|
return assert_1;
|
|
}
|
|
|
|
var codePathSegment;
|
|
var hasRequiredCodePathSegment;
|
|
function requireCodePathSegment() {
|
|
if (hasRequiredCodePathSegment) return codePathSegment;
|
|
hasRequiredCodePathSegment = 1;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Requirements
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Checks whether or not a given segment is reachable.
|
|
* @param {CodePathSegment} segment A segment to check.
|
|
* @returns {boolean} `true` if the segment is reachable.
|
|
*/
|
|
function isReachable(segment) {
|
|
return segment.reachable;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Interface
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* A code path segment.
|
|
*/
|
|
class CodePathSegment {
|
|
/**
|
|
* @param {string} id An identifier.
|
|
* @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
|
|
* This array includes unreachable segments.
|
|
* @param {boolean} reachable A flag which shows this is reachable.
|
|
*/
|
|
constructor(id, allPrevSegments, reachable) {
|
|
/**
|
|
* The identifier of this code path.
|
|
* Rules use it to store additional information of each rule.
|
|
* @type {string}
|
|
*/
|
|
this.id = id;
|
|
|
|
/**
|
|
* An array of the next segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
this.nextSegments = [];
|
|
|
|
/**
|
|
* An array of the previous segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
this.prevSegments = allPrevSegments.filter(isReachable);
|
|
|
|
/**
|
|
* An array of the next segments.
|
|
* This array includes unreachable segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
this.allNextSegments = [];
|
|
|
|
/**
|
|
* An array of the previous segments.
|
|
* This array includes unreachable segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
this.allPrevSegments = allPrevSegments;
|
|
|
|
/**
|
|
* A flag which shows this is reachable.
|
|
* @type {boolean}
|
|
*/
|
|
this.reachable = reachable;
|
|
|
|
// Internal data.
|
|
Object.defineProperty(this, 'internal', {
|
|
value: {
|
|
used: false,
|
|
loopedPrevSegments: []
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Checks a given previous segment is coming from the end of a loop.
|
|
* @param {CodePathSegment} segment A previous segment to check.
|
|
* @returns {boolean} `true` if the segment is coming from the end of a loop.
|
|
*/
|
|
isLoopedPrevSegment(segment) {
|
|
return this.internal.loopedPrevSegments.includes(segment);
|
|
}
|
|
|
|
/**
|
|
* Creates the root segment.
|
|
* @param {string} id An identifier.
|
|
* @returns {CodePathSegment} The created segment.
|
|
*/
|
|
static newRoot(id) {
|
|
return new CodePathSegment(id, [], true);
|
|
}
|
|
|
|
/**
|
|
* Creates a segment that follows given segments.
|
|
* @param {string} id An identifier.
|
|
* @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
|
|
* @returns {CodePathSegment} The created segment.
|
|
*/
|
|
static newNext(id, allPrevSegments) {
|
|
return new CodePathSegment(id, CodePathSegment.flattenUnusedSegments(allPrevSegments), allPrevSegments.some(isReachable));
|
|
}
|
|
|
|
/**
|
|
* Creates an unreachable segment that follows given segments.
|
|
* @param {string} id An identifier.
|
|
* @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
|
|
* @returns {CodePathSegment} The created segment.
|
|
*/
|
|
static newUnreachable(id, allPrevSegments) {
|
|
var segment = new CodePathSegment(id, CodePathSegment.flattenUnusedSegments(allPrevSegments), false);
|
|
|
|
/*
|
|
* In `if (a) return a; foo();` case, the unreachable segment preceded by
|
|
* the return statement is not used but must not be remove.
|
|
*/
|
|
CodePathSegment.markUsed(segment);
|
|
return segment;
|
|
}
|
|
|
|
/**
|
|
* Creates a segment that follows given segments.
|
|
* This factory method does not connect with `allPrevSegments`.
|
|
* But this inherits `reachable` flag.
|
|
* @param {string} id An identifier.
|
|
* @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
|
|
* @returns {CodePathSegment} The created segment.
|
|
*/
|
|
static newDisconnected(id, allPrevSegments) {
|
|
return new CodePathSegment(id, [], allPrevSegments.some(isReachable));
|
|
}
|
|
|
|
/**
|
|
* Makes a given segment being used.
|
|
*
|
|
* And this function registers the segment into the previous segments as a next.
|
|
* @param {CodePathSegment} segment A segment to mark.
|
|
* @returns {void}
|
|
*/
|
|
static markUsed(segment) {
|
|
if (segment.internal.used) {
|
|
return;
|
|
}
|
|
segment.internal.used = true;
|
|
var i;
|
|
if (segment.reachable) {
|
|
for (i = 0; i < segment.allPrevSegments.length; ++i) {
|
|
var prevSegment = segment.allPrevSegments[i];
|
|
prevSegment.allNextSegments.push(segment);
|
|
prevSegment.nextSegments.push(segment);
|
|
}
|
|
} else {
|
|
for (i = 0; i < segment.allPrevSegments.length; ++i) {
|
|
segment.allPrevSegments[i].allNextSegments.push(segment);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Marks a previous segment as looped.
|
|
* @param {CodePathSegment} segment A segment.
|
|
* @param {CodePathSegment} prevSegment A previous segment to mark.
|
|
* @returns {void}
|
|
*/
|
|
static markPrevSegmentAsLooped(segment, prevSegment) {
|
|
segment.internal.loopedPrevSegments.push(prevSegment);
|
|
}
|
|
|
|
/**
|
|
* Replaces unused segments with the previous segments of each unused segment.
|
|
* @param {CodePathSegment[]} segments An array of segments to replace.
|
|
* @returns {CodePathSegment[]} The replaced array.
|
|
*/
|
|
static flattenUnusedSegments(segments) {
|
|
var done = Object.create(null);
|
|
var retv = [];
|
|
for (var i = 0; i < segments.length; ++i) {
|
|
var segment = segments[i];
|
|
|
|
// Ignores duplicated.
|
|
if (done[segment.id]) {
|
|
continue;
|
|
}
|
|
|
|
// Use previous segments if unused.
|
|
if (!segment.internal.used) {
|
|
for (var j = 0; j < segment.allPrevSegments.length; ++j) {
|
|
var prevSegment = segment.allPrevSegments[j];
|
|
if (!done[prevSegment.id]) {
|
|
done[prevSegment.id] = true;
|
|
retv.push(prevSegment);
|
|
}
|
|
}
|
|
} else {
|
|
done[segment.id] = true;
|
|
retv.push(segment);
|
|
}
|
|
}
|
|
return retv;
|
|
}
|
|
}
|
|
codePathSegment = CodePathSegment;
|
|
return codePathSegment;
|
|
}
|
|
|
|
var forkContext;
|
|
var hasRequiredForkContext;
|
|
function requireForkContext() {
|
|
if (hasRequiredForkContext) return forkContext;
|
|
hasRequiredForkContext = 1;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Requirements
|
|
//------------------------------------------------------------------------------
|
|
|
|
// eslint-disable-next-line
|
|
var assert = requireAssert();
|
|
// eslint-disable-next-line
|
|
var CodePathSegment = requireCodePathSegment();
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Gets whether or not a given segment is reachable.
|
|
* @param {CodePathSegment} segment A segment to get.
|
|
* @returns {boolean} `true` if the segment is reachable.
|
|
*/
|
|
function isReachable(segment) {
|
|
return segment.reachable;
|
|
}
|
|
|
|
/**
|
|
* Creates new segments from the specific range of `context.segmentsList`.
|
|
*
|
|
* When `context.segmentsList` is `[[a, b], [c, d], [e, f]]`, `begin` is `0`, and
|
|
* `end` is `-1`, this creates `[g, h]`. This `g` is from `a`, `c`, and `e`.
|
|
* This `h` is from `b`, `d`, and `f`.
|
|
* @param {ForkContext} context An instance.
|
|
* @param {number} begin The first index of the previous segments.
|
|
* @param {number} end The last index of the previous segments.
|
|
* @param {Function} create A factory function of new segments.
|
|
* @returns {CodePathSegment[]} New segments.
|
|
*/
|
|
function makeSegments(context, begin, end, create) {
|
|
var list = context.segmentsList;
|
|
var normalizedBegin = begin >= 0 ? begin : list.length + begin;
|
|
var normalizedEnd = end >= 0 ? end : list.length + end;
|
|
var segments = [];
|
|
for (var i = 0; i < context.count; ++i) {
|
|
var allPrevSegments = [];
|
|
for (var j = normalizedBegin; j <= normalizedEnd; ++j) {
|
|
allPrevSegments.push(list[j][i]);
|
|
}
|
|
segments.push(create(context.idGenerator.next(), allPrevSegments));
|
|
}
|
|
return segments;
|
|
}
|
|
|
|
/**
|
|
* `segments` becomes doubly in a `finally` block. Then if a code path exits by a
|
|
* control statement (such as `break`, `continue`) from the `finally` block, the
|
|
* destination's segments may be half of the source segments. In that case, this
|
|
* merges segments.
|
|
* @param {ForkContext} context An instance.
|
|
* @param {CodePathSegment[]} segments Segments to merge.
|
|
* @returns {CodePathSegment[]} The merged segments.
|
|
*/
|
|
function mergeExtraSegments(context, segments) {
|
|
var currentSegments = segments;
|
|
while (currentSegments.length > context.count) {
|
|
var merged = [];
|
|
for (var i = 0, length = currentSegments.length / 2 | 0; i < length; ++i) {
|
|
merged.push(CodePathSegment.newNext(context.idGenerator.next(), [currentSegments[i], currentSegments[i + length]]));
|
|
}
|
|
currentSegments = merged;
|
|
}
|
|
return currentSegments;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Interface
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* A class to manage forking.
|
|
*/
|
|
class ForkContext {
|
|
/**
|
|
* @param {IdGenerator} idGenerator An identifier generator for segments.
|
|
* @param {ForkContext|null} upper An upper fork context.
|
|
* @param {number} count A number of parallel segments.
|
|
*/
|
|
constructor(idGenerator, upper, count) {
|
|
this.idGenerator = idGenerator;
|
|
this.upper = upper;
|
|
this.count = count;
|
|
this.segmentsList = [];
|
|
}
|
|
|
|
/**
|
|
* The head segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
get head() {
|
|
var list = this.segmentsList;
|
|
return list.length === 0 ? [] : list[list.length - 1];
|
|
}
|
|
|
|
/**
|
|
* A flag which shows empty.
|
|
* @type {boolean}
|
|
*/
|
|
get empty() {
|
|
return this.segmentsList.length === 0;
|
|
}
|
|
|
|
/**
|
|
* A flag which shows reachable.
|
|
* @type {boolean}
|
|
*/
|
|
get reachable() {
|
|
var segments = this.head;
|
|
return segments.length > 0 && segments.some(isReachable);
|
|
}
|
|
|
|
/**
|
|
* Creates new segments from this context.
|
|
* @param {number} begin The first index of previous segments.
|
|
* @param {number} end The last index of previous segments.
|
|
* @returns {CodePathSegment[]} New segments.
|
|
*/
|
|
makeNext(begin, end) {
|
|
return makeSegments(this, begin, end, CodePathSegment.newNext);
|
|
}
|
|
|
|
/**
|
|
* Creates new segments from this context.
|
|
* The new segments is always unreachable.
|
|
* @param {number} begin The first index of previous segments.
|
|
* @param {number} end The last index of previous segments.
|
|
* @returns {CodePathSegment[]} New segments.
|
|
*/
|
|
makeUnreachable(begin, end) {
|
|
return makeSegments(this, begin, end, CodePathSegment.newUnreachable);
|
|
}
|
|
|
|
/**
|
|
* Creates new segments from this context.
|
|
* The new segments don't have connections for previous segments.
|
|
* But these inherit the reachable flag from this context.
|
|
* @param {number} begin The first index of previous segments.
|
|
* @param {number} end The last index of previous segments.
|
|
* @returns {CodePathSegment[]} New segments.
|
|
*/
|
|
makeDisconnected(begin, end) {
|
|
return makeSegments(this, begin, end, CodePathSegment.newDisconnected);
|
|
}
|
|
|
|
/**
|
|
* Adds segments into this context.
|
|
* The added segments become the head.
|
|
* @param {CodePathSegment[]} segments Segments to add.
|
|
* @returns {void}
|
|
*/
|
|
add(segments) {
|
|
assert(segments.length >= this.count, segments.length + " >= " + this.count);
|
|
this.segmentsList.push(mergeExtraSegments(this, segments));
|
|
}
|
|
|
|
/**
|
|
* Replaces the head segments with given segments.
|
|
* The current head segments are removed.
|
|
* @param {CodePathSegment[]} segments Segments to add.
|
|
* @returns {void}
|
|
*/
|
|
replaceHead(segments) {
|
|
assert(segments.length >= this.count, segments.length + " >= " + this.count);
|
|
this.segmentsList.splice(-1, 1, mergeExtraSegments(this, segments));
|
|
}
|
|
|
|
/**
|
|
* Adds all segments of a given fork context into this context.
|
|
* @param {ForkContext} context A fork context to add.
|
|
* @returns {void}
|
|
*/
|
|
addAll(context) {
|
|
assert(context.count === this.count);
|
|
var source = context.segmentsList;
|
|
for (var i = 0; i < source.length; ++i) {
|
|
this.segmentsList.push(source[i]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clears all segments in this context.
|
|
* @returns {void}
|
|
*/
|
|
clear() {
|
|
this.segmentsList = [];
|
|
}
|
|
|
|
/**
|
|
* Creates the root fork context.
|
|
* @param {IdGenerator} idGenerator An identifier generator for segments.
|
|
* @returns {ForkContext} New fork context.
|
|
*/
|
|
static newRoot(idGenerator) {
|
|
var context = new ForkContext(idGenerator, null, 1);
|
|
context.add([CodePathSegment.newRoot(idGenerator.next())]);
|
|
return context;
|
|
}
|
|
|
|
/**
|
|
* Creates an empty fork context preceded by a given context.
|
|
* @param {ForkContext} parentContext The parent fork context.
|
|
* @param {boolean} forkLeavingPath A flag which shows inside of `finally` block.
|
|
* @returns {ForkContext} New fork context.
|
|
*/
|
|
static newEmpty(parentContext, forkLeavingPath) {
|
|
return new ForkContext(parentContext.idGenerator, parentContext, (forkLeavingPath ? 2 : 1) * parentContext.count);
|
|
}
|
|
}
|
|
forkContext = ForkContext;
|
|
return forkContext;
|
|
}
|
|
|
|
var codePathState;
|
|
var hasRequiredCodePathState;
|
|
function requireCodePathState() {
|
|
if (hasRequiredCodePathState) return codePathState;
|
|
hasRequiredCodePathState = 1;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Requirements
|
|
//------------------------------------------------------------------------------
|
|
|
|
// eslint-disable-next-line
|
|
var CodePathSegment = requireCodePathSegment();
|
|
// eslint-disable-next-line
|
|
var ForkContext = requireForkContext();
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Adds given segments into the `dest` array.
|
|
* If the `others` array does not includes the given segments, adds to the `all`
|
|
* array as well.
|
|
*
|
|
* This adds only reachable and used segments.
|
|
* @param {CodePathSegment[]} dest A destination array (`returnedSegments` or `thrownSegments`).
|
|
* @param {CodePathSegment[]} others Another destination array (`returnedSegments` or `thrownSegments`).
|
|
* @param {CodePathSegment[]} all The unified destination array (`finalSegments`).
|
|
* @param {CodePathSegment[]} segments Segments to add.
|
|
* @returns {void}
|
|
*/
|
|
function addToReturnedOrThrown(dest, others, all, segments) {
|
|
for (var i = 0; i < segments.length; ++i) {
|
|
var segment = segments[i];
|
|
dest.push(segment);
|
|
if (!others.includes(segment)) {
|
|
all.push(segment);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets a loop-context for a `continue` statement.
|
|
* @param {CodePathState} state A state to get.
|
|
* @param {string} label The label of a `continue` statement.
|
|
* @returns {LoopContext} A loop-context for a `continue` statement.
|
|
*/
|
|
function getContinueContext(state, label) {
|
|
if (!label) {
|
|
return state.loopContext;
|
|
}
|
|
var context = state.loopContext;
|
|
while (context) {
|
|
if (context.label === label) {
|
|
return context;
|
|
}
|
|
context = context.upper;
|
|
}
|
|
|
|
/* c8 ignore next */
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Gets a context for a `break` statement.
|
|
* @param {CodePathState} state A state to get.
|
|
* @param {string} label The label of a `break` statement.
|
|
* @returns {LoopContext|SwitchContext} A context for a `break` statement.
|
|
*/
|
|
function getBreakContext(state, label) {
|
|
var context = state.breakContext;
|
|
while (context) {
|
|
if (label ? context.label === label : context.breakable) {
|
|
return context;
|
|
}
|
|
context = context.upper;
|
|
}
|
|
|
|
/* c8 ignore next */
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Gets a context for a `return` statement.
|
|
* @param {CodePathState} state A state to get.
|
|
* @returns {TryContext|CodePathState} A context for a `return` statement.
|
|
*/
|
|
function getReturnContext(state) {
|
|
var context = state.tryContext;
|
|
while (context) {
|
|
if (context.hasFinalizer && context.position !== 'finally') {
|
|
return context;
|
|
}
|
|
context = context.upper;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
/**
|
|
* Gets a context for a `throw` statement.
|
|
* @param {CodePathState} state A state to get.
|
|
* @returns {TryContext|CodePathState} A context for a `throw` statement.
|
|
*/
|
|
function getThrowContext(state) {
|
|
var context = state.tryContext;
|
|
while (context) {
|
|
if (context.position === 'try' || context.hasFinalizer && context.position === 'catch') {
|
|
return context;
|
|
}
|
|
context = context.upper;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
/**
|
|
* Removes a given element from a given array.
|
|
* @param {any[]} xs An array to remove the specific element.
|
|
* @param {any} x An element to be removed.
|
|
* @returns {void}
|
|
*/
|
|
function remove(xs, x) {
|
|
xs.splice(xs.indexOf(x), 1);
|
|
}
|
|
|
|
/**
|
|
* Disconnect given segments.
|
|
*
|
|
* This is used in a process for switch statements.
|
|
* If there is the "default" chunk before other cases, the order is different
|
|
* between node's and running's.
|
|
* @param {CodePathSegment[]} prevSegments Forward segments to disconnect.
|
|
* @param {CodePathSegment[]} nextSegments Backward segments to disconnect.
|
|
* @returns {void}
|
|
*/
|
|
function removeConnection(prevSegments, nextSegments) {
|
|
for (var i = 0; i < prevSegments.length; ++i) {
|
|
var prevSegment = prevSegments[i];
|
|
var nextSegment = nextSegments[i];
|
|
remove(prevSegment.nextSegments, nextSegment);
|
|
remove(prevSegment.allNextSegments, nextSegment);
|
|
remove(nextSegment.prevSegments, prevSegment);
|
|
remove(nextSegment.allPrevSegments, prevSegment);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates looping path.
|
|
* @param {CodePathState} state The instance.
|
|
* @param {CodePathSegment[]} unflattenedFromSegments Segments which are source.
|
|
* @param {CodePathSegment[]} unflattenedToSegments Segments which are destination.
|
|
* @returns {void}
|
|
*/
|
|
function makeLooped(state, unflattenedFromSegments, unflattenedToSegments) {
|
|
var fromSegments = CodePathSegment.flattenUnusedSegments(unflattenedFromSegments);
|
|
var toSegments = CodePathSegment.flattenUnusedSegments(unflattenedToSegments);
|
|
var end = Math.min(fromSegments.length, toSegments.length);
|
|
for (var i = 0; i < end; ++i) {
|
|
var fromSegment = fromSegments[i];
|
|
var toSegment = toSegments[i];
|
|
if (toSegment.reachable) {
|
|
fromSegment.nextSegments.push(toSegment);
|
|
}
|
|
if (fromSegment.reachable) {
|
|
toSegment.prevSegments.push(fromSegment);
|
|
}
|
|
fromSegment.allNextSegments.push(toSegment);
|
|
toSegment.allPrevSegments.push(fromSegment);
|
|
if (toSegment.allPrevSegments.length >= 2) {
|
|
CodePathSegment.markPrevSegmentAsLooped(toSegment, fromSegment);
|
|
}
|
|
state.notifyLooped(fromSegment, toSegment);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finalizes segments of `test` chunk of a ForStatement.
|
|
*
|
|
* - Adds `false` paths to paths which are leaving from the loop.
|
|
* - Sets `true` paths to paths which go to the body.
|
|
* @param {LoopContext} context A loop context to modify.
|
|
* @param {ChoiceContext} choiceContext A choice context of this loop.
|
|
* @param {CodePathSegment[]} head The current head paths.
|
|
* @returns {void}
|
|
*/
|
|
function finalizeTestSegmentsOfFor(context, choiceContext, head) {
|
|
if (!choiceContext.processed) {
|
|
choiceContext.trueForkContext.add(head);
|
|
choiceContext.falseForkContext.add(head);
|
|
choiceContext.qqForkContext.add(head);
|
|
}
|
|
if (context.test !== true) {
|
|
context.brokenForkContext.addAll(choiceContext.falseForkContext);
|
|
}
|
|
context.endOfTestSegments = choiceContext.trueForkContext.makeNext(0, -1);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Interface
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* A class which manages state to analyze code paths.
|
|
*/
|
|
class CodePathState {
|
|
/**
|
|
* @param {IdGenerator} idGenerator An id generator to generate id for code
|
|
* path segments.
|
|
* @param {Function} onLooped A callback function to notify looping.
|
|
*/
|
|
constructor(idGenerator, onLooped) {
|
|
this.idGenerator = idGenerator;
|
|
this.notifyLooped = onLooped;
|
|
this.forkContext = ForkContext.newRoot(idGenerator);
|
|
this.choiceContext = null;
|
|
this.switchContext = null;
|
|
this.tryContext = null;
|
|
this.loopContext = null;
|
|
this.breakContext = null;
|
|
this.chainContext = null;
|
|
this.currentSegments = [];
|
|
this.initialSegment = this.forkContext.head[0];
|
|
|
|
// returnedSegments and thrownSegments push elements into finalSegments also.
|
|
var final = this.finalSegments = [];
|
|
var returned = this.returnedForkContext = [];
|
|
var thrown = this.thrownForkContext = [];
|
|
returned.add = addToReturnedOrThrown.bind(null, returned, thrown, final);
|
|
thrown.add = addToReturnedOrThrown.bind(null, thrown, returned, final);
|
|
}
|
|
|
|
/**
|
|
* The head segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
get headSegments() {
|
|
return this.forkContext.head;
|
|
}
|
|
|
|
/**
|
|
* The parent forking context.
|
|
* This is used for the root of new forks.
|
|
* @type {ForkContext}
|
|
*/
|
|
get parentForkContext() {
|
|
var current = this.forkContext;
|
|
return current && current.upper;
|
|
}
|
|
|
|
/**
|
|
* Creates and stacks new forking context.
|
|
* @param {boolean} forkLeavingPath A flag which shows being in a
|
|
* "finally" block.
|
|
* @returns {ForkContext} The created context.
|
|
*/
|
|
pushForkContext(forkLeavingPath) {
|
|
this.forkContext = ForkContext.newEmpty(this.forkContext, forkLeavingPath);
|
|
return this.forkContext;
|
|
}
|
|
|
|
/**
|
|
* Pops and merges the last forking context.
|
|
* @returns {ForkContext} The last context.
|
|
*/
|
|
popForkContext() {
|
|
var lastContext = this.forkContext;
|
|
this.forkContext = lastContext.upper;
|
|
this.forkContext.replaceHead(lastContext.makeNext(0, -1));
|
|
return lastContext;
|
|
}
|
|
|
|
/**
|
|
* Creates a new path.
|
|
* @returns {void}
|
|
*/
|
|
forkPath() {
|
|
this.forkContext.add(this.parentForkContext.makeNext(-1, -1));
|
|
}
|
|
|
|
/**
|
|
* Creates a bypass path.
|
|
* This is used for such as IfStatement which does not have "else" chunk.
|
|
* @returns {void}
|
|
*/
|
|
forkBypassPath() {
|
|
this.forkContext.add(this.parentForkContext.head);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ConditionalExpression, LogicalExpression, IfStatement
|
|
//--------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Creates a context for ConditionalExpression, LogicalExpression, AssignmentExpression (logical assignments only),
|
|
* IfStatement, WhileStatement, DoWhileStatement, or ForStatement.
|
|
*
|
|
* LogicalExpressions have cases that it goes different paths between the
|
|
* `true` case and the `false` case.
|
|
*
|
|
* For Example:
|
|
*
|
|
* if (a || b) {
|
|
* foo();
|
|
* } else {
|
|
* bar();
|
|
* }
|
|
*
|
|
* In this case, `b` is evaluated always in the code path of the `else`
|
|
* block, but it's not so in the code path of the `if` block.
|
|
* So there are 3 paths.
|
|
*
|
|
* a -> foo();
|
|
* a -> b -> foo();
|
|
* a -> b -> bar();
|
|
* @param {string} kind A kind string.
|
|
* If the new context is LogicalExpression's or AssignmentExpression's, this is `"&&"` or `"||"` or `"??"`.
|
|
* If it's IfStatement's or ConditionalExpression's, this is `"test"`.
|
|
* Otherwise, this is `"loop"`.
|
|
* @param {boolean} isForkingAsResult A flag that shows that goes different
|
|
* paths between `true` and `false`.
|
|
* @returns {void}
|
|
*/
|
|
pushChoiceContext(kind, isForkingAsResult) {
|
|
this.choiceContext = {
|
|
upper: this.choiceContext,
|
|
kind: kind,
|
|
isForkingAsResult: isForkingAsResult,
|
|
trueForkContext: ForkContext.newEmpty(this.forkContext),
|
|
falseForkContext: ForkContext.newEmpty(this.forkContext),
|
|
qqForkContext: ForkContext.newEmpty(this.forkContext),
|
|
processed: false
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Pops the last choice context and finalizes it.
|
|
* @throws {Error} (Unreachable.)
|
|
* @returns {ChoiceContext} The popped context.
|
|
*/
|
|
popChoiceContext() {
|
|
var context = this.choiceContext;
|
|
this.choiceContext = context.upper;
|
|
var forkContext = this.forkContext;
|
|
var headSegments = forkContext.head;
|
|
switch (context.kind) {
|
|
case '&&':
|
|
case '||':
|
|
case '??':
|
|
/*
|
|
* If any result were not transferred from child contexts,
|
|
* this sets the head segments to both cases.
|
|
* The head segments are the path of the right-hand operand.
|
|
*/
|
|
if (!context.processed) {
|
|
context.trueForkContext.add(headSegments);
|
|
context.falseForkContext.add(headSegments);
|
|
context.qqForkContext.add(headSegments);
|
|
}
|
|
|
|
/*
|
|
* Transfers results to upper context if this context is in
|
|
* test chunk.
|
|
*/
|
|
if (context.isForkingAsResult) {
|
|
var parentContext = this.choiceContext;
|
|
parentContext.trueForkContext.addAll(context.trueForkContext);
|
|
parentContext.falseForkContext.addAll(context.falseForkContext);
|
|
parentContext.qqForkContext.addAll(context.qqForkContext);
|
|
parentContext.processed = true;
|
|
return context;
|
|
}
|
|
break;
|
|
case 'test':
|
|
if (!context.processed) {
|
|
/*
|
|
* The head segments are the path of the `if` block here.
|
|
* Updates the `true` path with the end of the `if` block.
|
|
*/
|
|
context.trueForkContext.clear();
|
|
context.trueForkContext.add(headSegments);
|
|
} else {
|
|
/*
|
|
* The head segments are the path of the `else` block here.
|
|
* Updates the `false` path with the end of the `else`
|
|
* block.
|
|
*/
|
|
context.falseForkContext.clear();
|
|
context.falseForkContext.add(headSegments);
|
|
}
|
|
break;
|
|
case 'loop':
|
|
/*
|
|
* Loops are addressed in popLoopContext().
|
|
* This is called from popLoopContext().
|
|
*/
|
|
return context;
|
|
|
|
/* c8 ignore next */
|
|
default:
|
|
throw new Error('unreachable');
|
|
}
|
|
|
|
// Merges all paths.
|
|
var prevForkContext = context.trueForkContext;
|
|
prevForkContext.addAll(context.falseForkContext);
|
|
forkContext.replaceHead(prevForkContext.makeNext(0, -1));
|
|
return context;
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment of the right-hand operand of a logical
|
|
* expression.
|
|
* @throws {Error} (Unreachable.)
|
|
* @returns {void}
|
|
*/
|
|
makeLogicalRight() {
|
|
var context = this.choiceContext;
|
|
var forkContext = this.forkContext;
|
|
if (context.processed) {
|
|
/*
|
|
* This got segments already from the child choice context.
|
|
* Creates the next path from own true/false fork context.
|
|
*/
|
|
var prevForkContext;
|
|
switch (context.kind) {
|
|
case '&&':
|
|
// if true then go to the right-hand side.
|
|
prevForkContext = context.trueForkContext;
|
|
break;
|
|
case '||':
|
|
// if false then go to the right-hand side.
|
|
prevForkContext = context.falseForkContext;
|
|
break;
|
|
case '??':
|
|
// Both true/false can short-circuit, so needs the third path to go to the right-hand side. That's qqForkContext.
|
|
prevForkContext = context.qqForkContext;
|
|
break;
|
|
default:
|
|
throw new Error('unreachable');
|
|
}
|
|
forkContext.replaceHead(prevForkContext.makeNext(0, -1));
|
|
prevForkContext.clear();
|
|
context.processed = false;
|
|
} else {
|
|
/*
|
|
* This did not get segments from the child choice context.
|
|
* So addresses the head segments.
|
|
* The head segments are the path of the left-hand operand.
|
|
*/
|
|
switch (context.kind) {
|
|
case '&&':
|
|
// the false path can short-circuit.
|
|
context.falseForkContext.add(forkContext.head);
|
|
break;
|
|
case '||':
|
|
// the true path can short-circuit.
|
|
context.trueForkContext.add(forkContext.head);
|
|
break;
|
|
case '??':
|
|
// both can short-circuit.
|
|
context.trueForkContext.add(forkContext.head);
|
|
context.falseForkContext.add(forkContext.head);
|
|
break;
|
|
default:
|
|
throw new Error('unreachable');
|
|
}
|
|
forkContext.replaceHead(forkContext.makeNext(-1, -1));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment of the `if` block.
|
|
* @returns {void}
|
|
*/
|
|
makeIfConsequent() {
|
|
var context = this.choiceContext;
|
|
var forkContext = this.forkContext;
|
|
|
|
/*
|
|
* If any result were not transferred from child contexts,
|
|
* this sets the head segments to both cases.
|
|
* The head segments are the path of the test expression.
|
|
*/
|
|
if (!context.processed) {
|
|
context.trueForkContext.add(forkContext.head);
|
|
context.falseForkContext.add(forkContext.head);
|
|
context.qqForkContext.add(forkContext.head);
|
|
}
|
|
context.processed = false;
|
|
|
|
// Creates new path from the `true` case.
|
|
forkContext.replaceHead(context.trueForkContext.makeNext(0, -1));
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment of the `else` block.
|
|
* @returns {void}
|
|
*/
|
|
makeIfAlternate() {
|
|
var context = this.choiceContext;
|
|
var forkContext = this.forkContext;
|
|
|
|
/*
|
|
* The head segments are the path of the `if` block.
|
|
* Updates the `true` path with the end of the `if` block.
|
|
*/
|
|
context.trueForkContext.clear();
|
|
context.trueForkContext.add(forkContext.head);
|
|
context.processed = true;
|
|
|
|
// Creates new path from the `false` case.
|
|
forkContext.replaceHead(context.falseForkContext.makeNext(0, -1));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ChainExpression
|
|
//--------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Push a new `ChainExpression` context to the stack.
|
|
* This method is called on entering to each `ChainExpression` node.
|
|
* This context is used to count forking in the optional chain then merge them on the exiting from the `ChainExpression` node.
|
|
* @returns {void}
|
|
*/
|
|
pushChainContext() {
|
|
this.chainContext = {
|
|
upper: this.chainContext,
|
|
countChoiceContexts: 0
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Pop a `ChainExpression` context from the stack.
|
|
* This method is called on exiting from each `ChainExpression` node.
|
|
* This merges all forks of the last optional chaining.
|
|
* @returns {void}
|
|
*/
|
|
popChainContext() {
|
|
var context = this.chainContext;
|
|
this.chainContext = context.upper;
|
|
|
|
// pop all choice contexts of this.
|
|
for (var i = context.countChoiceContexts; i > 0; --i) {
|
|
this.popChoiceContext();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a choice context for optional access.
|
|
* This method is called on entering to each `(Call|Member)Expression[optional=true]` node.
|
|
* This creates a choice context as similar to `LogicalExpression[operator="??"]` node.
|
|
* @returns {void}
|
|
*/
|
|
makeOptionalNode() {
|
|
if (this.chainContext) {
|
|
this.chainContext.countChoiceContexts += 1;
|
|
this.pushChoiceContext('??', false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a fork.
|
|
* This method is called on entering to the `arguments|property` property of each `(Call|Member)Expression` node.
|
|
* @returns {void}
|
|
*/
|
|
makeOptionalRight() {
|
|
if (this.chainContext) {
|
|
this.makeLogicalRight();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// SwitchStatement
|
|
//--------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Creates a context object of SwitchStatement and stacks it.
|
|
* @param {boolean} hasCase `true` if the switch statement has one or more
|
|
* case parts.
|
|
* @param {string|null} label The label text.
|
|
* @returns {void}
|
|
*/
|
|
pushSwitchContext(hasCase, label) {
|
|
this.switchContext = {
|
|
upper: this.switchContext,
|
|
hasCase: hasCase,
|
|
defaultSegments: null,
|
|
defaultBodySegments: null,
|
|
foundDefault: false,
|
|
lastIsDefault: false,
|
|
countForks: 0
|
|
};
|
|
this.pushBreakContext(true, label);
|
|
}
|
|
|
|
/**
|
|
* Pops the last context of SwitchStatement and finalizes it.
|
|
*
|
|
* - Disposes all forking stack for `case` and `default`.
|
|
* - Creates the next code path segment from `context.brokenForkContext`.
|
|
* - If the last `SwitchCase` node is not a `default` part, creates a path
|
|
* to the `default` body.
|
|
* @returns {void}
|
|
*/
|
|
popSwitchContext() {
|
|
var context = this.switchContext;
|
|
this.switchContext = context.upper;
|
|
var forkContext = this.forkContext;
|
|
var brokenForkContext = this.popBreakContext().brokenForkContext;
|
|
if (context.countForks === 0) {
|
|
/*
|
|
* When there is only one `default` chunk and there is one or more
|
|
* `break` statements, even if forks are nothing, it needs to merge
|
|
* those.
|
|
*/
|
|
if (!brokenForkContext.empty) {
|
|
brokenForkContext.add(forkContext.makeNext(-1, -1));
|
|
forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
|
|
}
|
|
return;
|
|
}
|
|
var lastSegments = forkContext.head;
|
|
this.forkBypassPath();
|
|
var lastCaseSegments = forkContext.head;
|
|
|
|
/*
|
|
* `brokenForkContext` is used to make the next segment.
|
|
* It must add the last segment into `brokenForkContext`.
|
|
*/
|
|
brokenForkContext.add(lastSegments);
|
|
|
|
/*
|
|
* A path which is failed in all case test should be connected to path
|
|
* of `default` chunk.
|
|
*/
|
|
if (!context.lastIsDefault) {
|
|
if (context.defaultBodySegments) {
|
|
/*
|
|
* Remove a link from `default` label to its chunk.
|
|
* It's false route.
|
|
*/
|
|
removeConnection(context.defaultSegments, context.defaultBodySegments);
|
|
makeLooped(this, lastCaseSegments, context.defaultBodySegments);
|
|
} else {
|
|
/*
|
|
* It handles the last case body as broken if `default` chunk
|
|
* does not exist.
|
|
*/
|
|
brokenForkContext.add(lastCaseSegments);
|
|
}
|
|
}
|
|
|
|
// Pops the segment context stack until the entry segment.
|
|
for (var i = 0; i < context.countForks; ++i) {
|
|
this.forkContext = this.forkContext.upper;
|
|
}
|
|
|
|
/*
|
|
* Creates a path from all brokenForkContext paths.
|
|
* This is a path after switch statement.
|
|
*/
|
|
this.forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for a `SwitchCase` node.
|
|
* @param {boolean} isEmpty `true` if the body is empty.
|
|
* @param {boolean} isDefault `true` if the body is the default case.
|
|
* @returns {void}
|
|
*/
|
|
makeSwitchCaseBody(isEmpty, isDefault) {
|
|
var context = this.switchContext;
|
|
if (!context.hasCase) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Merge forks.
|
|
* The parent fork context has two segments.
|
|
* Those are from the current case and the body of the previous case.
|
|
*/
|
|
var parentForkContext = this.forkContext;
|
|
var forkContext = this.pushForkContext();
|
|
forkContext.add(parentForkContext.makeNext(0, -1));
|
|
|
|
/*
|
|
* Save `default` chunk info.
|
|
* If the `default` label is not at the last, we must make a path from
|
|
* the last `case` to the `default` chunk.
|
|
*/
|
|
if (isDefault) {
|
|
context.defaultSegments = parentForkContext.head;
|
|
if (isEmpty) {
|
|
context.foundDefault = true;
|
|
} else {
|
|
context.defaultBodySegments = forkContext.head;
|
|
}
|
|
} else {
|
|
if (!isEmpty && context.foundDefault) {
|
|
context.foundDefault = false;
|
|
context.defaultBodySegments = forkContext.head;
|
|
}
|
|
}
|
|
context.lastIsDefault = isDefault;
|
|
context.countForks += 1;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// TryStatement
|
|
//--------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Creates a context object of TryStatement and stacks it.
|
|
* @param {boolean} hasFinalizer `true` if the try statement has a
|
|
* `finally` block.
|
|
* @returns {void}
|
|
*/
|
|
pushTryContext(hasFinalizer) {
|
|
this.tryContext = {
|
|
upper: this.tryContext,
|
|
position: 'try',
|
|
hasFinalizer: hasFinalizer,
|
|
returnedForkContext: hasFinalizer ? ForkContext.newEmpty(this.forkContext) : null,
|
|
thrownForkContext: ForkContext.newEmpty(this.forkContext),
|
|
lastOfTryIsReachable: false,
|
|
lastOfCatchIsReachable: false
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Pops the last context of TryStatement and finalizes it.
|
|
* @returns {void}
|
|
*/
|
|
popTryContext() {
|
|
var context = this.tryContext;
|
|
this.tryContext = context.upper;
|
|
if (context.position === 'catch') {
|
|
// Merges two paths from the `try` block and `catch` block merely.
|
|
this.popForkContext();
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* The following process is executed only when there is the `finally`
|
|
* block.
|
|
*/
|
|
|
|
var returned = context.returnedForkContext;
|
|
var thrown = context.thrownForkContext;
|
|
if (returned.empty && thrown.empty) {
|
|
return;
|
|
}
|
|
|
|
// Separate head to normal paths and leaving paths.
|
|
var headSegments = this.forkContext.head;
|
|
this.forkContext = this.forkContext.upper;
|
|
var normalSegments = headSegments.slice(0, headSegments.length / 2 | 0);
|
|
var leavingSegments = headSegments.slice(headSegments.length / 2 | 0);
|
|
|
|
// Forwards the leaving path to upper contexts.
|
|
if (!returned.empty) {
|
|
getReturnContext(this).returnedForkContext.add(leavingSegments);
|
|
}
|
|
if (!thrown.empty) {
|
|
getThrowContext(this).thrownForkContext.add(leavingSegments);
|
|
}
|
|
|
|
// Sets the normal path as the next.
|
|
this.forkContext.replaceHead(normalSegments);
|
|
|
|
/*
|
|
* If both paths of the `try` block and the `catch` block are
|
|
* unreachable, the next path becomes unreachable as well.
|
|
*/
|
|
if (!context.lastOfTryIsReachable && !context.lastOfCatchIsReachable) {
|
|
this.forkContext.makeUnreachable();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for a `catch` block.
|
|
* @returns {void}
|
|
*/
|
|
makeCatchBlock() {
|
|
var context = this.tryContext;
|
|
var forkContext = this.forkContext;
|
|
var thrown = context.thrownForkContext;
|
|
|
|
// Update state.
|
|
context.position = 'catch';
|
|
context.thrownForkContext = ForkContext.newEmpty(forkContext);
|
|
context.lastOfTryIsReachable = forkContext.reachable;
|
|
|
|
// Merge thrown paths.
|
|
thrown.add(forkContext.head);
|
|
var thrownSegments = thrown.makeNext(0, -1);
|
|
|
|
// Fork to a bypass and the merged thrown path.
|
|
this.pushForkContext();
|
|
this.forkBypassPath();
|
|
this.forkContext.add(thrownSegments);
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for a `finally` block.
|
|
*
|
|
* In the `finally` block, parallel paths are created. The parallel paths
|
|
* are used as leaving-paths. The leaving-paths are paths from `return`
|
|
* statements and `throw` statements in a `try` block or a `catch` block.
|
|
* @returns {void}
|
|
*/
|
|
makeFinallyBlock() {
|
|
var context = this.tryContext;
|
|
var forkContext = this.forkContext;
|
|
var returned = context.returnedForkContext;
|
|
var thrown = context.thrownForkContext;
|
|
var headOfLeavingSegments = forkContext.head;
|
|
|
|
// Update state.
|
|
if (context.position === 'catch') {
|
|
// Merges two paths from the `try` block and `catch` block.
|
|
this.popForkContext();
|
|
forkContext = this.forkContext;
|
|
context.lastOfCatchIsReachable = forkContext.reachable;
|
|
} else {
|
|
context.lastOfTryIsReachable = forkContext.reachable;
|
|
}
|
|
context.position = 'finally';
|
|
if (returned.empty && thrown.empty) {
|
|
// This path does not leave.
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Create a parallel segment from merging returned and thrown.
|
|
* This segment will leave at the end of this finally block.
|
|
*/
|
|
var segments = forkContext.makeNext(-1, -1);
|
|
for (var i = 0; i < forkContext.count; ++i) {
|
|
var prevSegsOfLeavingSegment = [headOfLeavingSegments[i]];
|
|
for (var j = 0; j < returned.segmentsList.length; ++j) {
|
|
prevSegsOfLeavingSegment.push(returned.segmentsList[j][i]);
|
|
}
|
|
for (var _j = 0; _j < thrown.segmentsList.length; ++_j) {
|
|
prevSegsOfLeavingSegment.push(thrown.segmentsList[_j][i]);
|
|
}
|
|
segments.push(CodePathSegment.newNext(this.idGenerator.next(), prevSegsOfLeavingSegment));
|
|
}
|
|
this.pushForkContext(true);
|
|
this.forkContext.add(segments);
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment from the first throwable node to the `catch`
|
|
* block or the `finally` block.
|
|
* @returns {void}
|
|
*/
|
|
makeFirstThrowablePathInTryBlock() {
|
|
var forkContext = this.forkContext;
|
|
if (!forkContext.reachable) {
|
|
return;
|
|
}
|
|
var context = getThrowContext(this);
|
|
if (context === this || context.position !== 'try' || !context.thrownForkContext.empty) {
|
|
return;
|
|
}
|
|
context.thrownForkContext.add(forkContext.head);
|
|
forkContext.replaceHead(forkContext.makeNext(-1, -1));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Loop Statements
|
|
//--------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Creates a context object of a loop statement and stacks it.
|
|
* @param {string} type The type of the node which was triggered. One of
|
|
* `WhileStatement`, `DoWhileStatement`, `ForStatement`, `ForInStatement`,
|
|
* and `ForStatement`.
|
|
* @param {string|null} label A label of the node which was triggered.
|
|
* @throws {Error} (Unreachable - unknown type.)
|
|
* @returns {void}
|
|
*/
|
|
pushLoopContext(type, label) {
|
|
var forkContext = this.forkContext;
|
|
var breakContext = this.pushBreakContext(true, label);
|
|
switch (type) {
|
|
case 'WhileStatement':
|
|
this.pushChoiceContext('loop', false);
|
|
this.loopContext = {
|
|
upper: this.loopContext,
|
|
type: type,
|
|
label: label,
|
|
test: void 0,
|
|
continueDestSegments: null,
|
|
brokenForkContext: breakContext.brokenForkContext
|
|
};
|
|
break;
|
|
case 'DoWhileStatement':
|
|
this.pushChoiceContext('loop', false);
|
|
this.loopContext = {
|
|
upper: this.loopContext,
|
|
type: type,
|
|
label: label,
|
|
test: void 0,
|
|
entrySegments: null,
|
|
continueForkContext: ForkContext.newEmpty(forkContext),
|
|
brokenForkContext: breakContext.brokenForkContext
|
|
};
|
|
break;
|
|
case 'ForStatement':
|
|
this.pushChoiceContext('loop', false);
|
|
this.loopContext = {
|
|
upper: this.loopContext,
|
|
type: type,
|
|
label: label,
|
|
test: void 0,
|
|
endOfInitSegments: null,
|
|
testSegments: null,
|
|
endOfTestSegments: null,
|
|
updateSegments: null,
|
|
endOfUpdateSegments: null,
|
|
continueDestSegments: null,
|
|
brokenForkContext: breakContext.brokenForkContext
|
|
};
|
|
break;
|
|
case 'ForInStatement':
|
|
case 'ForOfStatement':
|
|
this.loopContext = {
|
|
upper: this.loopContext,
|
|
type: type,
|
|
label: label,
|
|
prevSegments: null,
|
|
leftSegments: null,
|
|
endOfLeftSegments: null,
|
|
continueDestSegments: null,
|
|
brokenForkContext: breakContext.brokenForkContext
|
|
};
|
|
break;
|
|
|
|
/* c8 ignore next */
|
|
default:
|
|
throw new Error("unknown type: \"" + type + "\"");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Pops the last context of a loop statement and finalizes it.
|
|
* @throws {Error} (Unreachable - unknown type.)
|
|
* @returns {void}
|
|
*/
|
|
popLoopContext() {
|
|
var context = this.loopContext;
|
|
this.loopContext = context.upper;
|
|
var forkContext = this.forkContext;
|
|
var brokenForkContext = this.popBreakContext().brokenForkContext;
|
|
|
|
// Creates a looped path.
|
|
switch (context.type) {
|
|
case 'WhileStatement':
|
|
case 'ForStatement':
|
|
this.popChoiceContext();
|
|
makeLooped(this, forkContext.head, context.continueDestSegments);
|
|
break;
|
|
case 'DoWhileStatement':
|
|
{
|
|
var choiceContext = this.popChoiceContext();
|
|
if (!choiceContext.processed) {
|
|
choiceContext.trueForkContext.add(forkContext.head);
|
|
choiceContext.falseForkContext.add(forkContext.head);
|
|
}
|
|
if (context.test !== true) {
|
|
brokenForkContext.addAll(choiceContext.falseForkContext);
|
|
}
|
|
|
|
// `true` paths go to looping.
|
|
var segmentsList = choiceContext.trueForkContext.segmentsList;
|
|
for (var i = 0; i < segmentsList.length; ++i) {
|
|
makeLooped(this, segmentsList[i], context.entrySegments);
|
|
}
|
|
break;
|
|
}
|
|
case 'ForInStatement':
|
|
case 'ForOfStatement':
|
|
brokenForkContext.add(forkContext.head);
|
|
makeLooped(this, forkContext.head, context.leftSegments);
|
|
break;
|
|
|
|
/* c8 ignore next */
|
|
default:
|
|
throw new Error('unreachable');
|
|
}
|
|
|
|
// Go next.
|
|
if (brokenForkContext.empty) {
|
|
forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
|
|
} else {
|
|
forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for the test part of a WhileStatement.
|
|
* @param {boolean|undefined} test The test value (only when constant).
|
|
* @returns {void}
|
|
*/
|
|
makeWhileTest(test) {
|
|
var context = this.loopContext;
|
|
var forkContext = this.forkContext;
|
|
var testSegments = forkContext.makeNext(0, -1);
|
|
|
|
// Update state.
|
|
context.test = test;
|
|
context.continueDestSegments = testSegments;
|
|
forkContext.replaceHead(testSegments);
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for the body part of a WhileStatement.
|
|
* @returns {void}
|
|
*/
|
|
makeWhileBody() {
|
|
var context = this.loopContext;
|
|
var choiceContext = this.choiceContext;
|
|
var forkContext = this.forkContext;
|
|
if (!choiceContext.processed) {
|
|
choiceContext.trueForkContext.add(forkContext.head);
|
|
choiceContext.falseForkContext.add(forkContext.head);
|
|
}
|
|
|
|
// Update state.
|
|
if (context.test !== true) {
|
|
context.brokenForkContext.addAll(choiceContext.falseForkContext);
|
|
}
|
|
forkContext.replaceHead(choiceContext.trueForkContext.makeNext(0, -1));
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for the body part of a DoWhileStatement.
|
|
* @returns {void}
|
|
*/
|
|
makeDoWhileBody() {
|
|
var context = this.loopContext;
|
|
var forkContext = this.forkContext;
|
|
var bodySegments = forkContext.makeNext(-1, -1);
|
|
|
|
// Update state.
|
|
context.entrySegments = bodySegments;
|
|
forkContext.replaceHead(bodySegments);
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for the test part of a DoWhileStatement.
|
|
* @param {boolean|undefined} test The test value (only when constant).
|
|
* @returns {void}
|
|
*/
|
|
makeDoWhileTest(test) {
|
|
var context = this.loopContext;
|
|
var forkContext = this.forkContext;
|
|
context.test = test;
|
|
|
|
// Creates paths of `continue` statements.
|
|
if (!context.continueForkContext.empty) {
|
|
context.continueForkContext.add(forkContext.head);
|
|
var testSegments = context.continueForkContext.makeNext(0, -1);
|
|
forkContext.replaceHead(testSegments);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for the test part of a ForStatement.
|
|
* @param {boolean|undefined} test The test value (only when constant).
|
|
* @returns {void}
|
|
*/
|
|
makeForTest(test) {
|
|
var context = this.loopContext;
|
|
var forkContext = this.forkContext;
|
|
var endOfInitSegments = forkContext.head;
|
|
var testSegments = forkContext.makeNext(-1, -1);
|
|
|
|
// Update state.
|
|
context.test = test;
|
|
context.endOfInitSegments = endOfInitSegments;
|
|
context.continueDestSegments = context.testSegments = testSegments;
|
|
forkContext.replaceHead(testSegments);
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for the update part of a ForStatement.
|
|
* @returns {void}
|
|
*/
|
|
makeForUpdate() {
|
|
var context = this.loopContext;
|
|
var choiceContext = this.choiceContext;
|
|
var forkContext = this.forkContext;
|
|
|
|
// Make the next paths of the test.
|
|
if (context.testSegments) {
|
|
finalizeTestSegmentsOfFor(context, choiceContext, forkContext.head);
|
|
} else {
|
|
context.endOfInitSegments = forkContext.head;
|
|
}
|
|
|
|
// Update state.
|
|
var updateSegments = forkContext.makeDisconnected(-1, -1);
|
|
context.continueDestSegments = context.updateSegments = updateSegments;
|
|
forkContext.replaceHead(updateSegments);
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for the body part of a ForStatement.
|
|
* @returns {void}
|
|
*/
|
|
makeForBody() {
|
|
var context = this.loopContext;
|
|
var choiceContext = this.choiceContext;
|
|
var forkContext = this.forkContext;
|
|
|
|
// Update state.
|
|
if (context.updateSegments) {
|
|
context.endOfUpdateSegments = forkContext.head;
|
|
|
|
// `update` -> `test`
|
|
if (context.testSegments) {
|
|
makeLooped(this, context.endOfUpdateSegments, context.testSegments);
|
|
}
|
|
} else if (context.testSegments) {
|
|
finalizeTestSegmentsOfFor(context, choiceContext, forkContext.head);
|
|
} else {
|
|
context.endOfInitSegments = forkContext.head;
|
|
}
|
|
var bodySegments = context.endOfTestSegments;
|
|
if (!bodySegments) {
|
|
/*
|
|
* If there is not the `test` part, the `body` path comes from the
|
|
* `init` part and the `update` part.
|
|
*/
|
|
var prevForkContext = ForkContext.newEmpty(forkContext);
|
|
prevForkContext.add(context.endOfInitSegments);
|
|
if (context.endOfUpdateSegments) {
|
|
prevForkContext.add(context.endOfUpdateSegments);
|
|
}
|
|
bodySegments = prevForkContext.makeNext(0, -1);
|
|
}
|
|
context.continueDestSegments = context.continueDestSegments || bodySegments;
|
|
forkContext.replaceHead(bodySegments);
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for the left part of a ForInStatement and a
|
|
* ForOfStatement.
|
|
* @returns {void}
|
|
*/
|
|
makeForInOfLeft() {
|
|
var context = this.loopContext;
|
|
var forkContext = this.forkContext;
|
|
var leftSegments = forkContext.makeDisconnected(-1, -1);
|
|
|
|
// Update state.
|
|
context.prevSegments = forkContext.head;
|
|
context.leftSegments = context.continueDestSegments = leftSegments;
|
|
forkContext.replaceHead(leftSegments);
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for the right part of a ForInStatement and a
|
|
* ForOfStatement.
|
|
* @returns {void}
|
|
*/
|
|
makeForInOfRight() {
|
|
var context = this.loopContext;
|
|
var forkContext = this.forkContext;
|
|
var temp = ForkContext.newEmpty(forkContext);
|
|
temp.add(context.prevSegments);
|
|
var rightSegments = temp.makeNext(-1, -1);
|
|
|
|
// Update state.
|
|
context.endOfLeftSegments = forkContext.head;
|
|
forkContext.replaceHead(rightSegments);
|
|
}
|
|
|
|
/**
|
|
* Makes a code path segment for the body part of a ForInStatement and a
|
|
* ForOfStatement.
|
|
* @returns {void}
|
|
*/
|
|
makeForInOfBody() {
|
|
var context = this.loopContext;
|
|
var forkContext = this.forkContext;
|
|
var temp = ForkContext.newEmpty(forkContext);
|
|
temp.add(context.endOfLeftSegments);
|
|
var bodySegments = temp.makeNext(-1, -1);
|
|
|
|
// Make a path: `right` -> `left`.
|
|
makeLooped(this, forkContext.head, context.leftSegments);
|
|
|
|
// Update state.
|
|
context.brokenForkContext.add(forkContext.head);
|
|
forkContext.replaceHead(bodySegments);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Control Statements
|
|
//--------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Creates new context for BreakStatement.
|
|
* @param {boolean} breakable The flag to indicate it can break by
|
|
* an unlabeled BreakStatement.
|
|
* @param {string|null} label The label of this context.
|
|
* @returns {Object} The new context.
|
|
*/
|
|
pushBreakContext(breakable, label) {
|
|
this.breakContext = {
|
|
upper: this.breakContext,
|
|
breakable: breakable,
|
|
label: label,
|
|
brokenForkContext: ForkContext.newEmpty(this.forkContext)
|
|
};
|
|
return this.breakContext;
|
|
}
|
|
|
|
/**
|
|
* Removes the top item of the break context stack.
|
|
* @returns {Object} The removed context.
|
|
*/
|
|
popBreakContext() {
|
|
var context = this.breakContext;
|
|
var forkContext = this.forkContext;
|
|
this.breakContext = context.upper;
|
|
|
|
// Process this context here for other than switches and loops.
|
|
if (!context.breakable) {
|
|
var brokenForkContext = context.brokenForkContext;
|
|
if (!brokenForkContext.empty) {
|
|
brokenForkContext.add(forkContext.head);
|
|
forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
|
|
}
|
|
}
|
|
return context;
|
|
}
|
|
|
|
/**
|
|
* Makes a path for a `break` statement.
|
|
*
|
|
* It registers the head segment to a context of `break`.
|
|
* It makes new unreachable segment, then it set the head with the segment.
|
|
* @param {string} label A label of the break statement.
|
|
* @returns {void}
|
|
*/
|
|
makeBreak(label) {
|
|
var forkContext = this.forkContext;
|
|
if (!forkContext.reachable) {
|
|
return;
|
|
}
|
|
var context = getBreakContext(this, label);
|
|
if (context) {
|
|
context.brokenForkContext.add(forkContext.head);
|
|
}
|
|
|
|
/* c8 ignore next */
|
|
forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
|
|
}
|
|
|
|
/**
|
|
* Makes a path for a `continue` statement.
|
|
*
|
|
* It makes a looping path.
|
|
* It makes new unreachable segment, then it set the head with the segment.
|
|
* @param {string} label A label of the continue statement.
|
|
* @returns {void}
|
|
*/
|
|
makeContinue(label) {
|
|
var forkContext = this.forkContext;
|
|
if (!forkContext.reachable) {
|
|
return;
|
|
}
|
|
var context = getContinueContext(this, label);
|
|
if (context) {
|
|
if (context.continueDestSegments) {
|
|
makeLooped(this, forkContext.head, context.continueDestSegments);
|
|
|
|
// If the context is a for-in/of loop, this effects a break also.
|
|
if (context.type === 'ForInStatement' || context.type === 'ForOfStatement') {
|
|
context.brokenForkContext.add(forkContext.head);
|
|
}
|
|
} else {
|
|
context.continueForkContext.add(forkContext.head);
|
|
}
|
|
}
|
|
forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
|
|
}
|
|
|
|
/**
|
|
* Makes a path for a `return` statement.
|
|
*
|
|
* It registers the head segment to a context of `return`.
|
|
* It makes new unreachable segment, then it set the head with the segment.
|
|
* @returns {void}
|
|
*/
|
|
makeReturn() {
|
|
var forkContext = this.forkContext;
|
|
if (forkContext.reachable) {
|
|
getReturnContext(this).returnedForkContext.add(forkContext.head);
|
|
forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes a path for a `throw` statement.
|
|
*
|
|
* It registers the head segment to a context of `throw`.
|
|
* It makes new unreachable segment, then it set the head with the segment.
|
|
* @returns {void}
|
|
*/
|
|
makeThrow() {
|
|
var forkContext = this.forkContext;
|
|
if (forkContext.reachable) {
|
|
getThrowContext(this).thrownForkContext.add(forkContext.head);
|
|
forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes the final path.
|
|
* @returns {void}
|
|
*/
|
|
makeFinal() {
|
|
var segments = this.currentSegments;
|
|
if (segments.length > 0 && segments[0].reachable) {
|
|
this.returnedForkContext.add(segments);
|
|
}
|
|
}
|
|
}
|
|
codePathState = CodePathState;
|
|
return codePathState;
|
|
}
|
|
|
|
var idGenerator;
|
|
var hasRequiredIdGenerator;
|
|
function requireIdGenerator() {
|
|
if (hasRequiredIdGenerator) return idGenerator;
|
|
hasRequiredIdGenerator = 1;
|
|
|
|
/* eslint-disable react-internal/safe-string-coercion */
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Interface
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* A generator for unique ids.
|
|
*/
|
|
class IdGenerator {
|
|
/**
|
|
* @param {string} prefix Optional. A prefix of generated ids.
|
|
*/
|
|
constructor(prefix) {
|
|
this.prefix = String(prefix);
|
|
this.n = 0;
|
|
}
|
|
|
|
/**
|
|
* Generates id.
|
|
* @returns {string} A generated id.
|
|
*/
|
|
next() {
|
|
this.n = 1 + this.n | 0;
|
|
|
|
/* c8 ignore start */
|
|
if (this.n < 0) {
|
|
this.n = 1;
|
|
} /* c8 ignore stop */
|
|
|
|
return this.prefix + this.n;
|
|
}
|
|
}
|
|
idGenerator = IdGenerator;
|
|
return idGenerator;
|
|
}
|
|
|
|
var codePath;
|
|
var hasRequiredCodePath;
|
|
function requireCodePath() {
|
|
if (hasRequiredCodePath) return codePath;
|
|
hasRequiredCodePath = 1;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Requirements
|
|
//------------------------------------------------------------------------------
|
|
|
|
// eslint-disable-next-line
|
|
var CodePathState = requireCodePathState();
|
|
// eslint-disable-next-line
|
|
var IdGenerator = requireIdGenerator();
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Interface
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* A code path.
|
|
*/
|
|
class CodePath {
|
|
/**
|
|
* Creates a new instance.
|
|
* @param {Object} options Options for the function (see below).
|
|
* @param {string} options.id An identifier.
|
|
* @param {string} options.origin The type of code path origin.
|
|
* @param {CodePath|null} options.upper The code path of the upper function scope.
|
|
* @param {Function} options.onLooped A callback function to notify looping.
|
|
*/
|
|
constructor(_ref) {
|
|
var id = _ref.id,
|
|
origin = _ref.origin,
|
|
upper = _ref.upper,
|
|
onLooped = _ref.onLooped;
|
|
/**
|
|
* The identifier of this code path.
|
|
* Rules use it to store additional information of each rule.
|
|
* @type {string}
|
|
*/
|
|
this.id = id;
|
|
|
|
/**
|
|
* The reason that this code path was started. May be "program",
|
|
* "function", "class-field-initializer", or "class-static-block".
|
|
* @type {string}
|
|
*/
|
|
this.origin = origin;
|
|
|
|
/**
|
|
* The code path of the upper function scope.
|
|
* @type {CodePath|null}
|
|
*/
|
|
this.upper = upper;
|
|
|
|
/**
|
|
* The code paths of nested function scopes.
|
|
* @type {CodePath[]}
|
|
*/
|
|
this.childCodePaths = [];
|
|
|
|
// Initializes internal state.
|
|
Object.defineProperty(this, 'internal', {
|
|
value: new CodePathState(new IdGenerator(id + "_"), onLooped)
|
|
});
|
|
|
|
// Adds this into `childCodePaths` of `upper`.
|
|
if (upper) {
|
|
upper.childCodePaths.push(this);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the state of a given code path.
|
|
* @param {CodePath} codePath A code path to get.
|
|
* @returns {CodePathState} The state of the code path.
|
|
*/
|
|
static getState(codePath) {
|
|
return codePath.internal;
|
|
}
|
|
|
|
/**
|
|
* The initial code path segment.
|
|
* @type {CodePathSegment}
|
|
*/
|
|
get initialSegment() {
|
|
return this.internal.initialSegment;
|
|
}
|
|
|
|
/**
|
|
* Final code path segments.
|
|
* This array is a mix of `returnedSegments` and `thrownSegments`.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
get finalSegments() {
|
|
return this.internal.finalSegments;
|
|
}
|
|
|
|
/**
|
|
* Final code path segments which is with `return` statements.
|
|
* This array contains the last path segment if it's reachable.
|
|
* Since the reachable last path returns `undefined`.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
get returnedSegments() {
|
|
return this.internal.returnedForkContext;
|
|
}
|
|
|
|
/**
|
|
* Final code path segments which is with `throw` statements.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
get thrownSegments() {
|
|
return this.internal.thrownForkContext;
|
|
}
|
|
|
|
/**
|
|
* Current code path segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
get currentSegments() {
|
|
return this.internal.currentSegments;
|
|
}
|
|
|
|
/**
|
|
* Traverses all segments in this code path.
|
|
*
|
|
* codePath.traverseSegments(function(segment, controller) {
|
|
* // do something.
|
|
* });
|
|
*
|
|
* This method enumerates segments in order from the head.
|
|
*
|
|
* The `controller` object has two methods.
|
|
*
|
|
* - `controller.skip()` - Skip the following segments in this branch.
|
|
* - `controller.break()` - Skip all following segments.
|
|
* @param {Object} [options] Omittable.
|
|
* @param {CodePathSegment} [options.first] The first segment to traverse.
|
|
* @param {CodePathSegment} [options.last] The last segment to traverse.
|
|
* @param {Function} callback A callback function.
|
|
* @returns {void}
|
|
*/
|
|
traverseSegments(options, callback) {
|
|
var resolvedOptions;
|
|
var resolvedCallback;
|
|
if (typeof options === 'function') {
|
|
resolvedCallback = options;
|
|
resolvedOptions = {};
|
|
} else {
|
|
resolvedOptions = options || {};
|
|
resolvedCallback = callback;
|
|
}
|
|
var startSegment = resolvedOptions.first || this.internal.initialSegment;
|
|
var lastSegment = resolvedOptions.last;
|
|
var item = null;
|
|
var index = 0;
|
|
var end = 0;
|
|
var segment = null;
|
|
var visited = Object.create(null);
|
|
var stack = [[startSegment, 0]];
|
|
var skippedSegment = null;
|
|
var broken = false;
|
|
var controller = {
|
|
skip: function () {
|
|
if (stack.length <= 1) {
|
|
broken = true;
|
|
} else {
|
|
skippedSegment = stack[stack.length - 2][0];
|
|
}
|
|
},
|
|
break: function () {
|
|
broken = true;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Checks a given previous segment has been visited.
|
|
* @param {CodePathSegment} prevSegment A previous segment to check.
|
|
* @returns {boolean} `true` if the segment has been visited.
|
|
*/
|
|
function isVisited(prevSegment) {
|
|
return visited[prevSegment.id] || segment.isLoopedPrevSegment(prevSegment);
|
|
}
|
|
while (stack.length > 0) {
|
|
item = stack[stack.length - 1];
|
|
segment = item[0];
|
|
index = item[1];
|
|
if (index === 0) {
|
|
// Skip if this segment has been visited already.
|
|
if (visited[segment.id]) {
|
|
stack.pop();
|
|
continue;
|
|
}
|
|
|
|
// Skip if all previous segments have not been visited.
|
|
if (segment !== startSegment && segment.prevSegments.length > 0 && !segment.prevSegments.every(isVisited)) {
|
|
stack.pop();
|
|
continue;
|
|
}
|
|
|
|
// Reset the flag of skipping if all branches have been skipped.
|
|
if (skippedSegment && segment.prevSegments.includes(skippedSegment)) {
|
|
skippedSegment = null;
|
|
}
|
|
visited[segment.id] = true;
|
|
|
|
// Call the callback when the first time.
|
|
if (!skippedSegment) {
|
|
resolvedCallback.call(this, segment, controller);
|
|
if (segment === lastSegment) {
|
|
controller.skip();
|
|
}
|
|
if (broken) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the stack.
|
|
end = segment.nextSegments.length - 1;
|
|
if (index < end) {
|
|
item[1] += 1;
|
|
stack.push([segment.nextSegments[index], 0]);
|
|
} else if (index === end) {
|
|
item[0] = segment.nextSegments[index];
|
|
item[1] = 0;
|
|
} else {
|
|
stack.pop();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
codePath = CodePath;
|
|
return codePath;
|
|
}
|
|
|
|
var codePathAnalyzer;
|
|
var hasRequiredCodePathAnalyzer;
|
|
function requireCodePathAnalyzer() {
|
|
if (hasRequiredCodePathAnalyzer) return codePathAnalyzer;
|
|
hasRequiredCodePathAnalyzer = 1;
|
|
|
|
/* eslint-disable react-internal/no-primitive-constructors */
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Requirements
|
|
//------------------------------------------------------------------------------
|
|
|
|
// eslint-disable-next-line
|
|
var assert = requireAssert();
|
|
// eslint-disable-next-line
|
|
var CodePath = requireCodePath();
|
|
// eslint-disable-next-line
|
|
var CodePathSegment = requireCodePathSegment();
|
|
// eslint-disable-next-line
|
|
var IdGenerator = requireIdGenerator();
|
|
var breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/u;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Checks whether or not a given node is a `case` node (not `default` node).
|
|
* @param {ASTNode} node A `SwitchCase` node to check.
|
|
* @returns {boolean} `true` if the node is a `case` node (not `default` node).
|
|
*/
|
|
function isCaseNode(node) {
|
|
return Boolean(node.test);
|
|
}
|
|
|
|
/**
|
|
* Checks if a given node appears as the value of a PropertyDefinition node.
|
|
* @param {ASTNode} node THe node to check.
|
|
* @returns {boolean} `true` if the node is a PropertyDefinition value,
|
|
* false if not.
|
|
*/
|
|
function isPropertyDefinitionValue(node) {
|
|
var parent = node.parent;
|
|
return parent && parent.type === 'PropertyDefinition' && parent.value === node;
|
|
}
|
|
|
|
/**
|
|
* Checks whether the given logical operator is taken into account for the code
|
|
* path analysis.
|
|
* @param {string} operator The operator found in the LogicalExpression node
|
|
* @returns {boolean} `true` if the operator is "&&" or "||" or "??"
|
|
*/
|
|
function isHandledLogicalOperator(operator) {
|
|
return operator === '&&' || operator === '||' || operator === '??';
|
|
}
|
|
|
|
/**
|
|
* Checks whether the given assignment operator is a logical assignment operator.
|
|
* Logical assignments are taken into account for the code path analysis
|
|
* because of their short-circuiting semantics.
|
|
* @param {string} operator The operator found in the AssignmentExpression node
|
|
* @returns {boolean} `true` if the operator is "&&=" or "||=" or "??="
|
|
*/
|
|
function isLogicalAssignmentOperator(operator) {
|
|
return operator === '&&=' || operator === '||=' || operator === '??=';
|
|
}
|
|
|
|
/**
|
|
* Gets the label if the parent node of a given node is a LabeledStatement.
|
|
* @param {ASTNode} node A node to get.
|
|
* @returns {string|null} The label or `null`.
|
|
*/
|
|
function getLabel(node) {
|
|
if (node.parent.type === 'LabeledStatement') {
|
|
return node.parent.label.name;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not a given logical expression node goes different path
|
|
* between the `true` case and the `false` case.
|
|
* @param {ASTNode} node A node to check.
|
|
* @returns {boolean} `true` if the node is a test of a choice statement.
|
|
*/
|
|
function isForkingByTrueOrFalse(node) {
|
|
var parent = node.parent;
|
|
switch (parent.type) {
|
|
case 'ConditionalExpression':
|
|
case 'IfStatement':
|
|
case 'WhileStatement':
|
|
case 'DoWhileStatement':
|
|
case 'ForStatement':
|
|
return parent.test === node;
|
|
case 'LogicalExpression':
|
|
return isHandledLogicalOperator(parent.operator);
|
|
case 'AssignmentExpression':
|
|
return isLogicalAssignmentOperator(parent.operator);
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the boolean value of a given literal node.
|
|
*
|
|
* This is used to detect infinity loops (e.g. `while (true) {}`).
|
|
* Statements preceded by an infinity loop are unreachable if the loop didn't
|
|
* have any `break` statement.
|
|
* @param {ASTNode} node A node to get.
|
|
* @returns {boolean|undefined} a boolean value if the node is a Literal node,
|
|
* otherwise `undefined`.
|
|
*/
|
|
function getBooleanValueIfSimpleConstant(node) {
|
|
if (node.type === 'Literal') {
|
|
return Boolean(node.value);
|
|
}
|
|
return void 0;
|
|
}
|
|
|
|
/**
|
|
* Checks that a given identifier node is a reference or not.
|
|
*
|
|
* This is used to detect the first throwable node in a `try` block.
|
|
* @param {ASTNode} node An Identifier node to check.
|
|
* @returns {boolean} `true` if the node is a reference.
|
|
*/
|
|
function isIdentifierReference(node) {
|
|
var parent = node.parent;
|
|
switch (parent.type) {
|
|
case 'LabeledStatement':
|
|
case 'BreakStatement':
|
|
case 'ContinueStatement':
|
|
case 'ArrayPattern':
|
|
case 'RestElement':
|
|
case 'ImportSpecifier':
|
|
case 'ImportDefaultSpecifier':
|
|
case 'ImportNamespaceSpecifier':
|
|
case 'CatchClause':
|
|
return false;
|
|
case 'FunctionDeclaration':
|
|
case 'ComponentDeclaration':
|
|
case 'HookDeclaration':
|
|
case 'FunctionExpression':
|
|
case 'ArrowFunctionExpression':
|
|
case 'ClassDeclaration':
|
|
case 'ClassExpression':
|
|
case 'VariableDeclarator':
|
|
return parent.id !== node;
|
|
case 'Property':
|
|
case 'PropertyDefinition':
|
|
case 'MethodDefinition':
|
|
return parent.key !== node || parent.computed || parent.shorthand;
|
|
case 'AssignmentPattern':
|
|
return parent.key !== node;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the current segment with the head segment.
|
|
* This is similar to local branches and tracking branches of git.
|
|
*
|
|
* To separate the current and the head is in order to not make useless segments.
|
|
*
|
|
* In this process, both "onCodePathSegmentStart" and "onCodePathSegmentEnd"
|
|
* events are fired.
|
|
* @param {CodePathAnalyzer} analyzer The instance.
|
|
* @param {ASTNode} node The current AST node.
|
|
* @returns {void}
|
|
*/
|
|
function forwardCurrentToHead(analyzer, node) {
|
|
var codePath = analyzer.codePath;
|
|
var state = CodePath.getState(codePath);
|
|
var currentSegments = state.currentSegments;
|
|
var headSegments = state.headSegments;
|
|
var end = Math.max(currentSegments.length, headSegments.length);
|
|
var i, currentSegment, headSegment;
|
|
|
|
// Fires leaving events.
|
|
for (i = 0; i < end; ++i) {
|
|
currentSegment = currentSegments[i];
|
|
headSegment = headSegments[i];
|
|
if (currentSegment !== headSegment && currentSegment) {
|
|
if (currentSegment.reachable) {
|
|
analyzer.emitter.emit('onCodePathSegmentEnd', currentSegment, node);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update state.
|
|
state.currentSegments = headSegments;
|
|
|
|
// Fires entering events.
|
|
for (i = 0; i < end; ++i) {
|
|
currentSegment = currentSegments[i];
|
|
headSegment = headSegments[i];
|
|
if (currentSegment !== headSegment && headSegment) {
|
|
CodePathSegment.markUsed(headSegment);
|
|
if (headSegment.reachable) {
|
|
analyzer.emitter.emit('onCodePathSegmentStart', headSegment, node);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the current segment with empty.
|
|
* This is called at the last of functions or the program.
|
|
* @param {CodePathAnalyzer} analyzer The instance.
|
|
* @param {ASTNode} node The current AST node.
|
|
* @returns {void}
|
|
*/
|
|
function leaveFromCurrentSegment(analyzer, node) {
|
|
var state = CodePath.getState(analyzer.codePath);
|
|
var currentSegments = state.currentSegments;
|
|
for (var i = 0; i < currentSegments.length; ++i) {
|
|
var currentSegment = currentSegments[i];
|
|
if (currentSegment.reachable) {
|
|
analyzer.emitter.emit('onCodePathSegmentEnd', currentSegment, node);
|
|
}
|
|
}
|
|
state.currentSegments = [];
|
|
}
|
|
|
|
/**
|
|
* Updates the code path due to the position of a given node in the parent node
|
|
* thereof.
|
|
*
|
|
* For example, if the node is `parent.consequent`, this creates a fork from the
|
|
* current path.
|
|
* @param {CodePathAnalyzer} analyzer The instance.
|
|
* @param {ASTNode} node The current AST node.
|
|
* @returns {void}
|
|
*/
|
|
function preprocess(analyzer, node) {
|
|
var codePath = analyzer.codePath;
|
|
var state = CodePath.getState(codePath);
|
|
var parent = node.parent;
|
|
switch (parent.type) {
|
|
// The `arguments.length == 0` case is in `postprocess` function.
|
|
case 'CallExpression':
|
|
if (parent.optional === true && parent.arguments.length >= 1 && parent.arguments[0] === node) {
|
|
state.makeOptionalRight();
|
|
}
|
|
break;
|
|
case 'MemberExpression':
|
|
if (parent.optional === true && parent.property === node) {
|
|
state.makeOptionalRight();
|
|
}
|
|
break;
|
|
case 'LogicalExpression':
|
|
if (parent.right === node && isHandledLogicalOperator(parent.operator)) {
|
|
state.makeLogicalRight();
|
|
}
|
|
break;
|
|
case 'AssignmentExpression':
|
|
if (parent.right === node && isLogicalAssignmentOperator(parent.operator)) {
|
|
state.makeLogicalRight();
|
|
}
|
|
break;
|
|
case 'ConditionalExpression':
|
|
case 'IfStatement':
|
|
/*
|
|
* Fork if this node is at `consequent`/`alternate`.
|
|
* `popForkContext()` exists at `IfStatement:exit` and
|
|
* `ConditionalExpression:exit`.
|
|
*/
|
|
if (parent.consequent === node) {
|
|
state.makeIfConsequent();
|
|
} else if (parent.alternate === node) {
|
|
state.makeIfAlternate();
|
|
}
|
|
break;
|
|
case 'SwitchCase':
|
|
if (parent.consequent[0] === node) {
|
|
state.makeSwitchCaseBody(false, !parent.test);
|
|
}
|
|
break;
|
|
case 'TryStatement':
|
|
if (parent.handler === node) {
|
|
state.makeCatchBlock();
|
|
} else if (parent.finalizer === node) {
|
|
state.makeFinallyBlock();
|
|
}
|
|
break;
|
|
case 'WhileStatement':
|
|
if (parent.test === node) {
|
|
state.makeWhileTest(getBooleanValueIfSimpleConstant(node));
|
|
} else {
|
|
assert(parent.body === node);
|
|
state.makeWhileBody();
|
|
}
|
|
break;
|
|
case 'DoWhileStatement':
|
|
if (parent.body === node) {
|
|
state.makeDoWhileBody();
|
|
} else {
|
|
assert(parent.test === node);
|
|
state.makeDoWhileTest(getBooleanValueIfSimpleConstant(node));
|
|
}
|
|
break;
|
|
case 'ForStatement':
|
|
if (parent.test === node) {
|
|
state.makeForTest(getBooleanValueIfSimpleConstant(node));
|
|
} else if (parent.update === node) {
|
|
state.makeForUpdate();
|
|
} else if (parent.body === node) {
|
|
state.makeForBody();
|
|
}
|
|
break;
|
|
case 'ForInStatement':
|
|
case 'ForOfStatement':
|
|
if (parent.left === node) {
|
|
state.makeForInOfLeft();
|
|
} else if (parent.right === node) {
|
|
state.makeForInOfRight();
|
|
} else {
|
|
assert(parent.body === node);
|
|
state.makeForInOfBody();
|
|
}
|
|
break;
|
|
case 'AssignmentPattern':
|
|
/*
|
|
* Fork if this node is at `right`.
|
|
* `left` is executed always, so it uses the current path.
|
|
* `popForkContext()` exists at `AssignmentPattern:exit`.
|
|
*/
|
|
if (parent.right === node) {
|
|
state.pushForkContext();
|
|
state.forkBypassPath();
|
|
state.forkPath();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the code path due to the type of a given node in entering.
|
|
* @param {CodePathAnalyzer} analyzer The instance.
|
|
* @param {ASTNode} node The current AST node.
|
|
* @returns {void}
|
|
*/
|
|
function processCodePathToEnter(analyzer, node) {
|
|
var codePath = analyzer.codePath;
|
|
var state = codePath && CodePath.getState(codePath);
|
|
var parent = node.parent;
|
|
|
|
/**
|
|
* Creates a new code path and trigger the onCodePathStart event
|
|
* based on the currently selected node.
|
|
* @param {string} origin The reason the code path was started.
|
|
* @returns {void}
|
|
*/
|
|
function startCodePath(origin) {
|
|
if (codePath) {
|
|
// Emits onCodePathSegmentStart events if updated.
|
|
forwardCurrentToHead(analyzer, node);
|
|
}
|
|
|
|
// Create the code path of this scope.
|
|
codePath = analyzer.codePath = new CodePath({
|
|
id: analyzer.idGenerator.next(),
|
|
origin: origin,
|
|
upper: codePath,
|
|
onLooped: analyzer.onLooped
|
|
});
|
|
state = CodePath.getState(codePath);
|
|
|
|
// Emits onCodePathStart events.
|
|
analyzer.emitter.emit('onCodePathStart', codePath, node);
|
|
}
|
|
|
|
/*
|
|
* Special case: The right side of class field initializer is considered
|
|
* to be its own function, so we need to start a new code path in this
|
|
* case.
|
|
*/
|
|
if (isPropertyDefinitionValue(node)) {
|
|
startCodePath('class-field-initializer');
|
|
|
|
/*
|
|
* Intentional fall through because `node` needs to also be
|
|
* processed by the code below. For example, if we have:
|
|
*
|
|
* class Foo {
|
|
* a = () => {}
|
|
* }
|
|
*
|
|
* In this case, we also need start a second code path.
|
|
*/
|
|
}
|
|
switch (node.type) {
|
|
case 'Program':
|
|
startCodePath('program');
|
|
break;
|
|
case 'FunctionDeclaration':
|
|
case 'ComponentDeclaration':
|
|
case 'HookDeclaration':
|
|
case 'FunctionExpression':
|
|
case 'ArrowFunctionExpression':
|
|
startCodePath('function');
|
|
break;
|
|
case 'StaticBlock':
|
|
startCodePath('class-static-block');
|
|
break;
|
|
case 'ChainExpression':
|
|
state.pushChainContext();
|
|
break;
|
|
case 'CallExpression':
|
|
if (node.optional === true) {
|
|
state.makeOptionalNode();
|
|
}
|
|
break;
|
|
case 'MemberExpression':
|
|
if (node.optional === true) {
|
|
state.makeOptionalNode();
|
|
}
|
|
break;
|
|
case 'LogicalExpression':
|
|
if (isHandledLogicalOperator(node.operator)) {
|
|
state.pushChoiceContext(node.operator, isForkingByTrueOrFalse(node));
|
|
}
|
|
break;
|
|
case 'AssignmentExpression':
|
|
if (isLogicalAssignmentOperator(node.operator)) {
|
|
state.pushChoiceContext(node.operator.slice(0, -1),
|
|
// removes `=` from the end
|
|
isForkingByTrueOrFalse(node));
|
|
}
|
|
break;
|
|
case 'ConditionalExpression':
|
|
case 'IfStatement':
|
|
state.pushChoiceContext('test', false);
|
|
break;
|
|
case 'SwitchStatement':
|
|
state.pushSwitchContext(node.cases.some(isCaseNode), getLabel(node));
|
|
break;
|
|
case 'TryStatement':
|
|
state.pushTryContext(Boolean(node.finalizer));
|
|
break;
|
|
case 'SwitchCase':
|
|
/*
|
|
* Fork if this node is after the 2st node in `cases`.
|
|
* It's similar to `else` blocks.
|
|
* The next `test` node is processed in this path.
|
|
*/
|
|
if (parent.discriminant !== node && parent.cases[0] !== node) {
|
|
state.forkPath();
|
|
}
|
|
break;
|
|
case 'WhileStatement':
|
|
case 'DoWhileStatement':
|
|
case 'ForStatement':
|
|
case 'ForInStatement':
|
|
case 'ForOfStatement':
|
|
state.pushLoopContext(node.type, getLabel(node));
|
|
break;
|
|
case 'LabeledStatement':
|
|
if (!breakableTypePattern.test(node.body.type)) {
|
|
state.pushBreakContext(false, node.label.name);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Emits onCodePathSegmentStart events if updated.
|
|
forwardCurrentToHead(analyzer, node);
|
|
}
|
|
|
|
/**
|
|
* Updates the code path due to the type of a given node in leaving.
|
|
* @param {CodePathAnalyzer} analyzer The instance.
|
|
* @param {ASTNode} node The current AST node.
|
|
* @returns {void}
|
|
*/
|
|
function processCodePathToExit(analyzer, node) {
|
|
var codePath = analyzer.codePath;
|
|
var state = CodePath.getState(codePath);
|
|
var dontForward = false;
|
|
switch (node.type) {
|
|
case 'ChainExpression':
|
|
state.popChainContext();
|
|
break;
|
|
case 'IfStatement':
|
|
case 'ConditionalExpression':
|
|
state.popChoiceContext();
|
|
break;
|
|
case 'LogicalExpression':
|
|
if (isHandledLogicalOperator(node.operator)) {
|
|
state.popChoiceContext();
|
|
}
|
|
break;
|
|
case 'AssignmentExpression':
|
|
if (isLogicalAssignmentOperator(node.operator)) {
|
|
state.popChoiceContext();
|
|
}
|
|
break;
|
|
case 'SwitchStatement':
|
|
state.popSwitchContext();
|
|
break;
|
|
case 'SwitchCase':
|
|
/*
|
|
* This is the same as the process at the 1st `consequent` node in
|
|
* `preprocess` function.
|
|
* Must do if this `consequent` is empty.
|
|
*/
|
|
if (node.consequent.length === 0) {
|
|
state.makeSwitchCaseBody(true, !node.test);
|
|
}
|
|
if (state.forkContext.reachable) {
|
|
dontForward = true;
|
|
}
|
|
break;
|
|
case 'TryStatement':
|
|
state.popTryContext();
|
|
break;
|
|
case 'BreakStatement':
|
|
forwardCurrentToHead(analyzer, node);
|
|
state.makeBreak(node.label && node.label.name);
|
|
dontForward = true;
|
|
break;
|
|
case 'ContinueStatement':
|
|
forwardCurrentToHead(analyzer, node);
|
|
state.makeContinue(node.label && node.label.name);
|
|
dontForward = true;
|
|
break;
|
|
case 'ReturnStatement':
|
|
forwardCurrentToHead(analyzer, node);
|
|
state.makeReturn();
|
|
dontForward = true;
|
|
break;
|
|
case 'ThrowStatement':
|
|
forwardCurrentToHead(analyzer, node);
|
|
state.makeThrow();
|
|
dontForward = true;
|
|
break;
|
|
case 'Identifier':
|
|
if (isIdentifierReference(node)) {
|
|
state.makeFirstThrowablePathInTryBlock();
|
|
dontForward = true;
|
|
}
|
|
break;
|
|
case 'CallExpression':
|
|
case 'ImportExpression':
|
|
case 'MemberExpression':
|
|
case 'NewExpression':
|
|
case 'YieldExpression':
|
|
state.makeFirstThrowablePathInTryBlock();
|
|
break;
|
|
case 'WhileStatement':
|
|
case 'DoWhileStatement':
|
|
case 'ForStatement':
|
|
case 'ForInStatement':
|
|
case 'ForOfStatement':
|
|
state.popLoopContext();
|
|
break;
|
|
case 'AssignmentPattern':
|
|
state.popForkContext();
|
|
break;
|
|
case 'LabeledStatement':
|
|
if (!breakableTypePattern.test(node.body.type)) {
|
|
state.popBreakContext();
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Emits onCodePathSegmentStart events if updated.
|
|
if (!dontForward) {
|
|
forwardCurrentToHead(analyzer, node);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the code path to finalize the current code path.
|
|
* @param {CodePathAnalyzer} analyzer The instance.
|
|
* @param {ASTNode} node The current AST node.
|
|
* @returns {void}
|
|
*/
|
|
function postprocess(analyzer, node) {
|
|
/**
|
|
* Ends the code path for the current node.
|
|
* @returns {void}
|
|
*/
|
|
function endCodePath() {
|
|
var codePath = analyzer.codePath;
|
|
|
|
// Mark the current path as the final node.
|
|
CodePath.getState(codePath).makeFinal();
|
|
|
|
// Emits onCodePathSegmentEnd event of the current segments.
|
|
leaveFromCurrentSegment(analyzer, node);
|
|
|
|
// Emits onCodePathEnd event of this code path.
|
|
analyzer.emitter.emit('onCodePathEnd', codePath, node);
|
|
codePath = analyzer.codePath = analyzer.codePath.upper;
|
|
}
|
|
switch (node.type) {
|
|
case 'Program':
|
|
case 'FunctionDeclaration':
|
|
case 'ComponentDeclaration':
|
|
case 'HookDeclaration':
|
|
case 'FunctionExpression':
|
|
case 'ArrowFunctionExpression':
|
|
case 'StaticBlock':
|
|
{
|
|
endCodePath();
|
|
break;
|
|
}
|
|
|
|
// The `arguments.length >= 1` case is in `preprocess` function.
|
|
case 'CallExpression':
|
|
if (node.optional === true && node.arguments.length === 0) {
|
|
CodePath.getState(analyzer.codePath).makeOptionalRight();
|
|
}
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Special case: The right side of class field initializer is considered
|
|
* to be its own function, so we need to end a code path in this
|
|
* case.
|
|
*
|
|
* We need to check after the other checks in order to close the
|
|
* code paths in the correct order for code like this:
|
|
*
|
|
*
|
|
* class Foo {
|
|
* a = () => {}
|
|
* }
|
|
*
|
|
* In this case, The ArrowFunctionExpression code path is closed first
|
|
* and then we need to close the code path for the PropertyDefinition
|
|
* value.
|
|
*/
|
|
if (isPropertyDefinitionValue(node)) {
|
|
endCodePath();
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Interface
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* The class to analyze code paths.
|
|
* This class implements the EventGenerator interface.
|
|
*/
|
|
class CodePathAnalyzer {
|
|
/**
|
|
* @param {EventGenerator} eventGenerator An event generator to wrap.
|
|
*/
|
|
constructor(emitters) {
|
|
this.emitter = {
|
|
emit: function (event) {
|
|
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
args[_key - 1] = arguments[_key];
|
|
}
|
|
emitters[event]?.(...args);
|
|
}
|
|
};
|
|
this.codePath = null;
|
|
this.idGenerator = new IdGenerator('s');
|
|
this.currentNode = null;
|
|
this.onLooped = this.onLooped.bind(this);
|
|
}
|
|
|
|
/**
|
|
* Does the process to enter a given AST node.
|
|
* This updates state of analysis and calls `enterNode` of the wrapped.
|
|
* @param {ASTNode} node A node which is entering.
|
|
* @returns {void}
|
|
*/
|
|
enterNode(node) {
|
|
this.currentNode = node;
|
|
|
|
// Updates the code path due to node's position in its parent node.
|
|
if (node.parent) {
|
|
preprocess(this, node);
|
|
}
|
|
|
|
/*
|
|
* Updates the code path.
|
|
* And emits onCodePathStart/onCodePathSegmentStart events.
|
|
*/
|
|
processCodePathToEnter(this, node);
|
|
this.currentNode = null;
|
|
}
|
|
|
|
/**
|
|
* Does the process to leave a given AST node.
|
|
* This updates state of analysis and calls `leaveNode` of the wrapped.
|
|
* @param {ASTNode} node A node which is leaving.
|
|
* @returns {void}
|
|
*/
|
|
leaveNode(node) {
|
|
this.currentNode = node;
|
|
|
|
/*
|
|
* Updates the code path.
|
|
* And emits onCodePathStart/onCodePathSegmentStart events.
|
|
*/
|
|
processCodePathToExit(this, node);
|
|
|
|
// Emits the last onCodePathStart/onCodePathSegmentStart events.
|
|
postprocess(this, node);
|
|
this.currentNode = null;
|
|
}
|
|
|
|
/**
|
|
* This is called on a code path looped.
|
|
* Then this raises a looped event.
|
|
* @param {CodePathSegment} fromSegment A segment of prev.
|
|
* @param {CodePathSegment} toSegment A segment of next.
|
|
* @returns {void}
|
|
*/
|
|
onLooped(fromSegment, toSegment) {
|
|
if (fromSegment.reachable && toSegment.reachable) {
|
|
this.emitter.emit('onCodePathSegmentLoop', fromSegment, toSegment, this.currentNode);
|
|
}
|
|
}
|
|
}
|
|
codePathAnalyzer = CodePathAnalyzer;
|
|
return codePathAnalyzer;
|
|
}
|
|
|
|
var codePathAnalyzerExports = requireCodePathAnalyzer();
|
|
var CodePathAnalyzer = /*@__PURE__*/getDefaultExportFromCjs(codePathAnalyzerExports);
|
|
|
|
function isHookName(s) {
|
|
return s === 'use' || /^use[A-Z0-9]/.test(s);
|
|
}
|
|
function isHook(node) {
|
|
if (node.type === 'Identifier') {
|
|
return isHookName(node.name);
|
|
}
|
|
else if (node.type === 'MemberExpression' &&
|
|
!node.computed &&
|
|
isHook(node.property)) {
|
|
const obj = node.object;
|
|
const isPascalCaseNameSpace = /^[A-Z].*/;
|
|
return obj.type === 'Identifier' && isPascalCaseNameSpace.test(obj.name);
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
function isComponentName(node) {
|
|
return node.type === 'Identifier' && /^[A-Z]/.test(node.name);
|
|
}
|
|
function isReactFunction(node, functionName) {
|
|
return (('name' in node && node.name === functionName) ||
|
|
(node.type === 'MemberExpression' &&
|
|
'name' in node.object &&
|
|
node.object.name === 'React' &&
|
|
'name' in node.property &&
|
|
node.property.name === functionName));
|
|
}
|
|
function isForwardRefCallback(node) {
|
|
return !!(node.parent &&
|
|
'callee' in node.parent &&
|
|
node.parent.callee &&
|
|
isReactFunction(node.parent.callee, 'forwardRef'));
|
|
}
|
|
function isMemoCallback(node) {
|
|
return !!(node.parent &&
|
|
'callee' in node.parent &&
|
|
node.parent.callee &&
|
|
isReactFunction(node.parent.callee, 'memo'));
|
|
}
|
|
function isInsideComponentOrHook(node) {
|
|
while (node) {
|
|
const functionName = getFunctionName(node);
|
|
if (functionName) {
|
|
if (isComponentName(functionName) || isHook(functionName)) {
|
|
return true;
|
|
}
|
|
}
|
|
if (isForwardRefCallback(node) || isMemoCallback(node)) {
|
|
return true;
|
|
}
|
|
node = node.parent;
|
|
}
|
|
return false;
|
|
}
|
|
function isInsideDoWhileLoop(node) {
|
|
while (node) {
|
|
if (node.type === 'DoWhileStatement') {
|
|
return true;
|
|
}
|
|
node = node.parent;
|
|
}
|
|
return false;
|
|
}
|
|
function isInsideTryCatch(node) {
|
|
while (node) {
|
|
if (node.type === 'TryStatement' || node.type === 'CatchClause') {
|
|
return true;
|
|
}
|
|
node = node.parent;
|
|
}
|
|
return false;
|
|
}
|
|
function getNodeWithoutReactNamespace(node) {
|
|
if (node.type === 'MemberExpression' &&
|
|
node.object.type === 'Identifier' &&
|
|
node.object.name === 'React' &&
|
|
node.property.type === 'Identifier' &&
|
|
!node.computed) {
|
|
return node.property;
|
|
}
|
|
return node;
|
|
}
|
|
function isEffectIdentifier(node, additionalHooks) {
|
|
const isBuiltInEffect = node.type === 'Identifier' &&
|
|
(node.name === 'useEffect' ||
|
|
node.name === 'useLayoutEffect' ||
|
|
node.name === 'useInsertionEffect');
|
|
if (isBuiltInEffect) {
|
|
return true;
|
|
}
|
|
if (additionalHooks && node.type === 'Identifier') {
|
|
return additionalHooks.test(node.name);
|
|
}
|
|
return false;
|
|
}
|
|
function isUseEffectEventIdentifier(node) {
|
|
return node.type === 'Identifier' && node.name === 'useEffectEvent';
|
|
}
|
|
function useEffectEventError(fn, called) {
|
|
if (fn === null) {
|
|
return (`React Hook "useEffectEvent" can only be called at the top level of your component.` +
|
|
` It cannot be passed down.`);
|
|
}
|
|
return (`\`${fn}\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
|
|
'Effects and Effect Events in the same component.' +
|
|
(called ? '' : ' It cannot be assigned to a variable or passed down.'));
|
|
}
|
|
function isUseIdentifier(node) {
|
|
return isReactFunction(node, 'use');
|
|
}
|
|
const rule = {
|
|
meta: {
|
|
type: 'problem',
|
|
docs: {
|
|
description: 'enforces the Rules of Hooks',
|
|
recommended: true,
|
|
url: 'https://react.dev/reference/rules/rules-of-hooks',
|
|
},
|
|
schema: [
|
|
{
|
|
type: 'object',
|
|
additionalProperties: false,
|
|
properties: {
|
|
additionalHooks: {
|
|
type: 'string',
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
create(context) {
|
|
const settings = context.settings || {};
|
|
const additionalEffectHooks = getAdditionalEffectHooksFromSettings(settings);
|
|
let lastEffect = null;
|
|
const codePathReactHooksMapStack = [];
|
|
const codePathSegmentStack = [];
|
|
const useEffectEventFunctions = new WeakSet();
|
|
function recordAllUseEffectEventFunctions(scope) {
|
|
for (const reference of scope.references) {
|
|
const parent = reference.identifier.parent;
|
|
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'VariableDeclarator' &&
|
|
parent.init &&
|
|
parent.init.type === 'CallExpression' &&
|
|
parent.init.callee &&
|
|
isUseEffectEventIdentifier(parent.init.callee)) {
|
|
if (reference.resolved === null) {
|
|
throw new Error('Unexpected null reference.resolved');
|
|
}
|
|
for (const ref of reference.resolved.references) {
|
|
if (ref !== reference) {
|
|
useEffectEventFunctions.add(ref.identifier);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const getSourceCode = typeof context.getSourceCode === 'function'
|
|
? () => {
|
|
return context.getSourceCode();
|
|
}
|
|
: () => {
|
|
return context.sourceCode;
|
|
};
|
|
const getScope = typeof context.getScope === 'function'
|
|
? () => {
|
|
return context.getScope();
|
|
}
|
|
: (node) => {
|
|
return getSourceCode().getScope(node);
|
|
};
|
|
function hasFlowSuppression(node, suppression) {
|
|
const sourceCode = getSourceCode();
|
|
const comments = sourceCode.getAllComments();
|
|
const flowSuppressionRegex = new RegExp('\\$FlowFixMe\\[' + suppression + '\\]');
|
|
return comments.some(commentNode => flowSuppressionRegex.test(commentNode.value) &&
|
|
commentNode.loc != null &&
|
|
node.loc != null &&
|
|
commentNode.loc.end.line === node.loc.start.line - 1);
|
|
}
|
|
const analyzer = new CodePathAnalyzer({
|
|
onCodePathSegmentStart: (segment) => codePathSegmentStack.push(segment),
|
|
onCodePathSegmentEnd: () => codePathSegmentStack.pop(),
|
|
onCodePathStart: () => codePathReactHooksMapStack.push(new Map()),
|
|
onCodePathEnd(codePath, codePathNode) {
|
|
const reactHooksMap = codePathReactHooksMapStack.pop();
|
|
if ((reactHooksMap === null || reactHooksMap === void 0 ? void 0 : reactHooksMap.size) === 0) {
|
|
return;
|
|
}
|
|
else if (typeof reactHooksMap === 'undefined') {
|
|
throw new Error('Unexpected undefined reactHooksMap');
|
|
}
|
|
const cyclic = new Set();
|
|
function countPathsFromStart(segment, pathHistory) {
|
|
const { cache } = countPathsFromStart;
|
|
let paths = cache.get(segment.id);
|
|
const pathList = new Set(pathHistory);
|
|
if (pathList.has(segment.id)) {
|
|
const pathArray = [...pathList];
|
|
const cyclicSegments = pathArray.slice(pathArray.indexOf(segment.id) + 1);
|
|
for (const cyclicSegment of cyclicSegments) {
|
|
cyclic.add(cyclicSegment);
|
|
}
|
|
return BigInt('0');
|
|
}
|
|
pathList.add(segment.id);
|
|
if (paths !== undefined) {
|
|
return paths;
|
|
}
|
|
if (codePath.thrownSegments.includes(segment)) {
|
|
paths = BigInt('0');
|
|
}
|
|
else if (segment.prevSegments.length === 0) {
|
|
paths = BigInt('1');
|
|
}
|
|
else {
|
|
paths = BigInt('0');
|
|
for (const prevSegment of segment.prevSegments) {
|
|
paths += countPathsFromStart(prevSegment, pathList);
|
|
}
|
|
}
|
|
if (segment.reachable && paths === BigInt('0')) {
|
|
cache.delete(segment.id);
|
|
}
|
|
else {
|
|
cache.set(segment.id, paths);
|
|
}
|
|
return paths;
|
|
}
|
|
function countPathsToEnd(segment, pathHistory) {
|
|
const { cache } = countPathsToEnd;
|
|
let paths = cache.get(segment.id);
|
|
const pathList = new Set(pathHistory);
|
|
if (pathList.has(segment.id)) {
|
|
const pathArray = Array.from(pathList);
|
|
const cyclicSegments = pathArray.slice(pathArray.indexOf(segment.id) + 1);
|
|
for (const cyclicSegment of cyclicSegments) {
|
|
cyclic.add(cyclicSegment);
|
|
}
|
|
return BigInt('0');
|
|
}
|
|
pathList.add(segment.id);
|
|
if (paths !== undefined) {
|
|
return paths;
|
|
}
|
|
if (codePath.thrownSegments.includes(segment)) {
|
|
paths = BigInt('0');
|
|
}
|
|
else if (segment.nextSegments.length === 0) {
|
|
paths = BigInt('1');
|
|
}
|
|
else {
|
|
paths = BigInt('0');
|
|
for (const nextSegment of segment.nextSegments) {
|
|
paths += countPathsToEnd(nextSegment, pathList);
|
|
}
|
|
}
|
|
cache.set(segment.id, paths);
|
|
return paths;
|
|
}
|
|
function shortestPathLengthToStart(segment) {
|
|
const { cache } = shortestPathLengthToStart;
|
|
let length = cache.get(segment.id);
|
|
if (length === null) {
|
|
return Infinity;
|
|
}
|
|
if (length !== undefined) {
|
|
return length;
|
|
}
|
|
cache.set(segment.id, null);
|
|
if (segment.prevSegments.length === 0) {
|
|
length = 1;
|
|
}
|
|
else {
|
|
length = Infinity;
|
|
for (const prevSegment of segment.prevSegments) {
|
|
const prevLength = shortestPathLengthToStart(prevSegment);
|
|
if (prevLength < length) {
|
|
length = prevLength;
|
|
}
|
|
}
|
|
length += 1;
|
|
}
|
|
cache.set(segment.id, length);
|
|
return length;
|
|
}
|
|
countPathsFromStart.cache = new Map();
|
|
countPathsToEnd.cache = new Map();
|
|
shortestPathLengthToStart.cache = new Map();
|
|
const allPathsFromStartToEnd = countPathsToEnd(codePath.initialSegment);
|
|
const codePathFunctionName = getFunctionName(codePathNode);
|
|
const isSomewhereInsideComponentOrHook = isInsideComponentOrHook(codePathNode);
|
|
const isDirectlyInsideComponentOrHook = codePathFunctionName
|
|
? isComponentName(codePathFunctionName) ||
|
|
isHook(codePathFunctionName)
|
|
: isForwardRefCallback(codePathNode) || isMemoCallback(codePathNode);
|
|
let shortestFinalPathLength = Infinity;
|
|
for (const finalSegment of codePath.finalSegments) {
|
|
if (!finalSegment.reachable) {
|
|
continue;
|
|
}
|
|
const length = shortestPathLengthToStart(finalSegment);
|
|
if (length < shortestFinalPathLength) {
|
|
shortestFinalPathLength = length;
|
|
}
|
|
}
|
|
for (const [segment, reactHooks] of reactHooksMap) {
|
|
if (!segment.reachable) {
|
|
continue;
|
|
}
|
|
const possiblyHasEarlyReturn = segment.nextSegments.length === 0
|
|
? shortestFinalPathLength <= shortestPathLengthToStart(segment)
|
|
: shortestFinalPathLength < shortestPathLengthToStart(segment);
|
|
const pathsFromStartToEnd = countPathsFromStart(segment) * countPathsToEnd(segment);
|
|
const cycled = cyclic.has(segment.id);
|
|
for (const hook of reactHooks) {
|
|
if (hasFlowSuppression(hook, 'react-rule-hook')) {
|
|
continue;
|
|
}
|
|
if (isUseIdentifier(hook) && isInsideTryCatch(hook)) {
|
|
context.report({
|
|
node: hook,
|
|
message: `React Hook "${getSourceCode().getText(hook)}" cannot be called in a try/catch block.`,
|
|
});
|
|
}
|
|
if ((cycled || isInsideDoWhileLoop(hook)) &&
|
|
!isUseIdentifier(hook)) {
|
|
context.report({
|
|
node: hook,
|
|
message: `React Hook "${getSourceCode().getText(hook)}" may be executed ` +
|
|
'more than once. Possibly because it is called in a loop. ' +
|
|
'React Hooks must be called in the exact same order in ' +
|
|
'every component render.',
|
|
});
|
|
}
|
|
if (isDirectlyInsideComponentOrHook) {
|
|
const isAsyncFunction = codePathNode.async;
|
|
if (isAsyncFunction) {
|
|
context.report({
|
|
node: hook,
|
|
message: `React Hook "${getSourceCode().getText(hook)}" cannot be ` +
|
|
'called in an async function.',
|
|
});
|
|
}
|
|
if (!cycled &&
|
|
pathsFromStartToEnd !== allPathsFromStartToEnd &&
|
|
!isUseIdentifier(hook) &&
|
|
!isInsideDoWhileLoop(hook)) {
|
|
const message = `React Hook "${getSourceCode().getText(hook)}" is called ` +
|
|
'conditionally. React Hooks must be called in the exact ' +
|
|
'same order in every component render.' +
|
|
(possiblyHasEarlyReturn
|
|
? ' Did you accidentally call a React Hook after an' +
|
|
' early return?'
|
|
: '');
|
|
context.report({ node: hook, message });
|
|
}
|
|
}
|
|
else if (codePathNode.parent != null &&
|
|
(codePathNode.parent.type === 'MethodDefinition' ||
|
|
codePathNode.parent.type === 'ClassProperty' ||
|
|
codePathNode.parent.type === 'PropertyDefinition') &&
|
|
codePathNode.parent.value === codePathNode) {
|
|
const message = `React Hook "${getSourceCode().getText(hook)}" cannot be called ` +
|
|
'in a class component. React Hooks must be called in a ' +
|
|
'React function component or a custom React Hook function.';
|
|
context.report({ node: hook, message });
|
|
}
|
|
else if (codePathFunctionName) {
|
|
const message = `React Hook "${getSourceCode().getText(hook)}" is called in ` +
|
|
`function "${getSourceCode().getText(codePathFunctionName)}" ` +
|
|
'that is neither a React function component nor a custom ' +
|
|
'React Hook function.' +
|
|
' React component names must start with an uppercase letter.' +
|
|
' React Hook names must start with the word "use".';
|
|
context.report({ node: hook, message });
|
|
}
|
|
else if (codePathNode.type === 'Program') {
|
|
const message = `React Hook "${getSourceCode().getText(hook)}" cannot be called ` +
|
|
'at the top level. React Hooks must be called in a ' +
|
|
'React function component or a custom React Hook function.';
|
|
context.report({ node: hook, message });
|
|
}
|
|
else {
|
|
if (isSomewhereInsideComponentOrHook && !isUseIdentifier(hook)) {
|
|
const message = `React Hook "${getSourceCode().getText(hook)}" cannot be called ` +
|
|
'inside a callback. React Hooks must be called in a ' +
|
|
'React function component or a custom React Hook function.';
|
|
context.report({ node: hook, message });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
});
|
|
return {
|
|
'*'(node) {
|
|
analyzer.enterNode(node);
|
|
},
|
|
'*:exit'(node) {
|
|
analyzer.leaveNode(node);
|
|
},
|
|
CallExpression(node) {
|
|
var _a, _b;
|
|
if (isHook(node.callee)) {
|
|
const reactHooksMap = last(codePathReactHooksMapStack);
|
|
const codePathSegment = last(codePathSegmentStack);
|
|
let reactHooks = reactHooksMap.get(codePathSegment);
|
|
if (!reactHooks) {
|
|
reactHooks = [];
|
|
reactHooksMap.set(codePathSegment, reactHooks);
|
|
}
|
|
reactHooks.push(node.callee);
|
|
}
|
|
const nodeWithoutNamespace = getNodeWithoutReactNamespace(node.callee);
|
|
if ((isEffectIdentifier(nodeWithoutNamespace, additionalEffectHooks) ||
|
|
isUseEffectEventIdentifier(nodeWithoutNamespace)) &&
|
|
node.arguments.length > 0) {
|
|
lastEffect = node;
|
|
}
|
|
if (isUseEffectEventIdentifier(nodeWithoutNamespace) &&
|
|
((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) !== 'VariableDeclarator' &&
|
|
((_b = node.parent) === null || _b === void 0 ? void 0 : _b.type) !== 'ExpressionStatement') {
|
|
const message = useEffectEventError(null, false);
|
|
context.report({
|
|
node,
|
|
message,
|
|
});
|
|
}
|
|
},
|
|
Identifier(node) {
|
|
if (lastEffect == null && useEffectEventFunctions.has(node)) {
|
|
const message = useEffectEventError(getSourceCode().getText(node), node.parent.type === 'CallExpression');
|
|
context.report({
|
|
node,
|
|
message,
|
|
});
|
|
}
|
|
},
|
|
'CallExpression:exit'(node) {
|
|
if (node === lastEffect) {
|
|
lastEffect = null;
|
|
}
|
|
},
|
|
FunctionDeclaration(node) {
|
|
if (isInsideComponentOrHook(node)) {
|
|
recordAllUseEffectEventFunctions(getScope(node));
|
|
}
|
|
},
|
|
ArrowFunctionExpression(node) {
|
|
if (isInsideComponentOrHook(node)) {
|
|
recordAllUseEffectEventFunctions(getScope(node));
|
|
}
|
|
},
|
|
ComponentDeclaration(node) {
|
|
recordAllUseEffectEventFunctions(getScope(node));
|
|
},
|
|
HookDeclaration(node) {
|
|
recordAllUseEffectEventFunctions(getScope(node));
|
|
},
|
|
};
|
|
},
|
|
};
|
|
function getFunctionName(node) {
|
|
var _a, _b, _c, _d;
|
|
if (node.type === 'ComponentDeclaration' ||
|
|
node.type === 'HookDeclaration' ||
|
|
node.type === 'FunctionDeclaration' ||
|
|
(node.type === 'FunctionExpression' && node.id)) {
|
|
return node.id;
|
|
}
|
|
else if (node.type === 'FunctionExpression' ||
|
|
node.type === 'ArrowFunctionExpression') {
|
|
if (((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) === 'VariableDeclarator' &&
|
|
node.parent.init === node) {
|
|
return node.parent.id;
|
|
}
|
|
else if (((_b = node.parent) === null || _b === void 0 ? void 0 : _b.type) === 'AssignmentExpression' &&
|
|
node.parent.right === node &&
|
|
node.parent.operator === '=') {
|
|
return node.parent.left;
|
|
}
|
|
else if (((_c = node.parent) === null || _c === void 0 ? void 0 : _c.type) === 'Property' &&
|
|
node.parent.value === node &&
|
|
!node.parent.computed) {
|
|
return node.parent.key;
|
|
}
|
|
else if (((_d = node.parent) === null || _d === void 0 ? void 0 : _d.type) === 'AssignmentPattern' &&
|
|
node.parent.right === node &&
|
|
!node.parent.computed) {
|
|
return node.parent.left;
|
|
}
|
|
else {
|
|
return undefined;
|
|
}
|
|
}
|
|
else {
|
|
return undefined;
|
|
}
|
|
}
|
|
function last(array) {
|
|
return array[array.length - 1];
|
|
}
|
|
|
|
function makeDeprecatedRule(version) {
|
|
return {
|
|
meta: {
|
|
type: 'suggestion',
|
|
docs: {
|
|
description: `Deprecated: this rule has been removed in ${version}.`,
|
|
},
|
|
schema: [],
|
|
deprecated: true,
|
|
},
|
|
create() {
|
|
return {};
|
|
},
|
|
};
|
|
}
|
|
const rules = Object.assign(Object.assign({ 'exhaustive-deps': rule$1, 'rules-of-hooks': rule }, Object.fromEntries(Object.entries(allRules).map(([name, config]) => [name, config.rule]))), { 'component-hook-factories': makeDeprecatedRule('7.1.0') });
|
|
const basicRuleConfigs = {
|
|
'react-hooks/rules-of-hooks': 'error',
|
|
'react-hooks/exhaustive-deps': 'warn',
|
|
};
|
|
const recommendedCompilerRuleConfigs = Object.fromEntries(Object.entries(recommendedRules).map(([name, ruleConfig]) => {
|
|
return [
|
|
`react-hooks/${name}`,
|
|
mapErrorSeverityToESlint(ruleConfig.severity),
|
|
];
|
|
}));
|
|
const recommendedLatestCompilerRuleConfigs = Object.fromEntries(Object.entries(recommendedLatestRules).map(([name, ruleConfig]) => {
|
|
return [
|
|
`react-hooks/${name}`,
|
|
mapErrorSeverityToESlint(ruleConfig.severity),
|
|
];
|
|
}));
|
|
const recommendedRuleConfigs = Object.assign(Object.assign({}, basicRuleConfigs), recommendedCompilerRuleConfigs);
|
|
const recommendedLatestRuleConfigs = Object.assign(Object.assign({}, basicRuleConfigs), recommendedLatestCompilerRuleConfigs);
|
|
const plugins = ['react-hooks'];
|
|
const configs = {
|
|
recommended: {
|
|
plugins,
|
|
rules: recommendedRuleConfigs,
|
|
},
|
|
'recommended-latest': {
|
|
plugins,
|
|
rules: recommendedLatestRuleConfigs,
|
|
},
|
|
flat: {},
|
|
};
|
|
const plugin = {
|
|
meta: {
|
|
name: 'eslint-plugin-react-hooks',
|
|
version: '7.0.0',
|
|
},
|
|
rules,
|
|
configs,
|
|
};
|
|
Object.assign(configs.flat, {
|
|
'recommended-latest': {
|
|
plugins: { 'react-hooks': plugin },
|
|
rules: configs['recommended-latest'].rules,
|
|
},
|
|
recommended: {
|
|
plugins: { 'react-hooks': plugin },
|
|
rules: configs.recommended.rules,
|
|
},
|
|
});
|
|
|
|
module.exports = plugin;
|
|
})();
|
|
}
|