58310 lines
2.0 MiB
58310 lines
2.0 MiB
/**
|
|
* @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;
|
|
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') {
|
|
continue;
|
|
}
|
|
if (!dependencies.has(dependency)) {
|
|
const resolved = reference.resolved;
|
|
const isStable = memoizedIsStableKnownHookValue(resolved) ||
|
|
memoizedIsFunctionWithoutCapturedValues(resolved);
|
|
dependencies.set(dependency, {
|
|
isStable,
|
|
references: [reference],
|
|
});
|
|
}
|
|
else {
|
|
(_e = dependencies.get(dependency)) === null || _e === void 0 ? void 0 : _e.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) {
|
|
if (!condition) {
|
|
const errors = new CompilerError();
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
reason: options.reason,
|
|
description: options.description,
|
|
category: ErrorCategory.Invariant,
|
|
}).withDetails(...options.details));
|
|
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.AutomaticEffectDependencies:
|
|
case ErrorCategory.CapitalizedCalls:
|
|
case ErrorCategory.Config:
|
|
case ErrorCategory.EffectDerivationsOfState:
|
|
case ErrorCategory.EffectSetState:
|
|
case ErrorCategory.ErrorBoundaries:
|
|
case ErrorCategory.Factories:
|
|
case ErrorCategory.FBT:
|
|
case ErrorCategory.Fire:
|
|
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: {
|
|
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["Factories"] = "Factories";
|
|
ErrorCategory["PreserveManualMemo"] = "PreserveManualMemo";
|
|
ErrorCategory["IncompatibleLibrary"] = "IncompatibleLibrary";
|
|
ErrorCategory["Immutability"] = "Immutability";
|
|
ErrorCategory["Globals"] = "Globals";
|
|
ErrorCategory["Refs"] = "Refs";
|
|
ErrorCategory["EffectDependencies"] = "EffectDependencies";
|
|
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["AutomaticEffectDependencies"] = "AutomaticEffectDependencies";
|
|
ErrorCategory["Fire"] = "Fire";
|
|
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.AutomaticEffectDependencies: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'automatic-effect-dependencies',
|
|
description: 'Verifies that automatic effect dependencies are compiled if opted-in',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
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.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, which can lead to re-renders that degrade performance',
|
|
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.Factories: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'component-hook-factories',
|
|
description: 'Validates against higher order functions defining nested components or hooks. ' +
|
|
'Components and hooks should be defined at the module level',
|
|
preset: LintRulePreset.Recommended,
|
|
};
|
|
}
|
|
case ErrorCategory.FBT: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'fbt',
|
|
description: 'Validates usage of fbt',
|
|
preset: LintRulePreset.Off,
|
|
};
|
|
}
|
|
case ErrorCategory.Fire: {
|
|
return {
|
|
category,
|
|
severity: ErrorSeverity.Error,
|
|
name: 'fire',
|
|
description: 'Validates usage of `fire`',
|
|
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.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 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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_a = fnPath.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
CompilerError.invariant(originalFnParams.length === compiledParams.length, {
|
|
reason: 'Expected React Compiler optimized function declarations to have the same number of parameters as source',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_b = fnPath.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_a = fnPath.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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 makeTypeId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected instruction id to be a non-negative integer',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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';
|
|
}
|
|
function isExpressionBlockKind(kind) {
|
|
return !isStatementBlockKind(kind);
|
|
}
|
|
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 forkTemporaryIdentifier(id, source) {
|
|
return Object.assign(Object.assign({}, source), { mutableRange: { start: makeInstructionId(0), end: makeInstructionId(0) }, id });
|
|
}
|
|
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}\``,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}\``,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: location,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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 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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
return id;
|
|
}
|
|
function makeScopeId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected block id to be a non-negative integer',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
return id;
|
|
}
|
|
function makeIdentifierId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected identifier id to be a non-negative integer',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
return id;
|
|
}
|
|
function makeDeclarationId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected declaration id to be a non-negative integer',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
return id;
|
|
}
|
|
function makeInstructionId(id) {
|
|
CompilerError.invariant(id >= 0 && Number.isInteger(id), {
|
|
reason: 'Expected instruction id to be a non-negative integer',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
return id;
|
|
}
|
|
function isObjectMethodType(id) {
|
|
return id.type.kind == 'ObjectMethod';
|
|
}
|
|
function isPrimitiveType(id) {
|
|
return id.type.kind === 'Primitive';
|
|
}
|
|
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 isStartTransitionType(id) {
|
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInStartTransition');
|
|
}
|
|
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 isFireFunctionType(id) {
|
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInFireFunction');
|
|
}
|
|
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));
|
|
}
|
|
function isStableTypeContainer(id) {
|
|
const type_ = id.type;
|
|
if (type_.kind !== 'Object') {
|
|
return false;
|
|
}
|
|
return (isUseStateType(id) ||
|
|
type_.shapeId === 'BuiltInUseActionState' ||
|
|
isUseReducerType(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':
|
|
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 isUseContextHookType(id) {
|
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInUseContextHook');
|
|
}
|
|
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('')}`;
|
|
}
|
|
|
|
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': {
|
|
value = `[${terminal.id}] MaybeThrow continuation=bb${terminal.continuation} handler=bb${terminal.handler}`;
|
|
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.',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instrValue.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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(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(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',
|
|
description: null,
|
|
suggestions: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: val.root.value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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 printSourceLocationLine(loc) {
|
|
if (typeof loc === 'symbol') {
|
|
return 'generated';
|
|
}
|
|
else {
|
|
return `${loc.start.line}:${loc.end.line}`;
|
|
}
|
|
}
|
|
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* 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 = fn(terminal.handler);
|
|
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;
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_b = (_a = block.instructions[0]) === null || _a === void 0 ? void 0 : _a.loc) !== null && _b !== void 0 ? _b : block.terminal.id,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
__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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: block.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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}\``,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.lvalue.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
CompilerError.invariant(!assignments.has(instr.lvalue.identifier.id), {
|
|
reason: `Expected lvalues to be assigned exactly once`,
|
|
description: `Found duplicate assignment of '${printPlace(instr.lvalue)}'`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.lvalue.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: loc !== null && loc !== void 0 ? loc : GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
|
|
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)}'`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_a = block.terminal.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
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})`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
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.errors = new CompilerError();
|
|
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");
|
|
}
|
|
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') {
|
|
CompilerError.throwDiagnostic({
|
|
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',
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
message: 'Rename to avoid conflict with fbt plugin',
|
|
loc: (_a = node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
if (node.name === 'this') {
|
|
CompilerError.throwDiagnostic({
|
|
category: ErrorCategory.UnsupportedSyntax,
|
|
reason: '`this` is not supported syntax',
|
|
description: 'React Compiler does not support compiling functions that use `this`',
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
message: '`this` was used here',
|
|
loc: (_b = node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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')) {
|
|
CompilerError.throwTodo({
|
|
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,
|
|
});
|
|
}
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
CompilerError.invariant(false, {
|
|
reason: 'Expected a loop to be in scope',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
_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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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!`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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}'`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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}'`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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.`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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 BuiltInStartTransitionId = 'BuiltInStartTransition';
|
|
const BuiltInFireId = 'BuiltInFire';
|
|
const BuiltInFireFunctionId = 'BuiltInFireFunction';
|
|
const BuiltInUseEffectEventId = 'BuiltInUseEffectEvent';
|
|
const BuiltinEffectEventId = 'BuiltInEffectEventFunction';
|
|
const BuiltInAutodepsId = 'BuiltInAutoDepsId';
|
|
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, 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.errors.pushDiagnostic(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.errors.pushDiagnostic(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.errors.pushDiagnostic(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()) {
|
|
builder.errors.merge(idResult.unwrapErr());
|
|
}
|
|
else {
|
|
validatedId = idResult.unwrap().value;
|
|
}
|
|
}
|
|
if (builder.errors.hasAnyErrors()) {
|
|
return Err(builder.errors);
|
|
}
|
|
builder.terminate({
|
|
kind: 'return',
|
|
returnVariant: 'Void',
|
|
loc: GeneratedSource,
|
|
value: lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: GeneratedSource,
|
|
}),
|
|
id: makeInstructionId(0),
|
|
effects: null,
|
|
}, null);
|
|
return Ok({
|
|
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: builder.build(),
|
|
context,
|
|
generator: func.node.generator === true,
|
|
async: func.node.async === true,
|
|
loc: (_c = func.node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
env,
|
|
effects: null,
|
|
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;
|
|
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.errors.push({
|
|
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}`,
|
|
suggestions: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_e = id.node.loc) !== null && _e !== void 0 ? _e : GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_h = id.node.loc) !== null && _h !== void 0 ? _h : GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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;
|
|
const init = stmt.get('init');
|
|
if (!init.isVariableDeclaration()) {
|
|
builder.errors.push({
|
|
reason: '(BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement',
|
|
category: ErrorCategory.Todo,
|
|
loc: (_a = stmt.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
suggestions: null,
|
|
});
|
|
return {
|
|
kind: 'unsupported',
|
|
id: makeInstructionId(0),
|
|
loc: (_c = (_b = init.node) === null || _b === void 0 ? void 0 : _b.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
|
|
};
|
|
}
|
|
lowerStatement(builder, init);
|
|
return {
|
|
kind: 'goto',
|
|
block: testBlock.id,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: (_d = init.node.loc) !== null && _d !== void 0 ? _d : 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.errors.push({
|
|
reason: `(BuildHIR::lowerStatement) Handle empty test in ForStatement`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_t = stmt.node.loc) !== null && _t !== void 0 ? _t : null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
else {
|
|
builder.terminateWithContinuation({
|
|
kind: 'branch',
|
|
test: lowerExpressionToTemporary(builder, test),
|
|
consequent: bodyBlock,
|
|
alternate: continuationBlock.id,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: (_u = stmt.node.loc) !== null && _u !== void 0 ? _u : 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 = (_v = stmt.node.loc) !== null && _v !== void 0 ? _v : 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: (_w = stmt.node.loc) !== null && _w !== void 0 ? _w : 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: (_x = stmt.node.loc) !== null && _x !== void 0 ? _x : 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.errors.push({
|
|
reason: `Expected at most one \`default\` branch in a switch statement, this code should have failed to parse`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_y = case_.node.loc) !== null && _y !== void 0 ? _y : 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: (_z = stmt.node.loc) !== null && _z !== void 0 ? _z : GeneratedSource,
|
|
}, continuationBlock);
|
|
return;
|
|
}
|
|
case 'VariableDeclaration': {
|
|
const stmt = stmtPath;
|
|
const nodeKind = stmt.node.kind;
|
|
if (nodeKind === 'var') {
|
|
builder.errors.push({
|
|
reason: `(BuildHIR::lowerStatement) Handle ${nodeKind} kinds in VariableDeclaration`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_0 = stmt.node.loc) !== null && _0 !== void 0 ? _0 : null,
|
|
suggestions: null,
|
|
});
|
|
return;
|
|
}
|
|
const kind = nodeKind === 'let' ? 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, (_1 = stmt.node.loc) !== null && _1 !== void 0 ? _1 : GeneratedSource, kind, id, value, id.isObjectPattern() || id.isArrayPattern()
|
|
? 'Destructure'
|
|
: 'Assignment');
|
|
}
|
|
else if (id.isIdentifier()) {
|
|
const binding = builder.resolveIdentifier(id);
|
|
if (binding.kind !== 'Identifier') {
|
|
builder.errors.push({
|
|
reason: `(BuildHIR::lowerAssignment) Could not find binding for declaration.`,
|
|
category: ErrorCategory.Invariant,
|
|
loc: (_2 = id.node.loc) !== null && _2 !== void 0 ? _2 : null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
else {
|
|
const place = {
|
|
effect: Effect.Unknown,
|
|
identifier: binding.identifier,
|
|
kind: 'Identifier',
|
|
reactive: false,
|
|
loc: (_3 = id.node.loc) !== null && _3 !== void 0 ? _3 : GeneratedSource,
|
|
};
|
|
if (builder.isContextIdentifier(id)) {
|
|
if (kind === InstructionKind.Const) {
|
|
const declRangeStart = declaration.parentPath.node.start;
|
|
builder.errors.push({
|
|
reason: `Expect \`const\` declaration not to be reassigned`,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_4 = id.node.loc) !== null && _4 !== void 0 ? _4 : 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: (_5 = id.node.loc) !== null && _5 !== void 0 ? _5 : 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: (_6 = id.node.loc) !== null && _6 !== void 0 ? _6 : GeneratedSource,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
builder.errors.push({
|
|
reason: `Expected variable declaration to be an identifier if no initializer was provided`,
|
|
description: `Got a \`${id.type}\``,
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_7 = stmt.node.loc) !== null && _7 !== void 0 ? _7 : 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 = (_8 = stmt.node.loc) !== null && _8 !== void 0 ? _8 : 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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_9 = stmt.node.loc) !== null && _9 !== void 0 ? _9 : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
const id = stmt.get('id');
|
|
const fn = lowerValueToTemporary(builder, lowerFunctionToValue(builder, stmt));
|
|
lowerAssignment(builder, (_10 = stmt.node.loc) !== null && _10 !== void 0 ? _10 : 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.errors.push({
|
|
reason: `(BuildHIR::lowerStatement) Handle for-await loops`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_11 = stmt.node.loc) !== null && _11 !== void 0 ? _11 : 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 = (_12 = stmt.node.loc) !== null && _12 !== void 0 ? _12 : 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: (_13 = stmt.node.loc) !== null && _13 !== void 0 ? _13 : GeneratedSource,
|
|
}, testBlock);
|
|
const left = stmt.get('left');
|
|
const leftLoc = (_14 = left.node.loc) !== null && _14 !== void 0 ? _14 : 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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_15 = left.node.loc) !== null && _15 !== void 0 ? _15 : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: leftLoc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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: (_16 = stmt.node.loc) !== null && _16 !== void 0 ? _16 : 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 = (_17 = stmt.node.loc) !== null && _17 !== void 0 ? _17 : 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 = (_18 = left.node.loc) !== null && _18 !== void 0 ? _18 : 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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_19 = left.node.loc) !== null && _19 !== void 0 ? _19 : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: leftLoc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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: (_20 = stmt.node.loc) !== null && _20 !== void 0 ? _20 : GeneratedSource,
|
|
}, continuationBlock);
|
|
return;
|
|
}
|
|
case 'DebuggerStatement': {
|
|
const stmt = stmtPath;
|
|
const loc = (_21 = stmt.node.loc) !== null && _21 !== void 0 ? _21 : 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.errors.push({
|
|
reason: `(BuildHIR::lowerStatement) Handle TryStatement without a catch clause`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_22 = stmt.node.loc) !== null && _22 !== void 0 ? _22 : null,
|
|
suggestions: null,
|
|
});
|
|
return;
|
|
}
|
|
if (hasNode(stmt.get('finalizer'))) {
|
|
builder.errors.push({
|
|
reason: `(BuildHIR::lowerStatement) Handle TryStatement with a finalizer ('finally') clause`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_23 = stmt.node.loc) !== null && _23 !== void 0 ? _23 : null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
const handlerBindingPath = handlerPath.get('param');
|
|
let handlerBinding = null;
|
|
if (hasNode(handlerBindingPath)) {
|
|
const place = {
|
|
kind: 'Identifier',
|
|
identifier: builder.makeTemporary((_24 = handlerBindingPath.node.loc) !== null && _24 !== void 0 ? _24 : GeneratedSource),
|
|
effect: Effect.Unknown,
|
|
reactive: false,
|
|
loc: (_25 = handlerBindingPath.node.loc) !== null && _25 !== void 0 ? _25 : GeneratedSource,
|
|
};
|
|
promoteTemporary(place.identifier);
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'DeclareLocal',
|
|
lvalue: {
|
|
kind: InstructionKind.Catch,
|
|
place: Object.assign({}, place),
|
|
},
|
|
type: null,
|
|
loc: (_26 = handlerBindingPath.node.loc) !== null && _26 !== void 0 ? _26 : 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: (_27 = stmt.node.loc) !== null && _27 !== void 0 ? _27 : GeneratedSource,
|
|
}, continuationBlock);
|
|
return;
|
|
}
|
|
case 'WithStatement': {
|
|
builder.errors.push({
|
|
reason: `JavaScript 'with' syntax is not supported`,
|
|
description: `'with' syntax is considered deprecated and removed from JavaScript standards, consider alternatives`,
|
|
category: ErrorCategory.UnsupportedSyntax,
|
|
loc: (_28 = stmtPath.node.loc) !== null && _28 !== void 0 ? _28 : null,
|
|
suggestions: null,
|
|
});
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
loc: (_29 = stmtPath.node.loc) !== null && _29 !== void 0 ? _29 : GeneratedSource,
|
|
node: stmtPath.node,
|
|
});
|
|
return;
|
|
}
|
|
case 'ClassDeclaration': {
|
|
builder.errors.push({
|
|
reason: 'Inline `class` declarations are not supported',
|
|
description: `Move class declarations outside of components/hooks`,
|
|
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 'EnumDeclaration':
|
|
case 'TSEnumDeclaration': {
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
loc: (_32 = stmtPath.node.loc) !== null && _32 !== void 0 ? _32 : GeneratedSource,
|
|
node: stmtPath.node,
|
|
});
|
|
return;
|
|
}
|
|
case 'ExportAllDeclaration':
|
|
case 'ExportDefaultDeclaration':
|
|
case 'ExportNamedDeclaration':
|
|
case 'ImportDeclaration':
|
|
case 'TSExportAssignment':
|
|
case 'TSImportEqualsDeclaration': {
|
|
builder.errors.push({
|
|
reason: 'JavaScript `import` and `export` statements may only appear at the top level of a module',
|
|
category: ErrorCategory.Syntax,
|
|
loc: (_33 = stmtPath.node.loc) !== null && _33 !== void 0 ? _33 : null,
|
|
suggestions: null,
|
|
});
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'UnsupportedNode',
|
|
loc: (_34 = stmtPath.node.loc) !== null && _34 !== void 0 ? _34 : GeneratedSource,
|
|
node: stmtPath.node,
|
|
});
|
|
return;
|
|
}
|
|
case 'TSNamespaceExportDeclaration': {
|
|
builder.errors.push({
|
|
reason: 'TypeScript `namespace` 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 '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);
|
|
if (!loweredFunc) {
|
|
return { kind: 'UnsupportedNode', node: property.node, loc: loc };
|
|
}
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_z = namePath.node.loc) !== null && _z !== void 0 ? _z : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_4 = openingIdentifier.node.loc) !== null && _4 !== void 0 ? _4 : GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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) {
|
|
CompilerError.throwDiagnostic({
|
|
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.errors.push({
|
|
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",
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_8 = expr.node.loc) !== null && _8 !== void 0 ? _8 : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
const value = expr.get('quasi').get('quasis').at(0).node.value;
|
|
if (value.raw !== value.cooked) {
|
|
builder.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.hasAnyErrors()) {
|
|
builder.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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.errors.push({
|
|
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)));
|
|
}
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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}\``,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_b = object.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}!`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_b = expression.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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.errors.push({
|
|
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);
|
|
if (!loweredFunc) {
|
|
return { kind: 'UnsupportedNode', node: exprNode, loc: exprLoc };
|
|
}
|
|
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 lowering = lower(expr, builder.environment, builder.bindings, new Map([...builder.context, ...capturedContext]));
|
|
let loweredFunc;
|
|
if (lowering.isErr()) {
|
|
const functionErrors = lowering.unwrapErr();
|
|
builder.errors.merge(functionErrors);
|
|
return null;
|
|
}
|
|
loweredFunc = lowering.unwrap();
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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;
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_e = lvaluePath.node.loc) !== null && _e !== void 0 ? _e : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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,
|
|
},
|
|
},
|
|
value,
|
|
loc,
|
|
});
|
|
for (const { place, path } of followups) {
|
|
lowerAssignment(builder, (_p = path.node.loc) !== null && _p !== void 0 ? _p : 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.errors.push({
|
|
reason: `(BuildHIR::lowerAssignment) Handle ${argument.node.type} rest element in ObjectPattern`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_q = argument.node.loc) !== null && _q !== void 0 ? _q : null,
|
|
suggestions: null,
|
|
});
|
|
continue;
|
|
}
|
|
if (forceTemporaries ||
|
|
getStoreKind(builder, argument) === 'StoreContext') {
|
|
const temp = buildTemporaryPlace(builder, (_r = property.node.loc) !== null && _r !== void 0 ? _r : GeneratedSource);
|
|
promoteTemporary(temp.identifier);
|
|
properties.push({
|
|
kind: 'Spread',
|
|
place: Object.assign({}, temp),
|
|
});
|
|
followups.push({ place: temp, path: argument });
|
|
}
|
|
else {
|
|
const identifier = lowerIdentifierForAssignment(builder, (_s = property.node.loc) !== null && _s !== void 0 ? _s : GeneratedSource, kind, argument);
|
|
if (identifier === null) {
|
|
continue;
|
|
}
|
|
else if (identifier.kind === 'Global') {
|
|
builder.errors.push({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Expected reassignment of globals to enable forceTemporaries',
|
|
loc: (_t = property.node.loc) !== null && _t !== void 0 ? _t : GeneratedSource,
|
|
});
|
|
continue;
|
|
}
|
|
properties.push({
|
|
kind: 'Spread',
|
|
place: identifier,
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
if (!property.isObjectProperty()) {
|
|
builder.errors.push({
|
|
reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in ObjectPattern`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_u = property.node.loc) !== null && _u !== void 0 ? _u : null,
|
|
suggestions: null,
|
|
});
|
|
continue;
|
|
}
|
|
if (property.node.computed) {
|
|
builder.errors.push({
|
|
reason: `(BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_v = property.node.loc) !== null && _v !== void 0 ? _v : null,
|
|
suggestions: null,
|
|
});
|
|
continue;
|
|
}
|
|
const loweredKey = lowerObjectPropertyKey(builder, property);
|
|
if (!loweredKey) {
|
|
continue;
|
|
}
|
|
const element = property.get('value');
|
|
if (!element.isLVal()) {
|
|
builder.errors.push({
|
|
reason: `(BuildHIR::lowerAssignment) Expected object property value to be an LVal, got: ${element.type}`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_w = element.node.loc) !== null && _w !== void 0 ? _w : null,
|
|
suggestions: null,
|
|
});
|
|
continue;
|
|
}
|
|
if (element.isIdentifier() &&
|
|
!forceTemporaries &&
|
|
(assignmentKind === 'Assignment' ||
|
|
getStoreKind(builder, element) === 'StoreLocal')) {
|
|
const identifier = lowerIdentifierForAssignment(builder, (_x = element.node.loc) !== null && _x !== void 0 ? _x : GeneratedSource, kind, element);
|
|
if (identifier === null) {
|
|
continue;
|
|
}
|
|
else if (identifier.kind === 'Global') {
|
|
builder.errors.push({
|
|
category: ErrorCategory.Todo,
|
|
reason: 'Expected reassignment of globals to enable forceTemporaries',
|
|
loc: (_y = element.node.loc) !== null && _y !== void 0 ? _y : GeneratedSource,
|
|
});
|
|
continue;
|
|
}
|
|
properties.push({
|
|
kind: 'ObjectProperty',
|
|
type: 'property',
|
|
place: identifier,
|
|
key: loweredKey,
|
|
});
|
|
}
|
|
else {
|
|
const temp = buildTemporaryPlace(builder, (_z = element.node.loc) !== null && _z !== void 0 ? _z : 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,
|
|
},
|
|
},
|
|
value,
|
|
loc,
|
|
});
|
|
for (const { place, path } of followups) {
|
|
lowerAssignment(builder, (_0 = path.node.loc) !== null && _0 !== void 0 ? _0 : loc, kind, path, place, assignmentKind);
|
|
}
|
|
return { kind: 'LoadLocal', place: temporary, loc: value.loc };
|
|
}
|
|
case 'AssignmentPattern': {
|
|
const lvalue = lvaluePath;
|
|
const loc = (_1 = lvalue.node.loc) !== null && _1 !== void 0 ? _1 : 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.errors.push({
|
|
reason: `(BuildHIR::lowerAssignment) Handle ${lvaluePath.type} assignments`,
|
|
category: ErrorCategory.Todo,
|
|
loc: (_2 = lvaluePath.node.loc) !== null && _2 !== void 0 ? _2 : 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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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,
|
|
}),
|
|
],
|
|
[
|
|
'use',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: Effect.Freeze,
|
|
returnType: { kind: 'Poly' },
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Frozen,
|
|
}, BuiltInUseOperatorId),
|
|
],
|
|
[
|
|
'fire',
|
|
addFunction(DEFAULT_SHAPES, [], {
|
|
positionalParams: [],
|
|
restParam: null,
|
|
returnType: {
|
|
kind: 'Function',
|
|
return: { kind: 'Poly' },
|
|
shapeId: BuiltInFireFunctionId,
|
|
isConstructor: false,
|
|
},
|
|
calleeEffect: Effect.Read,
|
|
returnValueKind: ValueKind.Frozen,
|
|
}, BuiltInFireId),
|
|
],
|
|
[
|
|
'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),
|
|
],
|
|
['AUTODEPS', addObject(DEFAULT_SHAPES, BuiltInAutodepsId, [])],
|
|
];
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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_resolveModuleType, _Environment_isKnownReactModule, _Environment_getCustomHookType;
|
|
const ReactElementSymbolSchema = v4.z.object({
|
|
elementSymbol: v4.z.union([
|
|
v4.z.literal('react.element'),
|
|
v4.z.literal('react.transitional.element'),
|
|
]),
|
|
globalDevVar: v4.z.string(),
|
|
});
|
|
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 USE_FIRE_FUNCTION_NAME = 'useFire';
|
|
const EMIT_FREEZE_GLOBAL_GATING = 'true';
|
|
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),
|
|
enablePreserveExistingManualUseMemo: v4.z.boolean().default(false),
|
|
enableForest: v4.z.boolean().default(false),
|
|
enableUseTypeAnnotations: v4.z.boolean().default(false),
|
|
flowTypeProvider: v4.z.nullable(v4.z.any()).default(null),
|
|
enableOptionalDependencies: v4.z.boolean().default(true),
|
|
enableFire: v4.z.boolean().default(false),
|
|
enableNameAnonymousFunctions: v4.z.boolean().default(false),
|
|
inferEffectDependencies: v4.z
|
|
.nullable(v4.z.array(v4.z.object({
|
|
function: ExternalFunctionSchema,
|
|
autodepsIndex: v4.z.number().min(1, 'autodepsIndex must be > 0'),
|
|
})))
|
|
.default(null),
|
|
inlineJsxTransform: ReactElementSymbolSchema.nullable().default(null),
|
|
validateHooksUsage: v4.z.boolean().default(true),
|
|
validateRefAccessDuringRender: v4.z.boolean().default(true),
|
|
validateNoSetStateInRender: v4.z.boolean().default(true),
|
|
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),
|
|
validateMemoizedEffectDependencies: 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),
|
|
validateNoImpureFunctionsInRender: v4.z.boolean().default(false),
|
|
validateNoFreezingKnownMutableFunctions: v4.z.boolean().default(false),
|
|
enableAssumeHooksFollowRulesOfReact: v4.z.boolean().default(true),
|
|
enableTransitivelyFreezeFunctionExpressions: v4.z.boolean().default(true),
|
|
enableEmitFreeze: ExternalFunctionSchema.nullable().default(null),
|
|
enableEmitHookGuards: ExternalFunctionSchema.nullable().default(null),
|
|
enableInstructionReordering: v4.z.boolean().default(false),
|
|
enableFunctionOutlining: v4.z.boolean().default(true),
|
|
enableJsxOutlining: v4.z.boolean().default(false),
|
|
enableEmitInstrumentForget: InstrumentationSchema.nullable().default(null),
|
|
assertValidMutableRanges: v4.z.boolean().default(false),
|
|
enableChangeVariableCodegen: v4.z.boolean().default(false),
|
|
enableMemoizationComments: v4.z.boolean().default(false),
|
|
throwUnknownException__testonly: v4.z.boolean().default(false),
|
|
enableTreatFunctionDepsAsConditional: v4.z.boolean().default(false),
|
|
disableMemoizationForDebugging: v4.z.boolean().default(false),
|
|
enableChangeDetectionForDebugging: ExternalFunctionSchema.nullable().default(null),
|
|
enableCustomTypeDefinitionForReanimated: v4.z.boolean().default(false),
|
|
hookPattern: v4.z.string().nullable().default(null),
|
|
enableTreatRefLikeIdentifiersAsRefs: v4.z.boolean().default(true),
|
|
enableTreatSetIdentifiersAsStateSetters: v4.z.boolean().default(false),
|
|
lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
|
|
validateNoVoidUseMemo: v4.z.boolean().default(true),
|
|
validateNoDynamicallyCreatedComponentsOrHooks: v4.z.boolean().default(false),
|
|
enableAllowSetStateFromRefsInEffects: v4.z.boolean().default(true),
|
|
});
|
|
class Environment {
|
|
constructor(scope, fnType, compilerMode, 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, []);
|
|
this.inferredEffectLocations = new Set();
|
|
_Environment_contextIdentifiers.set(this, void 0);
|
|
_Environment_hoistedIdentifiers.set(this, void 0);
|
|
_Environment_flowTypeEnvironment.set(this, void 0);
|
|
__classPrivateFieldSet(this, _Environment_scope, scope, "f");
|
|
this.fnType = fnType;
|
|
this.compilerMode = compilerMode;
|
|
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");
|
|
this.hasFireRewrite = false;
|
|
this.hasInferredEffect = false;
|
|
if (config.disableMemoizationForDebugging &&
|
|
config.enableChangeDetectionForDebugging != null) {
|
|
CompilerError.throwInvalidConfig({
|
|
reason: `Invalid environment config: the 'disableMemoizationForDebugging' and 'enableChangeDetectionForDebugging' options cannot be used together`,
|
|
description: null,
|
|
loc: null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
__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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
__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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
return __classPrivateFieldGet(this, _Environment_flowTypeEnvironment, "f");
|
|
}
|
|
get isInferredMemoEnabled() {
|
|
return this.compilerMode !== 'no_inferred_memo';
|
|
}
|
|
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,
|
|
});
|
|
}
|
|
}
|
|
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, _d;
|
|
if (this.config.hookPattern != null) {
|
|
const match = new RegExp(this.config.hookPattern).exec(binding.name);
|
|
if (match != null &&
|
|
typeof match[1] === 'string' &&
|
|
isHookName$2(match[1])) {
|
|
const resolvedName = match[1];
|
|
return (_a = __classPrivateFieldGet(this, _Environment_globals, "f").get(resolvedName)) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_getCustomHookType).call(this);
|
|
}
|
|
}
|
|
switch (binding.kind) {
|
|
case 'ModuleLocal': {
|
|
return isHookName$2(binding.name) ? __classPrivateFieldGet(this, _Environment_instances, "m", _Environment_getCustomHookType).call(this) : null;
|
|
}
|
|
case 'Global': {
|
|
return ((_b = __classPrivateFieldGet(this, _Environment_globals, "f").get(binding.name)) !== null && _b !== void 0 ? _b : (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 ((_c = __classPrivateFieldGet(this, _Environment_globals, "f").get(binding.imported)) !== null && _c !== void 0 ? _c : (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 ((_d = __classPrivateFieldGet(this, _Environment_globals, "f").get(binding.name)) !== null && _d !== void 0 ? _d : (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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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_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,
|
|
});
|
|
}
|
|
const DEFAULT_EXPORT = 'default';
|
|
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
description: `Scope @${scope.id} has range [${scope.range.start}:${scope.range.end}] but the valid range is [1:${maxInstruction + 1}]`,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
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) {
|
|
if (instr.value.kind === 'FunctionExpression' ||
|
|
instr.value.kind === 'ObjectMethod') {
|
|
if (operand.identifier.type.kind === 'Primitive') {
|
|
continue;
|
|
}
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: label.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: label.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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 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$1(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$1(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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_a = valuePath.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
handleAssignment(currentFn, identifiers, valuePath);
|
|
}
|
|
else {
|
|
CompilerError.invariant(property.isRestElement(), {
|
|
reason: `[FindContextIdentifiers] Invalid assumptions for babel types.`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_b = property.node.loc) !== null && _b !== void 0 ? _b : GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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!',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: func.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: lvalue.place.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: lvalue.place.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: 'Expected consistent kind for destructuring',
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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)`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: 'Expected consistent kind for destructuring',
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: 'Expected consistent kind for destructuring',
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
kind = InstructionKind.Reassign;
|
|
declaration.kind = InstructionKind.Let;
|
|
}
|
|
}
|
|
}
|
|
CompilerError.invariant(kind !== null, {
|
|
reason: 'Expected at least one operand',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: lvalue.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
if (operandValue.value !== value.value) {
|
|
return null;
|
|
}
|
|
break;
|
|
}
|
|
case 'LoadGlobal': {
|
|
CompilerError.invariant(value.kind === 'LoadGlobal', {
|
|
reason: 'value kind expected to be LoadGlobal',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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;
|
|
}
|
|
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() {
|
|
this.named = new Set();
|
|
this.identifiers = new Set();
|
|
}
|
|
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();
|
|
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 'Await':
|
|
case 'CallExpression':
|
|
case 'ComputedDelete':
|
|
case 'ComputedStore':
|
|
case 'PropertyDelete':
|
|
case 'MethodCall':
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
description: `Could not find mapping for predecessor bb${predecessor} in block bb${block.id} for phi ${printPlace(phi.place)}`,
|
|
suggestions: null,
|
|
});
|
|
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);
|
|
block.terminal = {
|
|
kind: 'goto',
|
|
block: terminal.continuation,
|
|
variant: GotoVariant.Break,
|
|
id: terminal.id,
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
}
|
|
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 inlineJsxTransform(fn, inlineJsxTransformConfig) {
|
|
var _a;
|
|
const inlinedJsxDeclarations = new Map();
|
|
for (const [_, currentBlock] of [...fn.body.blocks]) {
|
|
let fallthroughBlockInstructions = null;
|
|
const instructionCount = currentBlock.instructions.length;
|
|
for (let i = 0; i < instructionCount; i++) {
|
|
const instr = currentBlock.instructions[i];
|
|
if (currentBlock.kind === 'value') {
|
|
(_a = fn.env.logger) === null || _a === void 0 ? void 0 : _a.logEvent(fn.env.filename, {
|
|
kind: 'CompileDiagnostic',
|
|
fnLoc: null,
|
|
detail: {
|
|
category: ErrorCategory.Todo,
|
|
reason: 'JSX Inlining is not supported on value blocks',
|
|
loc: instr.loc,
|
|
},
|
|
});
|
|
continue;
|
|
}
|
|
switch (instr.value.kind) {
|
|
case 'JsxExpression':
|
|
case 'JsxFragment': {
|
|
const currentBlockInstructions = currentBlock.instructions.slice(0, i);
|
|
const thenBlockInstructions = currentBlock.instructions.slice(i, i + 1);
|
|
const elseBlockInstructions = [];
|
|
fallthroughBlockInstructions !== null && fallthroughBlockInstructions !== void 0 ? fallthroughBlockInstructions : (fallthroughBlockInstructions = currentBlock.instructions.slice(i + 1));
|
|
const fallthroughBlockId = fn.env.nextBlockId;
|
|
const fallthroughBlock = {
|
|
kind: currentBlock.kind,
|
|
id: fallthroughBlockId,
|
|
instructions: fallthroughBlockInstructions,
|
|
terminal: currentBlock.terminal,
|
|
preds: new Set(),
|
|
phis: new Set(),
|
|
};
|
|
const varPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
promoteTemporary(varPlace.identifier);
|
|
const varLValuePlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const thenVarPlace = Object.assign(Object.assign({}, varPlace), { identifier: forkTemporaryIdentifier(fn.env.nextIdentifierId, varPlace.identifier) });
|
|
const elseVarPlace = Object.assign(Object.assign({}, varPlace), { identifier: forkTemporaryIdentifier(fn.env.nextIdentifierId, varPlace.identifier) });
|
|
const varInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign({}, varLValuePlace),
|
|
value: {
|
|
kind: 'DeclareLocal',
|
|
lvalue: { place: Object.assign({}, varPlace), kind: InstructionKind.Let },
|
|
type: null,
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
currentBlockInstructions.push(varInstruction);
|
|
const devGlobalPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const devGlobalInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, devGlobalPlace), { effect: Effect.Mutate }),
|
|
value: {
|
|
kind: 'LoadGlobal',
|
|
binding: {
|
|
kind: 'Global',
|
|
name: inlineJsxTransformConfig.globalDevVar,
|
|
},
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
currentBlockInstructions.push(devGlobalInstruction);
|
|
const thenBlockId = fn.env.nextBlockId;
|
|
const elseBlockId = fn.env.nextBlockId;
|
|
const ifTerminal = {
|
|
kind: 'if',
|
|
test: Object.assign(Object.assign({}, devGlobalPlace), { effect: Effect.Read }),
|
|
consequent: thenBlockId,
|
|
alternate: elseBlockId,
|
|
fallthrough: fallthroughBlockId,
|
|
loc: instr.loc,
|
|
id: makeInstructionId(0),
|
|
};
|
|
currentBlock.instructions = currentBlockInstructions;
|
|
currentBlock.terminal = ifTerminal;
|
|
const thenBlock = {
|
|
id: thenBlockId,
|
|
instructions: thenBlockInstructions,
|
|
kind: 'block',
|
|
phis: new Set(),
|
|
preds: new Set(),
|
|
terminal: {
|
|
kind: 'goto',
|
|
block: fallthroughBlockId,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: instr.loc,
|
|
},
|
|
};
|
|
fn.body.blocks.set(thenBlockId, thenBlock);
|
|
const resassignElsePlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const reassignElseInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign({}, resassignElsePlace),
|
|
value: {
|
|
kind: 'StoreLocal',
|
|
lvalue: {
|
|
place: elseVarPlace,
|
|
kind: InstructionKind.Reassign,
|
|
},
|
|
value: Object.assign({}, instr.lvalue),
|
|
type: null,
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
thenBlockInstructions.push(reassignElseInstruction);
|
|
const elseBlockTerminal = {
|
|
kind: 'goto',
|
|
block: fallthroughBlockId,
|
|
variant: GotoVariant.Break,
|
|
id: makeInstructionId(0),
|
|
loc: instr.loc,
|
|
};
|
|
const elseBlock = {
|
|
id: elseBlockId,
|
|
instructions: elseBlockInstructions,
|
|
kind: 'block',
|
|
phis: new Set(),
|
|
preds: new Set(),
|
|
terminal: elseBlockTerminal,
|
|
};
|
|
fn.body.blocks.set(elseBlockId, elseBlock);
|
|
const { refProperty, keyProperty, propsProperty } = createPropsProperties(fn, instr, elseBlockInstructions, instr.value.kind === 'JsxExpression' ? instr.value.props : [], instr.value.children);
|
|
const reactElementInstructionPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const reactElementInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, reactElementInstructionPlace), { effect: Effect.Store }),
|
|
value: {
|
|
kind: 'ObjectExpression',
|
|
properties: [
|
|
createSymbolProperty(fn, instr, elseBlockInstructions, '$$typeof', inlineJsxTransformConfig.elementSymbol),
|
|
instr.value.kind === 'JsxExpression'
|
|
? createTagProperty(fn, instr, elseBlockInstructions, instr.value.tag)
|
|
: createSymbolProperty(fn, instr, elseBlockInstructions, 'type', 'react.fragment'),
|
|
refProperty,
|
|
keyProperty,
|
|
propsProperty,
|
|
],
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
elseBlockInstructions.push(reactElementInstruction);
|
|
const reassignConditionalInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign({}, createTemporaryPlace(fn.env, instr.value.loc)),
|
|
value: {
|
|
kind: 'StoreLocal',
|
|
lvalue: {
|
|
place: Object.assign({}, elseVarPlace),
|
|
kind: InstructionKind.Reassign,
|
|
},
|
|
value: Object.assign({}, reactElementInstruction.lvalue),
|
|
type: null,
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
elseBlockInstructions.push(reassignConditionalInstruction);
|
|
const operands = new Map();
|
|
operands.set(thenBlockId, Object.assign({}, elseVarPlace));
|
|
operands.set(elseBlockId, Object.assign({}, thenVarPlace));
|
|
const phiIdentifier = forkTemporaryIdentifier(fn.env.nextIdentifierId, varPlace.identifier);
|
|
const phiPlace = Object.assign(Object.assign({}, createTemporaryPlace(fn.env, instr.value.loc)), { identifier: phiIdentifier });
|
|
const phis = new Set([
|
|
{
|
|
kind: 'Phi',
|
|
operands,
|
|
place: phiPlace,
|
|
},
|
|
]);
|
|
fallthroughBlock.phis = phis;
|
|
fn.body.blocks.set(fallthroughBlockId, fallthroughBlock);
|
|
inlinedJsxDeclarations.set(instr.lvalue.identifier.declarationId, {
|
|
identifier: phiIdentifier,
|
|
blockIdsToIgnore: new Set([thenBlockId, elseBlockId]),
|
|
});
|
|
break;
|
|
}
|
|
case 'FunctionExpression':
|
|
case 'ObjectMethod': {
|
|
inlineJsxTransform(instr.value.loweredFunc.func, inlineJsxTransformConfig);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const [blockId, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
mapInstructionOperands(instr, place => handlePlace(place, blockId, inlinedJsxDeclarations));
|
|
mapInstructionLValues(instr, lvalue => handlelValue(lvalue, blockId, inlinedJsxDeclarations));
|
|
mapInstructionValueOperands(instr.value, place => handlePlace(place, blockId, inlinedJsxDeclarations));
|
|
}
|
|
mapTerminalOperands(block.terminal, place => handlePlace(place, blockId, inlinedJsxDeclarations));
|
|
if (block.terminal.kind === 'scope') {
|
|
const scope = block.terminal.scope;
|
|
for (const dep of scope.dependencies) {
|
|
dep.identifier = handleIdentifier(dep.identifier, inlinedJsxDeclarations);
|
|
}
|
|
for (const [origId, decl] of [...scope.declarations]) {
|
|
const newDecl = handleIdentifier(decl.identifier, inlinedJsxDeclarations);
|
|
if (newDecl.id !== origId) {
|
|
scope.declarations.delete(origId);
|
|
scope.declarations.set(decl.identifier.id, {
|
|
identifier: newDecl,
|
|
scope: decl.scope,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
reversePostorderBlocks(fn.body);
|
|
markPredecessors(fn.body);
|
|
markInstructionIds(fn.body);
|
|
fixScopeAndIdentifierRanges(fn.body);
|
|
}
|
|
function createSymbolProperty(fn, instr, nextInstructions, propertyName, symbolName) {
|
|
const symbolPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const symbolInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, symbolPlace), { effect: Effect.Mutate }),
|
|
value: {
|
|
kind: 'LoadGlobal',
|
|
binding: { kind: 'Global', name: 'Symbol' },
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
nextInstructions.push(symbolInstruction);
|
|
const symbolForPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const symbolForInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, symbolForPlace), { effect: Effect.Read }),
|
|
value: {
|
|
kind: 'PropertyLoad',
|
|
object: Object.assign({}, symbolInstruction.lvalue),
|
|
property: makePropertyLiteral('for'),
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
nextInstructions.push(symbolForInstruction);
|
|
const symbolValuePlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const symbolValueInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, symbolValuePlace), { effect: Effect.Mutate }),
|
|
value: {
|
|
kind: 'Primitive',
|
|
value: symbolName,
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
nextInstructions.push(symbolValueInstruction);
|
|
const $$typeofPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const $$typeofInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, $$typeofPlace), { effect: Effect.Mutate }),
|
|
value: {
|
|
kind: 'MethodCall',
|
|
receiver: symbolInstruction.lvalue,
|
|
property: symbolForInstruction.lvalue,
|
|
args: [symbolValueInstruction.lvalue],
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
const $$typeofProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: propertyName, kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign(Object.assign({}, $$typeofPlace), { effect: Effect.Capture }),
|
|
};
|
|
nextInstructions.push($$typeofInstruction);
|
|
return $$typeofProperty;
|
|
}
|
|
function createTagProperty(fn, instr, nextInstructions, componentTag) {
|
|
let tagProperty;
|
|
switch (componentTag.kind) {
|
|
case 'BuiltinTag': {
|
|
const tagPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const tagInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, tagPropertyPlace), { effect: Effect.Mutate }),
|
|
value: {
|
|
kind: 'Primitive',
|
|
value: componentTag.name,
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
tagProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'type', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign(Object.assign({}, tagPropertyPlace), { effect: Effect.Capture }),
|
|
};
|
|
nextInstructions.push(tagInstruction);
|
|
break;
|
|
}
|
|
case 'Identifier': {
|
|
tagProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'type', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign(Object.assign({}, componentTag), { effect: Effect.Capture }),
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
return tagProperty;
|
|
}
|
|
function createPropsProperties(fn, instr, nextInstructions, propAttributes, children) {
|
|
let refProperty;
|
|
let keyProperty;
|
|
const props = [];
|
|
const jsxAttributesWithoutKey = propAttributes.filter(p => p.kind === 'JsxAttribute' && p.name !== 'key');
|
|
const jsxSpreadAttributes = propAttributes.filter(p => p.kind === 'JsxSpreadAttribute');
|
|
const spreadPropsOnly = jsxAttributesWithoutKey.length === 0 && jsxSpreadAttributes.length === 1;
|
|
propAttributes.forEach(prop => {
|
|
switch (prop.kind) {
|
|
case 'JsxAttribute': {
|
|
switch (prop.name) {
|
|
case 'key': {
|
|
keyProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'key', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign({}, prop.place),
|
|
};
|
|
break;
|
|
}
|
|
case 'ref': {
|
|
refProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'ref', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign({}, prop.place),
|
|
};
|
|
const refPropProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'ref', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign({}, prop.place),
|
|
};
|
|
props.push(refPropProperty);
|
|
break;
|
|
}
|
|
default: {
|
|
const attributeProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: prop.name, kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign({}, prop.place),
|
|
};
|
|
props.push(attributeProperty);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 'JsxSpreadAttribute': {
|
|
props.push({
|
|
kind: 'Spread',
|
|
place: Object.assign({}, prop.argument),
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
const propsPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
if (children) {
|
|
let childrenPropProperty;
|
|
if (children.length === 1) {
|
|
childrenPropProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'children', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign(Object.assign({}, children[0]), { effect: Effect.Capture }),
|
|
};
|
|
}
|
|
else {
|
|
const childrenPropPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const childrenPropInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, childrenPropPropertyPlace), { effect: Effect.Mutate }),
|
|
value: {
|
|
kind: 'ArrayExpression',
|
|
elements: [...children],
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
nextInstructions.push(childrenPropInstruction);
|
|
childrenPropProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'children', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign(Object.assign({}, childrenPropPropertyPlace), { effect: Effect.Capture }),
|
|
};
|
|
}
|
|
props.push(childrenPropProperty);
|
|
}
|
|
if (refProperty == null) {
|
|
const refPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const refInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, refPropertyPlace), { effect: Effect.Mutate }),
|
|
value: {
|
|
kind: 'Primitive',
|
|
value: null,
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
refProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'ref', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign(Object.assign({}, refPropertyPlace), { effect: Effect.Capture }),
|
|
};
|
|
nextInstructions.push(refInstruction);
|
|
}
|
|
if (keyProperty == null) {
|
|
const keyPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc);
|
|
const keyInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, keyPropertyPlace), { effect: Effect.Mutate }),
|
|
value: {
|
|
kind: 'Primitive',
|
|
value: null,
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
keyProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'key', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign(Object.assign({}, keyPropertyPlace), { effect: Effect.Capture }),
|
|
};
|
|
nextInstructions.push(keyInstruction);
|
|
}
|
|
let propsProperty;
|
|
if (spreadPropsOnly) {
|
|
const spreadProp = jsxSpreadAttributes[0];
|
|
CompilerError.invariant(spreadProp.kind === 'JsxSpreadAttribute', {
|
|
reason: 'Spread prop attribute must be of kind JSXSpreadAttribute',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
propsProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'props', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign(Object.assign({}, spreadProp.argument), { effect: Effect.Mutate }),
|
|
};
|
|
}
|
|
else {
|
|
const propsInstruction = {
|
|
id: makeInstructionId(0),
|
|
lvalue: Object.assign(Object.assign({}, propsPropertyPlace), { effect: Effect.Mutate }),
|
|
value: {
|
|
kind: 'ObjectExpression',
|
|
properties: props,
|
|
loc: instr.value.loc,
|
|
},
|
|
effects: null,
|
|
loc: instr.loc,
|
|
};
|
|
propsProperty = {
|
|
kind: 'ObjectProperty',
|
|
key: { name: 'props', kind: 'string' },
|
|
type: 'property',
|
|
place: Object.assign(Object.assign({}, propsPropertyPlace), { effect: Effect.Capture }),
|
|
};
|
|
nextInstructions.push(propsInstruction);
|
|
}
|
|
return { refProperty, keyProperty, propsProperty };
|
|
}
|
|
function handlePlace(place, blockId, inlinedJsxDeclarations) {
|
|
const inlinedJsxDeclaration = inlinedJsxDeclarations.get(place.identifier.declarationId);
|
|
if (inlinedJsxDeclaration == null ||
|
|
inlinedJsxDeclaration.blockIdsToIgnore.has(blockId)) {
|
|
return place;
|
|
}
|
|
return Object.assign(Object.assign({}, place), { identifier: inlinedJsxDeclaration.identifier });
|
|
}
|
|
function handlelValue(lvalue, blockId, inlinedJsxDeclarations) {
|
|
const inlinedJsxDeclaration = inlinedJsxDeclarations.get(lvalue.identifier.declarationId);
|
|
if (inlinedJsxDeclaration == null ||
|
|
inlinedJsxDeclaration.blockIdsToIgnore.has(blockId)) {
|
|
return lvalue;
|
|
}
|
|
return Object.assign(Object.assign({}, lvalue), { identifier: inlinedJsxDeclaration.identifier });
|
|
}
|
|
function handleIdentifier(identifier, inlinedJsxDeclarations) {
|
|
const inlinedJsxDeclaration = inlinedJsxDeclarations.get(identifier.declarationId);
|
|
return inlinedJsxDeclaration == null
|
|
? identifier
|
|
: inlinedJsxDeclaration.identifier;
|
|
}
|
|
|
|
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.',
|
|
description: null,
|
|
suggestions: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
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$a(), new Set());
|
|
}
|
|
let Visitor$a = 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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: stmt.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
var _Context_nextScheduleId, _Context_scheduled, _Context_catchHandlers, _Context_controlFlowStack;
|
|
function buildReactiveFunction(fn) {
|
|
const cx = new Context$3(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;
|
|
}
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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 initBlock = this.cx.ir.blocks.get(init.block);
|
|
let initValue = init.value;
|
|
if (initValue.kind === 'SequenceExpression') {
|
|
const last = initBlock.instructions.at(-1);
|
|
initValue.instructions.push(last);
|
|
initValue.value = {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
else {
|
|
initValue = {
|
|
kind: 'SequenceExpression',
|
|
instructions: [initBlock.instructions.at(-1)],
|
|
id: terminal.id,
|
|
loc: terminal.loc,
|
|
value: {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: 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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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 initBlock = this.cx.ir.blocks.get(init.block);
|
|
let initValue = init.value;
|
|
if (initValue.kind === 'SequenceExpression') {
|
|
const last = initBlock.instructions.at(-1);
|
|
initValue.instructions.push(last);
|
|
initValue.value = {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
else {
|
|
initValue = {
|
|
kind: 'SequenceExpression',
|
|
instructions: [initBlock.instructions.at(-1)],
|
|
id: terminal.id,
|
|
loc: terminal.loc,
|
|
value: {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: terminal.loc,
|
|
},
|
|
};
|
|
}
|
|
const test = this.visitValueBlock(terminal.test, terminal.loc);
|
|
const testBlock = this.cx.ir.blocks.get(test.block);
|
|
let testValue = test.value;
|
|
if (testValue.kind === 'SequenceExpression') {
|
|
const last = testBlock.instructions.at(-1);
|
|
testValue.instructions.push(last);
|
|
testValue.value = {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
else {
|
|
testValue = {
|
|
kind: 'SequenceExpression',
|
|
instructions: [testBlock.instructions.at(-1)],
|
|
id: terminal.id,
|
|
loc: terminal.loc,
|
|
value: {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: 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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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 initBlock = this.cx.ir.blocks.get(init.block);
|
|
let initValue = init.value;
|
|
if (initValue.kind === 'SequenceExpression') {
|
|
const last = initBlock.instructions.at(-1);
|
|
initValue.instructions.push(last);
|
|
initValue.value = {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: terminal.loc,
|
|
};
|
|
}
|
|
else {
|
|
initValue = {
|
|
kind: 'SequenceExpression',
|
|
instructions: [initBlock.instructions.at(-1)],
|
|
id: terminal.id,
|
|
loc: terminal.loc,
|
|
value: {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: 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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
default: {
|
|
assertExhaustive$1(terminal, 'Unexpected terminal');
|
|
}
|
|
}
|
|
}
|
|
visitValueBlock(id, loc) {
|
|
const defaultBlock = this.cx.ir.blocks.get(id);
|
|
if (defaultBlock.terminal.kind === 'branch') {
|
|
const instructions = defaultBlock.instructions;
|
|
if (instructions.length === 0) {
|
|
return {
|
|
block: defaultBlock.id,
|
|
place: defaultBlock.terminal.test,
|
|
value: {
|
|
kind: 'LoadLocal',
|
|
place: defaultBlock.terminal.test,
|
|
loc: defaultBlock.terminal.test.loc,
|
|
},
|
|
id: defaultBlock.terminal.id,
|
|
};
|
|
}
|
|
else if (defaultBlock.instructions.length === 1) {
|
|
const instr = defaultBlock.instructions[0];
|
|
CompilerError.invariant(instr.lvalue.identifier.id ===
|
|
defaultBlock.terminal.test.identifier.id, {
|
|
reason: 'Expected branch block to end in an instruction that sets the test value',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.lvalue.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
return {
|
|
block: defaultBlock.id,
|
|
place: instr.lvalue,
|
|
value: instr.value,
|
|
id: instr.id,
|
|
};
|
|
}
|
|
else {
|
|
const instr = defaultBlock.instructions.at(-1);
|
|
const sequence = {
|
|
kind: 'SequenceExpression',
|
|
instructions: defaultBlock.instructions.slice(0, -1),
|
|
id: instr.id,
|
|
value: instr.value,
|
|
loc: loc,
|
|
};
|
|
return {
|
|
block: defaultBlock.id,
|
|
place: defaultBlock.terminal.test,
|
|
value: sequence,
|
|
id: defaultBlock.terminal.id,
|
|
};
|
|
}
|
|
}
|
|
else if (defaultBlock.terminal.kind === 'goto') {
|
|
const instructions = defaultBlock.instructions;
|
|
if (instructions.length === 0) {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Expected goto value block to have at least one instruction',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
else if (defaultBlock.instructions.length === 1) {
|
|
const instr = defaultBlock.instructions[0];
|
|
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,
|
|
};
|
|
}
|
|
return {
|
|
block: defaultBlock.id,
|
|
place,
|
|
value,
|
|
id: instr.id,
|
|
};
|
|
}
|
|
else {
|
|
const instr = defaultBlock.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,
|
|
};
|
|
}
|
|
const sequence = {
|
|
kind: 'SequenceExpression',
|
|
instructions: defaultBlock.instructions.slice(0, -1),
|
|
id: instr.id,
|
|
value,
|
|
loc: loc,
|
|
};
|
|
return {
|
|
block: defaultBlock.id,
|
|
place,
|
|
value: sequence,
|
|
id: instr.id,
|
|
};
|
|
}
|
|
}
|
|
else {
|
|
const init = this.visitValueBlockTerminal(defaultBlock.terminal);
|
|
const final = this.visitValueBlock(init.fallthrough, loc);
|
|
const sequence = {
|
|
kind: 'SequenceExpression',
|
|
instructions: [
|
|
...defaultBlock.instructions,
|
|
{
|
|
id: init.id,
|
|
loc,
|
|
lvalue: init.place,
|
|
value: init.value,
|
|
},
|
|
],
|
|
id: final.id,
|
|
value: final.value,
|
|
loc,
|
|
};
|
|
return {
|
|
block: init.fallthrough,
|
|
value: sequence,
|
|
place: final.place,
|
|
id: final.id,
|
|
};
|
|
}
|
|
}
|
|
visitValueBlockTerminal(terminal) {
|
|
switch (terminal.kind) {
|
|
case 'sequence': {
|
|
const block = this.visitValueBlock(terminal.block, terminal.loc);
|
|
return {
|
|
value: block.value,
|
|
place: block.place,
|
|
fallthrough: terminal.fallthrough,
|
|
id: terminal.id,
|
|
};
|
|
}
|
|
case 'optional': {
|
|
const test = this.visitValueBlock(terminal.test, terminal.loc);
|
|
const testBlock = this.cx.ir.blocks.get(test.block);
|
|
if (testBlock.terminal.kind !== 'branch') {
|
|
CompilerError.throwTodo({
|
|
reason: `Unexpected terminal kind \`${testBlock.terminal.kind}\` for optional test block`,
|
|
description: null,
|
|
loc: testBlock.terminal.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
const consequent = this.visitValueBlock(testBlock.terminal.consequent, terminal.loc);
|
|
const call = {
|
|
kind: 'SequenceExpression',
|
|
instructions: [
|
|
{
|
|
id: test.id,
|
|
loc: testBlock.terminal.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 = this.visitValueBlock(terminal.test, terminal.loc);
|
|
const testBlock = this.cx.ir.blocks.get(test.block);
|
|
if (testBlock.terminal.kind !== 'branch') {
|
|
CompilerError.throwTodo({
|
|
reason: `Unexpected terminal kind \`${testBlock.terminal.kind}\` for logical test block`,
|
|
description: null,
|
|
loc: testBlock.terminal.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
const leftFinal = this.visitValueBlock(testBlock.terminal.consequent, terminal.loc);
|
|
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(testBlock.terminal.alternate, terminal.loc);
|
|
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 = this.visitValueBlock(terminal.test, terminal.loc);
|
|
const testBlock = this.cx.ir.blocks.get(test.block);
|
|
if (testBlock.terminal.kind !== 'branch') {
|
|
CompilerError.throwTodo({
|
|
reason: `Unexpected terminal kind \`${testBlock.terminal.kind}\` for ternary test block`,
|
|
description: null,
|
|
loc: testBlock.terminal.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
const consequent = this.visitValueBlock(testBlock.terminal.consequent, terminal.loc);
|
|
const alternate = this.visitValueBlock(testBlock.terminal.alternate, terminal.loc);
|
|
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.throwTodo({
|
|
reason: `Support value blocks (conditional, logical, optional chaining, etc) within a try/catch statement`,
|
|
description: null,
|
|
loc: terminal.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
if (this.cx.scopeFallthroughs.has(target.block)) {
|
|
CompilerError.invariant(target.type === 'implicit', {
|
|
reason: 'Expected reactive scope to implicitly break to fallthrough',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
return {
|
|
kind: 'terminal',
|
|
terminal: {
|
|
kind: 'continue',
|
|
loc,
|
|
target: target.block,
|
|
id,
|
|
targetKind: target.type,
|
|
},
|
|
label: null,
|
|
};
|
|
}
|
|
}
|
|
let Context$3 = 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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
__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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
__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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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$2(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 compileResult = codegenReactiveFunction(cx, fn);
|
|
if (compileResult.isErr()) {
|
|
return compileResult;
|
|
}
|
|
const compiled = compileResult.unwrap();
|
|
const hookGuard = fn.env.config.enableEmitHookGuards;
|
|
if (hookGuard != null && fn.env.isInferredMemoEnabled) {
|
|
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.isInferredMemoEnabled) {
|
|
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()) {
|
|
return assertResult;
|
|
}
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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$2(cx.env, (_c = reactiveFunction.id) !== null && _c !== void 0 ? _c : '[[ anonymous ]]', identifiers, cx.fbtOperands), reactiveFunction);
|
|
if (codegen.isErr()) {
|
|
return codegen;
|
|
}
|
|
outlined.push({ fn: codegen.unwrap(), type });
|
|
}
|
|
compiled.outlined = outlined;
|
|
return compileResult;
|
|
}
|
|
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();
|
|
}
|
|
}
|
|
if (cx.errors.hasAnyErrors()) {
|
|
return Err(cx.errors);
|
|
}
|
|
const countMemoBlockVisitor = new CountMemoBlockVisitor(fn.env);
|
|
visitReactiveFunction(fn, countMemoBlockVisitor, undefined);
|
|
return Ok({
|
|
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: [],
|
|
hasFireRewrite: fn.env.hasFireRewrite,
|
|
hasInferredEffect: fn.env.hasInferredEffect,
|
|
inferredEffectLocations: fn.env.inferredEffectLocations,
|
|
});
|
|
}
|
|
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$2 = class Context {
|
|
constructor(env, fnName, uniqueIdentifiers, fbtOperands, temporaries = null) {
|
|
_Context_nextCacheIndex.set(this, 0);
|
|
_Context_declarations.set(this, new Set());
|
|
this.errors = new CompilerError();
|
|
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();
|
|
}
|
|
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',
|
|
description: null,
|
|
suggestions: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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 wrapCacheDep(cx, value) {
|
|
if (cx.env.config.enableEmitFreeze != null && cx.env.isInferredMemoEnabled) {
|
|
const emitFreezeIdentifier = cx.env.programContext.addImportSpecifier(cx.env.config.enableEmitFreeze).name;
|
|
cx.env.programContext
|
|
.assertGlobalBinding(EMIT_FREEZE_GLOBAL_GATING, cx.env.scope)
|
|
.unwrap();
|
|
return libExports$1.conditionalExpression(libExports$1.identifier(EMIT_FREEZE_GLOBAL_GATING), libExports$1.callExpression(libExports$1.identifier(emitFreezeIdentifier), [
|
|
value,
|
|
libExports$1.stringLiteral(cx.fnName),
|
|
]), value);
|
|
}
|
|
else {
|
|
return value;
|
|
}
|
|
}
|
|
function codegenReactiveScope(cx, statements, scope, block) {
|
|
const cacheStoreStatements = [];
|
|
const cacheLoadStatements = [];
|
|
const cacheLoads = [];
|
|
const changeExpressions = [];
|
|
const changeExpressionComments = [];
|
|
const outputComments = [];
|
|
for (const dep of [...scope.dependencies].sort(compareScopeDependency)) {
|
|
const index = cx.nextCacheIndex;
|
|
changeExpressionComments.push(printDependencyComment(dep));
|
|
const comparison = libExports$1.binaryExpression('!==', libExports$1.memberExpression(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.numericLiteral(index), true), codegenDependency(cx, dep));
|
|
if (cx.env.config.enableChangeVariableCodegen) {
|
|
const changeIdentifier = libExports$1.identifier(cx.synthesizeName(`c_${index}`));
|
|
statements.push(libExports$1.variableDeclaration('const', [
|
|
libExports$1.variableDeclarator(changeIdentifier, comparison),
|
|
]));
|
|
changeExpressions.push(changeIdentifier);
|
|
}
|
|
else {
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
const name = convertIdentifier(identifier);
|
|
outputComments.push(name.name);
|
|
if (!cx.hasDeclared(identifier)) {
|
|
statements.push(libExports$1.variableDeclaration('let', [libExports$1.variableDeclarator(name)]));
|
|
}
|
|
cacheLoads.push({ name, index, value: wrapCacheDep(cx, name) });
|
|
cx.declare(identifier);
|
|
}
|
|
for (const reassignment of scope.reassignments) {
|
|
const index = cx.nextCacheIndex;
|
|
if (firstOutputIndex === null) {
|
|
firstOutputIndex = index;
|
|
}
|
|
const name = convertIdentifier(reassignment);
|
|
outputComments.push(name.name);
|
|
cacheLoads.push({ name, index, value: wrapCacheDep(cx, 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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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)]));
|
|
}
|
|
if (cx.env.config.disableMemoizationForDebugging) {
|
|
CompilerError.invariant(cx.env.config.enableChangeDetectionForDebugging == null, {
|
|
reason: `Expected to not have both change detection enabled and memoization disabled`,
|
|
description: `Incompatible config options`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
testCondition = libExports$1.logicalExpression('||', testCondition, libExports$1.booleanLiteral(true));
|
|
}
|
|
let computationBlock = codegenBlock(cx, block);
|
|
let memoStatement;
|
|
const detectionFunction = cx.env.config.enableChangeDetectionForDebugging;
|
|
if (detectionFunction != null && changeExpressions.length > 0) {
|
|
const loc = typeof scope.loc === 'symbol'
|
|
? 'unknown location'
|
|
: `(${scope.loc.start.line}:${scope.loc.end.line})`;
|
|
const importedDetectionFunctionIdentifier = cx.env.programContext.addImportSpecifier(detectionFunction).name;
|
|
const cacheLoadOldValueStatements = [];
|
|
const changeDetectionStatements = [];
|
|
const idempotenceDetectionStatements = [];
|
|
for (const { name, index, value } of cacheLoads) {
|
|
const loadName = cx.synthesizeName(`old$${name.name}`);
|
|
const slot = libExports$1.memberExpression(libExports$1.identifier(cx.synthesizeName('$')), libExports$1.numericLiteral(index), true);
|
|
cacheStoreStatements.push(libExports$1.expressionStatement(libExports$1.assignmentExpression('=', slot, value)));
|
|
cacheLoadOldValueStatements.push(libExports$1.variableDeclaration('let', [
|
|
libExports$1.variableDeclarator(libExports$1.identifier(loadName), slot),
|
|
]));
|
|
changeDetectionStatements.push(libExports$1.expressionStatement(libExports$1.callExpression(libExports$1.identifier(importedDetectionFunctionIdentifier), [
|
|
libExports$1.identifier(loadName),
|
|
libExports$1.cloneNode(name, true),
|
|
libExports$1.stringLiteral(name.name),
|
|
libExports$1.stringLiteral(cx.fnName),
|
|
libExports$1.stringLiteral('cached'),
|
|
libExports$1.stringLiteral(loc),
|
|
])));
|
|
idempotenceDetectionStatements.push(libExports$1.expressionStatement(libExports$1.callExpression(libExports$1.identifier(importedDetectionFunctionIdentifier), [
|
|
libExports$1.cloneNode(slot, true),
|
|
libExports$1.cloneNode(name, true),
|
|
libExports$1.stringLiteral(name.name),
|
|
libExports$1.stringLiteral(cx.fnName),
|
|
libExports$1.stringLiteral('recomputed'),
|
|
libExports$1.stringLiteral(loc),
|
|
])));
|
|
idempotenceDetectionStatements.push(libExports$1.expressionStatement(libExports$1.assignmentExpression('=', name, slot)));
|
|
}
|
|
const condition = cx.synthesizeName('condition');
|
|
const recomputationBlock = libExports$1.cloneNode(computationBlock, true);
|
|
memoStatement = libExports$1.blockStatement([
|
|
...computationBlock.body,
|
|
libExports$1.variableDeclaration('let', [
|
|
libExports$1.variableDeclarator(libExports$1.identifier(condition), testCondition),
|
|
]),
|
|
libExports$1.ifStatement(libExports$1.unaryExpression('!', libExports$1.identifier(condition)), libExports$1.blockStatement([
|
|
...cacheLoadOldValueStatements,
|
|
...changeDetectionStatements,
|
|
])),
|
|
...cacheStoreStatements,
|
|
libExports$1.ifStatement(libExports$1.identifier(condition), libExports$1.blockStatement([
|
|
...recomputationBlock.body,
|
|
...idempotenceDetectionStatements,
|
|
])),
|
|
]);
|
|
}
|
|
else {
|
|
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));
|
|
}
|
|
if (cx.env.config.enableMemoizationComments) {
|
|
if (changeExpressionComments.length) {
|
|
libExports$1.addComment(memoStatement, 'leading', ` check if ${printDelimitedCommentList(changeExpressionComments, 'or')} changed`, true);
|
|
libExports$1.addComment(memoStatement, 'leading', ` "useMemo" for ${printDelimitedCommentList(outputComments, 'and')}:`, true);
|
|
}
|
|
else {
|
|
libExports$1.addComment(memoStatement, 'leading', ' cache value with no dependencies', true);
|
|
libExports$1.addComment(memoStatement, 'leading', ` "useMemo" for ${printDelimitedCommentList(outputComments, 'and')}:`, true);
|
|
}
|
|
if (computationBlock.body.length > 0) {
|
|
libExports$1.addComment(computationBlock.body[0], 'leading', ` Inputs changed, recompute`, true);
|
|
}
|
|
if (cacheLoadStatements.length > 0) {
|
|
libExports$1.addComment(cacheLoadStatements[0], 'leading', ` Inputs did not change, use cached value`, true);
|
|
}
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: earlyReturnValue.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.init.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
if (terminal.init.instructions.length !== 2) {
|
|
CompilerError.throwTodo({
|
|
reason: 'Support non-trivial for..in inits',
|
|
description: null,
|
|
loc: terminal.init.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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': {
|
|
CompilerError.throwTodo({
|
|
reason: 'Support non-trivial for..in inits',
|
|
description: null,
|
|
loc: terminal.init.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
default:
|
|
CompilerError.invariant(false, {
|
|
reason: `Expected a StoreLocal or Destructure to be assigned to the collection`,
|
|
description: `Found ${iterableItem.value.kind}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: iterableItem.value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: iterableItem.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: iterableItem.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.init.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.test.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
if (terminal.test.instructions.length !== 2) {
|
|
CompilerError.throwTodo({
|
|
reason: 'Support non-trivial for..of inits',
|
|
description: null,
|
|
loc: terminal.init.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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': {
|
|
CompilerError.throwTodo({
|
|
reason: 'Support non-trivial for..of inits',
|
|
description: null,
|
|
loc: terminal.init.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
default:
|
|
CompilerError.invariant(false, {
|
|
reason: `Expected a StoreLocal or Destructure to be assigned to the collection`,
|
|
description: `Found ${iterableItem.value.kind}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: iterableItem.value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: iterableItem.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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 libExports$1.returnStatement();
|
|
}
|
|
return libExports$1.returnStatement(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;
|
|
let hasReassign = false;
|
|
let hasDeclaration = false;
|
|
for (const place of eachPatternOperand(lvalue)) {
|
|
if (kind !== InstructionKind.Reassign &&
|
|
place.identifier.name === null) {
|
|
cx.temp.set(place.identifier.declarationId, null);
|
|
}
|
|
const isDeclared = cx.hasDeclared(place.identifier);
|
|
hasReassign || (hasReassign = isDeclared);
|
|
hasDeclaration || (hasDeclaration = !isDeclared);
|
|
}
|
|
if (hasReassign && hasDeclaration) {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Encountered a destructuring operation where some identifiers are already declared (reassignments) but others are not (declarations)',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
else if (hasReassign) {
|
|
kind = InstructionKind.Reassign;
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: `this is ${kind}`,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
return createVariableDeclaration(instr.loc, 'const', [
|
|
libExports$1.variableDeclarator(codegenLValue(cx, lvalue), value),
|
|
]);
|
|
}
|
|
case InstructionKind.Function: {
|
|
CompilerError.invariant(instr.lvalue === null, {
|
|
reason: `Function declaration cannot be referenced as an expression`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: `this is ${kind}`,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
const genLvalue = codegenLValue(cx, lvalue);
|
|
CompilerError.invariant(genLvalue.type === 'Identifier', {
|
|
reason: 'Expected an identifier as a function declaration lvalue',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: 'this is const',
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
return createVariableDeclaration(instr.loc, 'let', [
|
|
libExports$1.variableDeclarator(codegenLValue(cx, lvalue), value),
|
|
]);
|
|
}
|
|
case InstructionKind.Reassign: {
|
|
CompilerError.invariant(value !== null, {
|
|
reason: 'Expected a value for reassignment',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: init.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
description: `Got ${instr.type}`,
|
|
suggestions: null,
|
|
});
|
|
if (instr.kind === 'let') {
|
|
kind = 'let';
|
|
}
|
|
declarators.push(...instr.declarations);
|
|
}
|
|
});
|
|
CompilerError.invariant(declarators.length > 0, {
|
|
reason: 'Expected a variable declaration',
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: init.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
description: null,
|
|
suggestions: null,
|
|
});
|
|
return libExports$1.variableDeclaration(kind, declarators);
|
|
}
|
|
else {
|
|
return codegenInstructionValueToExpression(cx, init);
|
|
}
|
|
}
|
|
function printDependencyComment(dependency) {
|
|
const identifier = convertIdentifier(dependency.identifier);
|
|
let name = identifier.name;
|
|
if (dependency.path !== null) {
|
|
for (const path of dependency.path) {
|
|
name += `.${path.property}`;
|
|
}
|
|
}
|
|
return name;
|
|
}
|
|
function printDelimitedCommentList(items, finalCompletion) {
|
|
if (items.length === 2) {
|
|
return items.join(` ${finalCompletion} `);
|
|
}
|
|
else if (items.length <= 1) {
|
|
return items.join('');
|
|
}
|
|
let output = [];
|
|
for (let i = 0; i < items.length; i++) {
|
|
const item = items[i];
|
|
if (i < items.length - 2) {
|
|
output.push(`${item}, `);
|
|
}
|
|
else if (i === items.length - 2) {
|
|
output.push(`${item}, ${finalCompletion} `);
|
|
}
|
|
else {
|
|
output.push(item);
|
|
}
|
|
}
|
|
return output.join('');
|
|
}
|
|
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 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);
|
|
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.isInferredMemoEnabled) {
|
|
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', [
|
|
libExports$1.variableDeclarator(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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_a = optionalValue.callee.loc) !== null && _a !== void 0 ? _a : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_b = property.loc) !== null && _b !== void 0 ? _b : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}\``,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instrValue.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_c = memberExpr.loc) !== null && _c !== void 0 ? _c : null,
|
|
message: `Got: '${memberExpr.type}'`,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_d = memberExpr.loc) !== null && _d !== void 0 ? _d : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
const loweredFunc = method.loweredFunc;
|
|
const reactiveFunction = buildReactiveFunction(loweredFunc.func);
|
|
pruneUnusedLabels(reactiveFunction);
|
|
pruneUnusedLValues(reactiveFunction);
|
|
const fn = codegenReactiveFunction(new Context$2(cx.env, (_e = reactiveFunction.id) !== null && _e !== void 0 ? _e : '[[ anonymous ]]', cx.uniqueIdentifiers, cx.fbtOperands, cx.temp), reactiveFunction).unwrap();
|
|
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}\``,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_f = tagValue.loc) !== null && _f !== void 0 ? _f : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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, {
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instrValue.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
reason: 'Expected fbt element to have children',
|
|
suggestions: null,
|
|
description: null,
|
|
});
|
|
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$2(cx.env, (_g = reactiveFunction.id) !== null && _g !== void 0 ? _g : '[[ anonymous ]]', cx.uniqueIdentifiers, cx.fbtOperands, cx.temp), reactiveFunction).unwrap();
|
|
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.errors.push({
|
|
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.errors.push({
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instrValue.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instrValue.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_a = expr.loc) !== null && _a !== void 0 ? _a : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_b = expr.object.loc) !== null && _b !== void 0 ? _b : null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: key.name.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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 = libExports$1.arrayPattern([]);
|
|
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 libExports$1.arrayPattern(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 libExports$1.objectPattern(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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
description: `identifier ${identifier.id} is unnamed`,
|
|
suggestions: null,
|
|
});
|
|
return libExports$1.identifier(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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: a.identifier.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: a.identifier.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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$9(), state);
|
|
}
|
|
let State$1 = class State {
|
|
constructor(env) {
|
|
this.declared = new Set();
|
|
this.env = env;
|
|
}
|
|
};
|
|
let Visitor$9 = 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);
|
|
if (instruction.value.kind === 'Destructure') {
|
|
const transformed = transformDestructuring(state, instruction, instruction.value);
|
|
if (transformed) {
|
|
return {
|
|
kind: 'replace-many',
|
|
value: transformed.map(instruction => ({
|
|
kind: 'instruction',
|
|
instruction,
|
|
})),
|
|
};
|
|
}
|
|
}
|
|
return { kind: 'keep' };
|
|
}
|
|
};
|
|
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);
|
|
}
|
|
hasDeclaration || (hasDeclaration = !isDeclared);
|
|
}
|
|
if (reassigned.size === 0 || !hasDeclaration) {
|
|
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()',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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: [],
|
|
}))), 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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instruction.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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$8(), {
|
|
activeScopes: empty(),
|
|
uninitialized: new Map(),
|
|
});
|
|
}
|
|
let Visitor$8 = 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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instruction.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: fn.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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$1(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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: fn.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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 Ok(undefined);
|
|
}
|
|
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;
|
|
}
|
|
let Context$1 = 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') {
|
|
const handlerParam = context.catchHandlers.get(terminal.handler);
|
|
if (handlerParam != null) {
|
|
CompilerError.invariant(state.kind(handlerParam) != null, {
|
|
reason: 'Expected catch binding to be intialized with a DeclareLocal Catch instruction',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instruction.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: effect.into.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: effect.into.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: effect.into.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: effect.into.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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.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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: effect.into.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
__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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: 'this is uninitialized',
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: 'this is uninitialized',
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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)}\``,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: value.loc,
|
|
message: 'Expected value for identifier to be initialized',
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
__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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: value.loc,
|
|
message: 'Expected value for identifier to be initialized',
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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),
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: value.loc,
|
|
message: 'Expected value for identifier to be initialized',
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
__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.isInferredMemoEnabled) {
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}\``,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: stmt.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: reassignment.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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$7 = 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$7();
|
|
const state = new Set();
|
|
visitReactiveFunction(fn, visitor, state);
|
|
return state;
|
|
}
|
|
|
|
function pruneNonReactiveDependencies(fn) {
|
|
const reactiveIdentifiers = collectReactiveIdentifiers(fn);
|
|
visitReactiveFunction(fn, new Visitor$6(), reactiveIdentifiers);
|
|
}
|
|
let Visitor$6 = 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$5(), lvalues);
|
|
for (const [, instr] of lvalues) {
|
|
instr.lvalue = null;
|
|
}
|
|
}
|
|
let Visitor$5 = 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$4(), identifiers);
|
|
return identifiers;
|
|
}
|
|
let Visitor$4 = 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$3(), 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$3 = 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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
_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 errors = new CompilerError();
|
|
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') {
|
|
errors.pushDiagnostic(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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: block.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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, errors);
|
|
}
|
|
for (const render of renders) {
|
|
state.render(render.index, render.place.identifier, errors);
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: effect.function.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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 = [];
|
|
const ignoredErrors = new CompilerError();
|
|
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, ignoredErrors);
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: into.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (errors.hasAnyErrors() && !isFunctionExpression) {
|
|
return Err(errors);
|
|
}
|
|
return Ok(functionEffects);
|
|
}
|
|
function appendFunctionErrors(errors, fn) {
|
|
var _a;
|
|
for (const effect of (_a = fn.aliasingEffects) !== null && _a !== void 0 ? _a : []) {
|
|
switch (effect.kind) {
|
|
case 'Impure':
|
|
case 'MutateFrozen':
|
|
case 'MutateGlobal': {
|
|
errors.pushDiagnostic(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, errors) {
|
|
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(errors, 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, errors) {
|
|
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(errors, 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,
|
|
}).unwrap();
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: effect.function.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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: [],
|
|
};
|
|
}
|
|
case 'PropertyLoad': {
|
|
const object = maybeDeps.get(value.object.identifier.id);
|
|
if (object != null) {
|
|
return {
|
|
root: object.root,
|
|
path: [...object.path, { property: value.property, optional }],
|
|
};
|
|
}
|
|
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),
|
|
},
|
|
path: [],
|
|
};
|
|
}
|
|
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, 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, memoDecl, manualMemoId) {
|
|
return [
|
|
{
|
|
id: makeInstructionId(0),
|
|
lvalue: createTemporaryPlace(env, fnExpr.loc),
|
|
value: {
|
|
kind: 'StartMemoize',
|
|
manualMemoId,
|
|
deps: depsList,
|
|
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, errors) {
|
|
const [fnPlace, depsListPlace] = instr.value.args;
|
|
if (fnPlace == null) {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.UseMemo,
|
|
reason: `Expected a callback function to be passed to ${kind}`,
|
|
description: `Expected a callback function to be passed to ${kind}`,
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: `Expected a callback function to be passed to ${kind}`,
|
|
}));
|
|
return { fnPlace: null, depsList: null };
|
|
}
|
|
if (fnPlace.kind === 'Spread' || (depsListPlace === null || depsListPlace === void 0 ? void 0 : depsListPlace.kind) === 'Spread') {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.UseMemo,
|
|
reason: `Unexpected spread argument to ${kind}`,
|
|
description: `Unexpected spread argument to ${kind}`,
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: `Unexpected spread argument to ${kind}`,
|
|
}));
|
|
return { fnPlace: null, depsList: null };
|
|
}
|
|
let depsList = null;
|
|
if (depsListPlace != null) {
|
|
const maybeDepsList = sidemap.maybeDepsLists.get(depsListPlace.identifier.id);
|
|
if (maybeDepsList == null) {
|
|
errors.pushDiagnostic(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.loc,
|
|
message: `Expected the dependency list for ${kind} to be an array literal`,
|
|
}));
|
|
return { fnPlace, depsList: null };
|
|
}
|
|
depsList = [];
|
|
for (const dep of maybeDepsList) {
|
|
const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
|
|
if (maybeDep == null) {
|
|
errors.pushDiagnostic(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,
|
|
};
|
|
}
|
|
function dropManualMemoization(func) {
|
|
const errors = new CompilerError();
|
|
const isValidationEnabled = func.env.config.validatePreserveExistingMemoizationGuarantees ||
|
|
func.env.config.validateNoSetStateInRender ||
|
|
func.env.config.enablePreserveExistingMemoizationGuarantees;
|
|
const optionals = findOptionalPlaces(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 { fnPlace, depsList } = extractManualMemoizationArgs(instr, manualMemo.kind, sidemap, errors);
|
|
if (fnPlace == null) {
|
|
continue;
|
|
}
|
|
instr.value = getManualMemoizationReplacement(fnPlace, instr.value.loc, manualMemo.kind);
|
|
if (isValidationEnabled) {
|
|
if (!sidemap.functions.has(fnPlace.identifier.id)) {
|
|
errors.pushDiagnostic(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, 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);
|
|
}
|
|
}
|
|
return errors.asResult();
|
|
}
|
|
function findOptionalPlaces(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;
|
|
}
|
|
default: {
|
|
CompilerError.invariant(false, {
|
|
reason: `Unexpected terminal in optional`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: `Unexpected ${terminal.kind} in optional`,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return optionals;
|
|
}
|
|
|
|
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 postDominators = computePostDominatorTree(fn, {
|
|
includeThrowsAsExitNode: false,
|
|
});
|
|
const postDominatorFrontierCache = new Map();
|
|
function isReactiveControlledBlock(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 (reactiveIdentifiers.isReactive(controlBlock.terminal.test)) {
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
case 'switch': {
|
|
if (reactiveIdentifiers.isReactive(controlBlock.terminal.test)) {
|
|
return true;
|
|
}
|
|
for (const case_ of controlBlock.terminal.cases) {
|
|
if (case_.test !== null &&
|
|
reactiveIdentifiers.isReactive(case_.test)) {
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: operand.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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);
|
|
}
|
|
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 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 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: fn.env.config.enableTreatFunctionDepsAsConditional
|
|
? new Set()
|
|
: getAssumedInvokedFunctions(fn),
|
|
});
|
|
}
|
|
function collectHoistablePropertyLoadsInInnerFn(fnInstr, temporaries, hoistableFromOptionals) {
|
|
const fn = fnInstr.value.loweredFunc.func;
|
|
const initialContext = {
|
|
temporaries,
|
|
knownImmutableIdentifiers: new Set(),
|
|
hoistableFromOptionals,
|
|
registry: new PropertyPathRegistry(),
|
|
nestedFnImmutableContext: null,
|
|
assumedInvokedFns: fn.env.config.enableTreatFunctionDepsAsConditional
|
|
? new Set()
|
|
: getAssumedInvokedFunctions(fn),
|
|
};
|
|
const nestedFnImmutableContext = new Set(fn.context
|
|
.filter(place => isImmutableAtInstr(place.identifier, fnInstr.id, initialContext))
|
|
.map(place => place.identifier.id));
|
|
initialContext.nestedFnImmutableContext = nestedFnImmutableContext;
|
|
return collectHoistablePropertyLoadsImpl(fn, initialContext);
|
|
}
|
|
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) {
|
|
let rootNode = this.roots.get(identifier.id);
|
|
if (rootNode === undefined) {
|
|
rootNode = {
|
|
root: identifier.id,
|
|
properties: new Map(),
|
|
optionalProperties: new Map(),
|
|
fullPath: {
|
|
identifier,
|
|
reactive,
|
|
path: [],
|
|
},
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: identifier.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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),
|
|
},
|
|
hasOptional: parent.hasOptional || entry.optional,
|
|
};
|
|
map.set(entry.property, child);
|
|
}
|
|
return child;
|
|
}
|
|
getOrCreateProperty(n) {
|
|
let currNode = this.getOrCreateIdentifier(n.identifier, n.reactive);
|
|
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(instr, context) {
|
|
var _a, _b, _c;
|
|
let path = null;
|
|
if (instr.kind === 'PropertyLoad') {
|
|
path = (_a = context.temporaries.get(instr.object.identifier.id)) !== null && _a !== void 0 ? _a : {
|
|
identifier: instr.object.identifier,
|
|
reactive: instr.object.reactive,
|
|
path: [],
|
|
};
|
|
}
|
|
else if (instr.kind === 'Destructure') {
|
|
path = (_b = context.temporaries.get(instr.value.identifier.id)) !== null && _b !== void 0 ? _b : null;
|
|
}
|
|
else if (instr.kind === 'ComputedLoad') {
|
|
path = (_c = context.temporaries.get(instr.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));
|
|
}
|
|
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,
|
|
});
|
|
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}`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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 } = original.fullPath;
|
|
let currNode = registry.getOrCreateIdentifier(identifier, reactive);
|
|
for (let i = 0; i < origPath.length; i++) {
|
|
const entry = origPath[i];
|
|
const nextEntry = entry.optional && nodes.has(currNode)
|
|
? { property: entry.property, optional: false }
|
|
: 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;
|
|
}
|
|
|
|
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)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: propertyLoad.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
CompilerError.invariant(storeLocal.value.identifier.id === propertyLoad.lvalue.identifier.id, {
|
|
reason: '[OptionalChainDeps] Unexpected storeLocal',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: propertyLoad.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
return {
|
|
consequentId: storeLocal.lvalue.place.identifier.id,
|
|
property: propertyLoad.value.property,
|
|
propertyId: propertyLoad.lvalue.identifier.id,
|
|
storeLocalInstr,
|
|
consequentGoto: consequentBlock.terminal.block,
|
|
};
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: optional.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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 });
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
CompilerError.invariant(maybeTest.terminal.test.identifier.id ===
|
|
maybeTest.instructions.at(-1).lvalue.identifier.id, {
|
|
reason: '[OptionalChainDeps] Unexpected test expression',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: maybeTest.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
baseObject = {
|
|
identifier: maybeTest.instructions[0].value.place.identifier,
|
|
reactive: maybeTest.instructions[0].value.place.reactive,
|
|
path,
|
|
};
|
|
test = maybeTest.terminal;
|
|
}
|
|
else if (maybeTest.terminal.kind === 'optional') {
|
|
const testBlock = context.blocks.get(maybeTest.terminal.fallthrough);
|
|
if (testBlock.terminal.kind !== 'branch') {
|
|
CompilerError.throwTodo({
|
|
reason: `Unexpected terminal kind \`${testBlock.terminal.kind}\` for optional fallthrough block`,
|
|
loc: maybeTest.terminal.loc,
|
|
});
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: optional.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: optional.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
const load = {
|
|
identifier: baseObject.identifier,
|
|
reactive: baseObject.reactive,
|
|
path: [
|
|
...baseObject.path,
|
|
{
|
|
property: matchConsequentResult.property,
|
|
optional: optional.terminal.optional,
|
|
},
|
|
],
|
|
};
|
|
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 _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 } 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');
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
let nextNode = currNode.properties.get(path[i].property);
|
|
if (nextNode == null) {
|
|
nextNode = {
|
|
properties: new Map(),
|
|
accessType,
|
|
};
|
|
currNode.properties.set(path[i].property, nextNode);
|
|
}
|
|
currNode = nextNode;
|
|
}
|
|
}
|
|
}
|
|
addDependency(dep) {
|
|
const { identifier, reactive, path } = dep;
|
|
let depCursor = __classPrivateFieldGet(_a, _a, "m", _ReactiveScopeDependencyTreeHIR_getOrCreateRoot).call(_a, identifier, reactive, __classPrivateFieldGet(this, _ReactiveScopeDependencyTreeHIR_deps, "f"), PropertyAccessType.UnconditionalAccess);
|
|
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);
|
|
}
|
|
else if (hoistableCursor != null &&
|
|
hoistableCursor.accessType === 'NonNull') {
|
|
nextHoistableCursor = hoistableCursor.properties.get(entry.property);
|
|
nextDepCursor = makeOrMergeProperty(depCursor, entry.property, PropertyAccessType.UnconditionalAccess);
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
depCursor = nextDepCursor;
|
|
hoistableCursor = nextHoistableCursor;
|
|
}
|
|
depCursor.accessType = merge$1(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) {
|
|
let rootNode = roots.get(identifier);
|
|
if (rootNode === undefined) {
|
|
rootNode = {
|
|
properties: new Map(),
|
|
reactive,
|
|
accessType: defaultAccessType,
|
|
};
|
|
roots.set(identifier, rootNode);
|
|
}
|
|
else {
|
|
CompilerError.invariant(reactive === rootNode.reactive, {
|
|
reason: '[DeriveMinimalDependenciesHIR] Conflicting reactive root flag',
|
|
description: `Identifier ${printIdentifier(identifier)}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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$1(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 });
|
|
}
|
|
else {
|
|
for (const [childName, childNode] of node.properties) {
|
|
collectMinimalDependenciesInSubtree(childNode, reactive, rootIdentifier, [
|
|
...path,
|
|
{
|
|
property: childName,
|
|
optional: isOptional(childNode.accessType),
|
|
},
|
|
], 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) {
|
|
let child = node.properties.get(property);
|
|
if (child == null) {
|
|
child = {
|
|
properties: new Map(),
|
|
accessType,
|
|
};
|
|
node.properties.set(property, child);
|
|
}
|
|
else {
|
|
child.accessType = merge$1(child.accessType, accessType);
|
|
}
|
|
return child;
|
|
}
|
|
|
|
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$1(fn, usedOutsideDeclaringScope);
|
|
const { temporariesReadInOptional, processedInstrsInOptional, hoistableObjects, } = collectOptionalChainSidemap(fn);
|
|
const hoistablePropertyLoads = keyByScopeId(fn, collectHoistablePropertyLoads(fn, temporaries, hoistableObjects));
|
|
const scopeDeps = collectDependencies(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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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$1(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, 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: [],
|
|
});
|
|
}
|
|
}
|
|
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, temporaries) {
|
|
const resolvedDependency = temporaries.get(object.identifier.id);
|
|
let property;
|
|
if (resolvedDependency == null) {
|
|
property = {
|
|
identifier: object.identifier,
|
|
reactive: object.reactive,
|
|
path: [{ property: propertyName, optional }],
|
|
};
|
|
}
|
|
else {
|
|
property = {
|
|
identifier: resolvedDependency.identifier,
|
|
reactive: resolvedDependency.reactive,
|
|
path: [...resolvedDependency.path, { property: propertyName, optional }],
|
|
};
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: scope.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
__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: [],
|
|
});
|
|
}
|
|
visitProperty(object, property, optional) {
|
|
const nextDependency = getProperty(object, property, optional, __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: [],
|
|
};
|
|
}
|
|
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: [],
|
|
})) {
|
|
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);
|
|
}
|
|
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(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 buildDependencyInstructions(dep, env) {
|
|
const builder = new HIRBuilder(env, {
|
|
entryBlockKind: 'value',
|
|
});
|
|
let dependencyValue;
|
|
if (dep.path.every(path => !path.optional)) {
|
|
dependencyValue = writeNonOptionalDependency(dep, env, builder);
|
|
}
|
|
else {
|
|
dependencyValue = writeOptionalDependency(dep, builder, null);
|
|
}
|
|
const exitBlockId = builder.terminate({
|
|
kind: 'unsupported',
|
|
loc: GeneratedSource,
|
|
id: makeInstructionId(0),
|
|
}, null);
|
|
return {
|
|
place: {
|
|
kind: 'Identifier',
|
|
identifier: dependencyValue,
|
|
effect: Effect.Freeze,
|
|
reactive: dep.reactive,
|
|
loc: GeneratedSource,
|
|
},
|
|
value: builder.build(),
|
|
exitBlockId,
|
|
};
|
|
}
|
|
function writeNonOptionalDependency(dep, env, builder) {
|
|
const loc = dep.identifier.loc;
|
|
let curr = makeTemporaryIdentifier(env.nextIdentifierId, loc);
|
|
builder.push({
|
|
lvalue: {
|
|
identifier: curr,
|
|
kind: 'Identifier',
|
|
effect: Effect.Mutate,
|
|
reactive: dep.reactive,
|
|
loc,
|
|
},
|
|
value: {
|
|
kind: 'LoadLocal',
|
|
place: {
|
|
identifier: dep.identifier,
|
|
kind: 'Identifier',
|
|
effect: Effect.Freeze,
|
|
reactive: dep.reactive,
|
|
loc,
|
|
},
|
|
loc,
|
|
},
|
|
id: makeInstructionId(1),
|
|
loc: loc,
|
|
effects: null,
|
|
});
|
|
for (const path of dep.path) {
|
|
const next = makeTemporaryIdentifier(env.nextIdentifierId, loc);
|
|
builder.push({
|
|
lvalue: {
|
|
identifier: next,
|
|
kind: 'Identifier',
|
|
effect: Effect.Mutate,
|
|
reactive: dep.reactive,
|
|
loc,
|
|
},
|
|
value: {
|
|
kind: 'PropertyLoad',
|
|
object: {
|
|
identifier: curr,
|
|
kind: 'Identifier',
|
|
effect: Effect.Freeze,
|
|
reactive: dep.reactive,
|
|
loc,
|
|
},
|
|
property: path.property,
|
|
loc,
|
|
},
|
|
id: makeInstructionId(1),
|
|
loc: loc,
|
|
effects: null,
|
|
});
|
|
curr = next;
|
|
}
|
|
return curr;
|
|
}
|
|
function writeOptionalDependency(dep, builder, parentAlternate) {
|
|
const env = builder.environment;
|
|
const dependencyValue = {
|
|
kind: 'Identifier',
|
|
identifier: makeTemporaryIdentifier(env.nextIdentifierId, GeneratedSource),
|
|
effect: Effect.Mutate,
|
|
reactive: dep.reactive,
|
|
loc: GeneratedSource,
|
|
};
|
|
const continuationBlock = builder.reserve(builder.currentBlockKind());
|
|
let alternate;
|
|
if (parentAlternate != null) {
|
|
alternate = parentAlternate;
|
|
}
|
|
else {
|
|
alternate = builder.enter('value', () => {
|
|
const temp = lowerValueToTemporary(builder, {
|
|
kind: 'Primitive',
|
|
value: undefined,
|
|
loc: GeneratedSource,
|
|
});
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, dependencyValue) },
|
|
value: Object.assign({}, temp),
|
|
type: null,
|
|
loc: GeneratedSource,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
variant: GotoVariant.Break,
|
|
block: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
};
|
|
});
|
|
}
|
|
const consequent = builder.reserve('value');
|
|
let testIdentifier = null;
|
|
const testBlock = builder.enter('value', () => {
|
|
const testDependency = Object.assign(Object.assign({}, dep), { path: dep.path.slice(0, dep.path.length - 1) });
|
|
const firstOptional = dep.path.findIndex(path => path.optional);
|
|
CompilerError.invariant(firstOptional !== -1, {
|
|
reason: '[ScopeDependencyUtils] Internal invariant broken: expected optional path',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: dep.identifier.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
if (firstOptional === dep.path.length - 1) {
|
|
testIdentifier = writeNonOptionalDependency(testDependency, env, builder);
|
|
}
|
|
else {
|
|
testIdentifier = writeOptionalDependency(testDependency, builder, alternate);
|
|
}
|
|
return {
|
|
kind: 'branch',
|
|
test: {
|
|
identifier: testIdentifier,
|
|
effect: Effect.Freeze,
|
|
kind: 'Identifier',
|
|
loc: GeneratedSource,
|
|
reactive: dep.reactive,
|
|
},
|
|
consequent: consequent.id,
|
|
alternate,
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
fallthrough: continuationBlock.id,
|
|
};
|
|
});
|
|
builder.enterReserved(consequent, () => {
|
|
CompilerError.invariant(testIdentifier !== null, {
|
|
reason: 'Satisfy type checker',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
lowerValueToTemporary(builder, {
|
|
kind: 'StoreLocal',
|
|
lvalue: { kind: InstructionKind.Const, place: Object.assign({}, dependencyValue) },
|
|
value: lowerValueToTemporary(builder, {
|
|
kind: 'PropertyLoad',
|
|
object: {
|
|
identifier: testIdentifier,
|
|
kind: 'Identifier',
|
|
effect: Effect.Freeze,
|
|
reactive: dep.reactive,
|
|
loc: GeneratedSource,
|
|
},
|
|
property: dep.path.at(-1).property,
|
|
loc: GeneratedSource,
|
|
}),
|
|
type: null,
|
|
loc: GeneratedSource,
|
|
});
|
|
return {
|
|
kind: 'goto',
|
|
variant: GotoVariant.Break,
|
|
block: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
};
|
|
});
|
|
builder.terminateWithContinuation({
|
|
kind: 'optional',
|
|
optional: dep.path.at(-1).optional,
|
|
test: testBlock,
|
|
fallthrough: continuationBlock.id,
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
}, continuationBlock);
|
|
return dependencyValue.identifier;
|
|
}
|
|
|
|
function inferEffectDependencies(fn) {
|
|
var _a, _b;
|
|
const fnExpressions = new Map();
|
|
const autodepFnConfigs = new Map();
|
|
for (const effectTarget of fn.env.config.inferEffectDependencies) {
|
|
const moduleTargets = getOrInsertWith(autodepFnConfigs, effectTarget.function.source, () => new Map());
|
|
moduleTargets.set(effectTarget.function.importSpecifierName, effectTarget.autodepsIndex);
|
|
}
|
|
const autodepFnLoads = new Map();
|
|
const autodepModuleLoads = new Map();
|
|
const scopeInfos = new Map();
|
|
const loadGlobals = new Set();
|
|
const reactiveIds = inferReactiveIdentifiers(fn);
|
|
const rewriteBlocks = [];
|
|
for (const [, block] of fn.body.blocks) {
|
|
if (block.terminal.kind === 'scope') {
|
|
const scopeBlock = fn.body.blocks.get(block.terminal.block);
|
|
if (scopeBlock.instructions.length === 1 &&
|
|
scopeBlock.terminal.kind === 'goto' &&
|
|
scopeBlock.terminal.block === block.terminal.fallthrough) {
|
|
scopeInfos.set(block.terminal.scope.id, block.terminal.scope.dependencies);
|
|
}
|
|
}
|
|
const rewriteInstrs = [];
|
|
for (const instr of block.instructions) {
|
|
const { value, lvalue } = instr;
|
|
if (value.kind === 'FunctionExpression') {
|
|
fnExpressions.set(lvalue.identifier.id, instr);
|
|
}
|
|
else if (value.kind === 'PropertyLoad') {
|
|
if (typeof value.property === 'string' &&
|
|
autodepModuleLoads.has(value.object.identifier.id)) {
|
|
const moduleTargets = autodepModuleLoads.get(value.object.identifier.id);
|
|
const propertyName = value.property;
|
|
const numRequiredArgs = moduleTargets.get(propertyName);
|
|
if (numRequiredArgs != null) {
|
|
autodepFnLoads.set(lvalue.identifier.id, numRequiredArgs);
|
|
}
|
|
}
|
|
}
|
|
else if (value.kind === 'LoadGlobal') {
|
|
loadGlobals.add(lvalue.identifier.id);
|
|
if (value.binding.kind === 'ImportNamespace') {
|
|
const moduleTargets = autodepFnConfigs.get(value.binding.module);
|
|
if (moduleTargets != null) {
|
|
autodepModuleLoads.set(lvalue.identifier.id, moduleTargets);
|
|
}
|
|
}
|
|
if (value.binding.kind === 'ImportSpecifier' ||
|
|
value.binding.kind === 'ImportDefault') {
|
|
const moduleTargets = autodepFnConfigs.get(value.binding.module);
|
|
if (moduleTargets != null) {
|
|
const importSpecifierName = value.binding.kind === 'ImportSpecifier'
|
|
? value.binding.imported
|
|
: DEFAULT_EXPORT;
|
|
const numRequiredArgs = moduleTargets.get(importSpecifierName);
|
|
if (numRequiredArgs != null) {
|
|
autodepFnLoads.set(lvalue.identifier.id, numRequiredArgs);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (value.kind === 'CallExpression' ||
|
|
value.kind === 'MethodCall') {
|
|
const callee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
const autodepsArgIndex = value.args.findIndex(arg => arg.kind === 'Identifier' &&
|
|
arg.identifier.type.kind === 'Object' &&
|
|
arg.identifier.type.shapeId === BuiltInAutodepsId);
|
|
const autodepsArgExpectedIndex = autodepFnLoads.get(callee.identifier.id);
|
|
if (value.args.length > 0 &&
|
|
autodepsArgExpectedIndex != null &&
|
|
autodepsArgIndex === autodepsArgExpectedIndex &&
|
|
autodepFnLoads.has(callee.identifier.id) &&
|
|
value.args[0].kind === 'Identifier') {
|
|
const effectDeps = [];
|
|
const deps = {
|
|
kind: 'ArrayExpression',
|
|
elements: effectDeps,
|
|
loc: GeneratedSource,
|
|
};
|
|
const depsPlace = createTemporaryPlace(fn.env, GeneratedSource);
|
|
depsPlace.effect = Effect.Read;
|
|
const fnExpr = fnExpressions.get(value.args[0].identifier.id);
|
|
if (fnExpr != null) {
|
|
const scopeInfo = fnExpr.lvalue.identifier.scope != null
|
|
? scopeInfos.get(fnExpr.lvalue.identifier.scope.id)
|
|
: null;
|
|
let minimalDeps;
|
|
if (scopeInfo != null) {
|
|
minimalDeps = new Set(scopeInfo);
|
|
}
|
|
else {
|
|
minimalDeps = inferMinimalDependencies(fnExpr);
|
|
}
|
|
const usedDeps = [];
|
|
for (const maybeDep of minimalDeps) {
|
|
if (((isUseRefType(maybeDep.identifier) ||
|
|
isSetStateType(maybeDep.identifier)) &&
|
|
!reactiveIds.has(maybeDep.identifier.id)) ||
|
|
isFireFunctionType(maybeDep.identifier) ||
|
|
isEffectEventFunctionType(maybeDep.identifier)) {
|
|
continue;
|
|
}
|
|
const dep = truncateDepAtCurrent(maybeDep);
|
|
const { place, value, exitBlockId } = buildDependencyInstructions(dep, fn.env);
|
|
rewriteInstrs.push({
|
|
kind: 'block',
|
|
location: instr.id,
|
|
value,
|
|
exitBlockId: exitBlockId,
|
|
});
|
|
effectDeps.push(place);
|
|
usedDeps.push(dep);
|
|
}
|
|
const decorations = [];
|
|
for (const loc of collectDepUsages(usedDeps, fnExpr.value)) {
|
|
if (typeof loc === 'symbol') {
|
|
continue;
|
|
}
|
|
decorations.push(loc);
|
|
}
|
|
if (typeof value.loc !== 'symbol') {
|
|
(_a = fn.env.logger) === null || _a === void 0 ? void 0 : _a.logEvent(fn.env.filename, {
|
|
kind: 'AutoDepsDecorations',
|
|
fnLoc: value.loc,
|
|
decorations,
|
|
});
|
|
}
|
|
rewriteInstrs.push({
|
|
kind: 'instr',
|
|
location: instr.id,
|
|
value: {
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
lvalue: Object.assign(Object.assign({}, depsPlace), { effect: Effect.Mutate }),
|
|
value: deps,
|
|
effects: null,
|
|
},
|
|
});
|
|
value.args[autodepsArgIndex] = Object.assign(Object.assign({}, depsPlace), { effect: Effect.Freeze });
|
|
fn.env.inferredEffectLocations.add(callee.loc);
|
|
}
|
|
else if (loadGlobals.has(value.args[0].identifier.id)) {
|
|
rewriteInstrs.push({
|
|
kind: 'instr',
|
|
location: instr.id,
|
|
value: {
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
lvalue: Object.assign(Object.assign({}, depsPlace), { effect: Effect.Mutate }),
|
|
value: deps,
|
|
effects: null,
|
|
},
|
|
});
|
|
value.args[autodepsArgIndex] = Object.assign(Object.assign({}, depsPlace), { effect: Effect.Freeze });
|
|
fn.env.inferredEffectLocations.add(callee.loc);
|
|
}
|
|
}
|
|
else if (value.args.length >= 2 &&
|
|
value.args.length - 1 === autodepFnLoads.get(callee.identifier.id) &&
|
|
value.args[0] != null &&
|
|
value.args[0].kind === 'Identifier') {
|
|
const penultimateArg = value.args[value.args.length - 2];
|
|
const depArrayArg = value.args[value.args.length - 1];
|
|
if (depArrayArg.kind !== 'Spread' &&
|
|
penultimateArg.kind !== 'Spread' &&
|
|
typeof depArrayArg.loc !== 'symbol' &&
|
|
typeof penultimateArg.loc !== 'symbol' &&
|
|
typeof value.loc !== 'symbol') {
|
|
(_b = fn.env.logger) === null || _b === void 0 ? void 0 : _b.logEvent(fn.env.filename, {
|
|
kind: 'AutoDepsEligible',
|
|
fnLoc: value.loc,
|
|
depArrayLoc: Object.assign(Object.assign({}, depArrayArg.loc), { start: penultimateArg.loc.end, end: depArrayArg.loc.end }),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
rewriteSplices(block, rewriteInstrs, rewriteBlocks);
|
|
}
|
|
if (rewriteBlocks.length > 0) {
|
|
for (const block of rewriteBlocks) {
|
|
fn.body.blocks.set(block.id, block);
|
|
}
|
|
reversePostorderBlocks(fn.body);
|
|
markPredecessors(fn.body);
|
|
markInstructionIds(fn.body);
|
|
fixScopeAndIdentifierRanges(fn.body);
|
|
deadCodeElimination(fn);
|
|
fn.env.hasInferredEffect = true;
|
|
}
|
|
}
|
|
function truncateDepAtCurrent(dep) {
|
|
const idx = dep.path.findIndex(path => path.property === 'current');
|
|
if (idx === -1) {
|
|
return dep;
|
|
}
|
|
else {
|
|
return Object.assign(Object.assign({}, dep), { path: dep.path.slice(0, idx) });
|
|
}
|
|
}
|
|
function rewriteSplices(originalBlock, splices, rewriteBlocks) {
|
|
if (splices.length === 0) {
|
|
return;
|
|
}
|
|
const originalInstrs = originalBlock.instructions;
|
|
let currBlock = Object.assign(Object.assign({}, originalBlock), { instructions: [] });
|
|
rewriteBlocks.push(currBlock);
|
|
let cursor = 0;
|
|
for (const rewrite of splices) {
|
|
while (originalInstrs[cursor].id < rewrite.location) {
|
|
CompilerError.invariant(originalInstrs[cursor].id < originalInstrs[cursor + 1].id, {
|
|
reason: '[InferEffectDependencies] Internal invariant broken: expected block instructions to be sorted',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: originalInstrs[cursor].loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
currBlock.instructions.push(originalInstrs[cursor]);
|
|
cursor++;
|
|
}
|
|
CompilerError.invariant(originalInstrs[cursor].id === rewrite.location, {
|
|
reason: '[InferEffectDependencies] Internal invariant broken: splice location not found',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: originalInstrs[cursor].loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
if (rewrite.kind === 'instr') {
|
|
currBlock.instructions.push(rewrite.value);
|
|
}
|
|
else if (rewrite.kind === 'block') {
|
|
const { entry, blocks } = rewrite.value;
|
|
const entryBlock = blocks.get(entry);
|
|
currBlock.instructions.push(...entryBlock.instructions);
|
|
if (blocks.size > 1) {
|
|
CompilerError.invariant(terminalFallthrough(entryBlock.terminal) === rewrite.exitBlockId, {
|
|
reason: '[InferEffectDependencies] Internal invariant broken: expected entry block to have a fallthrough',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: entryBlock.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
const originalTerminal = currBlock.terminal;
|
|
currBlock.terminal = entryBlock.terminal;
|
|
for (const [id, block] of blocks) {
|
|
if (id === entry) {
|
|
continue;
|
|
}
|
|
if (id === rewrite.exitBlockId) {
|
|
block.terminal = originalTerminal;
|
|
currBlock = block;
|
|
}
|
|
rewriteBlocks.push(block);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
currBlock.instructions.push(...originalInstrs.slice(cursor));
|
|
}
|
|
function inferReactiveIdentifiers(fn) {
|
|
const reactiveIds = new Set();
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
for (const place of eachInstructionOperand(instr)) {
|
|
if (place.reactive) {
|
|
reactiveIds.add(place.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
for (const place of eachTerminalOperand(block.terminal)) {
|
|
if (place.reactive) {
|
|
reactiveIds.add(place.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
return reactiveIds;
|
|
}
|
|
function collectDepUsages(deps, fnExpr) {
|
|
const identifiers = new Map();
|
|
const loadedDeps = new Set();
|
|
const sourceLocations = [];
|
|
for (const dep of deps) {
|
|
identifiers.set(dep.identifier.id, dep);
|
|
}
|
|
for (const [, block] of fnExpr.loweredFunc.func.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
if (instr.value.kind === 'LoadLocal' &&
|
|
identifiers.has(instr.value.place.identifier.id)) {
|
|
loadedDeps.add(instr.lvalue.identifier.id);
|
|
}
|
|
for (const place of eachInstructionOperand(instr)) {
|
|
if (loadedDeps.has(place.identifier.id)) {
|
|
sourceLocations.push(place.identifier.loc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return sourceLocations;
|
|
}
|
|
function inferMinimalDependencies(fnInstr) {
|
|
const fn = fnInstr.value.loweredFunc.func;
|
|
const temporaries = collectTemporariesSidemap$1(fn, new Set());
|
|
const { hoistableObjects, processedInstrsInOptional, temporariesReadInOptional, } = collectOptionalChainSidemap(fn);
|
|
const hoistablePropertyLoads = collectHoistablePropertyLoadsInInnerFn(fnInstr, temporaries, hoistableObjects);
|
|
const hoistableToFnEntry = hoistablePropertyLoads.get(fn.body.entry);
|
|
CompilerError.invariant(hoistableToFnEntry != null, {
|
|
reason: '[InferEffectDependencies] Internal invariant broken: missing entry block',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: fnInstr.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
const dependencies = inferDependencies(fnInstr, new Map([...temporaries, ...temporariesReadInOptional]), processedInstrsInOptional);
|
|
const tree = new ReactiveScopeDependencyTreeHIR([...hoistableToFnEntry.assumedNonNullObjects].map(o => o.fullPath));
|
|
for (const dep of dependencies) {
|
|
tree.addDependency(Object.assign({}, dep));
|
|
}
|
|
return tree.deriveMinimalDependencies();
|
|
}
|
|
function inferDependencies(fnInstr, temporaries, processedInstrsInOptional) {
|
|
const fn = fnInstr.value.loweredFunc.func;
|
|
const context = new DependencyCollectionContext(new Set(), temporaries, processedInstrsInOptional);
|
|
for (const dep of fn.context) {
|
|
context.declare(dep.identifier, {
|
|
id: makeInstructionId(0),
|
|
scope: empty(),
|
|
});
|
|
}
|
|
const placeholderScope = {
|
|
id: makeScopeId(0),
|
|
range: {
|
|
start: fnInstr.id,
|
|
end: makeInstructionId(fnInstr.id + 1),
|
|
},
|
|
dependencies: new Set(),
|
|
reassignments: new Set(),
|
|
declarations: new Map(),
|
|
earlyReturnValue: null,
|
|
merged: new Set(),
|
|
loc: GeneratedSource,
|
|
};
|
|
context.enterScope(placeholderScope);
|
|
inferDependenciesInFn(fn, context, temporaries);
|
|
context.exitScope(placeholderScope, false);
|
|
const resultUnfiltered = context.deps.get(placeholderScope);
|
|
CompilerError.invariant(resultUnfiltered != null, {
|
|
reason: '[InferEffectDependencies] Internal invariant broken: missing scope dependencies',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: fn.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
const fnContext = new Set(fn.context.map(dep => dep.identifier.id));
|
|
const result = new Set();
|
|
for (const dep of resultUnfiltered) {
|
|
if (fnContext.has(dep.identifier.id)) {
|
|
result.add(dep);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function inferDependenciesInFn(fn, context, temporaries) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
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, () => {
|
|
inferDependenciesInFn(innerFn, context, temporaries);
|
|
});
|
|
}
|
|
else {
|
|
handleInstruction(instr, context);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function instructionReordering(fn) {
|
|
var _a;
|
|
const shared = new Map();
|
|
const references = findReferencedRangeOfTemporaries(fn);
|
|
for (const [, block] of fn.body.blocks) {
|
|
reorderBlock(fn.env, block, shared, references);
|
|
}
|
|
CompilerError.invariant(shared.size === 0, {
|
|
reason: `InstructionReordering: expected all reorderable nodes to have been emitted`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_a = [...shared.values()]
|
|
.map(node => { var _a; return (_a = node.instruction) === null || _a === void 0 ? void 0 : _a.loc; })
|
|
.filter(loc => loc != null)[0]) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
markInstructionIds(fn.body);
|
|
}
|
|
var ReferenceKind;
|
|
(function (ReferenceKind) {
|
|
ReferenceKind[ReferenceKind["Read"] = 0] = "Read";
|
|
ReferenceKind[ReferenceKind["Write"] = 1] = "Write";
|
|
})(ReferenceKind || (ReferenceKind = {}));
|
|
function findReferencedRangeOfTemporaries(fn) {
|
|
const singleUseIdentifiers = new Map();
|
|
const lastAssignments = new Map();
|
|
function reference(instr, place, kind) {
|
|
var _a;
|
|
if (place.identifier.name !== null &&
|
|
place.identifier.name.kind === 'named') {
|
|
if (kind === ReferenceKind.Write) {
|
|
const name = place.identifier.name.value;
|
|
const previous = lastAssignments.get(name);
|
|
if (previous === undefined) {
|
|
lastAssignments.set(name, instr);
|
|
}
|
|
else {
|
|
lastAssignments.set(name, makeInstructionId(Math.max(previous, instr)));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
else if (kind === ReferenceKind.Read) {
|
|
const previousCount = (_a = singleUseIdentifiers.get(place.identifier.id)) !== null && _a !== void 0 ? _a : 0;
|
|
singleUseIdentifiers.set(place.identifier.id, previousCount + 1);
|
|
}
|
|
}
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
for (const operand of eachInstructionValueLValue(instr.value)) {
|
|
reference(instr.id, operand, ReferenceKind.Read);
|
|
}
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
reference(instr.id, lvalue, ReferenceKind.Write);
|
|
}
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
reference(block.terminal.id, operand, ReferenceKind.Read);
|
|
}
|
|
}
|
|
return {
|
|
singleUseIdentifiers: new Set([...singleUseIdentifiers]
|
|
.filter(([, count]) => count === 1)
|
|
.map(([id]) => id)),
|
|
lastAssignments,
|
|
};
|
|
}
|
|
function reorderBlock(env, block, shared, references) {
|
|
var _a, _b;
|
|
const locals = new Map();
|
|
const named = new Map();
|
|
let previous = null;
|
|
for (const instr of block.instructions) {
|
|
const { lvalue, value } = instr;
|
|
const reorderability = getReorderability(instr, references);
|
|
const node = getOrInsertWith(locals, lvalue.identifier.id, () => ({
|
|
instruction: instr,
|
|
dependencies: new Set(),
|
|
reorderability,
|
|
depth: null,
|
|
}));
|
|
if (reorderability === Reorderability.Nonreorderable) {
|
|
if (previous !== null) {
|
|
node.dependencies.add(previous);
|
|
}
|
|
previous = lvalue.identifier.id;
|
|
}
|
|
for (const operand of eachInstructionValueOperand(value)) {
|
|
const { name, id } = operand.identifier;
|
|
if (name !== null && name.kind === 'named') {
|
|
const previous = named.get(name.value);
|
|
if (previous !== undefined) {
|
|
node.dependencies.add(previous);
|
|
}
|
|
named.set(name.value, lvalue.identifier.id);
|
|
}
|
|
else if (locals.has(id) || shared.has(id)) {
|
|
node.dependencies.add(id);
|
|
}
|
|
}
|
|
for (const lvalueOperand of eachInstructionValueLValue(value)) {
|
|
const lvalueNode = getOrInsertWith(locals, lvalueOperand.identifier.id, () => ({
|
|
instruction: null,
|
|
dependencies: new Set(),
|
|
depth: null,
|
|
}));
|
|
lvalueNode.dependencies.add(lvalue.identifier.id);
|
|
const name = lvalueOperand.identifier.name;
|
|
if (name !== null && name.kind === 'named') {
|
|
const previous = named.get(name.value);
|
|
if (previous !== undefined) {
|
|
node.dependencies.add(previous);
|
|
}
|
|
named.set(name.value, lvalue.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
const nextInstructions = [];
|
|
if (isExpressionBlockKind(block.kind)) {
|
|
if (previous !== null) {
|
|
emit(env, locals, shared, nextInstructions, previous);
|
|
}
|
|
if (block.instructions.length !== 0) {
|
|
emit(env, locals, shared, nextInstructions, block.instructions.at(-1).lvalue.identifier.id);
|
|
}
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
emit(env, locals, shared, nextInstructions, operand.identifier.id);
|
|
}
|
|
for (const [id, node] of locals) {
|
|
if (node.instruction == null) {
|
|
continue;
|
|
}
|
|
CompilerError.invariant(node.reorderability === Reorderability.Reorderable, {
|
|
reason: `Expected all remaining instructions to be reorderable`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_b = (_a = node.instruction) === null || _a === void 0 ? void 0 : _a.loc) !== null && _b !== void 0 ? _b : block.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
description: node.instruction != null
|
|
? `Instruction [${node.instruction.id}] was not emitted yet but is not reorderable`
|
|
: `Lvalue $${id} was not emitted yet but is not reorderable`,
|
|
});
|
|
shared.set(id, node);
|
|
}
|
|
}
|
|
else {
|
|
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
emit(env, locals, shared, nextInstructions, operand.identifier.id);
|
|
}
|
|
for (const id of Array.from(locals.keys()).reverse()) {
|
|
const node = locals.get(id);
|
|
if (node === undefined) {
|
|
continue;
|
|
}
|
|
if (node.reorderability === Reorderability.Reorderable) {
|
|
shared.set(id, node);
|
|
}
|
|
else {
|
|
emit(env, locals, shared, nextInstructions, id);
|
|
}
|
|
}
|
|
}
|
|
block.instructions = nextInstructions;
|
|
}
|
|
function getDepth(env, nodes, id) {
|
|
const node = nodes.get(id);
|
|
if (node == null) {
|
|
return 0;
|
|
}
|
|
if (node.depth != null) {
|
|
return node.depth;
|
|
}
|
|
node.depth = 0;
|
|
let depth = node.reorderability === Reorderability.Reorderable ? 1 : 10;
|
|
for (const dep of node.dependencies) {
|
|
depth += getDepth(env, nodes, dep);
|
|
}
|
|
node.depth = depth;
|
|
return depth;
|
|
}
|
|
function emit(env, locals, shared, instructions, id) {
|
|
var _a;
|
|
const node = (_a = locals.get(id)) !== null && _a !== void 0 ? _a : shared.get(id);
|
|
if (node == null) {
|
|
return;
|
|
}
|
|
locals.delete(id);
|
|
shared.delete(id);
|
|
const deps = [...node.dependencies];
|
|
deps.sort((a, b) => {
|
|
const aDepth = getDepth(env, locals, a);
|
|
const bDepth = getDepth(env, locals, b);
|
|
return bDepth - aDepth;
|
|
});
|
|
for (const dep of deps) {
|
|
emit(env, locals, shared, instructions, dep);
|
|
}
|
|
if (node.instruction !== null) {
|
|
instructions.push(node.instruction);
|
|
}
|
|
}
|
|
var Reorderability;
|
|
(function (Reorderability) {
|
|
Reorderability[Reorderability["Reorderable"] = 0] = "Reorderable";
|
|
Reorderability[Reorderability["Nonreorderable"] = 1] = "Nonreorderable";
|
|
})(Reorderability || (Reorderability = {}));
|
|
function getReorderability(instr, references) {
|
|
switch (instr.value.kind) {
|
|
case 'JsxExpression':
|
|
case 'JsxFragment':
|
|
case 'JSXText':
|
|
case 'LoadGlobal':
|
|
case 'Primitive':
|
|
case 'TemplateLiteral':
|
|
case 'BinaryExpression':
|
|
case 'UnaryExpression': {
|
|
return Reorderability.Reorderable;
|
|
}
|
|
case 'LoadLocal': {
|
|
const name = instr.value.place.identifier.name;
|
|
if (name !== null && name.kind === 'named') {
|
|
const lastAssignment = references.lastAssignments.get(name.value);
|
|
if (lastAssignment !== undefined &&
|
|
lastAssignment < instr.id &&
|
|
references.singleUseIdentifiers.has(instr.lvalue.identifier.id)) {
|
|
return Reorderability.Reorderable;
|
|
}
|
|
}
|
|
return Reorderability.Nonreorderable;
|
|
}
|
|
default: {
|
|
return Reorderability.Nonreorderable;
|
|
}
|
|
}
|
|
}
|
|
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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' };
|
|
}
|
|
}
|
|
|
|
let Visitor$2 = class Visitor extends ReactiveFunctionVisitor {
|
|
constructor(env, aliases, paths) {
|
|
super();
|
|
this.map = new Map();
|
|
this.aliases = aliases;
|
|
this.paths = paths;
|
|
this.env = env;
|
|
}
|
|
join(values) {
|
|
function join2(l, r) {
|
|
if (l === 'Update' || r === 'Update') {
|
|
return 'Update';
|
|
}
|
|
else if (l === 'Create' || r === 'Create') {
|
|
return 'Create';
|
|
}
|
|
else if (l === 'Unknown' || r === 'Unknown') {
|
|
return 'Unknown';
|
|
}
|
|
assertExhaustive$1(r, `Unhandled variable kind ${r}`);
|
|
}
|
|
return values.reduce(join2, 'Unknown');
|
|
}
|
|
isCreateOnlyHook(id) {
|
|
return isUseStateType(id) || isUseRefType(id);
|
|
}
|
|
visitPlace(_, place, state) {
|
|
var _a;
|
|
this.map.set(place.identifier.id, this.join([state, (_a = this.map.get(place.identifier.id)) !== null && _a !== void 0 ? _a : 'Unknown']));
|
|
}
|
|
visitBlock(block, state) {
|
|
super.visitBlock([...block].reverse(), state);
|
|
}
|
|
visitInstruction(instruction) {
|
|
const state = this.join([...eachInstructionLValue(instruction)].map(operand => { var _a; return (_a = this.map.get(operand.identifier.id)) !== null && _a !== void 0 ? _a : 'Unknown'; }));
|
|
const visitCallOrMethodNonArgs = () => {
|
|
switch (instruction.value.kind) {
|
|
case 'CallExpression': {
|
|
this.visitPlace(instruction.id, instruction.value.callee, state);
|
|
break;
|
|
}
|
|
case 'MethodCall': {
|
|
this.visitPlace(instruction.id, instruction.value.property, state);
|
|
this.visitPlace(instruction.id, instruction.value.receiver, state);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
const isHook = () => {
|
|
let callee = null;
|
|
switch (instruction.value.kind) {
|
|
case 'CallExpression': {
|
|
callee = instruction.value.callee.identifier;
|
|
break;
|
|
}
|
|
case 'MethodCall': {
|
|
callee = instruction.value.property.identifier;
|
|
break;
|
|
}
|
|
}
|
|
return callee != null && getHookKind(this.env, callee) != null;
|
|
};
|
|
switch (instruction.value.kind) {
|
|
case 'CallExpression':
|
|
case 'MethodCall': {
|
|
if (instruction.lvalue &&
|
|
this.isCreateOnlyHook(instruction.lvalue.identifier)) {
|
|
[...eachCallArgument(instruction.value.args)].forEach(operand => this.visitPlace(instruction.id, operand, 'Create'));
|
|
visitCallOrMethodNonArgs();
|
|
}
|
|
else {
|
|
this.traverseInstruction(instruction, isHook() ? 'Update' : state);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
this.traverseInstruction(instruction, state);
|
|
}
|
|
}
|
|
}
|
|
visitScope(scope) {
|
|
const state = this.join([
|
|
...scope.scope.declarations.keys(),
|
|
...[...scope.scope.reassignments.values()].map(ident => ident.id),
|
|
].map(id => { var _a; return (_a = this.map.get(id)) !== null && _a !== void 0 ? _a : 'Unknown'; }));
|
|
super.visitScope(scope, state);
|
|
[...scope.scope.dependencies].forEach(ident => {
|
|
var _a;
|
|
let target = (_a = this.aliases.find(ident.identifier.id)) !== null && _a !== void 0 ? _a : ident.identifier.id;
|
|
ident.path.forEach(token => {
|
|
var _a;
|
|
target && (target = (_a = this.paths.get(target)) === null || _a === void 0 ? void 0 : _a.get(token.property));
|
|
});
|
|
if (target && this.map.get(target) === 'Create') {
|
|
scope.scope.dependencies.delete(ident);
|
|
}
|
|
});
|
|
}
|
|
visitTerminal(stmt, state) {
|
|
CompilerError.invariant(state !== 'Create', {
|
|
reason: "Visiting a terminal statement with state 'Create'",
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: stmt.terminal.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
super.visitTerminal(stmt, state);
|
|
}
|
|
visitReactiveFunctionValue(_id, _dependencies, fn, state) {
|
|
visitReactiveFunction(fn, this, state);
|
|
}
|
|
};
|
|
function pruneInitializationDependencies(fn) {
|
|
const [aliases, paths] = getAliases(fn);
|
|
visitReactiveFunction(fn, new Visitor$2(fn.env, aliases, paths), 'Update');
|
|
}
|
|
function update(map, key, path, value) {
|
|
var _a;
|
|
const inner = (_a = map.get(key)) !== null && _a !== void 0 ? _a : new Map();
|
|
inner.set(path, value);
|
|
map.set(key, inner);
|
|
}
|
|
class AliasVisitor extends ReactiveFunctionVisitor {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.scopeIdentifiers = new DisjointSet();
|
|
this.scopePaths = new Map();
|
|
}
|
|
visitInstruction(instr) {
|
|
if (instr.value.kind === 'StoreLocal' ||
|
|
instr.value.kind === 'StoreContext') {
|
|
this.scopeIdentifiers.union([
|
|
instr.value.lvalue.place.identifier.id,
|
|
instr.value.value.identifier.id,
|
|
]);
|
|
}
|
|
else if (instr.value.kind === 'LoadLocal' ||
|
|
instr.value.kind === 'LoadContext') {
|
|
instr.lvalue &&
|
|
this.scopeIdentifiers.union([
|
|
instr.lvalue.identifier.id,
|
|
instr.value.place.identifier.id,
|
|
]);
|
|
}
|
|
else if (instr.value.kind === 'PropertyLoad') {
|
|
instr.lvalue &&
|
|
update(this.scopePaths, instr.value.object.identifier.id, instr.value.property, instr.lvalue.identifier.id);
|
|
}
|
|
else if (instr.value.kind === 'PropertyStore') {
|
|
update(this.scopePaths, instr.value.object.identifier.id, instr.value.property, instr.value.value.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
function getAliases(fn) {
|
|
var _a, _b;
|
|
const visitor = new AliasVisitor();
|
|
visitReactiveFunction(fn, visitor, null);
|
|
let disjoint = visitor.scopeIdentifiers;
|
|
let scopePaths = new Map();
|
|
for (const [key, value] of visitor.scopePaths) {
|
|
for (const [path, id] of value) {
|
|
update(scopePaths, (_a = disjoint.find(key)) !== null && _a !== void 0 ? _a : key, path, (_b = disjoint.find(id)) !== null && _b !== void 0 ? _b : id);
|
|
}
|
|
}
|
|
return [disjoint, scopePaths];
|
|
}
|
|
|
|
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': {
|
|
if (env.config.enableUseTypeAnnotations) {
|
|
yield equation(value.lvalue.place.identifier.type, value.value.identifier.type);
|
|
const valueType = value.type === null ? makeType() : lowerType(value.type);
|
|
yield equation(valueType, value.lvalue.place.identifier.type);
|
|
yield equation(left, valueType);
|
|
}
|
|
else {
|
|
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': {
|
|
if (env.config.enableUseTypeAnnotations) {
|
|
yield equation(value.type, value.value.identifier.type);
|
|
yield equation(left, value.type);
|
|
}
|
|
else {
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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);
|
|
}
|
|
function validateContextVariableLValuesImpl(fn, identifierKinds) {
|
|
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');
|
|
break;
|
|
}
|
|
case 'LoadContext': {
|
|
visit(identifierKinds, value.place, 'context');
|
|
break;
|
|
}
|
|
case 'StoreLocal':
|
|
case 'DeclareLocal': {
|
|
visit(identifierKinds, value.lvalue.place, 'local');
|
|
break;
|
|
}
|
|
case 'LoadLocal': {
|
|
visit(identifierKinds, value.place, 'local');
|
|
break;
|
|
}
|
|
case 'PostfixUpdate':
|
|
case 'PrefixUpdate': {
|
|
visit(identifierKinds, value.lvalue, 'local');
|
|
break;
|
|
}
|
|
case 'Destructure': {
|
|
for (const lvalue of eachPatternOperand(value.lvalue.pattern)) {
|
|
visit(identifierKinds, lvalue, 'destructure');
|
|
}
|
|
break;
|
|
}
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
validateContextVariableLValuesImpl(value.loweredFunc.func, identifierKinds);
|
|
break;
|
|
}
|
|
default: {
|
|
for (const _ of eachInstructionValueLValue(value)) {
|
|
CompilerError.throwTodo({
|
|
reason: 'ValidateContextVariableLValues: unhandled instruction variant',
|
|
loc: value.loc,
|
|
description: `Handle '${value.kind} lvalues`,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function visit(identifiers, place, kind) {
|
|
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') {
|
|
CompilerError.throwTodo({
|
|
reason: `Support destructuring of context variables`,
|
|
loc: kind === 'destructure' ? place.loc : prev.place.loc,
|
|
description: null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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`,
|
|
suggestions: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: place.loc,
|
|
message: `this is ${prev.kind}`,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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 errors = new CompilerError();
|
|
const errorsByPlace = new Map();
|
|
function recordError(loc, errorDetail) {
|
|
if (typeof loc === 'symbol') {
|
|
errors.pushErrorDetail(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) {
|
|
recordError(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) {
|
|
recordError(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) {
|
|
recordError(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(errors, 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) {
|
|
errors.pushErrorDetail(error);
|
|
}
|
|
return errors.asResult();
|
|
}
|
|
function visitFunctionExpression(errors, fn) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
switch (instr.value.kind) {
|
|
case 'ObjectMethod':
|
|
case 'FunctionExpression': {
|
|
visitFunctionExpression(errors, 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) {
|
|
errors.pushErrorDetail(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 validateMemoizedEffectDependencies(fn) {
|
|
const errors = new CompilerError();
|
|
visitReactiveFunction(fn, new Visitor$1(), errors);
|
|
return errors.asResult();
|
|
}
|
|
let Visitor$1 = class Visitor extends ReactiveFunctionVisitor {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.scopes = new Set();
|
|
}
|
|
visitScope(scopeBlock, state) {
|
|
this.traverseScope(scopeBlock, state);
|
|
let areDependenciesMemoized = true;
|
|
for (const dep of scopeBlock.scope.dependencies) {
|
|
if (isUnmemoized$1(dep.identifier, this.scopes)) {
|
|
areDependenciesMemoized = false;
|
|
break;
|
|
}
|
|
}
|
|
if (areDependenciesMemoized) {
|
|
this.scopes.add(scopeBlock.scope.id);
|
|
for (const id of scopeBlock.scope.merged) {
|
|
this.scopes.add(id);
|
|
}
|
|
}
|
|
}
|
|
visitInstruction(instruction, state) {
|
|
this.traverseInstruction(instruction, state);
|
|
if (instruction.value.kind === 'CallExpression' &&
|
|
isEffectHook(instruction.value.callee.identifier) &&
|
|
instruction.value.args.length >= 2) {
|
|
const deps = instruction.value.args[1];
|
|
if (deps.kind === 'Identifier' &&
|
|
(isMutable(instruction, deps) ||
|
|
isUnmemoized$1(deps.identifier, this.scopes))) {
|
|
state.push({
|
|
category: ErrorCategory.EffectDependencies,
|
|
reason: 'React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior',
|
|
description: null,
|
|
loc: typeof instruction.loc !== 'symbol' ? instruction.loc : null,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
};
|
|
function isUnmemoized$1(operand, scopes) {
|
|
return operand.scope != null && !scopes.has(operand.scope.id);
|
|
}
|
|
function isEffectHook(identifier) {
|
|
return (isUseEffectHookType(identifier) ||
|
|
isUseLayoutEffectHookType(identifier) ||
|
|
isUseInsertionEffectHookType(identifier));
|
|
}
|
|
|
|
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 hookPattern = envConfig.hookPattern != null ? new RegExp(envConfig.hookPattern) : null;
|
|
const isAllowed = (name) => {
|
|
return (ALLOW_LIST.has(name) || (hookPattern != null && hookPattern.test(name)));
|
|
};
|
|
const errors = new CompilerError();
|
|
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) {
|
|
CompilerError.throwInvalidReact({
|
|
category: ErrorCategory.CapitalizedCalls,
|
|
reason,
|
|
description: `${calleeName} may be a component`,
|
|
loc: value.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
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) {
|
|
errors.push({
|
|
category: ErrorCategory.CapitalizedCalls,
|
|
reason,
|
|
description: `${propertyName} may be a component`,
|
|
loc: value.loc,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return errors.asResult();
|
|
}
|
|
|
|
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',
|
|
description: null,
|
|
suggestions: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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(fn, env);
|
|
return validateNoRefAccessInRenderImpl(fn, env).map(_ => undefined);
|
|
}
|
|
function collectTemporariesSidemap(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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
return a.refId === b.refId;
|
|
case 'RefValue':
|
|
CompilerError.invariant(b.kind === 'RefValue', {
|
|
reason: 'Expected ref value',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
return a.loc == b.loc;
|
|
case 'Structure': {
|
|
CompilerError.invariant(b.kind === 'Structure', {
|
|
reason: 'Expected structure',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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) {
|
|
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 = [];
|
|
const errors = new CompilerError();
|
|
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 result = validateNoRefAccessInRenderImpl(instr.value.loweredFunc.func, env);
|
|
if (result.isOk()) {
|
|
returnType = result.unwrap();
|
|
}
|
|
else if (result.isErr()) {
|
|
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);
|
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
if (isRefLValue ||
|
|
(hookKind != null &&
|
|
hookKind !== 'useState' &&
|
|
hookKind !== 'useReducer')) {
|
|
validateNoDirectRefValueAccess(errors, operand, env);
|
|
}
|
|
else if (interpolatedAsJsx.has(instr.lvalue.identifier.id)) {
|
|
validateNoRefValueAccess(errors, env, operand);
|
|
}
|
|
else {
|
|
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 Err(errors);
|
|
}
|
|
}
|
|
CompilerError.invariant(!env.hasChanged(), {
|
|
reason: 'Ref type environment did not converge',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
return Ok(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();
|
|
return validateNoSetStateInRenderImpl(fn, unconditionalSetStateFunctions);
|
|
}
|
|
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).isErr()) {
|
|
unconditionalSetStateFunctions.add(instr.lvalue.identifier.id);
|
|
}
|
|
break;
|
|
}
|
|
case 'StartMemoize': {
|
|
CompilerError.invariant(activeManualMemoId === null, {
|
|
reason: 'Unexpected nested StartMemoize instructions',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
activeManualMemoId = instr.value.manualMemoId;
|
|
break;
|
|
}
|
|
case 'FinishMemoize': {
|
|
CompilerError.invariant(activeManualMemoId === instr.value.manualMemoId, {
|
|
reason: 'Expected FinishMemoize to align with previous StartMemoize instruction',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: instr.value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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)) {
|
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
category: ErrorCategory.RenderSetState,
|
|
reason: 'Calling setState during render may trigger an infinite loop',
|
|
description: 'Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: callee.loc,
|
|
message: 'Found setState() in render',
|
|
}));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return errors.asResult();
|
|
}
|
|
|
|
function validatePreservedManualMemoization(fn) {
|
|
const state = {
|
|
errors: new CompilerError(),
|
|
manualMemoState: null,
|
|
};
|
|
visitReactiveFunction(fn, new Visitor(), state);
|
|
return state.errors.asResult();
|
|
}
|
|
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(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, errorState, memoLocation) {
|
|
var _a;
|
|
let normalizedDep;
|
|
const maybeNormalizedRoot = temporaries.get(dep.identifier.id);
|
|
if (maybeNormalizedRoot != null) {
|
|
normalizedDep = {
|
|
root: maybeNormalizedRoot.root,
|
|
path: [...maybeNormalizedRoot.path, ...dep.path],
|
|
};
|
|
}
|
|
else {
|
|
CompilerError.invariant(((_a = dep.identifier.name) === null || _a === void 0 ? void 0 : _a.kind) === 'named', {
|
|
reason: 'ValidatePreservedManualMemoization: expected scope dependency to be named',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
normalizedDep = {
|
|
root: {
|
|
kind: 'NamedLocal',
|
|
value: {
|
|
kind: 'Identifier',
|
|
identifier: dep.identifier,
|
|
loc: GeneratedSource,
|
|
effect: Effect.Read,
|
|
reactive: false,
|
|
},
|
|
},
|
|
path: [...dep.path],
|
|
};
|
|
}
|
|
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(errorDiagnostic !== null && errorDiagnostic !== void 0 ? errorDiagnostic : compareResult, compareResult);
|
|
}
|
|
}
|
|
errorState.pushDiagnostic(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(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,
|
|
},
|
|
path: [],
|
|
});
|
|
}
|
|
}
|
|
}
|
|
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),
|
|
},
|
|
path: [],
|
|
});
|
|
}
|
|
}
|
|
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.errors, 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, _c;
|
|
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') {
|
|
let depsFromSource = null;
|
|
if (value.deps != null) {
|
|
depsFromSource = value.deps;
|
|
}
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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.errors.pushDiagnostic(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') {
|
|
CompilerError.invariant(state.manualMemoState != null &&
|
|
state.manualMemoState.manualMemoId === value.manualMemoId, {
|
|
reason: 'Unexpected mismatch between StartMemoize and FinishMemoize',
|
|
description: `Encountered StartMemoize id=${(_b = state.manualMemoState) === null || _b === void 0 ? void 0 : _b.manualMemoId} followed by FinishMemoize id=${value.manualMemoId}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: value.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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 = (_c = reassignments.get(identifier.declarationId)) !== null && _c !== void 0 ? _c : [identifier];
|
|
}
|
|
else {
|
|
decls = [identifier];
|
|
}
|
|
for (const identifier of decls) {
|
|
if (isUnmemoized(identifier, this.scopes)) {
|
|
state.errors.pushDiagnostic(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);
|
|
}
|
|
|
|
function validateUseMemo(fn) {
|
|
const errors = new CompilerError();
|
|
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;
|
|
errors.pushDiagnostic(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) {
|
|
errors.pushDiagnostic(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, errors);
|
|
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());
|
|
return errors.asResult();
|
|
}
|
|
function validateNoContextVariableAssignment(fn, errors) {
|
|
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)) {
|
|
errors.pushDiagnostic(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);
|
|
if (reassignment !== null) {
|
|
const errors = new CompilerError();
|
|
const variable = reassignment.identifier.name != null &&
|
|
reassignment.identifier.name.kind === 'named'
|
|
? `\`${reassignment.identifier.name.value}\``
|
|
: 'variable';
|
|
errors.pushDiagnostic(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`,
|
|
}));
|
|
throw errors;
|
|
}
|
|
}
|
|
function getContextReassignment(fn, contextVariables, isFunctionExpression, isAsync) {
|
|
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);
|
|
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 errors = new CompilerError();
|
|
const variable = reassignment.identifier.name !== null &&
|
|
reassignment.identifier.name.kind === 'named'
|
|
? `\`${reassignment.identifier.name.value}\``
|
|
: 'variable';
|
|
errors.pushDiagnostic(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}`,
|
|
}));
|
|
throw errors;
|
|
}
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: operand.loc,
|
|
message: '',
|
|
},
|
|
],
|
|
});
|
|
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 lowerContextAccess(fn, loweredContextCalleeConfig) {
|
|
const contextAccess = new Map();
|
|
const contextKeys = new Map();
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
const { value, lvalue } = instr;
|
|
if (value.kind === 'CallExpression' &&
|
|
isUseContextHookType(value.callee.identifier)) {
|
|
contextAccess.set(lvalue.identifier.id, value);
|
|
continue;
|
|
}
|
|
if (value.kind !== 'Destructure') {
|
|
continue;
|
|
}
|
|
const destructureId = value.value.identifier.id;
|
|
if (!contextAccess.has(destructureId)) {
|
|
continue;
|
|
}
|
|
const keys = getContextKeys(value);
|
|
if (keys === null) {
|
|
return;
|
|
}
|
|
if (contextKeys.has(destructureId)) {
|
|
return;
|
|
}
|
|
else {
|
|
contextKeys.set(destructureId, keys);
|
|
}
|
|
}
|
|
}
|
|
let importLoweredContextCallee = null;
|
|
if (contextAccess.size > 0 && contextKeys.size > 0) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
let nextInstructions = null;
|
|
for (let i = 0; i < block.instructions.length; i++) {
|
|
const instr = block.instructions[i];
|
|
const { lvalue, value } = instr;
|
|
if (value.kind === 'CallExpression' &&
|
|
isUseContextHookType(value.callee.identifier) &&
|
|
contextKeys.has(lvalue.identifier.id)) {
|
|
importLoweredContextCallee !== null && importLoweredContextCallee !== void 0 ? importLoweredContextCallee : (importLoweredContextCallee = fn.env.programContext.addImportSpecifier(loweredContextCalleeConfig));
|
|
const loweredContextCalleeInstr = emitLoadLoweredContextCallee(fn.env, importLoweredContextCallee);
|
|
if (nextInstructions === null) {
|
|
nextInstructions = block.instructions.slice(0, i);
|
|
}
|
|
nextInstructions.push(loweredContextCalleeInstr);
|
|
const keys = contextKeys.get(lvalue.identifier.id);
|
|
const selectorFnInstr = emitSelectorFn(fn.env, keys);
|
|
nextInstructions.push(selectorFnInstr);
|
|
const lowerContextCallId = loweredContextCalleeInstr.lvalue;
|
|
value.callee = lowerContextCallId;
|
|
const selectorFn = selectorFnInstr.lvalue;
|
|
value.args.push(selectorFn);
|
|
}
|
|
if (nextInstructions) {
|
|
nextInstructions.push(instr);
|
|
}
|
|
}
|
|
if (nextInstructions) {
|
|
block.instructions = nextInstructions;
|
|
}
|
|
}
|
|
markInstructionIds(fn.body);
|
|
inferTypes(fn);
|
|
}
|
|
}
|
|
function emitLoadLoweredContextCallee(env, importedLowerContextCallee) {
|
|
const loadGlobal = {
|
|
kind: 'LoadGlobal',
|
|
binding: Object.assign({}, importedLowerContextCallee),
|
|
loc: GeneratedSource,
|
|
};
|
|
return {
|
|
id: makeInstructionId(0),
|
|
loc: GeneratedSource,
|
|
lvalue: createTemporaryPlace(env, GeneratedSource),
|
|
effects: null,
|
|
value: loadGlobal,
|
|
};
|
|
}
|
|
function getContextKeys(value) {
|
|
const keys = [];
|
|
const pattern = value.lvalue.pattern;
|
|
switch (pattern.kind) {
|
|
case 'ArrayPattern': {
|
|
return null;
|
|
}
|
|
case 'ObjectPattern': {
|
|
for (const place of pattern.properties) {
|
|
if (place.kind !== 'ObjectProperty' ||
|
|
place.type !== 'property' ||
|
|
place.key.kind !== 'identifier' ||
|
|
place.place.identifier.name === null ||
|
|
place.place.identifier.name.kind !== 'named') {
|
|
return null;
|
|
}
|
|
keys.push(place.key.name);
|
|
}
|
|
return keys;
|
|
}
|
|
}
|
|
}
|
|
function emitPropertyLoad(env, obj, property) {
|
|
const loadObj = {
|
|
kind: 'LoadLocal',
|
|
place: obj,
|
|
loc: GeneratedSource,
|
|
};
|
|
const object = createTemporaryPlace(env, GeneratedSource);
|
|
const loadLocalInstr = {
|
|
lvalue: object,
|
|
value: loadObj,
|
|
id: makeInstructionId(0),
|
|
effects: null,
|
|
loc: GeneratedSource,
|
|
};
|
|
const loadProp = {
|
|
kind: 'PropertyLoad',
|
|
object,
|
|
property: makePropertyLiteral(property),
|
|
loc: GeneratedSource,
|
|
};
|
|
const element = createTemporaryPlace(env, GeneratedSource);
|
|
const loadPropInstr = {
|
|
lvalue: element,
|
|
value: loadProp,
|
|
id: makeInstructionId(0),
|
|
effects: null,
|
|
loc: GeneratedSource,
|
|
};
|
|
return {
|
|
instructions: [loadLocalInstr, loadPropInstr],
|
|
element: element,
|
|
};
|
|
}
|
|
function emitSelectorFn(env, keys) {
|
|
const obj = createTemporaryPlace(env, GeneratedSource);
|
|
promoteTemporary(obj.identifier);
|
|
const instr = [];
|
|
const elements = [];
|
|
for (const key of keys) {
|
|
const { instructions, element: prop } = emitPropertyLoad(env, obj, key);
|
|
instr.push(...instructions);
|
|
elements.push(prop);
|
|
}
|
|
const arrayInstr = emitArrayInstr(elements, env);
|
|
instr.push(arrayInstr);
|
|
const block = {
|
|
kind: 'block',
|
|
id: makeBlockId(0),
|
|
instructions: instr,
|
|
terminal: {
|
|
id: makeInstructionId(0),
|
|
kind: 'return',
|
|
returnVariant: 'Explicit',
|
|
loc: GeneratedSource,
|
|
value: arrayInstr.lvalue,
|
|
effects: null,
|
|
},
|
|
preds: new Set(),
|
|
phis: new Set(),
|
|
};
|
|
const fn = {
|
|
loc: GeneratedSource,
|
|
id: null,
|
|
nameHint: null,
|
|
fnType: 'Other',
|
|
env,
|
|
params: [obj],
|
|
returnTypeAnnotation: null,
|
|
returns: createTemporaryPlace(env, GeneratedSource),
|
|
context: [],
|
|
body: {
|
|
entry: block.id,
|
|
blocks: new Map([[block.id, block]]),
|
|
},
|
|
generator: false,
|
|
async: false,
|
|
directives: [],
|
|
aliasingEffects: [],
|
|
};
|
|
reversePostorderBlocks(fn.body);
|
|
markInstructionIds(fn.body);
|
|
enterSSA(fn);
|
|
inferTypes(fn);
|
|
const fnInstr = {
|
|
id: makeInstructionId(0),
|
|
value: {
|
|
kind: 'FunctionExpression',
|
|
name: null,
|
|
nameHint: null,
|
|
loweredFunc: {
|
|
func: fn,
|
|
},
|
|
type: 'ArrowFunctionExpression',
|
|
loc: GeneratedSource,
|
|
},
|
|
lvalue: createTemporaryPlace(env, GeneratedSource),
|
|
effects: null,
|
|
loc: GeneratedSource,
|
|
};
|
|
return fnInstr;
|
|
}
|
|
function emitArrayInstr(elements, env) {
|
|
const array = {
|
|
kind: 'ArrayExpression',
|
|
elements,
|
|
loc: GeneratedSource,
|
|
};
|
|
const arrayLvalue = createTemporaryPlace(env, GeneratedSource);
|
|
const arrayInstr = {
|
|
id: makeInstructionId(0),
|
|
value: array,
|
|
lvalue: arrayLvalue,
|
|
effects: null,
|
|
loc: GeneratedSource,
|
|
};
|
|
return arrayInstr;
|
|
}
|
|
|
|
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.receiver
|
|
: instr.value.callee;
|
|
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) {
|
|
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 refDerivedValues = new Set();
|
|
const isDerivedFromRef = (place) => {
|
|
return (refDerivedValues.has(place.identifier.id) ||
|
|
isUseRefType(place.identifier) ||
|
|
isRefValueType(place.identifier));
|
|
};
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
if (env.config.enableAllowSetStateFromRefsInEffects) {
|
|
const hasRefOperand = Iterable_some(eachInstructionValueOperand(instr.value), isDerivedFromRef);
|
|
if (hasRefOperand) {
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
refDerivedValues.add(lvalue.identifier.id);
|
|
}
|
|
}
|
|
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 (env.config.enableAllowSetStateFromRefsInEffects) {
|
|
const arg = instr.value.args.at(0);
|
|
if (arg !== undefined &&
|
|
arg.kind === 'Identifier' &&
|
|
refDerivedValues.has(arg.identifier.id)) {
|
|
return null;
|
|
}
|
|
}
|
|
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 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,
|
|
},
|
|
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,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var _Context_env, _Context_errors, _Context_callExpressions, _Context_functionExpressions, _Context_loadLocals, _Context_fireCalleesToFireFunctions, _Context_calleesWithInsertedFire, _Context_capturedCalleeIdentifierIds, _Context_inUseEffectLambda, _Context_loadGlobalInstructionIds, _Context_arrayExpressions;
|
|
const CANNOT_COMPILE_FIRE = 'Cannot compile `fire`';
|
|
function transformFire(fn) {
|
|
const context = new Context(fn.env);
|
|
replaceFireFunctions(fn, context);
|
|
if (!context.hasErrors()) {
|
|
ensureNoMoreFireUses(fn, context);
|
|
}
|
|
context.throwIfErrorsFound();
|
|
}
|
|
function replaceFireFunctions(fn, context) {
|
|
let importedUseFire = null;
|
|
let hasRewrite = false;
|
|
for (const [, block] of fn.body.blocks) {
|
|
const rewriteInstrs = new Map();
|
|
const deleteInstrs = new Set();
|
|
for (const instr of block.instructions) {
|
|
const { value, lvalue } = instr;
|
|
if (value.kind === 'CallExpression' &&
|
|
isUseEffectHookType(value.callee.identifier) &&
|
|
value.args.length > 0 &&
|
|
value.args[0].kind === 'Identifier') {
|
|
const lambda = context.getFunctionExpression(value.args[0].identifier.id);
|
|
if (lambda != null) {
|
|
const capturedCallees = visitFunctionExpressionAndPropagateFireDependencies(lambda, context, true);
|
|
const newInstrs = [];
|
|
for (const [fireCalleePlace, fireCalleeInfo,] of capturedCallees.entries()) {
|
|
if (!context.hasCalleeWithInsertedFire(fireCalleePlace)) {
|
|
context.addCalleeWithInsertedFire(fireCalleePlace);
|
|
importedUseFire !== null && importedUseFire !== void 0 ? importedUseFire : (importedUseFire = fn.env.programContext.addImportSpecifier({
|
|
source: fn.env.programContext.reactRuntimeModule,
|
|
importSpecifierName: USE_FIRE_FUNCTION_NAME,
|
|
}));
|
|
const loadUseFireInstr = makeLoadUseFireInstruction(fn.env, importedUseFire);
|
|
const loadFireCalleeInstr = makeLoadFireCalleeInstruction(fn.env, fireCalleeInfo.capturedCalleeIdentifier);
|
|
const callUseFireInstr = makeCallUseFireInstruction(fn.env, loadUseFireInstr.lvalue, loadFireCalleeInstr.lvalue);
|
|
const storeUseFireInstr = makeStoreUseFireInstruction(fn.env, callUseFireInstr.lvalue, fireCalleeInfo.fireFunctionBinding);
|
|
newInstrs.push(loadUseFireInstr, loadFireCalleeInstr, callUseFireInstr, storeUseFireInstr);
|
|
const loadUseEffectInstrId = context.getLoadGlobalInstrId(value.callee.identifier.id);
|
|
if (loadUseEffectInstrId == null) {
|
|
context.pushError({
|
|
loc: value.loc,
|
|
description: null,
|
|
category: ErrorCategory.Invariant,
|
|
reason: '[InsertFire] No LoadGlobal found for useEffect call',
|
|
suggestions: null,
|
|
});
|
|
continue;
|
|
}
|
|
rewriteInstrs.set(loadUseEffectInstrId, newInstrs);
|
|
}
|
|
}
|
|
ensureNoRemainingCalleeCaptures(lambda.loweredFunc.func, context, capturedCallees);
|
|
if (value.args.length > 1 &&
|
|
value.args[1] != null &&
|
|
value.args[1].kind === 'Identifier') {
|
|
const depArray = value.args[1];
|
|
const depArrayExpression = context.getArrayExpression(depArray.identifier.id);
|
|
if (depArrayExpression != null) {
|
|
for (const dependency of depArrayExpression.elements) {
|
|
if (dependency.kind === 'Identifier') {
|
|
const loadOfDependency = context.getLoadLocalInstr(dependency.identifier.id);
|
|
if (loadOfDependency != null) {
|
|
const replacedDepArrayItem = capturedCallees.get(loadOfDependency.place.identifier.id);
|
|
if (replacedDepArrayItem != null) {
|
|
loadOfDependency.place =
|
|
replacedDepArrayItem.fireFunctionBinding;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
context.pushError({
|
|
loc: value.args[1].loc,
|
|
description: 'You must use an array literal for an effect dependency array when that effect uses `fire()`',
|
|
category: ErrorCategory.Fire,
|
|
reason: CANNOT_COMPILE_FIRE,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
else if (value.args.length > 1 && value.args[1].kind === 'Spread') {
|
|
context.pushError({
|
|
loc: value.args[1].place.loc,
|
|
description: 'You must use an array literal for an effect dependency array when that effect uses `fire()`',
|
|
category: ErrorCategory.Fire,
|
|
reason: CANNOT_COMPILE_FIRE,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
else if (value.kind === 'CallExpression' &&
|
|
value.callee.identifier.type.kind === 'Function' &&
|
|
value.callee.identifier.type.shapeId === BuiltInFireId &&
|
|
context.inUseEffectLambda()) {
|
|
if (value.args.length === 1 && value.args[0].kind === 'Identifier') {
|
|
const callExpr = context.getCallExpression(value.args[0].identifier.id);
|
|
if (callExpr != null) {
|
|
const calleeId = callExpr.callee.identifier.id;
|
|
const loadLocal = context.getLoadLocalInstr(calleeId);
|
|
if (loadLocal == null) {
|
|
context.pushError({
|
|
loc: value.loc,
|
|
description: null,
|
|
category: ErrorCategory.Invariant,
|
|
reason: '[InsertFire] No loadLocal found for fire call argument',
|
|
suggestions: null,
|
|
});
|
|
continue;
|
|
}
|
|
const fireFunctionBinding = context.getOrGenerateFireFunctionBinding(loadLocal.place, value.loc);
|
|
loadLocal.place = Object.assign({}, fireFunctionBinding);
|
|
deleteInstrs.add(instr.id);
|
|
}
|
|
else {
|
|
context.pushError({
|
|
loc: value.loc,
|
|
description: '`fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed',
|
|
category: ErrorCategory.Fire,
|
|
reason: CANNOT_COMPILE_FIRE,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
let description = 'fire() can only take in a single call expression as an argument';
|
|
if (value.args.length === 0) {
|
|
description += ' but received none';
|
|
}
|
|
else if (value.args.length > 1) {
|
|
description += ' but received multiple arguments';
|
|
}
|
|
else if (value.args[0].kind === 'Spread') {
|
|
description += ' but received a spread argument';
|
|
}
|
|
context.pushError({
|
|
loc: value.loc,
|
|
description,
|
|
category: ErrorCategory.Fire,
|
|
reason: CANNOT_COMPILE_FIRE,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
else if (value.kind === 'CallExpression') {
|
|
context.addCallExpression(lvalue.identifier.id, value);
|
|
}
|
|
else if (value.kind === 'FunctionExpression' &&
|
|
context.inUseEffectLambda()) {
|
|
visitFunctionExpressionAndPropagateFireDependencies(value, context, false);
|
|
}
|
|
else if (value.kind === 'FunctionExpression') {
|
|
context.addFunctionExpression(lvalue.identifier.id, value);
|
|
}
|
|
else if (value.kind === 'LoadLocal') {
|
|
context.addLoadLocalInstr(lvalue.identifier.id, value);
|
|
}
|
|
else if (value.kind === 'LoadGlobal' &&
|
|
value.binding.kind === 'ImportSpecifier' &&
|
|
value.binding.module === 'react' &&
|
|
value.binding.imported === 'fire' &&
|
|
context.inUseEffectLambda()) {
|
|
deleteInstrs.add(instr.id);
|
|
}
|
|
else if (value.kind === 'LoadGlobal') {
|
|
context.addLoadGlobalInstrId(lvalue.identifier.id, instr.id);
|
|
}
|
|
else if (value.kind === 'ArrayExpression') {
|
|
context.addArrayExpression(lvalue.identifier.id, value);
|
|
}
|
|
}
|
|
block.instructions = rewriteInstructions(rewriteInstrs, block.instructions);
|
|
block.instructions = deleteInstructions(deleteInstrs, block.instructions);
|
|
if (rewriteInstrs.size > 0 || deleteInstrs.size > 0) {
|
|
hasRewrite = true;
|
|
fn.env.hasFireRewrite = true;
|
|
}
|
|
}
|
|
if (hasRewrite) {
|
|
markInstructionIds(fn.body);
|
|
}
|
|
}
|
|
function visitFunctionExpressionAndPropagateFireDependencies(fnExpr, context, enteringUseEffect) {
|
|
let withScope = enteringUseEffect
|
|
? context.withUseEffectLambdaScope.bind(context)
|
|
: context.withFunctionScope.bind(context);
|
|
const calleesCapturedByFnExpression = withScope(() => replaceFireFunctions(fnExpr.loweredFunc.func, context));
|
|
for (let contextIdx = 0; contextIdx < fnExpr.loweredFunc.func.context.length; contextIdx++) {
|
|
const contextItem = fnExpr.loweredFunc.func.context[contextIdx];
|
|
const replacedCallee = calleesCapturedByFnExpression.get(contextItem.identifier.id);
|
|
if (replacedCallee != null) {
|
|
fnExpr.loweredFunc.func.context[contextIdx] = Object.assign({}, replacedCallee.fireFunctionBinding);
|
|
}
|
|
}
|
|
context.mergeCalleesFromInnerScope(calleesCapturedByFnExpression);
|
|
return calleesCapturedByFnExpression;
|
|
}
|
|
function* eachReachablePlace(fn) {
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
if (instr.value.kind === 'FunctionExpression' ||
|
|
instr.value.kind === 'ObjectMethod') {
|
|
yield* eachReachablePlace(instr.value.loweredFunc.func);
|
|
}
|
|
else {
|
|
yield* eachInstructionOperand(instr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function ensureNoRemainingCalleeCaptures(fn, context, capturedCallees) {
|
|
var _a;
|
|
for (const place of eachReachablePlace(fn)) {
|
|
const calleeInfo = capturedCallees.get(place.identifier.id);
|
|
if (calleeInfo != null) {
|
|
const calleeName = ((_a = calleeInfo.capturedCalleeIdentifier.name) === null || _a === void 0 ? void 0 : _a.kind) === 'named'
|
|
? calleeInfo.capturedCalleeIdentifier.name.value
|
|
: '<unknown>';
|
|
context.pushError({
|
|
loc: place.loc,
|
|
description: `All uses of ${calleeName} must be either used with a fire() call in \
|
|
this effect or not used with a fire() call at all. ${calleeName} was used with fire() on line \
|
|
${printSourceLocationLine(calleeInfo.fireLoc)} in this effect`,
|
|
category: ErrorCategory.Fire,
|
|
reason: CANNOT_COMPILE_FIRE,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
function ensureNoMoreFireUses(fn, context) {
|
|
for (const place of eachReachablePlace(fn)) {
|
|
if (place.identifier.type.kind === 'Function' &&
|
|
place.identifier.type.shapeId === BuiltInFireId) {
|
|
context.pushError({
|
|
loc: place.identifier.loc,
|
|
description: 'Cannot use `fire` outside of a useEffect function',
|
|
category: ErrorCategory.Fire,
|
|
reason: CANNOT_COMPILE_FIRE,
|
|
suggestions: null,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
function makeLoadUseFireInstruction(env, importedLoadUseFire) {
|
|
const useFirePlace = createTemporaryPlace(env, GeneratedSource);
|
|
useFirePlace.effect = Effect.Read;
|
|
useFirePlace.identifier.type = DefaultNonmutatingHook;
|
|
const instrValue = {
|
|
kind: 'LoadGlobal',
|
|
binding: Object.assign({}, importedLoadUseFire),
|
|
loc: GeneratedSource,
|
|
};
|
|
return {
|
|
id: makeInstructionId(0),
|
|
value: instrValue,
|
|
lvalue: Object.assign({}, useFirePlace),
|
|
loc: GeneratedSource,
|
|
effects: null,
|
|
};
|
|
}
|
|
function makeLoadFireCalleeInstruction(env, fireCalleeIdentifier) {
|
|
const loadedFireCallee = createTemporaryPlace(env, GeneratedSource);
|
|
const fireCallee = {
|
|
kind: 'Identifier',
|
|
identifier: fireCalleeIdentifier,
|
|
reactive: false,
|
|
effect: Effect.Unknown,
|
|
loc: fireCalleeIdentifier.loc,
|
|
};
|
|
return {
|
|
id: makeInstructionId(0),
|
|
value: {
|
|
kind: 'LoadLocal',
|
|
loc: GeneratedSource,
|
|
place: Object.assign({}, fireCallee),
|
|
},
|
|
lvalue: Object.assign({}, loadedFireCallee),
|
|
loc: GeneratedSource,
|
|
effects: null,
|
|
};
|
|
}
|
|
function makeCallUseFireInstruction(env, useFirePlace, argPlace) {
|
|
const useFireCallResultPlace = createTemporaryPlace(env, GeneratedSource);
|
|
useFireCallResultPlace.effect = Effect.Read;
|
|
const useFireCall = {
|
|
kind: 'CallExpression',
|
|
callee: Object.assign({}, useFirePlace),
|
|
args: [argPlace],
|
|
loc: GeneratedSource,
|
|
};
|
|
return {
|
|
id: makeInstructionId(0),
|
|
value: useFireCall,
|
|
lvalue: Object.assign({}, useFireCallResultPlace),
|
|
loc: GeneratedSource,
|
|
effects: null,
|
|
};
|
|
}
|
|
function makeStoreUseFireInstruction(env, useFireCallResultPlace, fireFunctionBindingPlace) {
|
|
promoteTemporary(fireFunctionBindingPlace.identifier);
|
|
const fireFunctionBindingLValuePlace = createTemporaryPlace(env, GeneratedSource);
|
|
return {
|
|
id: makeInstructionId(0),
|
|
value: {
|
|
kind: 'StoreLocal',
|
|
lvalue: {
|
|
kind: InstructionKind.Const,
|
|
place: Object.assign({}, fireFunctionBindingPlace),
|
|
},
|
|
value: Object.assign({}, useFireCallResultPlace),
|
|
type: null,
|
|
loc: GeneratedSource,
|
|
},
|
|
lvalue: fireFunctionBindingLValuePlace,
|
|
loc: GeneratedSource,
|
|
effects: null,
|
|
};
|
|
}
|
|
class Context {
|
|
constructor(env) {
|
|
_Context_env.set(this, void 0);
|
|
_Context_errors.set(this, new CompilerError());
|
|
_Context_callExpressions.set(this, new Map());
|
|
_Context_functionExpressions.set(this, new Map());
|
|
_Context_loadLocals.set(this, new Map());
|
|
_Context_fireCalleesToFireFunctions.set(this, new Map());
|
|
_Context_calleesWithInsertedFire.set(this, new Set());
|
|
_Context_capturedCalleeIdentifierIds.set(this, new Map());
|
|
_Context_inUseEffectLambda.set(this, false);
|
|
_Context_loadGlobalInstructionIds.set(this, new Map());
|
|
_Context_arrayExpressions.set(this, new Map());
|
|
__classPrivateFieldSet(this, _Context_env, env, "f");
|
|
}
|
|
pushError(error) {
|
|
__classPrivateFieldGet(this, _Context_errors, "f").push(error);
|
|
}
|
|
withFunctionScope(fn) {
|
|
fn();
|
|
return __classPrivateFieldGet(this, _Context_capturedCalleeIdentifierIds, "f");
|
|
}
|
|
withUseEffectLambdaScope(fn) {
|
|
const capturedCalleeIdentifierIds = __classPrivateFieldGet(this, _Context_capturedCalleeIdentifierIds, "f");
|
|
const inUseEffectLambda = __classPrivateFieldGet(this, _Context_inUseEffectLambda, "f");
|
|
__classPrivateFieldSet(this, _Context_capturedCalleeIdentifierIds, new Map(), "f");
|
|
__classPrivateFieldSet(this, _Context_inUseEffectLambda, true, "f");
|
|
const resultCapturedCalleeIdentifierIds = this.withFunctionScope(fn);
|
|
__classPrivateFieldSet(this, _Context_capturedCalleeIdentifierIds, capturedCalleeIdentifierIds, "f");
|
|
__classPrivateFieldSet(this, _Context_inUseEffectLambda, inUseEffectLambda, "f");
|
|
return resultCapturedCalleeIdentifierIds;
|
|
}
|
|
addCallExpression(id, callExpr) {
|
|
__classPrivateFieldGet(this, _Context_callExpressions, "f").set(id, callExpr);
|
|
}
|
|
getCallExpression(id) {
|
|
return __classPrivateFieldGet(this, _Context_callExpressions, "f").get(id);
|
|
}
|
|
addLoadLocalInstr(id, loadLocal) {
|
|
__classPrivateFieldGet(this, _Context_loadLocals, "f").set(id, loadLocal);
|
|
}
|
|
getLoadLocalInstr(id) {
|
|
return __classPrivateFieldGet(this, _Context_loadLocals, "f").get(id);
|
|
}
|
|
getOrGenerateFireFunctionBinding(callee, fireLoc) {
|
|
const fireFunctionBinding = getOrInsertWith(__classPrivateFieldGet(this, _Context_fireCalleesToFireFunctions, "f"), callee.identifier.id, () => createTemporaryPlace(__classPrivateFieldGet(this, _Context_env, "f"), GeneratedSource));
|
|
fireFunctionBinding.identifier.type = {
|
|
kind: 'Function',
|
|
shapeId: BuiltInFireFunctionId,
|
|
return: { kind: 'Poly' },
|
|
isConstructor: false,
|
|
};
|
|
__classPrivateFieldGet(this, _Context_capturedCalleeIdentifierIds, "f").set(callee.identifier.id, {
|
|
fireFunctionBinding,
|
|
capturedCalleeIdentifier: callee.identifier,
|
|
fireLoc,
|
|
});
|
|
return fireFunctionBinding;
|
|
}
|
|
mergeCalleesFromInnerScope(innerCallees) {
|
|
for (const [id, calleeInfo] of innerCallees.entries()) {
|
|
__classPrivateFieldGet(this, _Context_capturedCalleeIdentifierIds, "f").set(id, calleeInfo);
|
|
}
|
|
}
|
|
addCalleeWithInsertedFire(id) {
|
|
__classPrivateFieldGet(this, _Context_calleesWithInsertedFire, "f").add(id);
|
|
}
|
|
hasCalleeWithInsertedFire(id) {
|
|
return __classPrivateFieldGet(this, _Context_calleesWithInsertedFire, "f").has(id);
|
|
}
|
|
inUseEffectLambda() {
|
|
return __classPrivateFieldGet(this, _Context_inUseEffectLambda, "f");
|
|
}
|
|
addFunctionExpression(id, fn) {
|
|
__classPrivateFieldGet(this, _Context_functionExpressions, "f").set(id, fn);
|
|
}
|
|
getFunctionExpression(id) {
|
|
return __classPrivateFieldGet(this, _Context_functionExpressions, "f").get(id);
|
|
}
|
|
addLoadGlobalInstrId(id, instrId) {
|
|
__classPrivateFieldGet(this, _Context_loadGlobalInstructionIds, "f").set(id, instrId);
|
|
}
|
|
getLoadGlobalInstrId(id) {
|
|
return __classPrivateFieldGet(this, _Context_loadGlobalInstructionIds, "f").get(id);
|
|
}
|
|
addArrayExpression(id, array) {
|
|
__classPrivateFieldGet(this, _Context_arrayExpressions, "f").set(id, array);
|
|
}
|
|
getArrayExpression(id) {
|
|
return __classPrivateFieldGet(this, _Context_arrayExpressions, "f").get(id);
|
|
}
|
|
hasErrors() {
|
|
return __classPrivateFieldGet(this, _Context_errors, "f").hasAnyErrors();
|
|
}
|
|
throwIfErrorsFound() {
|
|
if (this.hasErrors())
|
|
throw __classPrivateFieldGet(this, _Context_errors, "f");
|
|
}
|
|
}
|
|
_Context_env = new WeakMap(), _Context_errors = new WeakMap(), _Context_callExpressions = new WeakMap(), _Context_functionExpressions = new WeakMap(), _Context_loadLocals = new WeakMap(), _Context_fireCalleesToFireFunctions = new WeakMap(), _Context_calleesWithInsertedFire = new WeakMap(), _Context_capturedCalleeIdentifierIds = new WeakMap(), _Context_inUseEffectLambda = new WeakMap(), _Context_loadGlobalInstructionIds = new WeakMap(), _Context_arrayExpressions = new WeakMap();
|
|
function deleteInstructions(deleteInstrs, instructions) {
|
|
if (deleteInstrs.size > 0) {
|
|
const newInstrs = instructions.filter(instr => !deleteInstrs.has(instr.id));
|
|
return newInstrs;
|
|
}
|
|
return instructions;
|
|
}
|
|
function rewriteInstructions(rewriteInstrs, instructions) {
|
|
if (rewriteInstrs.size > 0) {
|
|
const newInstrs = [];
|
|
for (const instr of instructions) {
|
|
const newInstrsAtId = rewriteInstrs.get(instr.id);
|
|
if (newInstrsAtId != null) {
|
|
newInstrs.push(...newInstrsAtId, instr);
|
|
}
|
|
else {
|
|
newInstrs.push(instr);
|
|
}
|
|
}
|
|
return newInstrs;
|
|
}
|
|
return instructions;
|
|
}
|
|
|
|
function validateNoImpureFunctionsInRender(fn) {
|
|
const errors = new CompilerError();
|
|
for (const [, block] of fn.body.blocks) {
|
|
for (const instr of block.instructions) {
|
|
const value = instr.value;
|
|
if (value.kind === 'MethodCall' || value.kind == 'CallExpression') {
|
|
const callee = value.kind === 'MethodCall' ? value.property : value.callee;
|
|
const signature = getFunctionCallSignature(fn.env, callee.identifier.type);
|
|
if (signature != null && signature.impure === true) {
|
|
errors.pushDiagnostic(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)',
|
|
suggestions: null,
|
|
}).withDetails({
|
|
kind: 'error',
|
|
loc: callee.loc,
|
|
message: 'Cannot call impure function',
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return errors.asResult();
|
|
}
|
|
|
|
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 errors = new CompilerError();
|
|
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';
|
|
errors.pushDiagnostic(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);
|
|
}
|
|
}
|
|
return errors.asResult();
|
|
}
|
|
|
|
function validateNoDerivedComputationsInEffects(fn) {
|
|
const candidateDependencies = new Map();
|
|
const functions = new Map();
|
|
const locals = new Map();
|
|
const errors = new CompilerError();
|
|
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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: value.loc,
|
|
message: 'this is checked as a place above',
|
|
},
|
|
],
|
|
});
|
|
return (_a = locals.get(dep.identifier.id)) !== null && _a !== void 0 ? _a : dep.identifier.id;
|
|
});
|
|
validateEffect$1(effectFunction.loweredFunc.func, dependencies, errors);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (errors.hasAnyErrors()) {
|
|
throw errors;
|
|
}
|
|
}
|
|
function validateEffect$1(effectFunction, effectDeps, errors) {
|
|
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) {
|
|
errors.push({
|
|
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,
|
|
});
|
|
}
|
|
}
|
|
|
|
class DerivationCache {
|
|
constructor() {
|
|
this.hasChanges = false;
|
|
this.cache = new Map();
|
|
}
|
|
snapshot() {
|
|
const hasChanges = this.hasChanges;
|
|
this.hasChanges = false;
|
|
return hasChanges;
|
|
}
|
|
addDerivationEntry(derivedVar, sourcesIds, typeOfValue) {
|
|
var _a, _b;
|
|
let newValue = {
|
|
place: derivedVar,
|
|
sourcesIds: new Set(),
|
|
typeOfValue: typeOfValue !== null && typeOfValue !== void 0 ? typeOfValue : 'ignored',
|
|
};
|
|
if (sourcesIds !== undefined) {
|
|
for (const id of sourcesIds) {
|
|
const sourcePlace = (_a = this.cache.get(id)) === null || _a === void 0 ? void 0 : _a.place;
|
|
if (sourcePlace === undefined) {
|
|
continue;
|
|
}
|
|
if (sourcePlace.identifier.name === null ||
|
|
((_b = sourcePlace.identifier.name) === null || _b === void 0 ? void 0 : _b.kind) === 'promoted') {
|
|
newValue.sourcesIds.add(derivedVar.identifier.id);
|
|
}
|
|
else {
|
|
newValue.sourcesIds.add(sourcePlace.identifier.id);
|
|
}
|
|
}
|
|
}
|
|
if (newValue.sourcesIds.size === 0) {
|
|
newValue.sourcesIds.add(derivedVar.identifier.id);
|
|
}
|
|
const existingValue = this.cache.get(derivedVar.identifier.id);
|
|
if (existingValue === undefined ||
|
|
!this.isDerivationEqual(existingValue, newValue)) {
|
|
this.cache.set(derivedVar.identifier.id, newValue);
|
|
this.hasChanges = true;
|
|
}
|
|
}
|
|
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 validateNoDerivedComputationsInEffects_exp(fn) {
|
|
const functions = new Map();
|
|
const derivationCache = new DerivationCache();
|
|
const errors = new CompilerError();
|
|
const effects = new Set();
|
|
const setStateCache = new Map();
|
|
const effectSetStateCache = new Map();
|
|
const context = {
|
|
functions,
|
|
errors,
|
|
derivationCache,
|
|
effects,
|
|
setStateCache,
|
|
effectSetStateCache,
|
|
};
|
|
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([param.identifier.id]),
|
|
typeOfValue: 'fromProps',
|
|
});
|
|
context.derivationCache.hasChanges = 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([props.identifier.id]),
|
|
typeOfValue: 'fromProps',
|
|
});
|
|
context.derivationCache.hasChanges = true;
|
|
}
|
|
}
|
|
let isFirstPass = true;
|
|
do {
|
|
for (const block of fn.body.blocks.values()) {
|
|
recordPhiDerivations(block, context);
|
|
for (const instr of block.instructions) {
|
|
recordInstructionDerivations(instr, context, isFirstPass);
|
|
}
|
|
}
|
|
isFirstPass = false;
|
|
} while (context.derivationCache.snapshot());
|
|
for (const effect of effects) {
|
|
validateEffect(effect, context);
|
|
}
|
|
if (errors.hasAnyErrors()) {
|
|
throw errors;
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
function joinValue(lvalueType, valueType) {
|
|
if (lvalueType === 'ignored')
|
|
return valueType;
|
|
if (valueType === 'ignored')
|
|
return lvalueType;
|
|
if (lvalueType === valueType)
|
|
return lvalueType;
|
|
return 'fromPropsAndState';
|
|
}
|
|
function recordInstructionDerivations(instr, context, isFirstPass) {
|
|
let typeOfValue = 'ignored';
|
|
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) {
|
|
for (const instr of block.instructions) {
|
|
recordInstructionDerivations(instr, context, isFirstPass);
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
if (effectFunction != null) {
|
|
context.effects.add(effectFunction.loweredFunc.func);
|
|
}
|
|
}
|
|
else if (isUseStateType(lvalue.identifier) && value.args.length > 0) {
|
|
const stateValueSource = value.args[0];
|
|
if (stateValueSource.kind === 'Identifier') {
|
|
sources.add(stateValueSource.identifier.id);
|
|
}
|
|
typeOfValue = joinValue(typeOfValue, 'fromState');
|
|
}
|
|
}
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
if (isSetStateType(operand.identifier) &&
|
|
operand.loc !== GeneratedSource &&
|
|
isFirstPass) {
|
|
if (context.setStateCache.has(operand.loc.identifierName)) {
|
|
context.setStateCache.get(operand.loc.identifierName).push(operand);
|
|
}
|
|
else {
|
|
context.setStateCache.set(operand.loc.identifierName, [operand]);
|
|
}
|
|
}
|
|
const operandMetadata = context.derivationCache.cache.get(operand.identifier.id);
|
|
if (operandMetadata === undefined) {
|
|
continue;
|
|
}
|
|
typeOfValue = joinValue(typeOfValue, operandMetadata.typeOfValue);
|
|
for (const id of operandMetadata.sourcesIds) {
|
|
sources.add(id);
|
|
}
|
|
}
|
|
if (typeOfValue === 'ignored') {
|
|
return;
|
|
}
|
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
context.derivationCache.addDerivationEntry(lvalue, sources, typeOfValue);
|
|
}
|
|
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)) {
|
|
context.derivationCache.addDerivationEntry(operand, sources, typeOfValue);
|
|
}
|
|
break;
|
|
}
|
|
case Effect.Freeze:
|
|
case Effect.Read: {
|
|
break;
|
|
}
|
|
case Effect.Unknown: {
|
|
CompilerError.invariant(false, {
|
|
reason: 'Unexpected unknown effect',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: operand.loc,
|
|
message: 'Unexpected unknown effect',
|
|
},
|
|
],
|
|
});
|
|
}
|
|
default: {
|
|
assertExhaustive$1(operand.effect, `Unexpected effect kind \`${operand.effect}\``);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function validateEffect(effectFunction, context) {
|
|
const seenBlocks = new Set();
|
|
const effectDerivedSetStateCalls = [];
|
|
const globals = new Set();
|
|
for (const block of effectFunction.body.blocks.values()) {
|
|
for (const pred of block.preds) {
|
|
if (!seenBlocks.has(pred)) {
|
|
return;
|
|
}
|
|
}
|
|
for (const instr of block.instructions) {
|
|
if (isUseRefType(instr.lvalue.identifier)) {
|
|
return;
|
|
}
|
|
for (const operand of eachInstructionOperand(instr)) {
|
|
if (isSetStateType(operand.identifier) &&
|
|
operand.loc !== GeneratedSource) {
|
|
if (context.effectSetStateCache.has(operand.loc.identifierName)) {
|
|
context.effectSetStateCache
|
|
.get(operand.loc.identifierName)
|
|
.push(operand);
|
|
}
|
|
else {
|
|
context.effectSetStateCache.set(operand.loc.identifierName, [
|
|
operand,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
if (instr.value.kind === 'CallExpression' &&
|
|
isSetStateType(instr.value.callee.identifier) &&
|
|
instr.value.args.length === 1 &&
|
|
instr.value.args[0].kind === 'Identifier') {
|
|
const argMetadata = context.derivationCache.cache.get(instr.value.args[0].identifier.id);
|
|
if (argMetadata !== undefined) {
|
|
effectDerivedSetStateCalls.push({
|
|
value: instr.value,
|
|
loc: instr.value.callee.loc,
|
|
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) {
|
|
if (derivedSetStateCall.loc !== GeneratedSource &&
|
|
context.effectSetStateCache.has(derivedSetStateCall.loc.identifierName) &&
|
|
context.setStateCache.has(derivedSetStateCall.loc.identifierName) &&
|
|
context.effectSetStateCache.get(derivedSetStateCall.loc.identifierName)
|
|
.length ===
|
|
context.setStateCache.get(derivedSetStateCall.loc.identifierName)
|
|
.length -
|
|
1) {
|
|
const derivedDepsStr = Array.from(derivedSetStateCall.sourceIds)
|
|
.map(sourceId => {
|
|
var _a;
|
|
const sourceMetadata = context.derivationCache.cache.get(sourceId);
|
|
return (_a = sourceMetadata === null || sourceMetadata === void 0 ? void 0 : sourceMetadata.place.identifier.name) === null || _a === void 0 ? void 0 : _a.value;
|
|
})
|
|
.filter(Boolean)
|
|
.join(', ');
|
|
let description;
|
|
if (derivedSetStateCall.typeOfValue === 'fromProps') {
|
|
description = `From props: [${derivedDepsStr}]`;
|
|
}
|
|
else if (derivedSetStateCall.typeOfValue === 'fromState') {
|
|
description = `From local state: [${derivedDepsStr}]`;
|
|
}
|
|
else {
|
|
description = `From props and local state: [${derivedDepsStr}]`;
|
|
}
|
|
context.errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
description: `Derived values (${description}) should be computed during render, rather than in effects. Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user`,
|
|
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 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).unwrap();
|
|
log({ kind: 'hir', name: 'HIR', value: hir });
|
|
pruneMaybeThrows(hir);
|
|
log({ kind: 'hir', name: 'PruneMaybeThrows', value: hir });
|
|
validateContextVariableLValues(hir);
|
|
validateUseMemo(hir).unwrap();
|
|
if (env.isInferredMemoEnabled &&
|
|
!env.config.enablePreserveExistingManualUseMemo &&
|
|
!env.config.disableMemoizationForDebugging &&
|
|
!env.config.enableChangeDetectionForDebugging) {
|
|
dropManualMemoization(hir).unwrap();
|
|
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.isInferredMemoEnabled) {
|
|
if (env.config.validateHooksUsage) {
|
|
validateHooksUsage(hir).unwrap();
|
|
}
|
|
if (env.config.validateNoCapitalizedCalls) {
|
|
validateNoCapitalizedCalls(hir).unwrap();
|
|
}
|
|
}
|
|
if (env.config.enableFire) {
|
|
transformFire(hir);
|
|
log({ kind: 'hir', name: 'TransformFire', value: hir });
|
|
}
|
|
if (env.config.lowerContextAccess) {
|
|
lowerContextAccess(hir, env.config.lowerContextAccess);
|
|
}
|
|
optimizePropsMethodCalls(hir);
|
|
log({ kind: 'hir', name: 'OptimizePropsMethodCalls', value: hir });
|
|
analyseFunctions(hir);
|
|
log({ kind: 'hir', name: 'AnalyseFunctions', value: hir });
|
|
const mutabilityAliasingErrors = inferMutationAliasingEffects(hir);
|
|
log({ kind: 'hir', name: 'InferMutationAliasingEffects', value: hir });
|
|
if (env.isInferredMemoEnabled) {
|
|
if (mutabilityAliasingErrors.isErr()) {
|
|
throw mutabilityAliasingErrors.unwrapErr();
|
|
}
|
|
}
|
|
deadCodeElimination(hir);
|
|
log({ kind: 'hir', name: 'DeadCodeElimination', value: hir });
|
|
if (env.config.enableInstructionReordering) {
|
|
instructionReordering(hir);
|
|
log({ kind: 'hir', name: 'InstructionReordering', value: hir });
|
|
}
|
|
pruneMaybeThrows(hir);
|
|
log({ kind: 'hir', name: 'PruneMaybeThrows', value: hir });
|
|
const mutabilityAliasingRangeErrors = inferMutationAliasingRanges(hir, {
|
|
isFunctionExpression: false,
|
|
});
|
|
log({ kind: 'hir', name: 'InferMutationAliasingRanges', value: hir });
|
|
if (env.isInferredMemoEnabled) {
|
|
if (mutabilityAliasingRangeErrors.isErr()) {
|
|
throw mutabilityAliasingRangeErrors.unwrapErr();
|
|
}
|
|
validateLocalsNotReassignedAfterRender(hir);
|
|
}
|
|
if (env.isInferredMemoEnabled) {
|
|
if (env.config.assertValidMutableRanges) {
|
|
assertValidMutableRanges(hir);
|
|
}
|
|
if (env.config.validateRefAccessDuringRender) {
|
|
validateNoRefAccessInRender(hir).unwrap();
|
|
}
|
|
if (env.config.validateNoSetStateInRender) {
|
|
validateNoSetStateInRender(hir).unwrap();
|
|
}
|
|
if (env.config.validateNoDerivedComputationsInEffects) {
|
|
validateNoDerivedComputationsInEffects(hir);
|
|
}
|
|
if (env.config.validateNoDerivedComputationsInEffects_exp) {
|
|
validateNoDerivedComputationsInEffects_exp(hir);
|
|
}
|
|
if (env.config.validateNoSetStateInEffects) {
|
|
env.logErrors(validateNoSetStateInEffects(hir, env));
|
|
}
|
|
if (env.config.validateNoJSXInTryStatements) {
|
|
env.logErrors(validateNoJSXInTryStatement(hir));
|
|
}
|
|
if (env.config.validateNoImpureFunctionsInRender) {
|
|
validateNoImpureFunctionsInRender(hir).unwrap();
|
|
}
|
|
validateNoFreezingKnownMutableFunctions(hir).unwrap();
|
|
}
|
|
inferReactivePlaces(hir);
|
|
log({ kind: 'hir', name: 'InferReactivePlaces', value: hir });
|
|
rewriteInstructionKindsBasedOnReassignment(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'RewriteInstructionKindsBasedOnReassignment',
|
|
value: hir,
|
|
});
|
|
if (env.isInferredMemoEnabled) {
|
|
if (env.config.validateStaticComponents) {
|
|
env.logErrors(validateStaticComponents(hir));
|
|
}
|
|
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,
|
|
});
|
|
if (env.config.inferEffectDependencies) {
|
|
inferEffectDependencies(hir);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'InferEffectDependencies',
|
|
value: hir,
|
|
});
|
|
}
|
|
if (env.config.inlineJsxTransform) {
|
|
inlineJsxTransform(hir, env.config.inlineJsxTransform);
|
|
log({
|
|
kind: 'hir',
|
|
name: 'inlineJsxTransform',
|
|
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,
|
|
});
|
|
if (env.config.enableChangeDetectionForDebugging != null) {
|
|
pruneInitializationDependencies(reactiveFunction);
|
|
log({
|
|
kind: 'reactive',
|
|
name: 'PruneInitializationDependencies',
|
|
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.validateMemoizedEffectDependencies) {
|
|
validateMemoizedEffectDependencies(reactiveFunction).unwrap();
|
|
}
|
|
if (env.config.enablePreserveExistingMemoizationGuarantees ||
|
|
env.config.validatePreserveExistingMemoizationGuarantees) {
|
|
validatePreservedManualMemoization(reactiveFunction).unwrap();
|
|
}
|
|
const ast = codegenFunction(reactiveFunction, {
|
|
uniqueIdentifiers,
|
|
fbtOperands,
|
|
}).unwrap();
|
|
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.throwUnknownException__testonly) {
|
|
throw new Error('unexpected error');
|
|
}
|
|
return 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.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`,
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_c = (_b = insertedFuncDecl.node) === null || _b === void 0 ? void 0 : _b.loc) !== null && _c !== void 0 ? _c : null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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;
|
|
if (shouldSkipCompilation(program, pass)) {
|
|
return null;
|
|
}
|
|
const restrictedImportsErr = validateRestrictedImports(program, pass.opts.environment);
|
|
if (restrictedImportsErr) {
|
|
handleError(restrictedImportsErr, pass, null);
|
|
return null;
|
|
}
|
|
const suppressions = findProgramSuppressions(pass.comments, (_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 = [];
|
|
while (queue.length !== 0) {
|
|
const current = queue.shift();
|
|
const compiled = processFn(current.fn, current.fnType, programContext);
|
|
if (compiled != null) {
|
|
for (const outlined of compiled.outlined) {
|
|
CompilerError.invariant(outlined.fn.outlined.length === 0, {
|
|
reason: 'Unexpected nested outlined functions',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: outlined.fn.loc,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
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 null;
|
|
}
|
|
applyCompiledFunctions(program, compiledFns, pass, programContext);
|
|
return {
|
|
retryErrors: programContext.retryErrors,
|
|
inferredEffectLocations: programContext.inferredEffectLocations,
|
|
};
|
|
}
|
|
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 (pass.opts.environment.validateNoDynamicallyCreatedComponentsOrHooks) {
|
|
validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext);
|
|
}
|
|
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) {
|
|
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);
|
|
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);
|
|
}
|
|
const retryResult = retryCompileFunction(fn, fnType, programContext);
|
|
if (retryResult == null) {
|
|
return null;
|
|
}
|
|
compiledFn = retryResult;
|
|
}
|
|
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.noEmit) {
|
|
for (const loc of compiledFn.inferredEffectLocations) {
|
|
if (loc !== GeneratedSource) {
|
|
programContext.inferredEffectLocations.add(loc);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
else if (programContext.opts.compilationMode === 'annotation' &&
|
|
directives.optIn == null) {
|
|
return null;
|
|
}
|
|
else {
|
|
return compiledFn;
|
|
}
|
|
}
|
|
function tryCompileFunction(fn, fnType, programContext) {
|
|
const suppressionsInFunction = filterSuppressionsThatAffectFunction(programContext.suppressions, fn);
|
|
if (suppressionsInFunction.length > 0) {
|
|
return {
|
|
kind: 'error',
|
|
error: suppressionsToCompilerError(suppressionsInFunction),
|
|
};
|
|
}
|
|
try {
|
|
return {
|
|
kind: 'compile',
|
|
compiledFn: compileFn(fn, programContext.opts.environment, fnType, 'all_features', programContext, programContext.opts.logger, programContext.filename, programContext.code),
|
|
};
|
|
}
|
|
catch (err) {
|
|
return { kind: 'error', error: err };
|
|
}
|
|
}
|
|
function retryCompileFunction(fn, fnType, programContext) {
|
|
const environment = programContext.opts.environment;
|
|
if (!(environment.enableFire || environment.inferEffectDependencies != null)) {
|
|
return null;
|
|
}
|
|
try {
|
|
const retryResult = compileFn(fn, environment, fnType, 'no_inferred_memo', programContext, programContext.opts.logger, programContext.filename, programContext.code);
|
|
if (!retryResult.hasFireRewrite && !retryResult.hasInferredEffect) {
|
|
return null;
|
|
}
|
|
return retryResult;
|
|
}
|
|
catch (err) {
|
|
if (err instanceof CompilerError) {
|
|
programContext.retryErrors.push({ fn, error: err });
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
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 validateNoDynamicallyCreatedComponentsOrHooks(fn, pass, programContext) {
|
|
const parentNameExpr = getFunctionName$1(fn);
|
|
const parentName = parentNameExpr !== null && parentNameExpr.isIdentifier()
|
|
? parentNameExpr.node.name
|
|
: '<anonymous>';
|
|
const validateNestedFunction = (nestedFn) => {
|
|
var _a, _b, _c, _d;
|
|
if (nestedFn.node === fn.node ||
|
|
programContext.alreadyCompiled.has(nestedFn.node)) {
|
|
return;
|
|
}
|
|
if (nestedFn.scope.getProgramParent() !== nestedFn.scope.parent) {
|
|
const nestedFnType = getReactFunctionType(nestedFn, pass);
|
|
const nestedFnNameExpr = getFunctionName$1(nestedFn);
|
|
const nestedName = nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
|
|
? nestedFnNameExpr.node.name
|
|
: '<anonymous>';
|
|
if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
|
|
CompilerError.throwDiagnostic({
|
|
category: ErrorCategory.Factories,
|
|
reason: `Components and hooks cannot be created dynamically`,
|
|
description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
message: 'this function dynamically created a component/hook',
|
|
loc: (_b = (_a = parentNameExpr === null || parentNameExpr === void 0 ? void 0 : parentNameExpr.node.loc) !== null && _a !== void 0 ? _a : fn.node.loc) !== null && _b !== void 0 ? _b : null,
|
|
},
|
|
{
|
|
kind: 'error',
|
|
message: 'the component is created here',
|
|
loc: (_d = (_c = nestedFnNameExpr === null || nestedFnNameExpr === void 0 ? void 0 : nestedFnNameExpr.node.loc) !== null && _c !== void 0 ? _c : nestedFn.node.loc) !== null && _d !== void 0 ? _d : null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}
|
|
nestedFn.skip();
|
|
};
|
|
fn.traverse({
|
|
FunctionDeclaration: validateNestedFunction,
|
|
FunctionExpression: validateNestedFunction,
|
|
ArrowFunctionExpression: validateNestedFunction,
|
|
});
|
|
}
|
|
function getReactFunctionType(fn, pass) {
|
|
var _a, _b;
|
|
const hookPattern = pass.opts.environment.hookPattern;
|
|
if (fn.node.body.type === 'BlockStatement') {
|
|
const optInDirectives = tryFindDirectiveEnablingMemoization(fn.node.body.directives, pass.opts);
|
|
if (optInDirectives.unwrapOr(null) != null) {
|
|
return (_a = getComponentOrHookLike(fn, hookPattern)) !== 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, hookPattern);
|
|
}
|
|
case 'syntax': {
|
|
return componentSyntaxType;
|
|
}
|
|
case 'all': {
|
|
return (_b = getComponentOrHookLike(fn, hookPattern)) !== 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, hookPattern) {
|
|
if (hookPattern !== null) {
|
|
return new RegExp(hookPattern).test(s);
|
|
}
|
|
return /^use[A-Z0-9]/.test(s);
|
|
}
|
|
function isHook$1(path, hookPattern) {
|
|
if (path.isIdentifier()) {
|
|
return isHookName$1(path.node.name, hookPattern);
|
|
}
|
|
else if (path.isMemberExpression() &&
|
|
!path.node.computed &&
|
|
isHook$1(path.get('property'), hookPattern)) {
|
|
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, hookPattern) {
|
|
const functionName = getFunctionName$1(node);
|
|
if (functionName !== null && isComponentName$1(functionName)) {
|
|
let isComponent = callsHooksOrCreatesJsx(node, hookPattern) &&
|
|
isValidComponentParams(node.get('params')) &&
|
|
!returnsNonNode(node);
|
|
return isComponent ? 'Component' : null;
|
|
}
|
|
else if (functionName !== null && isHook$1(functionName, hookPattern)) {
|
|
return callsHooksOrCreatesJsx(node, hookPattern) ? 'Hook' : null;
|
|
}
|
|
if (node.isFunctionExpression() || node.isArrowFunctionExpression()) {
|
|
if (isForwardRefCallback$1(node) || isMemoCallback$1(node)) {
|
|
return callsHooksOrCreatesJsx(node, hookPattern) ? 'Component' : null;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
function skipNestedFunctions(node) {
|
|
return (fn) => {
|
|
if (fn.node !== node.node) {
|
|
fn.skip();
|
|
}
|
|
};
|
|
}
|
|
function callsHooksOrCreatesJsx(node, hookPattern) {
|
|
let invokesHooks = false;
|
|
let createsJsx = false;
|
|
node.traverse({
|
|
JSX() {
|
|
createsJsx = true;
|
|
},
|
|
CallExpression(call) {
|
|
const callee = call.get('callee');
|
|
if (callee.isExpression() && isHook$1(callee, hookPattern)) {
|
|
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',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: null,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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.retryErrors = [];
|
|
this.inferredEffectLocations = new Set();
|
|
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) {
|
|
if (this.opts.environment.hookPattern == null) {
|
|
return isHookName$2(name);
|
|
}
|
|
else {
|
|
const match = new RegExp(this.opts.environment.hookPattern).exec(name);
|
|
return (match != null && typeof match[1] === 'string' && isHookName$2(match[1]));
|
|
}
|
|
}
|
|
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})`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
suggestions: null,
|
|
});
|
|
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}`,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: GeneratedSource,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
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',
|
|
]);
|
|
const defaultOptions = {
|
|
compilationMode: 'infer',
|
|
panicThreshold: 'none',
|
|
environment: parseEnvironmentConfig({}).unwrap(),
|
|
logger: null,
|
|
gating: null,
|
|
noEmit: false,
|
|
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 }) });
|
|
}
|
|
|
|
function throwInvalidReact(options, { logger, filename }) {
|
|
logger === null || logger === void 0 ? void 0 : logger.logEvent(filename, {
|
|
kind: 'CompileError',
|
|
fnLoc: null,
|
|
detail: new CompilerDiagnostic(options),
|
|
});
|
|
CompilerError.throwDiagnostic(options);
|
|
}
|
|
function isAutodepsSigil(arg) {
|
|
if (arg.isIdentifier() && arg.node.name === 'AUTODEPS') {
|
|
const binding = arg.scope.getBinding(arg.node.name);
|
|
if (binding && binding.path.isImportSpecifier()) {
|
|
const importSpecifier = binding.path.node;
|
|
if (importSpecifier.imported.type === 'Identifier') {
|
|
return importSpecifier.imported.name === 'AUTODEPS';
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
if (arg.isMemberExpression() && !arg.node.computed) {
|
|
const object = arg.get('object');
|
|
const property = arg.get('property');
|
|
if (object.isIdentifier() &&
|
|
object.node.name === 'React' &&
|
|
property.isIdentifier() &&
|
|
property.node.name === 'AUTODEPS') {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function assertValidEffectImportReference(autodepsIndex, paths, context) {
|
|
var _a;
|
|
for (const path of paths) {
|
|
const parent = path.parentPath;
|
|
if (parent != null && parent.isCallExpression()) {
|
|
const args = parent.get('arguments');
|
|
const maybeCalleeLoc = path.node.loc;
|
|
const hasInferredEffect = maybeCalleeLoc != null &&
|
|
context.inferredEffectLocations.has(maybeCalleeLoc);
|
|
const hasAutodepsArg = args.some(isAutodepsSigil);
|
|
if (hasAutodepsArg && !hasInferredEffect) {
|
|
const maybeErrorDiagnostic = matchCompilerDiagnostic(path, context.transformErrors);
|
|
throwInvalidReact({
|
|
category: ErrorCategory.AutomaticEffectDependencies,
|
|
reason: 'Cannot infer dependencies of this effect. This will break your build!',
|
|
description: 'To resolve, either pass a dependency array or fix reported compiler bailout diagnostics' +
|
|
(maybeErrorDiagnostic ? ` ${maybeErrorDiagnostic}` : ''),
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
message: 'Cannot infer dependencies',
|
|
loc: (_a = parent.node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
},
|
|
],
|
|
}, context);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function assertValidFireImportReference(paths, context) {
|
|
var _a;
|
|
if (paths.length > 0) {
|
|
const maybeErrorDiagnostic = matchCompilerDiagnostic(paths[0], context.transformErrors);
|
|
throwInvalidReact({
|
|
category: ErrorCategory.Fire,
|
|
reason: '[Fire] Untransformed reference to compiler-required feature.',
|
|
description: 'Either remove this `fire` call or ensure it is successfully transformed by the compiler' +
|
|
(maybeErrorDiagnostic != null ? ` ${maybeErrorDiagnostic}` : ''),
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
message: 'Untransformed `fire` call',
|
|
loc: (_a = paths[0].node.loc) !== null && _a !== void 0 ? _a : GeneratedSource,
|
|
},
|
|
],
|
|
}, context);
|
|
}
|
|
}
|
|
function validateNoUntransformedReferences(path, filename, logger, env, compileResult) {
|
|
const moduleLoadChecks = new Map();
|
|
if (env.enableFire) {
|
|
for (const module of Environment.knownReactModules) {
|
|
const react = getOrInsertWith(moduleLoadChecks, module, () => new Map());
|
|
react.set('fire', assertValidFireImportReference);
|
|
}
|
|
}
|
|
if (env.inferEffectDependencies) {
|
|
for (const { function: { source, importSpecifierName }, autodepsIndex, } of env.inferEffectDependencies) {
|
|
const module = getOrInsertWith(moduleLoadChecks, source, () => new Map());
|
|
module.set(importSpecifierName, assertValidEffectImportReference.bind(null, autodepsIndex));
|
|
}
|
|
}
|
|
if (moduleLoadChecks.size > 0) {
|
|
transformProgram(path, moduleLoadChecks, filename, logger, compileResult);
|
|
}
|
|
}
|
|
function validateImportSpecifier(specifier, importSpecifierChecks, state) {
|
|
var _a;
|
|
const imported = specifier.get('imported');
|
|
const specifierName = imported.node.type === 'Identifier'
|
|
? imported.node.name
|
|
: imported.node.value;
|
|
const checkFn = importSpecifierChecks.get(specifierName);
|
|
if (checkFn == null) {
|
|
return;
|
|
}
|
|
if (state.shouldInvalidateScopes) {
|
|
state.shouldInvalidateScopes = false;
|
|
state.program.scope.crawl();
|
|
}
|
|
const local = specifier.get('local');
|
|
const binding = local.scope.getBinding(local.node.name);
|
|
CompilerError.invariant(binding != null, {
|
|
reason: 'Expected binding to be found for import specifier',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_a = local.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
checkFn(binding.referencePaths, state);
|
|
}
|
|
function validateNamespacedImport(specifier, importSpecifierChecks, state) {
|
|
var _a;
|
|
if (state.shouldInvalidateScopes) {
|
|
state.shouldInvalidateScopes = false;
|
|
state.program.scope.crawl();
|
|
}
|
|
const local = specifier.get('local');
|
|
const binding = local.scope.getBinding(local.node.name);
|
|
const defaultCheckFn = importSpecifierChecks.get(DEFAULT_EXPORT);
|
|
CompilerError.invariant(binding != null, {
|
|
reason: 'Expected binding to be found for import specifier',
|
|
description: null,
|
|
details: [
|
|
{
|
|
kind: 'error',
|
|
loc: (_a = local.node.loc) !== null && _a !== void 0 ? _a : null,
|
|
message: null,
|
|
},
|
|
],
|
|
});
|
|
const filteredReferences = new Map();
|
|
for (const reference of binding.referencePaths) {
|
|
if (defaultCheckFn != null) {
|
|
getOrInsertWith(filteredReferences, defaultCheckFn, () => []).push(reference);
|
|
}
|
|
const parent = reference.parentPath;
|
|
if (parent != null &&
|
|
parent.isMemberExpression() &&
|
|
parent.get('object') === reference) {
|
|
if (parent.node.computed || parent.node.property.type !== 'Identifier') {
|
|
continue;
|
|
}
|
|
const checkFn = importSpecifierChecks.get(parent.node.property.name);
|
|
if (checkFn != null) {
|
|
getOrInsertWith(filteredReferences, checkFn, () => []).push(parent);
|
|
}
|
|
}
|
|
}
|
|
for (const [checkFn, references] of filteredReferences) {
|
|
checkFn(references, state);
|
|
}
|
|
}
|
|
function transformProgram(path, moduleLoadChecks, filename, logger, compileResult) {
|
|
var _a, _b;
|
|
const traversalState = {
|
|
shouldInvalidateScopes: true,
|
|
program: path,
|
|
filename,
|
|
logger,
|
|
transformErrors: (_a = compileResult === null || compileResult === void 0 ? void 0 : compileResult.retryErrors) !== null && _a !== void 0 ? _a : [],
|
|
inferredEffectLocations: (_b = compileResult === null || compileResult === void 0 ? void 0 : compileResult.inferredEffectLocations) !== null && _b !== void 0 ? _b : new Set(),
|
|
};
|
|
path.traverse({
|
|
ImportDeclaration(path) {
|
|
const importSpecifierChecks = moduleLoadChecks.get(path.node.source.value);
|
|
if (importSpecifierChecks == null) {
|
|
return;
|
|
}
|
|
const specifiers = path.get('specifiers');
|
|
for (const specifier of specifiers) {
|
|
if (specifier.isImportSpecifier()) {
|
|
validateImportSpecifier(specifier, importSpecifierChecks, traversalState);
|
|
}
|
|
else {
|
|
validateNamespacedImport(specifier, importSpecifierChecks, traversalState);
|
|
}
|
|
}
|
|
},
|
|
});
|
|
}
|
|
function matchCompilerDiagnostic(badReference, transformErrors) {
|
|
for (const { fn, error } of transformErrors) {
|
|
if (fn.isAncestor(badReference)) {
|
|
return error.toString();
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
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, _d;
|
|
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 }) });
|
|
}
|
|
const result = 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,
|
|
});
|
|
validateNoUntransformedReferences(prog, (_d = pass.filename) !== null && _d !== void 0 ? _d : null, opts.logger, opts.environment, result);
|
|
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,
|
|
});
|
|
}
|
|
}
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
var _LRUCache_values, _LRUCache_headIdx;
|
|
const COMPILER_OPTIONS = {
|
|
noEmit: true,
|
|
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,
|
|
},
|
|
};
|
|
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;
|
|
}
|
|
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,
|
|
},
|
|
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));
|
|
}
|
|
},
|
|
};
|
|
},
|
|
};
|
|
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];
|
|
}
|
|
|
|
const rules = Object.assign({ 'exhaustive-deps': rule$1, 'rules-of-hooks': rule }, Object.fromEntries(Object.entries(allRules).map(([name, config]) => [name, config.rule])));
|
|
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;
|
|
})();
|
|
}
|