From a6d5784b20f586cbec0aec58e1ccc15ddaca7469 Mon Sep 17 00:00:00 2001 From: XMadrid Date: Wed, 11 Jun 2025 17:55:37 +0800 Subject: [PATCH 1/5] support listTestName transform --- bin/cli.js | 7 +- src/core/precompile.ts | 64 +++-- src/index.ts | 3 +- src/interface.ts | 6 + src/type/global.d.ts | 2 + transform/listTestNames.mjs | 435 +++++++++++++++++++++++++++++ transform/listTestNames.mts | 529 ++++++++++++++++++++++++++++++++++++ transform/tsconfig.json | 2 +- 8 files changed, 1024 insertions(+), 24 deletions(-) create mode 100644 transform/listTestNames.mjs create mode 100644 transform/listTestNames.mts diff --git a/bin/cli.js b/bin/cli.js index 8134565..c529148 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -16,7 +16,8 @@ program .option("--temp ", "test template file folder") .option("--output ", "coverage report output folder") .option("--mode ", "test result output format") - .option("--coverageLimit [error warning...]", "set warn(yellow) and error(red) upper limit in coverage report"); + .option("--coverageLimit [error warning...]", "set warn(yellow) and error(red) upper limit in coverage report") + .option("--testNamePattern ", "run only tests with a name that matches the regex pattern"); program.parse(process.argv); const options = program.opts(); @@ -53,9 +54,11 @@ let outputFolder = options.output || config.output || "coverage"; let errorLimit = options.coverageLimit?.at(0); let warnLimit = options.coverageLimit?.at(1); +let testNamePattern = options.testNamePattern; + validatArgument(includes, excludes); start_unit_test( - { includes, excludes, testcases }, + { includes, excludes, testcases, testNamePattern }, { flags, imports }, { tempFolder, outputFolder, mode, warnLimit, errorLimit } ) diff --git a/src/core/precompile.ts b/src/core/precompile.ts index 1fe290b..d2a8378 100644 --- a/src/core/precompile.ts +++ b/src/core/precompile.ts @@ -9,34 +9,73 @@ import { getIncludeFiles } from "../utils/pathResolver.js"; import { SourceFunctionInfo, UnittestPackage } from "../interface.js"; import { projectRoot } from "../utils/projectRoot.js"; -const sourceFunctions = new Map(); export async function precompile( includes: string[], excludes: string[], testcases: string[] | undefined, - flags: string, - transformFunction = join(projectRoot, "transform", "listFunctions.mjs") + testNamePattern: string | undefined, + flags: string ): Promise { // if specify testcases, use testcases for unittest // otherwise, get testcases(*.test.ts) in includes directory const testCodePaths = testcases ?? getRelatedFiles(includes, excludes, (path: string) => path.endsWith(".test.ts")); - const sourceCodePaths = getRelatedFiles(includes, excludes, (path: string) => !path.endsWith(".test.ts")); + const matchedTestNames: string[] = []; + if (testNamePattern) { + const testNameInfos = new Map(); + const testNameTransformFunction = join(projectRoot, "transform", "listTestNames.mjs"); + for (const testCodePath of testCodePaths) { + await transform(testNameTransformFunction, testCodePath, flags, () => { + testNameInfos.set(testCodePath, testNames); + }); + } + const regexPattern = new RegExp(testNamePattern); + for (const [fileName, testNames] of testNameInfos) { + for (const testName of testNames) { + if (regexPattern.test(testName)) { + matchedTestNames.push(testName); + } + } + } + } + const sourceCodePaths = getRelatedFiles(includes, excludes, (path: string) => !path.endsWith(".test.ts")); + const sourceFunctions = new Map(); + const sourceTransformFunction = join(projectRoot, "transform", "listFunctions.mjs"); // The batchSize = 2 is empirical data after benchmarking const batchSize = 2; for (let i = 0; i < sourceCodePaths.length; i += batchSize) { await Promise.all( - sourceCodePaths.slice(i, i + batchSize).map((sourcePath) => transform(sourcePath, transformFunction, flags)) + sourceCodePaths.slice(i, i + batchSize).map((sourcePath) => + transform(sourceTransformFunction, sourcePath, flags, () => { + sourceFunctions.set(sourcePath, functionInfos); + }) + ) ); } return { testCodePaths, + matchedTestNames, sourceFunctions, }; } +async function transform(transformFunction: string, codePath: string, flags: string, collectCallback: () => void) { + let ascArgv = [codePath, "--noEmit", "--disableWarning", "--transform", transformFunction, "-O0"]; + if (flags) { + const argv = flags.split(" "); + ascArgv = ascArgv.concat(argv); + } + const { error, stderr } = await main(ascArgv); + if (error) { + // eslint-disable-next-line @typescript-eslint/no-base-to-string + console.error(stderr.toString()); + throw error; + } + collectCallback(); +} + // a. include in config // b. exclude in config export function getRelatedFiles(includes: string[], excludes: string[], filter: (path: string) => boolean) { @@ -58,18 +97,3 @@ export function getRelatedFiles(includes: string[], excludes: string[], filter: } return result; } - -async function transform(sourceCodePath: string, transformFunction: string, flags: string) { - let ascArgv = [sourceCodePath, "--noEmit", "--disableWarning", "--transform", transformFunction, "-O0"]; - if (flags) { - const argv = flags.split(" "); - ascArgv = ascArgv.concat(argv); - } - const { error, stderr } = await main(ascArgv); - if (error) { - // eslint-disable-next-line @typescript-eslint/no-base-to-string - console.error(stderr.toString()); - throw error; - } - sourceFunctions.set(sourceCodePath, functionInfos); -} diff --git a/src/index.ts b/src/index.ts index e6458cf..30e9bbf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -55,6 +55,7 @@ export interface FileOption { includes: string[]; excludes: string[]; testcases: string[] | undefined; + testNamePattern: string | undefined; } export interface TestOption { flags: string; @@ -75,7 +76,7 @@ export type OutputMode = "html" | "json" | "table"; export async function start_unit_test(fo: FileOption, to: TestOption, oo: OutputOption): Promise { emptydirSync(oo.outputFolder); emptydirSync(oo.tempFolder); - const unittestPackage = await precompile(fo.includes, fo.excludes, fo.testcases, to.flags); + const unittestPackage = await precompile(fo.includes, fo.excludes, fo.testcases, fo.testNamePattern, to.flags); console.log(chalk.blueBright("code analysis: ") + chalk.bold.greenBright("OK")); const wasmPaths = await compile(unittestPackage.testCodePaths, oo.tempFolder, to.flags); console.log(chalk.blueBright("compile testcases: ") + chalk.bold.greenBright("OK")); diff --git a/src/interface.ts b/src/interface.ts index 705a646..d9e5d43 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -150,6 +150,7 @@ export class CodeCoverage { export interface UnittestPackage { readonly testCodePaths: string[]; + readonly matchedTestNames: string[]; readonly sourceFunctions: Map; } @@ -158,5 +159,10 @@ export interface SourceFunctionInfo { range: [number, number]; } +export interface TestNameInfo { + testName: string; + testFilePath: string; +} + export const OrganizationName = "wasm-ecosystem"; export const Repository = "https://github.com/wasm-ecosystem/assemblyscript-unittest-framework"; diff --git a/src/type/global.d.ts b/src/type/global.d.ts index 36acbbd..c4caa07 100644 --- a/src/type/global.d.ts +++ b/src/type/global.d.ts @@ -3,6 +3,8 @@ import { SourceFunctionInfo } from "../interface.ts"; declare global { // store listFunctions transform results in global let functionInfos: SourceFunctionInfo[]; + // store listTestNames transform results in global + let testNames: string[]; } export {}; diff --git a/transform/listTestNames.mjs b/transform/listTestNames.mjs new file mode 100644 index 0000000..ad22cf4 --- /dev/null +++ b/transform/listTestNames.mjs @@ -0,0 +1,435 @@ +import { Transform } from "assemblyscript/transform"; +import assert from "node:assert"; +class SourceFunctionTransform extends Transform { + constructor() { + super(...arguments); + this.testNames = []; + this.currentTestDescriptions = []; + } + afterInitialize(program) { + // There will be two sources with SourceKind.UserEntry, ~lib/rt/index-incremental.ts should be filtered + const entrySource = program.sources.find((source) => source.sourceKind === 1 /* SourceKind.UserEntry */ && !source.normalizedPath.startsWith("~lib/")); + this.testFileName = entrySource.normalizedPath; + this.visitNode(entrySource); + globalThis.testNames = this.testNames; + } + visitNode(node) { + // eslint-disable-next-line sonarjs/max-switch-cases + switch (node.kind) { + case 0 /* NodeKind.Source */: { + this.visitSource(node); + break; + } + // types + case 1 /* NodeKind.NamedType */: + case 2 /* NodeKind.FunctionType */: + case 3 /* NodeKind.TypeName */: + case 4 /* NodeKind.TypeParameter */: { + break; + } + case 5 /* NodeKind.Parameter */: { + this.visitParameterNode(node); + break; + } + // Expressions + case 6 /* NodeKind.Identifier */: + case 13 /* NodeKind.False */: + case 16 /* NodeKind.Literal */: + case 18 /* NodeKind.Null */: + case 19 /* NodeKind.Omitted */: + case 23 /* NodeKind.Super */: + case 24 /* NodeKind.This */: + case 25 /* NodeKind.True */: + case 26 /* NodeKind.Constructor */: + case 29 /* NodeKind.Compiled */: { + break; + } + case 7 /* NodeKind.Assertion */: { + this.visitAssertionExpression(node); + break; + } + case 8 /* NodeKind.Binary */: { + this.visitBinaryExpression(node); + break; + } + case 9 /* NodeKind.Call */: { + this.visitCallExpression(node); + break; + } + case 10 /* NodeKind.Class */: { + this.visitClassExpression(node); + break; + } + case 11 /* NodeKind.Comma */: { + this.visitCommaExpression(node); + break; + } + case 12 /* NodeKind.ElementAccess */: { + this.visitElementAccessExpression(node); + break; + } + case 14 /* NodeKind.Function */: { + this.visitFunctionExpression(node); + break; + } + case 15 /* NodeKind.InstanceOf */: { + this.visitInstanceOfExpression(node); + break; + } + case 17 /* NodeKind.New */: { + this.visitNewExpression(node); + break; + } + case 20 /* NodeKind.Parenthesized */: { + this.visitParenthesizedExpression(node); + break; + } + case 21 /* NodeKind.PropertyAccess */: { + this.visitPropertyAccessExpression(node); + break; + } + case 22 /* NodeKind.Ternary */: { + this.visitTernaryExpression(node); + break; + } + case 27 /* NodeKind.UnaryPostfix */: { + this.visitUnaryPostfixExpression(node); + break; + } + case 28 /* NodeKind.UnaryPrefix */: { + this.visitUnaryPrefixExpression(node); + break; + } + // statements: + case 31 /* NodeKind.Break */: + case 34 /* NodeKind.Empty */: + case 35 /* NodeKind.Export */: + case 36 /* NodeKind.ExportDefault */: + case 37 /* NodeKind.ExportImport */: + case 32 /* NodeKind.Continue */: + case 42 /* NodeKind.Import */: + case 50 /* NodeKind.Module */: { + break; + } + case 30 /* NodeKind.Block */: { + this.visitBlockStatement(node); + break; + } + case 33 /* NodeKind.Do */: { + this.visitDoStatement(node); + break; + } + case 38 /* NodeKind.Expression */: { + this.visitExpressionStatement(node); + break; + } + case 39 /* NodeKind.For */: { + this.visitForStatement(node); + break; + } + case 40 /* NodeKind.ForOf */: { + this.visitForOfStatement(node); + break; + } + case 41 /* NodeKind.If */: { + this.visitIfStatement(node); + break; + } + case 43 /* NodeKind.Return */: { + this.visitReturnStatement(node); + break; + } + case 44 /* NodeKind.Switch */: { + this.visitSwitchStatement(node); + break; + } + case 45 /* NodeKind.Throw */: { + this.visitThrowStatement(node); + break; + } + case 46 /* NodeKind.Try */: { + this.visitTryStatement(node); + break; + } + case 47 /* NodeKind.Variable */: { + this.visitVariableStatement(node); + break; + } + case 48 /* NodeKind.Void */: { + this.visitVoidStatement(node); + break; + } + case 49 /* NodeKind.While */: { + this.visitWhileStatement(node); + break; + } + // declaration statements + case 56 /* NodeKind.ImportDeclaration */: + case 60 /* NodeKind.TypeDeclaration */: { + break; + } + case 51 /* NodeKind.ClassDeclaration */: { + this.visitClassDeclaration(node); + break; + } + case 52 /* NodeKind.EnumDeclaration */: { + this.visitEnumDeclaration(node); + break; + } + case 53 /* NodeKind.EnumValueDeclaration */: { + this.visitEnumValueDeclaration(node); + break; + } + case 54 /* NodeKind.FieldDeclaration */: { + this.visitFieldDeclaration(node); + break; + } + case 55 /* NodeKind.FunctionDeclaration */: { + this.visitFunctionDeclaration(node); + break; + } + case 57 /* NodeKind.InterfaceDeclaration */: { + this.visitInterfaceDeclaration(node); + break; + } + case 58 /* NodeKind.MethodDeclaration */: { + this.visitMethodDeclaration(node); + break; + } + case 59 /* NodeKind.NamespaceDeclaration */: { + this.visitNamespaceDeclaration(node); + break; + } + case 61 /* NodeKind.VariableDeclaration */: { + this.visitVariableDeclaration(node); + break; + } + // special + case 63 /* NodeKind.ExportMember */: + case 65 /* NodeKind.IndexSignature */: + case 66 /* NodeKind.Comment */: + case 62 /* NodeKind.Decorator */: { + break; + } + case 64 /* NodeKind.SwitchCase */: { + this.visitSwitchCase(node); + break; + } + } + } + visitSource(node) { + for (const statement of node.statements) { + this.visitNode(statement); + } + } + visitParameterNode(node) { + if (node.initializer) { + this.visitNode(node.initializer); + } + } + visitAssertionExpression(node) { + this.visitNode(node.expression); + } + visitBinaryExpression(node) { + this.visitNode(node.left); + this.visitNode(node.right); + } + visitCallExpression(node) { + if (node.expression.kind === 6 /* NodeKind.Identifier */) { + const fncName = node.expression.text; + if (fncName === "describe" || fncName === "test") { + assert(node.args.length === 2); + assert(node.args[0].kind === 16 /* NodeKind.Literal */ && + node.args[0].literalKind === 2 /* LiteralKind.String */); + const testName = node.args[0].value; + this.currentTestDescriptions.push(testName); + if (fncName === "test") { + this.testNames.push(this.currentTestDescriptions.join("")); + } + this.visitNode(node.expression); + for (const arg of node.args) { + this.visitNode(arg); + } + this.currentTestDescriptions.pop(); + } + } + else { + this.visitNode(node.expression); + for (const arg of node.args) { + this.visitNode(arg); + } + } + } + visitClassExpression(node) { + this.visitClassDeclaration(node.declaration); + } + visitCommaExpression(node) { + for (const expr of node.expressions) { + this.visitNode(expr); + } + } + visitElementAccessExpression(node) { + this.visitNode(node.expression); + this.visitNode(node.elementExpression); + } + visitFunctionExpression(node) { + this.visitFunctionDeclaration(node.declaration); + } + visitInstanceOfExpression(node) { + this.visitNode(node.expression); + } + visitNewExpression(node) { + for (const arg of node.args) { + this.visitNode(arg); + } + } + visitParenthesizedExpression(node) { + this.visitNode(node.expression); + } + visitPropertyAccessExpression(node) { + this.visitNode(node.expression); + } + visitTernaryExpression(node) { + this.visitNode(node.condition); + this.visitNode(node.ifThen); + this.visitNode(node.ifElse); + } + visitUnaryPostfixExpression(node) { + this.visitNode(node.operand); + } + visitUnaryPrefixExpression(node) { + this.visitNode(node.operand); + } + // eslint-disable-next-line sonarjs/no-identical-functions + visitBlockStatement(node) { + for (const statement of node.statements) { + this.visitNode(statement); + } + } + visitDoStatement(node) { + this.visitNode(node.body); + this.visitNode(node.condition); + } + visitExpressionStatement(node) { + this.visitNode(node.expression); + } + visitForStatement(node) { + if (node.initializer) { + this.visitNode(node.initializer); + } + if (node.condition) { + this.visitNode(node.condition); + } + if (node.incrementor) { + this.visitNode(node.incrementor); + } + this.visitNode(node.body); + } + visitForOfStatement(node) { + this.visitNode(node.variable); + this.visitNode(node.iterable); + this.visitNode(node.body); + } + visitIfStatement(node) { + this.visitNode(node.condition); + this.visitNode(node.ifTrue); + if (node.ifFalse) { + this.visitNode(node.ifFalse); + } + } + visitReturnStatement(node) { + if (node.value) { + this.visitNode(node.value); + } + } + visitSwitchStatement(node) { + this.visitNode(node.condition); + for (const switchCase of node.cases) { + this.visitSwitchCase(switchCase); + } + } + visitThrowStatement(node) { + this.visitNode(node.value); + } + visitTryStatement(node) { + for (const stat of node.bodyStatements) { + this.visitNode(stat); + } + if (node.catchStatements) { + for (const stat of node.catchStatements) { + this.visitNode(stat); + } + } + if (node.finallyStatements) { + for (const stat of node.finallyStatements) { + this.visitNode(stat); + } + } + } + visitVariableStatement(node) { + for (const declaration of node.declarations) { + this.visitVariableDeclaration(declaration); + } + } + visitVoidStatement(node) { + this.visitNode(node.expression); + } + visitWhileStatement(node) { + this.visitNode(node.condition); + this.visitNode(node.body); + } + visitClassDeclaration(node) { + for (const member of node.members) { + this.visitNode(member); + } + } + visitEnumDeclaration(node) { + for (const value of node.values) { + this.visitEnumValueDeclaration(value); + } + } + // eslint-disable-next-line sonarjs/no-identical-functions + visitEnumValueDeclaration(node) { + if (node.initializer) { + this.visitNode(node.initializer); + } + } + // eslint-disable-next-line sonarjs/no-identical-functions + visitFieldDeclaration(node) { + if (node.initializer) { + this.visitNode(node.initializer); + } + } + visitFunctionDeclaration(node) { + if (node.body) { + this.visitNode(node.body); + } + } + visitInterfaceDeclaration(node) { + this.visitClassDeclaration(node); + } + visitMethodDeclaration(node) { + this.visitFunctionDeclaration(node); + } + // eslint-disable-next-line sonarjs/no-identical-functions + visitNamespaceDeclaration(node) { + for (const member of node.members) { + this.visitNode(member); + } + } + // eslint-disable-next-line sonarjs/no-identical-functions + visitVariableDeclaration(node) { + if (node.initializer) { + this.visitNode(node.initializer); + } + } + visitSwitchCase(node) { + if (node.label) { + this.visitNode(node.label); + } + for (const stat of node.statements) { + this.visitNode(stat); + } + } +} +export default SourceFunctionTransform; diff --git a/transform/listTestNames.mts b/transform/listTestNames.mts new file mode 100644 index 0000000..5d95f03 --- /dev/null +++ b/transform/listTestNames.mts @@ -0,0 +1,529 @@ +import { Transform } from "assemblyscript/transform"; +import { + NodeKind, + SourceKind, + Node, + Source, + ParameterNode, + AssertionExpression, + BinaryExpression, + CallExpression, + ClassExpression, + CommaExpression, + ElementAccessExpression, + FunctionExpression, + InstanceOfExpression, + NewExpression, + ParenthesizedExpression, + PropertyAccessExpression, + TernaryExpression, + UnaryPostfixExpression, + UnaryPrefixExpression, + BlockStatement, + DoStatement, + ExpressionStatement, + ForStatement, + ForOfStatement, + IfStatement, + ReturnStatement, + SwitchStatement, + ThrowStatement, + TryStatement, + VariableStatement, + VoidStatement, + WhileStatement, + ClassDeclaration, + EnumDeclaration, + EnumValueDeclaration, + FieldDeclaration, + FunctionDeclaration, + InterfaceDeclaration, + MethodDeclaration, + NamespaceDeclaration, + VariableDeclaration, + SwitchCase, + Program, + IdentifierExpression, + LiteralExpression, + LiteralKind, + StringLiteralExpression, +} from "assemblyscript"; +import assert from "node:assert"; + +class SourceFunctionTransform extends Transform { + testNames: string[] = []; + currentTestDescriptions: string[] = []; + testFileName: string; + + afterInitialize(program: Program) { + // There will be two sources with SourceKind.UserEntry, ~lib/rt/index-incremental.ts should be filtered + const entrySource = program.sources.find( + (source) => source.sourceKind === SourceKind.UserEntry && !source.normalizedPath.startsWith("~lib/") + ); + this.testFileName = entrySource.normalizedPath; + this.visitNode(entrySource); + globalThis.testNames = this.testNames; + } + + visitNode(node: Node) { + // eslint-disable-next-line sonarjs/max-switch-cases + switch (node.kind) { + case NodeKind.Source: { + this.visitSource(node as Source); + break; + } + + // types + case NodeKind.NamedType: + case NodeKind.FunctionType: + case NodeKind.TypeName: + case NodeKind.TypeParameter: { + break; + } + case NodeKind.Parameter: { + this.visitParameterNode(node as ParameterNode); + break; + } + + // Expressions + case NodeKind.Identifier: + case NodeKind.False: + case NodeKind.Literal: + case NodeKind.Null: + case NodeKind.Omitted: + case NodeKind.Super: + case NodeKind.This: + case NodeKind.True: + case NodeKind.Constructor: + case NodeKind.Compiled: { + break; + } + case NodeKind.Assertion: { + this.visitAssertionExpression(node as AssertionExpression); + break; + } + case NodeKind.Binary: { + this.visitBinaryExpression(node as BinaryExpression); + break; + } + case NodeKind.Call: { + this.visitCallExpression(node as CallExpression); + break; + } + case NodeKind.Class: { + this.visitClassExpression(node as ClassExpression); + break; + } + case NodeKind.Comma: { + this.visitCommaExpression(node as CommaExpression); + break; + } + case NodeKind.ElementAccess: { + this.visitElementAccessExpression(node as ElementAccessExpression); + break; + } + case NodeKind.Function: { + this.visitFunctionExpression(node as FunctionExpression); + break; + } + case NodeKind.InstanceOf: { + this.visitInstanceOfExpression(node as InstanceOfExpression); + break; + } + case NodeKind.New: { + this.visitNewExpression(node as NewExpression); + break; + } + case NodeKind.Parenthesized: { + this.visitParenthesizedExpression(node as ParenthesizedExpression); + break; + } + case NodeKind.PropertyAccess: { + this.visitPropertyAccessExpression(node as PropertyAccessExpression); + break; + } + case NodeKind.Ternary: { + this.visitTernaryExpression(node as TernaryExpression); + break; + } + case NodeKind.UnaryPostfix: { + this.visitUnaryPostfixExpression(node as UnaryPostfixExpression); + break; + } + case NodeKind.UnaryPrefix: { + this.visitUnaryPrefixExpression(node as UnaryPrefixExpression); + break; + } + + // statements: + + case NodeKind.Break: + case NodeKind.Empty: + case NodeKind.Export: + case NodeKind.ExportDefault: + case NodeKind.ExportImport: + case NodeKind.Continue: + case NodeKind.Import: + case NodeKind.Module: { + break; + } + case NodeKind.Block: { + this.visitBlockStatement(node as BlockStatement); + break; + } + case NodeKind.Do: { + this.visitDoStatement(node as DoStatement); + break; + } + case NodeKind.Expression: { + this.visitExpressionStatement(node as ExpressionStatement); + break; + } + case NodeKind.For: { + this.visitForStatement(node as ForStatement); + break; + } + case NodeKind.ForOf: { + this.visitForOfStatement(node as ForOfStatement); + break; + } + case NodeKind.If: { + this.visitIfStatement(node as IfStatement); + break; + } + case NodeKind.Return: { + this.visitReturnStatement(node as ReturnStatement); + break; + } + case NodeKind.Switch: { + this.visitSwitchStatement(node as SwitchStatement); + break; + } + case NodeKind.Throw: { + this.visitThrowStatement(node as ThrowStatement); + break; + } + case NodeKind.Try: { + this.visitTryStatement(node as TryStatement); + break; + } + case NodeKind.Variable: { + this.visitVariableStatement(node as VariableStatement); + break; + } + case NodeKind.Void: { + this.visitVoidStatement(node as VoidStatement); + break; + } + case NodeKind.While: { + this.visitWhileStatement(node as WhileStatement); + break; + } + + // declaration statements + case NodeKind.ImportDeclaration: + case NodeKind.TypeDeclaration: { + break; + } + case NodeKind.ClassDeclaration: { + this.visitClassDeclaration(node as ClassDeclaration); + break; + } + case NodeKind.EnumDeclaration: { + this.visitEnumDeclaration(node as EnumDeclaration); + break; + } + case NodeKind.EnumValueDeclaration: { + this.visitEnumValueDeclaration(node as EnumValueDeclaration); + break; + } + case NodeKind.FieldDeclaration: { + this.visitFieldDeclaration(node as FieldDeclaration); + break; + } + case NodeKind.FunctionDeclaration: { + this.visitFunctionDeclaration(node as FunctionDeclaration); + break; + } + case NodeKind.InterfaceDeclaration: { + this.visitInterfaceDeclaration(node as InterfaceDeclaration); + break; + } + case NodeKind.MethodDeclaration: { + this.visitMethodDeclaration(node as MethodDeclaration); + break; + } + case NodeKind.NamespaceDeclaration: { + this.visitNamespaceDeclaration(node as NamespaceDeclaration); + break; + } + case NodeKind.VariableDeclaration: { + this.visitVariableDeclaration(node as VariableDeclaration); + break; + } + + // special + case NodeKind.ExportMember: + case NodeKind.IndexSignature: + case NodeKind.Comment: + case NodeKind.Decorator: { + break; + } + case NodeKind.SwitchCase: { + this.visitSwitchCase(node as SwitchCase); + break; + } + } + } + + visitSource(node: Source) { + for (const statement of node.statements) { + this.visitNode(statement); + } + } + + visitParameterNode(node: ParameterNode) { + if (node.initializer) { + this.visitNode(node.initializer); + } + } + + visitAssertionExpression(node: AssertionExpression) { + this.visitNode(node.expression); + } + + visitBinaryExpression(node: BinaryExpression) { + this.visitNode(node.left); + this.visitNode(node.right); + } + + visitCallExpression(node: CallExpression) { + if (node.expression.kind === NodeKind.Identifier) { + const fncName = (node.expression as IdentifierExpression).text; + if (fncName === "describe" || fncName === "test") { + assert(node.args.length === 2); + assert( + node.args[0].kind === NodeKind.Literal && + (node.args[0] as LiteralExpression).literalKind === LiteralKind.String + ); + const testName = (node.args[0] as StringLiteralExpression).value; + this.currentTestDescriptions.push(testName); + if (fncName === "test") { + this.testNames.push(this.currentTestDescriptions.join("")); + } + this.visitNode(node.expression); + for (const arg of node.args) { + this.visitNode(arg); + } + this.currentTestDescriptions.pop(); + } + } else { + this.visitNode(node.expression); + for (const arg of node.args) { + this.visitNode(arg); + } + } + } + + visitClassExpression(node: ClassExpression) { + this.visitClassDeclaration(node.declaration); + } + + visitCommaExpression(node: CommaExpression) { + for (const expr of node.expressions) { + this.visitNode(expr); + } + } + + visitElementAccessExpression(node: ElementAccessExpression) { + this.visitNode(node.expression); + this.visitNode(node.elementExpression); + } + + visitFunctionExpression(node: FunctionExpression) { + this.visitFunctionDeclaration(node.declaration); + } + + visitInstanceOfExpression(node: InstanceOfExpression) { + this.visitNode(node.expression); + } + + visitNewExpression(node: NewExpression) { + for (const arg of node.args) { + this.visitNode(arg); + } + } + + visitParenthesizedExpression(node: ParenthesizedExpression) { + this.visitNode(node.expression); + } + + visitPropertyAccessExpression(node: PropertyAccessExpression) { + this.visitNode(node.expression); + } + + visitTernaryExpression(node: TernaryExpression) { + this.visitNode(node.condition); + this.visitNode(node.ifThen); + this.visitNode(node.ifElse); + } + + visitUnaryPostfixExpression(node: UnaryPostfixExpression) { + this.visitNode(node.operand); + } + + visitUnaryPrefixExpression(node: UnaryPrefixExpression) { + this.visitNode(node.operand); + } + // eslint-disable-next-line sonarjs/no-identical-functions + visitBlockStatement(node: BlockStatement) { + for (const statement of node.statements) { + this.visitNode(statement); + } + } + + visitDoStatement(node: DoStatement) { + this.visitNode(node.body); + this.visitNode(node.condition); + } + + visitExpressionStatement(node: ExpressionStatement) { + this.visitNode(node.expression); + } + + visitForStatement(node: ForStatement) { + if (node.initializer) { + this.visitNode(node.initializer); + } + if (node.condition) { + this.visitNode(node.condition); + } + if (node.incrementor) { + this.visitNode(node.incrementor); + } + this.visitNode(node.body); + } + + visitForOfStatement(node: ForOfStatement) { + this.visitNode(node.variable); + this.visitNode(node.iterable); + this.visitNode(node.body); + } + + visitIfStatement(node: IfStatement) { + this.visitNode(node.condition); + this.visitNode(node.ifTrue); + if (node.ifFalse) { + this.visitNode(node.ifFalse); + } + } + + visitReturnStatement(node: ReturnStatement) { + if (node.value) { + this.visitNode(node.value); + } + } + + visitSwitchStatement(node: SwitchStatement) { + this.visitNode(node.condition); + for (const switchCase of node.cases) { + this.visitSwitchCase(switchCase); + } + } + + visitThrowStatement(node: ThrowStatement) { + this.visitNode(node.value); + } + + visitTryStatement(node: TryStatement) { + for (const stat of node.bodyStatements) { + this.visitNode(stat); + } + if (node.catchStatements) { + for (const stat of node.catchStatements) { + this.visitNode(stat); + } + } + if (node.finallyStatements) { + for (const stat of node.finallyStatements) { + this.visitNode(stat); + } + } + } + + visitVariableStatement(node: VariableStatement) { + for (const declaration of node.declarations) { + this.visitVariableDeclaration(declaration); + } + } + + visitVoidStatement(node: VoidStatement) { + this.visitNode(node.expression); + } + + visitWhileStatement(node: WhileStatement) { + this.visitNode(node.condition); + this.visitNode(node.body); + } + + visitClassDeclaration(node: ClassDeclaration) { + for (const member of node.members) { + this.visitNode(member); + } + } + + visitEnumDeclaration(node: EnumDeclaration) { + for (const value of node.values) { + this.visitEnumValueDeclaration(value); + } + } + // eslint-disable-next-line sonarjs/no-identical-functions + visitEnumValueDeclaration(node: EnumValueDeclaration) { + if (node.initializer) { + this.visitNode(node.initializer); + } + } + // eslint-disable-next-line sonarjs/no-identical-functions + visitFieldDeclaration(node: FieldDeclaration) { + if (node.initializer) { + this.visitNode(node.initializer); + } + } + + visitFunctionDeclaration(node: FunctionDeclaration) { + if (node.body) { + this.visitNode(node.body); + } + } + + visitInterfaceDeclaration(node: InterfaceDeclaration) { + this.visitClassDeclaration(node); + } + + visitMethodDeclaration(node: MethodDeclaration) { + this.visitFunctionDeclaration(node); + } + // eslint-disable-next-line sonarjs/no-identical-functions + visitNamespaceDeclaration(node: NamespaceDeclaration) { + for (const member of node.members) { + this.visitNode(member); + } + } + // eslint-disable-next-line sonarjs/no-identical-functions + visitVariableDeclaration(node: VariableDeclaration) { + if (node.initializer) { + this.visitNode(node.initializer); + } + } + + visitSwitchCase(node: SwitchCase) { + if (node.label) { + this.visitNode(node.label); + } + for (const stat of node.statements) { + this.visitNode(stat); + } + } +} + +export default SourceFunctionTransform; diff --git a/transform/tsconfig.json b/transform/tsconfig.json index 6bce599..1bfcd67 100644 --- a/transform/tsconfig.json +++ b/transform/tsconfig.json @@ -10,6 +10,6 @@ "assemblyscript/transform": ["../node_modules/assemblyscript/dist/transform"] } }, - "files": ["listFunctions.mts"], + "files": ["listFunctions.mts", "listTestNames.mts"], "exclude": [] } From ed83bf935f1ee2354a9be35fbc20b22f9057add0 Mon Sep 17 00:00:00 2001 From: XMadrid Date: Tue, 17 Jun 2025 10:41:00 +0800 Subject: [PATCH 2/5] register test function --- assembly/env.ts | 2 ++ assembly/implement.ts | 1 + src/core/executionRecorder.ts | 8 ++++++++ 3 files changed, 11 insertions(+) diff --git a/assembly/env.ts b/assembly/env.ts index bae6bcf..8927fbe 100644 --- a/assembly/env.ts +++ b/assembly/env.ts @@ -7,6 +7,8 @@ export namespace assertResult { @external("__unittest_framework_env","removeDescription") export declare function removeDescription(): void; + @external("__unittest_framework_env","registerTestFunction") + export declare function registerTestFunction(index: u32): void; @external("__unittest_framework_env","collectCheckResult") export declare function collectCheckResult( diff --git a/assembly/implement.ts b/assembly/implement.ts index 92ab21f..9e21335 100644 --- a/assembly/implement.ts +++ b/assembly/implement.ts @@ -11,6 +11,7 @@ export function describeImpl( } export function testImpl(description: string, testFunction: () => void): void { assertResult.addDescription(description); + assertResult.registerTestFunction(testFunction.index); testFunction(); assertResult.removeDescription(); mockFunctionStatus.clear(); diff --git a/src/core/executionRecorder.ts b/src/core/executionRecorder.ts index a55219e..89cc88c 100644 --- a/src/core/executionRecorder.ts +++ b/src/core/executionRecorder.ts @@ -5,6 +5,7 @@ export class ExecutionRecorder implements IAssertResult { total: number = 0; fail: number = 0; failed_info: AssertFailMessage = {}; + registerFunctions: [string, number][] = []; _currentTestDescriptions: string[] = []; _addDescription(description: string): void { @@ -13,6 +14,10 @@ export class ExecutionRecorder implements IAssertResult { _removeDescription(): void { this._currentTestDescriptions.pop(); } + registerTestFunction(fncIndex: number): void { + const testCaseFullName = this._currentTestDescriptions.join(" - "); + this.registerFunctions.push([testCaseFullName, fncIndex]); + } collectCheckResult(result: boolean, codeInfoIndex: number, actualValue: string, expectValue: string): void { this.total++; if (!result) { @@ -33,6 +38,9 @@ export class ExecutionRecorder implements IAssertResult { removeDescription: (): void => { this._removeDescription(); }, + registerTestFunction: (index: number): void => { + this.registerTestFunction(index); + }, collectCheckResult: (result: number, codeInfoIndex: number, actualValue: number, expectValue: number): void => { this.collectCheckResult( result !== 0, From 5a1cb9e00cd5fd9920e57823132477ca11375ffa Mon Sep 17 00:00:00 2001 From: XMadrid Date: Tue, 17 Jun 2025 10:47:10 +0800 Subject: [PATCH 3/5] fix --- src/core/precompile.ts | 2 +- tests/ts/test/core/precompile.test.ts | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/core/precompile.ts b/src/core/precompile.ts index d2a8378..c4aea04 100644 --- a/src/core/precompile.ts +++ b/src/core/precompile.ts @@ -30,7 +30,7 @@ export async function precompile( }); } const regexPattern = new RegExp(testNamePattern); - for (const [fileName, testNames] of testNameInfos) { + for (const testNames of testNameInfos.values()) { for (const testName of testNames) { if (regexPattern.test(testName)) { matchedTestNames.push(testName); diff --git a/tests/ts/test/core/precompile.test.ts b/tests/ts/test/core/precompile.test.ts index bdf2e98..ac5e4e0 100644 --- a/tests/ts/test/core/precompile.test.ts +++ b/tests/ts/test/core/precompile.test.ts @@ -1,10 +1,7 @@ -import { join } from "node:path"; import { precompile } from "../../../../src/core/precompile.js"; -import { projectRoot } from "../../../../src/utils/projectRoot.js"; test("listFunction transform", async () => { - const transformFunction = join(projectRoot, "transform", "listFunctions.mjs"); - const unittestPackages = await precompile(["tests/ts/fixture/transformFunction.ts"], [], [], "", transformFunction); + const unittestPackages = await precompile(["tests/ts/fixture/transformFunction.ts"], [], undefined, undefined, ""); expect(unittestPackages.testCodePaths).toEqual([]); expect(unittestPackages.sourceFunctions).toMatchSnapshot(); }); From fc4a5a8e1ed9a33859519345d3eaa42d92a2db6c Mon Sep 17 00:00:00 2001 From: XMadrid Date: Tue, 17 Jun 2025 11:04:27 +0800 Subject: [PATCH 4/5] fix --- assembly/env.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/assembly/env.ts b/assembly/env.ts index 8927fbe..f2a2e2a 100644 --- a/assembly/env.ts +++ b/assembly/env.ts @@ -7,9 +7,11 @@ export namespace assertResult { @external("__unittest_framework_env","removeDescription") export declare function removeDescription(): void; + @external("__unittest_framework_env","registerTestFunction") export declare function registerTestFunction(index: u32): void; + @external("__unittest_framework_env","collectCheckResult") export declare function collectCheckResult( result: bool, From 0337a4b565978b04c5616b8b2566b788e735b145 Mon Sep 17 00:00:00 2001 From: XMadrid Date: Tue, 17 Jun 2025 11:22:41 +0800 Subject: [PATCH 5/5] git ignore transform/*.mjs --- .gitignore | 2 +- transform/listTestNames.mjs | 435 ------------------------------------ 2 files changed, 1 insertion(+), 436 deletions(-) delete mode 100644 transform/listTestNames.mjs diff --git a/.gitignore b/.gitignore index b57a61e..ba083b8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ /dist /build* -/transform/listFunctions.mjs +/transform/*.mjs /transform/tsconfig.tsbuildinfo /coverage diff --git a/transform/listTestNames.mjs b/transform/listTestNames.mjs deleted file mode 100644 index ad22cf4..0000000 --- a/transform/listTestNames.mjs +++ /dev/null @@ -1,435 +0,0 @@ -import { Transform } from "assemblyscript/transform"; -import assert from "node:assert"; -class SourceFunctionTransform extends Transform { - constructor() { - super(...arguments); - this.testNames = []; - this.currentTestDescriptions = []; - } - afterInitialize(program) { - // There will be two sources with SourceKind.UserEntry, ~lib/rt/index-incremental.ts should be filtered - const entrySource = program.sources.find((source) => source.sourceKind === 1 /* SourceKind.UserEntry */ && !source.normalizedPath.startsWith("~lib/")); - this.testFileName = entrySource.normalizedPath; - this.visitNode(entrySource); - globalThis.testNames = this.testNames; - } - visitNode(node) { - // eslint-disable-next-line sonarjs/max-switch-cases - switch (node.kind) { - case 0 /* NodeKind.Source */: { - this.visitSource(node); - break; - } - // types - case 1 /* NodeKind.NamedType */: - case 2 /* NodeKind.FunctionType */: - case 3 /* NodeKind.TypeName */: - case 4 /* NodeKind.TypeParameter */: { - break; - } - case 5 /* NodeKind.Parameter */: { - this.visitParameterNode(node); - break; - } - // Expressions - case 6 /* NodeKind.Identifier */: - case 13 /* NodeKind.False */: - case 16 /* NodeKind.Literal */: - case 18 /* NodeKind.Null */: - case 19 /* NodeKind.Omitted */: - case 23 /* NodeKind.Super */: - case 24 /* NodeKind.This */: - case 25 /* NodeKind.True */: - case 26 /* NodeKind.Constructor */: - case 29 /* NodeKind.Compiled */: { - break; - } - case 7 /* NodeKind.Assertion */: { - this.visitAssertionExpression(node); - break; - } - case 8 /* NodeKind.Binary */: { - this.visitBinaryExpression(node); - break; - } - case 9 /* NodeKind.Call */: { - this.visitCallExpression(node); - break; - } - case 10 /* NodeKind.Class */: { - this.visitClassExpression(node); - break; - } - case 11 /* NodeKind.Comma */: { - this.visitCommaExpression(node); - break; - } - case 12 /* NodeKind.ElementAccess */: { - this.visitElementAccessExpression(node); - break; - } - case 14 /* NodeKind.Function */: { - this.visitFunctionExpression(node); - break; - } - case 15 /* NodeKind.InstanceOf */: { - this.visitInstanceOfExpression(node); - break; - } - case 17 /* NodeKind.New */: { - this.visitNewExpression(node); - break; - } - case 20 /* NodeKind.Parenthesized */: { - this.visitParenthesizedExpression(node); - break; - } - case 21 /* NodeKind.PropertyAccess */: { - this.visitPropertyAccessExpression(node); - break; - } - case 22 /* NodeKind.Ternary */: { - this.visitTernaryExpression(node); - break; - } - case 27 /* NodeKind.UnaryPostfix */: { - this.visitUnaryPostfixExpression(node); - break; - } - case 28 /* NodeKind.UnaryPrefix */: { - this.visitUnaryPrefixExpression(node); - break; - } - // statements: - case 31 /* NodeKind.Break */: - case 34 /* NodeKind.Empty */: - case 35 /* NodeKind.Export */: - case 36 /* NodeKind.ExportDefault */: - case 37 /* NodeKind.ExportImport */: - case 32 /* NodeKind.Continue */: - case 42 /* NodeKind.Import */: - case 50 /* NodeKind.Module */: { - break; - } - case 30 /* NodeKind.Block */: { - this.visitBlockStatement(node); - break; - } - case 33 /* NodeKind.Do */: { - this.visitDoStatement(node); - break; - } - case 38 /* NodeKind.Expression */: { - this.visitExpressionStatement(node); - break; - } - case 39 /* NodeKind.For */: { - this.visitForStatement(node); - break; - } - case 40 /* NodeKind.ForOf */: { - this.visitForOfStatement(node); - break; - } - case 41 /* NodeKind.If */: { - this.visitIfStatement(node); - break; - } - case 43 /* NodeKind.Return */: { - this.visitReturnStatement(node); - break; - } - case 44 /* NodeKind.Switch */: { - this.visitSwitchStatement(node); - break; - } - case 45 /* NodeKind.Throw */: { - this.visitThrowStatement(node); - break; - } - case 46 /* NodeKind.Try */: { - this.visitTryStatement(node); - break; - } - case 47 /* NodeKind.Variable */: { - this.visitVariableStatement(node); - break; - } - case 48 /* NodeKind.Void */: { - this.visitVoidStatement(node); - break; - } - case 49 /* NodeKind.While */: { - this.visitWhileStatement(node); - break; - } - // declaration statements - case 56 /* NodeKind.ImportDeclaration */: - case 60 /* NodeKind.TypeDeclaration */: { - break; - } - case 51 /* NodeKind.ClassDeclaration */: { - this.visitClassDeclaration(node); - break; - } - case 52 /* NodeKind.EnumDeclaration */: { - this.visitEnumDeclaration(node); - break; - } - case 53 /* NodeKind.EnumValueDeclaration */: { - this.visitEnumValueDeclaration(node); - break; - } - case 54 /* NodeKind.FieldDeclaration */: { - this.visitFieldDeclaration(node); - break; - } - case 55 /* NodeKind.FunctionDeclaration */: { - this.visitFunctionDeclaration(node); - break; - } - case 57 /* NodeKind.InterfaceDeclaration */: { - this.visitInterfaceDeclaration(node); - break; - } - case 58 /* NodeKind.MethodDeclaration */: { - this.visitMethodDeclaration(node); - break; - } - case 59 /* NodeKind.NamespaceDeclaration */: { - this.visitNamespaceDeclaration(node); - break; - } - case 61 /* NodeKind.VariableDeclaration */: { - this.visitVariableDeclaration(node); - break; - } - // special - case 63 /* NodeKind.ExportMember */: - case 65 /* NodeKind.IndexSignature */: - case 66 /* NodeKind.Comment */: - case 62 /* NodeKind.Decorator */: { - break; - } - case 64 /* NodeKind.SwitchCase */: { - this.visitSwitchCase(node); - break; - } - } - } - visitSource(node) { - for (const statement of node.statements) { - this.visitNode(statement); - } - } - visitParameterNode(node) { - if (node.initializer) { - this.visitNode(node.initializer); - } - } - visitAssertionExpression(node) { - this.visitNode(node.expression); - } - visitBinaryExpression(node) { - this.visitNode(node.left); - this.visitNode(node.right); - } - visitCallExpression(node) { - if (node.expression.kind === 6 /* NodeKind.Identifier */) { - const fncName = node.expression.text; - if (fncName === "describe" || fncName === "test") { - assert(node.args.length === 2); - assert(node.args[0].kind === 16 /* NodeKind.Literal */ && - node.args[0].literalKind === 2 /* LiteralKind.String */); - const testName = node.args[0].value; - this.currentTestDescriptions.push(testName); - if (fncName === "test") { - this.testNames.push(this.currentTestDescriptions.join("")); - } - this.visitNode(node.expression); - for (const arg of node.args) { - this.visitNode(arg); - } - this.currentTestDescriptions.pop(); - } - } - else { - this.visitNode(node.expression); - for (const arg of node.args) { - this.visitNode(arg); - } - } - } - visitClassExpression(node) { - this.visitClassDeclaration(node.declaration); - } - visitCommaExpression(node) { - for (const expr of node.expressions) { - this.visitNode(expr); - } - } - visitElementAccessExpression(node) { - this.visitNode(node.expression); - this.visitNode(node.elementExpression); - } - visitFunctionExpression(node) { - this.visitFunctionDeclaration(node.declaration); - } - visitInstanceOfExpression(node) { - this.visitNode(node.expression); - } - visitNewExpression(node) { - for (const arg of node.args) { - this.visitNode(arg); - } - } - visitParenthesizedExpression(node) { - this.visitNode(node.expression); - } - visitPropertyAccessExpression(node) { - this.visitNode(node.expression); - } - visitTernaryExpression(node) { - this.visitNode(node.condition); - this.visitNode(node.ifThen); - this.visitNode(node.ifElse); - } - visitUnaryPostfixExpression(node) { - this.visitNode(node.operand); - } - visitUnaryPrefixExpression(node) { - this.visitNode(node.operand); - } - // eslint-disable-next-line sonarjs/no-identical-functions - visitBlockStatement(node) { - for (const statement of node.statements) { - this.visitNode(statement); - } - } - visitDoStatement(node) { - this.visitNode(node.body); - this.visitNode(node.condition); - } - visitExpressionStatement(node) { - this.visitNode(node.expression); - } - visitForStatement(node) { - if (node.initializer) { - this.visitNode(node.initializer); - } - if (node.condition) { - this.visitNode(node.condition); - } - if (node.incrementor) { - this.visitNode(node.incrementor); - } - this.visitNode(node.body); - } - visitForOfStatement(node) { - this.visitNode(node.variable); - this.visitNode(node.iterable); - this.visitNode(node.body); - } - visitIfStatement(node) { - this.visitNode(node.condition); - this.visitNode(node.ifTrue); - if (node.ifFalse) { - this.visitNode(node.ifFalse); - } - } - visitReturnStatement(node) { - if (node.value) { - this.visitNode(node.value); - } - } - visitSwitchStatement(node) { - this.visitNode(node.condition); - for (const switchCase of node.cases) { - this.visitSwitchCase(switchCase); - } - } - visitThrowStatement(node) { - this.visitNode(node.value); - } - visitTryStatement(node) { - for (const stat of node.bodyStatements) { - this.visitNode(stat); - } - if (node.catchStatements) { - for (const stat of node.catchStatements) { - this.visitNode(stat); - } - } - if (node.finallyStatements) { - for (const stat of node.finallyStatements) { - this.visitNode(stat); - } - } - } - visitVariableStatement(node) { - for (const declaration of node.declarations) { - this.visitVariableDeclaration(declaration); - } - } - visitVoidStatement(node) { - this.visitNode(node.expression); - } - visitWhileStatement(node) { - this.visitNode(node.condition); - this.visitNode(node.body); - } - visitClassDeclaration(node) { - for (const member of node.members) { - this.visitNode(member); - } - } - visitEnumDeclaration(node) { - for (const value of node.values) { - this.visitEnumValueDeclaration(value); - } - } - // eslint-disable-next-line sonarjs/no-identical-functions - visitEnumValueDeclaration(node) { - if (node.initializer) { - this.visitNode(node.initializer); - } - } - // eslint-disable-next-line sonarjs/no-identical-functions - visitFieldDeclaration(node) { - if (node.initializer) { - this.visitNode(node.initializer); - } - } - visitFunctionDeclaration(node) { - if (node.body) { - this.visitNode(node.body); - } - } - visitInterfaceDeclaration(node) { - this.visitClassDeclaration(node); - } - visitMethodDeclaration(node) { - this.visitFunctionDeclaration(node); - } - // eslint-disable-next-line sonarjs/no-identical-functions - visitNamespaceDeclaration(node) { - for (const member of node.members) { - this.visitNode(member); - } - } - // eslint-disable-next-line sonarjs/no-identical-functions - visitVariableDeclaration(node) { - if (node.initializer) { - this.visitNode(node.initializer); - } - } - visitSwitchCase(node) { - if (node.label) { - this.visitNode(node.label); - } - for (const stat of node.statements) { - this.visitNode(stat); - } - } -} -export default SourceFunctionTransform;