Skip to content

[perf] findAll with matcher slow after typescript parserΒ #1920

@Timeless0911

Description

@Timeless0911

Please read the FAQ for the bug you encountered.

  • I have read the existing FAQ

⏯ Playground Link

The playground is too big to share.

πŸ’» Code

Reproduction repo: https://github.com/Timeless0911/ast-grep-matcher-performance

Reproduction steps:

  • pnpm i
  • pnpm build

In Rslib, I use below matcher to find out the import and require statement in DTS files.

const matcher: NapiConfig = {
  rule: {
    kind: "string_fragment",
    any: [
      {
        inside: {
          stopBy: "end",
          kind: "import_statement",
          field: "source",
        },
      },
      {
        inside: {
          stopBy: "end",
          kind: "export_statement",
          field: "source",
        },
      },
      {
        inside: {
          kind: "string",
          inside: {
            kind: "arguments",
            inside: {
              kind: "call_expression",
              has: {
                field: "function",
                regex: "^(import|require)$",
              },
            },
          },
        },
      },
    ],
  },
};

The usage is like below:

const content = await fsP.readFile(dtsFile, 'utf-8');
const sgNode = (await parseAsync('typescript', content)).root();
const matchModule = sgNode.findAll(matcher).map((matchNode) => {
    return {
      n: matchNode.text(),
      s: matchNode.range().start.index,
      e: matchNode.range().end.index,
    };
  });

I found that there are some performance issues when in large files with some inline import/require statements.

πŸ™ Actual behavior

In repro demo, I use four files to test and the result is as below:

File: ./file/less-import-no-format.d.ts, Time: 228ms
File: ./file/less-import-format.d.ts, Time: 187ms
File: ./file/much-import-no-format.d.ts, Time: 7119ms
File: ./file/much-import-format.d.ts, Time: 2228ms
  • less-import-no-format.d.ts: 4161 lines with import statement only in few lines of the head
  • less-import-format.d.ts: 11415 lines with formatter applying in less-import-format.d.ts
  • much-import-no-format.d.ts: 4161 lines with many import statement in lines
import: import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodArray<import("zod").ZodString, "many">]>;
  • much-import-format.d.ts: 12401 lines with formatter applying in much-import-no-format.d.ts

πŸ™‚ Expected behavior

All files without formatter applied be completed in as fast as possible to hundred ms.

Additional information about the issue

Whether or not to format is a factor that I found to affect the time.

In addition, I also divided the matcher into two parts and found that stopBy: "end" is the main reason affecting performance.

{
  inside: {
+ stopBy: "end",
    kind: "import_statement",
    field: "source",
  },
},

I need to match these import/require statements:

import { foo } from "bar";
export { foo } from "bar";
require("bar");
import("bar");

I don't know if you have any suggestions on this issue, many thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions