UNPKG

vscode-tmlanguage-snapshot

Version:
139 lines (132 loc) 4.62 kB
import { createRequire } from "node:module"; import { readFile } from "node:fs/promises"; import { dirname, extname, isAbsolute, join } from "node:path"; import * as _oniguruma from "vscode-oniguruma"; import * as _textmate from "vscode-textmate"; //#region rolldown:runtime var __require = /* @__PURE__ */ createRequire(import.meta.url); //#endregion //#region src/onigurama.ts const oniguruma = _oniguruma.default ? _oniguruma.default : _oniguruma; async function createOniguramaLib() { const wasmBin = await readFile(join(dirname(__require.resolve("vscode-oniguruma")), "onig.wasm")); await oniguruma.loadWASM(wasmBin); return { createOnigScanner(patterns) { return new oniguruma.OnigScanner(patterns); }, createOnigString(s) { return new oniguruma.OnigString(s); } }; } //#endregion //#region src/snapshot.ts function renderSnapshotFromLineAndTokens(lineWithTokens) { const lines = []; for (const { line, tokens } of lineWithTokens) lines.push(`>${line}`, ...renderTokens(tokens)); return lines.join("\n"); } function renderTokens(tokens) { const lines = []; for (const token of tokens) { let line = "#"; line += " ".repeat(token.startIndex); line += "^".repeat(token.endIndex - token.startIndex); line += ` ${token.scopes.join(" ")}`; lines.push(line); } return lines; } //#endregion //#region src/textmate.ts const textmate = _textmate.default ? _textmate.default : _textmate; function createTextmateRegistry(grammars, onigLib) { const grammarMap = /* @__PURE__ */ new Map(); const injectionMap = /* @__PURE__ */ new Map(); for (const { grammar, content } of grammars) { const rawGrammar = textmate.parseRawGrammar(content, grammar.path); grammarMap.set(grammar.scopeName || rawGrammar.scopeName, rawGrammar); if (grammar.injectTo) for (const injectScope of grammar.injectTo) { let injections = injectionMap.get(injectScope); if (!injections) injectionMap.set(injectScope, injections = []); injections.push(grammar.scopeName); } } return new textmate.Registry({ onigLib, async loadGrammar(scope) { if (grammarMap.has(scope)) return grammarMap.get(scope); return null; }, getInjections(scope) { const splittedScope = scope.split("."); const injections = []; for (let i = 1; i <= splittedScope.length; i++) { const subScopeName = splittedScope.slice(0, i).join("."); injections.push(...injectionMap.get(subScopeName) ?? []); } return injections; } }); } //#endregion //#region src/token.ts const newlineRe = /\r?\n/; async function getLineWithTokens(registry, scope, source) { const grammar = await registry.loadGrammar(scope); if (!grammar) throw new Error(`Could not load scope ${scope}`); let prevRuleStack = null; return source.split(newlineRe).map((line) => { const { tokens, ruleStack } = grammar.tokenizeLine(line, prevRuleStack); prevRuleStack = ruleStack; return { line, tokens }; }); } //#endregion //#region src/index.ts async function createGrammarSnapshot(packageJsonPath, options = {}) { const grammars = []; if (options.extraGrammarPaths) grammars.push(...options.extraGrammarPaths.map((path) => ({ path, scopeName: "" }))); const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8")); const rootDir = dirname(packageJsonPath); const contributeGrammars = packageJson.contributes?.grammars ?? []; const contributeLanguages = packageJson.contributes?.languages ?? []; grammars.push(...contributeGrammars.map((grammar) => { const path = join(rootDir, grammar.path); return { ...grammar, path }; })); const languageToScope = grammars.filter((language) => !!language.language).map(({ language, scopeName }) => ({ [language]: scopeName })).reduce((a, b) => ({ ...a, ...b }), {}); const extensionToLang = contributeLanguages.filter((language) => !!language.extensions).flatMap(({ extensions, id }) => extensions.map((e) => ({ [e]: id }))).reduce((a, b) => ({ ...a, ...b }), {}); const getScope = (extension) => languageToScope[extensionToLang[extension]]; const registry = createTextmateRegistry(await Promise.all(grammars.map(async (grammar) => { return { grammar, content: await readFile(grammar.path, "utf-8") }; })), createOniguramaLib()); async function snapshot(path) { const scope = getScope(extname(path)); if (!scope) throw new Error(`No scope found for ${path}`); path = isAbsolute(path) ? path : join(rootDir, path); return renderSnapshotFromLineAndTokens(await getLineWithTokens(registry, scope, await readFile(path, "utf-8"))); } return snapshot; } //#endregion export { createGrammarSnapshot };