| | |
| | | |
| | | class InnerGraphPlugin { |
| | | /** |
| | | * Apply the plugin |
| | | * Applies the plugin by registering its hooks on the compiler. |
| | | * @param {Compiler} compiler the compiler instance |
| | | * @returns {void} |
| | | */ |
| | |
| | | ); |
| | | |
| | | /** |
| | | * Handles the hook callback for this code path. |
| | | * @param {JavascriptParser} parser the parser |
| | | * @param {JavascriptParserOptions} parserOptions options |
| | | * @returns {void} |
| | | */ |
| | | const handler = (parser, parserOptions) => { |
| | | /** |
| | | * Processes the provided sup. |
| | | * @param {Expression} sup sup |
| | | */ |
| | | const onUsageSuper = (sup) => { |
| | |
| | | |
| | | parser.hooks.program.tap(PLUGIN_NAME, () => { |
| | | InnerGraph.enable(parser.state); |
| | | |
| | | statementWithTopLevelSymbol = new WeakMap(); |
| | | statementPurePart = new WeakMap(); |
| | | classWithTopLevelSymbol = new WeakMap(); |
| | | declWithTopLevelSymbol = new WeakMap(); |
| | | pureDeclarators = new WeakSet(); |
| | | }); |
| | | |
| | | parser.hooks.finish.tap(PLUGIN_NAME, () => { |
| | |
| | | // 3. variable declarators (const x = ...) |
| | | |
| | | /** @type {WeakMap<Node | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration, TopLevelSymbol>} */ |
| | | const statementWithTopLevelSymbol = new WeakMap(); |
| | | let statementWithTopLevelSymbol = new WeakMap(); |
| | | /** @type {WeakMap<Node | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration, Node>} */ |
| | | const statementPurePart = new WeakMap(); |
| | | let statementPurePart = new WeakMap(); |
| | | |
| | | /** @type {WeakMap<ClassExpression | ClassDeclaration | MaybeNamedClassDeclaration, TopLevelSymbol>} */ |
| | | const classWithTopLevelSymbol = new WeakMap(); |
| | | let classWithTopLevelSymbol = new WeakMap(); |
| | | |
| | | /** @type {WeakMap<VariableDeclarator, TopLevelSymbol>} */ |
| | | const declWithTopLevelSymbol = new WeakMap(); |
| | | let declWithTopLevelSymbol = new WeakMap(); |
| | | /** @type {WeakSet<VariableDeclarator>} */ |
| | | const pureDeclarators = new WeakSet(); |
| | | let pureDeclarators = new WeakSet(); |
| | | |
| | | // The following hooks are used during prewalking: |
| | | |
| | |
| | | statement.type === "FunctionDeclaration" |
| | | ) { |
| | | const name = statement.id ? statement.id.name : "*default*"; |
| | | const fn = |
| | | const symbol = |
| | | /** @type {TopLevelSymbol} */ |
| | | (InnerGraph.tagTopLevelSymbol(parser, name)); |
| | | statementWithTopLevelSymbol.set(statement, fn); |
| | | statementWithTopLevelSymbol.set(statement, symbol); |
| | | return true; |
| | | } |
| | | }); |
| | |
| | | ) |
| | | ) { |
| | | const name = statement.id ? statement.id.name : "*default*"; |
| | | const fn = /** @type {TopLevelSymbol} */ ( |
| | | const symbol = /** @type {TopLevelSymbol} */ ( |
| | | InnerGraph.tagTopLevelSymbol(parser, name) |
| | | ); |
| | | classWithTopLevelSymbol.set(statement, fn); |
| | | classWithTopLevelSymbol.set(statement, symbol); |
| | | return true; |
| | | } |
| | | if (statement.type === "ExportDefaultDeclaration") { |
| | | const name = "*default*"; |
| | | const fn = |
| | | const symbol = |
| | | /** @type {TopLevelSymbol} */ |
| | | (InnerGraph.tagTopLevelSymbol(parser, name)); |
| | | const decl = statement.declaration; |
| | |
| | | classWithTopLevelSymbol.set( |
| | | /** @type {ClassExpression | ClassDeclaration} */ |
| | | (decl), |
| | | fn |
| | | symbol |
| | | ); |
| | | } else if ( |
| | | parser.isPure( |
| | |
| | | (statement.range)[0] |
| | | ) |
| | | ) { |
| | | statementWithTopLevelSymbol.set(statement, fn); |
| | | statementWithTopLevelSymbol.set(statement, symbol); |
| | | if ( |
| | | !decl.type.endsWith("FunctionExpression") && |
| | | !decl.type.endsWith("Declaration") && |
| | |
| | | /** @type {Range} */ (decl.id.range)[1] |
| | | ) |
| | | ) { |
| | | const fn = |
| | | const symbol = |
| | | /** @type {TopLevelSymbol} */ |
| | | (InnerGraph.tagTopLevelSymbol(parser, name)); |
| | | classWithTopLevelSymbol.set(decl.init, fn); |
| | | classWithTopLevelSymbol.set(decl.init, symbol); |
| | | } else if ( |
| | | parser.isPure( |
| | | decl.init, |
| | | /** @type {Range} */ (decl.id.range)[1] |
| | | ) |
| | | ) { |
| | | const fn = |
| | | const symbol = |
| | | /** @type {TopLevelSymbol} */ |
| | | (InnerGraph.tagTopLevelSymbol(parser, name)); |
| | | declWithTopLevelSymbol.set(decl, fn); |
| | | declWithTopLevelSymbol.set(decl, symbol); |
| | | if ( |
| | | !decl.init.type.endsWith("FunctionExpression") && |
| | | decl.init.type !== "Literal" |
| | |
| | | if (parser.scope.topLevelScope === true) { |
| | | InnerGraph.setTopLevelSymbol(parser.state, undefined); |
| | | |
| | | const fn = statementWithTopLevelSymbol.get(statement); |
| | | if (fn) { |
| | | InnerGraph.setTopLevelSymbol(parser.state, fn); |
| | | const symbol = statementWithTopLevelSymbol.get(statement); |
| | | if (symbol) { |
| | | InnerGraph.setTopLevelSymbol(parser.state, symbol); |
| | | const purePart = statementPurePart.get(statement); |
| | | if (purePart) { |
| | | InnerGraph.onUsage(parser.state, (usedByExports) => { |
| | |
| | | (expr, statement) => { |
| | | if (!InnerGraph.isEnabled(parser.state)) return; |
| | | if (parser.scope.topLevelScope === true) { |
| | | const fn = classWithTopLevelSymbol.get(statement); |
| | | const symbol = classWithTopLevelSymbol.get(statement); |
| | | if ( |
| | | fn && |
| | | symbol && |
| | | parser.isPure( |
| | | expr, |
| | | statement.id |
| | |
| | | : /** @type {Range} */ (statement.range)[0] |
| | | ) |
| | | ) { |
| | | InnerGraph.setTopLevelSymbol(parser.state, fn); |
| | | InnerGraph.setTopLevelSymbol(parser.state, symbol); |
| | | onUsageSuper(expr); |
| | | } |
| | | } |
| | |
| | | (element, classDefinition) => { |
| | | if (!InnerGraph.isEnabled(parser.state)) return; |
| | | if (parser.scope.topLevelScope === true) { |
| | | const fn = classWithTopLevelSymbol.get(classDefinition); |
| | | if (fn) { |
| | | const symbol = classWithTopLevelSymbol.get(classDefinition); |
| | | if (symbol) { |
| | | InnerGraph.setTopLevelSymbol(parser.state, undefined); |
| | | } |
| | | } |
| | |
| | | (expression, element, classDefinition) => { |
| | | if (!InnerGraph.isEnabled(parser.state)) return; |
| | | if (parser.scope.topLevelScope === true) { |
| | | const fn = classWithTopLevelSymbol.get(classDefinition); |
| | | if (fn) { |
| | | const symbol = classWithTopLevelSymbol.get(classDefinition); |
| | | if (symbol) { |
| | | if ( |
| | | !element.static || |
| | | parser.isPure( |
| | |
| | | : /** @type {Range} */ (element.range)[0] |
| | | ) |
| | | ) { |
| | | InnerGraph.setTopLevelSymbol(parser.state, fn); |
| | | InnerGraph.setTopLevelSymbol(parser.state, symbol); |
| | | if (element.type !== "MethodDefinition" && element.static) { |
| | | InnerGraph.onUsage(parser.state, (usedByExports) => { |
| | | switch (usedByExports) { |
| | |
| | | |
| | | parser.hooks.declarator.tap(PLUGIN_NAME, (decl, _statement) => { |
| | | if (!InnerGraph.isEnabled(parser.state)) return; |
| | | const fn = declWithTopLevelSymbol.get(decl); |
| | | const symbol = declWithTopLevelSymbol.get(decl); |
| | | |
| | | if (fn) { |
| | | InnerGraph.setTopLevelSymbol(parser.state, fn); |
| | | if (symbol) { |
| | | InnerGraph.setTopLevelSymbol(parser.state, symbol); |
| | | if (pureDeclarators.has(decl)) { |
| | | if ( |
| | | /** @type {ClassExpression} */ |