From 124ad10b8ccc05c716e727fff2eacf83b320520d Mon Sep 17 00:00:00 2001 From: dpiercey Date: Sun, 24 Nov 2024 14:25:59 -0700 Subject: [PATCH] perf: improve script parsing --- .changeset/bright-moons-push.md | 5 ++++ .../src/extractors/script/index.ts | 2 +- .../extractors/script/util/script-parser.ts | 30 ++++++++++++------- 3 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 .changeset/bright-moons-push.md diff --git a/.changeset/bright-moons-push.md b/.changeset/bright-moons-push.md new file mode 100644 index 00000000..521703d6 --- /dev/null +++ b/.changeset/bright-moons-push.md @@ -0,0 +1,5 @@ +--- +"@marko/language-tools": patch +--- + +Improve script parsing performance. diff --git a/packages/language-tools/src/extractors/script/index.ts b/packages/language-tools/src/extractors/script/index.ts index 8b24af72..c35b4788 100644 --- a/packages/language-tools/src/extractors/script/index.ts +++ b/packages/language-tools/src/extractors/script/index.ts @@ -119,7 +119,7 @@ class ScriptExtractor { this.#ts = opts.ts; this.#runtimeTypes = opts.runtimeTypesCode; this.#extractor = new Extractor(parsed); - this.#scriptParser = new ScriptParser(parsed.filename, parsed.code); + this.#scriptParser = new ScriptParser(parsed); this.#read = parsed.read.bind(parsed); this.#mutationOffsets = crawlProgramScope(this.#parsed, this.#scriptParser); this.#writeProgram(parsed.program); diff --git a/packages/language-tools/src/extractors/script/util/script-parser.ts b/packages/language-tools/src/extractors/script/util/script-parser.ts index 874ee54c..266997b5 100644 --- a/packages/language-tools/src/extractors/script/util/script-parser.ts +++ b/packages/language-tools/src/extractors/script/util/script-parser.ts @@ -5,6 +5,8 @@ import { } from "@babel/parser"; import type * as t from "@babel/types"; +import type { Parsed } from "../../../parser"; + const plugins: ParserOptions["plugins"] = [ "exportDefaultFrom", "importAssertions", @@ -12,17 +14,19 @@ const plugins: ParserOptions["plugins"] = [ ]; export class ScriptParser { - #sourceFileName: string; - #whitespace: string; - constructor(sourceFileName: string, code: string) { - this.#sourceFileName = sourceFileName; - this.#whitespace = code.replace(/[^\s]/g, " "); // used to ensure that babel provides the correct source locations. + #parsed: Parsed; + constructor(parsed: Parsed) { + this.#parsed = parsed; } - statementAt(offset: number, src: string) { + statementAt(startIndex: number, src: string) { + const pos = this.#parsed.positionAt(startIndex); try { - return parseStatement(this.#whitespace.slice(0, offset) + src, { + return parseStatement(src, { plugins, + startIndex, + startLine: pos.line + 1, + startColumn: pos.character, strictMode: true, errorRecovery: true, sourceType: "module", @@ -30,17 +34,21 @@ export class ScriptParser { allowSuperOutsideMethod: true, allowAwaitOutsideFunction: true, allowReturnOutsideFunction: true, - sourceFilename: this.#sourceFileName, + sourceFilename: this.#parsed.filename, }).program.body as unknown as T extends unknown[] ? T : Readonly<[T]>; } catch { return []; } } - expressionAt(offset: number, src: string) { + expressionAt(startIndex: number, src: string) { + const pos = this.#parsed.positionAt(startIndex); try { - return parseExpression(this.#whitespace.slice(0, offset) + src, { + return parseExpression(src, { plugins, + startIndex, + startLine: pos.line + 1, + startColumn: pos.character, strictMode: true, errorRecovery: true, sourceType: "module", @@ -48,7 +56,7 @@ export class ScriptParser { allowSuperOutsideMethod: true, allowAwaitOutsideFunction: true, allowReturnOutsideFunction: true, - sourceFilename: this.#sourceFileName, + sourceFilename: this.#parsed.filename, }) as unknown as T; } catch { return;