@swiftuijs/twill 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -14
- package/bin/run.mjs +15 -0
- package/bin/twill.mjs +34 -11
- package/dist/branches.d.ts +6 -3
- package/dist/cli.js +13 -6
- package/dist/cli.js.map +1 -1
- package/dist/compilation-cache-7SugqJ4n.js +172 -0
- package/dist/compilation-cache-7SugqJ4n.js.map +1 -0
- package/dist/compilation-cache.d.ts +21 -0
- package/dist/{compiler-Bi9TNOhX.js → compiler-CbNSBUI2.js} +583 -64
- package/dist/compiler-CbNSBUI2.js.map +1 -0
- package/dist/compiler.d.ts +17 -2
- package/dist/config.d.ts +1 -6
- package/dist/config.js +1 -54
- package/dist/configuration-BVMf6Q_j.js +149 -0
- package/dist/configuration-BVMf6Q_j.js.map +1 -0
- package/dist/configuration.d.ts +12 -0
- package/dist/defer-helper.d.ts +1 -0
- package/dist/defer.d.ts +2 -2
- package/dist/doctor.js +9 -5
- package/dist/doctor.js.map +1 -1
- package/dist/editor.d.ts +2 -0
- package/dist/editor.js +75 -4
- package/dist/editor.js.map +1 -1
- package/dist/enums.d.ts +27 -0
- package/dist/esbuild.js +1 -1
- package/dist/extensions-B1xTkoYP.js +9 -0
- package/dist/extensions-B1xTkoYP.js.map +1 -0
- package/dist/extensions.d.ts +2 -0
- package/dist/{files-D1mERoxc.js → files-BW9geU0_.js} +2 -2
- package/dist/files-BW9geU0_.js.map +1 -0
- package/dist/index.js +2 -1
- package/dist/loader-compiler-D1teTrXw.js +19 -0
- package/dist/loader-compiler-D1teTrXw.js.map +1 -0
- package/dist/loader-compiler.d.ts +4 -0
- package/dist/loader.d.ts +4 -0
- package/dist/loader.js +29 -22
- package/dist/loader.js.map +1 -1
- package/dist/parser.d.ts +2 -0
- package/dist/{plugin-BGabvyT6.js → plugin-BHfiQ2L-.js} +41 -12
- package/dist/plugin-BHfiQ2L-.js.map +1 -0
- package/dist/project.js +39 -11
- package/dist/project.js.map +1 -1
- package/dist/recovery.d.ts +2 -2
- package/dist/rollup.js +1 -1
- package/dist/rspack.js +1 -1
- package/dist/syntax.d.ts +2 -0
- package/dist/syntax.js +1 -1
- package/dist/{transpile-DwVekVFM.js → transpile-D8P8Lsbx.js} +2 -2
- package/dist/{transpile-DwVekVFM.js.map → transpile-D8P8Lsbx.js.map} +1 -1
- package/dist/typescript-plugin.cjs +783 -82
- package/dist/typescript-plugin.cjs.map +1 -1
- package/dist/vite.js +1 -1
- package/dist/webpack.js +1 -1
- package/package.json +8 -4
- package/schemas/twill.schema.json +6 -0
- package/dist/compiler-Bi9TNOhX.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/files-D1mERoxc.js.map +0 -1
- package/dist/plugin-BGabvyT6.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configuration-BVMf6Q_j.js","names":[],"sources":["../src/configuration.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport ts from 'typescript';\nimport type { TransformOptions } from './compiler.js';\nimport {\n digest,\n observe,\n observationsMatch,\n type ConfigurationObservation,\n} from './compilation-cache.js';\n\ntype Config = Pick<TransformOptions, 'implicitReturn' | 'jsxImportSource' | 'runtime'>;\ntype Observations = Map<string, ConfigurationObservation>;\nconst jsxConfigs = new Map<string, { files: Map<string, number>; source?: string }>();\nconst loaderConfigs = new Map<\n string,\n { config: Config; observations: ConfigurationObservation[] }\n>();\n\nfunction record(observations: Observations, path: string, kind: ConfigurationObservation['kind']) {\n path = resolve(path);\n observations.set(kind + path, { path, kind, value: observe(path, kind) });\n}\n\n/** Use the project's standard JSX setting, including extended tsconfigs. */\nfunction jsxSource(\n root: string,\n configFile?: string,\n observations?: Observations,\n): string | undefined {\n const system = observations\n ? {\n ...ts.sys,\n fileExists(path: string) {\n record(observations, path, 'file');\n return ts.sys.fileExists(path);\n },\n directoryExists(path: string) {\n record(observations, path, 'directory');\n return ts.sys.directoryExists(path);\n },\n }\n : ts.sys;\n const filename = configFile ?? ts.findConfigFile(root, system.fileExists);\n if (!filename) return undefined;\n const cached = jsxConfigs.get(filename);\n if (\n !observations &&\n cached &&\n [...cached.files].every(\n ([file, time]) => (existsSync(file) ? statSync(file).mtimeMs : -1) === time,\n )\n )\n return cached.source;\n const files = new Map<string, number>();\n const parsed = ts.getParsedCommandLineOfConfigFile(\n filename,\n {},\n {\n ...system,\n // Only read configuration, not the project's source tree.\n readDirectory: () => [],\n readFile(file) {\n files.set(file, existsSync(file) ? statSync(file).mtimeMs : -1);\n if (!observations) return ts.sys.readFile(file);\n const path = resolve(file);\n let bytes: Buffer;\n try {\n bytes = readFileSync(file);\n } catch {\n observations.set('file' + path, { path, kind: 'file', value: 'unavailable' });\n return undefined;\n }\n observations.set('file' + path, { path, kind: 'file', value: digest(bytes) });\n // Match ts.sys.readFile's BOM decoding while hashing the exact read bytes.\n if (bytes[0] === 254 && bytes[1] === 255) {\n for (let i = 0; i < (bytes.length & ~1); i += 2) {\n const byte = bytes[i]!;\n bytes[i] = bytes[i + 1]!;\n bytes[i + 1] = byte;\n }\n return bytes.toString('utf16le', 2);\n }\n if (bytes[0] === 255 && bytes[1] === 254) return bytes.toString('utf16le', 2);\n return bytes.toString(\n 'utf8',\n bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191 ? 3 : 0,\n );\n },\n getCurrentDirectory: () => root,\n onUnRecoverableConfigFileDiagnostic() {},\n },\n );\n const source = parsed?.options.jsxImportSource;\n jsxConfigs.set(filename, { files, source });\n return source;\n}\n\nfunction readConfig(root: string, configFile?: string, observations?: Observations): Config {\n const filename = resolve(root, 'twill.config.json');\n const jsxImportSource = jsxSource(root, configFile, observations);\n if (observations) record(observations, filename, 'file');\n if (!existsSync(filename)) return { jsxImportSource };\n const text = readFileSync(filename, 'utf8');\n if (observations) {\n observations.set('file' + filename, { path: filename, kind: 'file', value: digest(text) });\n }\n const value = JSON.parse(text);\n if (!value || typeof value !== 'object' || Array.isArray(value))\n throw new Error(`${filename}: expected an object`);\n if (value.implicitReturn !== undefined && typeof value.implicitReturn !== 'boolean')\n throw new Error(`${filename}: implicitReturn must be a boolean`);\n if (value.runtime !== undefined && !['inline', 'external'].includes(value.runtime))\n throw new Error(`${filename}: runtime must be inline or external`);\n for (const key of Object.keys(value))\n if (!['implicitReturn', 'runtime', '$schema'].includes(key))\n throw new Error(`${filename}: unknown option ${key}`);\n return {\n implicitReturn: value.implicitReturn,\n jsxImportSource,\n ...(value.runtime === undefined ? {} : { runtime: value.runtime }),\n };\n}\n\nexport function loadConfig(root = process.cwd(), configFile?: string): Config {\n return readConfig(root, configFile);\n}\n\n/** Config dependencies, including inherited tsconfigs and optional new files. */\nexport function configurationFiles(root: string): string[] {\n jsxSource(root);\n const tsconfig = ts.findConfigFile(root, ts.sys.fileExists);\n return [\n ...new Set(\n [\n resolve(root, 'twill.config.json'),\n resolve(root, 'tsconfig.json'),\n ...(tsconfig ? [...(jsxConfigs.get(tsconfig)?.files.keys() ?? [tsconfig])] : []),\n ].map((file) => resolve(file)),\n ),\n ];\n}\n\n/** Fresh, content-based observations for persistent runner cache validation. */\nexport function loaderConfiguration(filename: string): {\n config: Config;\n observations: ConfigurationObservation[];\n} {\n const directory = resolve(dirname(filename));\n const cached = loaderConfigs.get(directory);\n // Still hash every observed dependency and missing-file probe. Reusing only\n // the parsed configuration cannot hide same-mtime edits or nearer configs.\n if (cached && observationsMatch(cached.observations)) return cached;\n const observations: Observations = new Map();\n let root = directory;\n for (;;) {\n const twill = resolve(root, 'twill.config.json');\n const typescript = resolve(root, 'tsconfig.json');\n record(observations, twill, 'file');\n record(observations, typescript, 'file');\n if (existsSync(twill) || existsSync(typescript)) {\n const result = {\n config: readConfig(root, undefined, observations),\n observations: [...observations.values()],\n };\n loaderConfigs.delete(directory);\n if (loaderConfigs.size >= 64) loaderConfigs.delete(loaderConfigs.keys().next().value!);\n loaderConfigs.set(directory, result);\n return result;\n }\n const parent = dirname(root);\n if (parent === root) return { config: {}, observations: [...observations.values()] };\n root = parent;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TransformOptions } from './compiler.js';
|
|
2
|
+
import { ConfigurationObservation } from './compilation-cache.js';
|
|
3
|
+
type Config = Pick<TransformOptions, 'implicitReturn' | 'jsxImportSource' | 'runtime'>;
|
|
4
|
+
export declare function loadConfig(root?: string, configFile?: string): Config;
|
|
5
|
+
/** Config dependencies, including inherited tsconfigs and optional new files. */
|
|
6
|
+
export declare function configurationFiles(root: string): string[];
|
|
7
|
+
/** Fresh, content-based observations for persistent runner cache validation. */
|
|
8
|
+
export declare function loaderConfiguration(filename: string): {
|
|
9
|
+
config: Config;
|
|
10
|
+
observations: ConfigurationObservation[];
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function syncDeferBody(names: Record<'stack' | 'failed' | 'failure' | 'cleanup' | 'error', string>): string;
|
package/dist/defer.d.ts
CHANGED
|
@@ -12,6 +12,6 @@ type Comment = {
|
|
|
12
12
|
value: string;
|
|
13
13
|
type: string;
|
|
14
14
|
};
|
|
15
|
-
/**
|
|
16
|
-
export declare function lowerDefers(source: string, ast: Node, code: MagicString, language: Language, usedNames: Set<string>, contentStarts: Map<Node, number>, comments: Comment[], fail: (node: Node, message: string) => never): void;
|
|
15
|
+
/** Native finally where scope permits; callbacks retain dynamic registration semantics. */
|
|
16
|
+
export declare function lowerDefers(source: string, ast: Node, code: MagicString, language: Language, usedNames: Set<string>, contentStarts: Map<Node, number>, comments: Comment[], runtime: 'inline' | 'external', sourceType: 'module' | 'script', fail: (node: Node, message: string) => never): void;
|
|
17
17
|
export {};
|
package/dist/doctor.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as isTwillFile } from "./extensions-B1xTkoYP.js";
|
|
2
2
|
import ts from "typescript";
|
|
3
3
|
var package_default = {
|
|
4
4
|
name: "@swiftuijs/twill",
|
|
5
|
-
version: "0.
|
|
5
|
+
version: "0.3.0",
|
|
6
6
|
description: "Twill extends TypeScript with Swift-inspired syntax: trailing closures, guards, defer and checked switch expressions. Compiles to ordinary JavaScript.",
|
|
7
7
|
main: "./dist/typescript-plugin.cjs",
|
|
8
8
|
repository: {
|
|
@@ -134,7 +134,7 @@ var package_default = {
|
|
|
134
134
|
publishConfig: { "access": "public" },
|
|
135
135
|
module: "./dist/index.js",
|
|
136
136
|
scripts: {
|
|
137
|
-
"build": "vite build && vite build --config vite.plugin.config.ts && node scripts/prepare-core.mjs",
|
|
137
|
+
"build": "node ../../scripts/generate-runtime-helper.mjs && vite build && vite build --config vite.plugin.config.ts && node scripts/prepare-core.mjs",
|
|
138
138
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
139
139
|
"prepack": "pnpm run build",
|
|
140
140
|
"test:unit": "vitest run",
|
|
@@ -145,7 +145,10 @@ var package_default = {
|
|
|
145
145
|
"test:browser": "playwright test",
|
|
146
146
|
"benchmark": "node benchmarks/compiler.mjs",
|
|
147
147
|
"test": "pnpm run test:unit",
|
|
148
|
-
"benchmark:branching": "node benchmarks/branching.mjs"
|
|
148
|
+
"benchmark:branching": "node benchmarks/branching.mjs",
|
|
149
|
+
"benchmark:enum-patterns": "node benchmarks/enum-patterns.mjs",
|
|
150
|
+
"benchmark:runtime": "node benchmarks/runtime-helpers.mjs",
|
|
151
|
+
"benchmark:if-bindings": "node benchmarks/if-bindings.mjs"
|
|
149
152
|
},
|
|
150
153
|
devDependencies: {
|
|
151
154
|
"vite": "catalog:",
|
|
@@ -164,7 +167,8 @@ var package_default = {
|
|
|
164
167
|
"rollup": "catalog:",
|
|
165
168
|
"vue": "catalog:",
|
|
166
169
|
"webpack": "catalog:",
|
|
167
|
-
"@playwright/test": "catalog:"
|
|
170
|
+
"@playwright/test": "catalog:",
|
|
171
|
+
"@swiftuijs/twill-runtime": "workspace:*"
|
|
168
172
|
}
|
|
169
173
|
};
|
|
170
174
|
//#endregion
|
package/dist/doctor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","names":["metadata"],"sources":["../package.json","../src/doctor.ts"],"sourcesContent":["{\n \"name\": \"@swiftuijs/twill\",\n \"version\": \"0.
|
|
1
|
+
{"version":3,"file":"doctor.js","names":["metadata"],"sources":["../package.json","../src/doctor.ts"],"sourcesContent":["{\n \"name\": \"@swiftuijs/twill\",\n \"version\": \"0.3.0\",\n \"description\": \"Twill extends TypeScript with Swift-inspired syntax: trailing closures, guards, defer and checked switch expressions. Compiles to ordinary JavaScript.\",\n \"main\": \"./dist/typescript-plugin.cjs\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/swiftuijs/twill.git\",\n \"directory\": \"packages/twill\"\n },\n \"keywords\": [\n \"javascript\",\n \"typescript\",\n \"trailing-closures\",\n \"swift\",\n \"vite\",\n \"unplugin\",\n \"react\",\n \"vue\",\n \"twill\",\n \"guard\",\n \"defer\"\n ],\n \"author\": {\n \"name\": \"forth.ink\",\n \"url\": \"https://forth.ink\"\n },\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"bugs\": {\n \"url\": \"https://github.com/swiftuijs/twill/issues\"\n },\n \"homepage\": \"https://twill.evecalm.com/\",\n \"dependencies\": {\n \"@ampproject/remapping\": \"^2.3.0\",\n \"@jridgewell/trace-mapping\": \"^0.3.31\",\n \"acorn\": \"8.18.0\",\n \"acorn-jsx\": \"^5.3.2\",\n \"acorn-typescript\": \"1.4.13\",\n \"magic-string\": \"^1.4.2\",\n \"typescript\": \"catalog:\",\n \"unplugin\": \"^3.4.0\"\n },\n \"sideEffects\": false,\n \"engines\": {\n \"node\": \"^20.19.0 || >=22.12.0\"\n },\n \"files\": [\n \"bin\",\n \"dist/**/*.js\",\n \"dist/**/*.js.map\",\n \"dist/**/*.d.ts\",\n \"schemas\",\n \"README.md\",\n \"LICENSE\",\n \"dist/**/*.cjs\",\n \"dist/**/*.cjs.map\",\n \"dist/*.LICENSE.txt\"\n ],\n \"bin\": {\n \"twill\": \"./bin/twill.mjs\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./vite\": {\n \"types\": \"./dist/vite.d.ts\",\n \"import\": \"./dist/vite.js\"\n },\n \"./rollup\": {\n \"types\": \"./dist/rollup.d.ts\",\n \"import\": \"./dist/rollup.js\"\n },\n \"./esbuild\": {\n \"types\": \"./dist/esbuild.d.ts\",\n \"import\": \"./dist/esbuild.js\"\n },\n \"./webpack\": {\n \"types\": \"./dist/webpack.d.ts\",\n \"import\": \"./dist/webpack.js\"\n },\n \"./rspack\": {\n \"types\": \"./dist/rspack.d.ts\",\n \"import\": \"./dist/rspack.js\"\n },\n \"./project\": {\n \"types\": \"./dist/project.d.ts\",\n \"import\": \"./dist/project.js\"\n },\n \"./editor\": {\n \"types\": \"./dist/editor.d.ts\",\n \"import\": \"./dist/editor.js\"\n },\n \"./register\": {\n \"types\": \"./dist/register.d.ts\",\n \"import\": \"./dist/register.js\"\n },\n \"./schema\": \"./schemas/twill.schema.json\",\n \"./typescript-plugin\": {\n \"types\": \"./dist/typescript-plugin.d.ts\",\n \"require\": \"./dist/typescript-plugin.cjs\",\n \"default\": \"./dist/typescript-plugin.cjs\"\n },\n \"./doctor\": {\n \"types\": \"./dist/doctor.d.ts\",\n \"import\": \"./dist/doctor.js\"\n },\n \"./syntax\": {\n \"types\": \"./dist/syntax.d.ts\",\n \"import\": \"./dist/syntax.js\"\n },\n \"./config\": {\n \"types\": \"./dist/config.d.ts\",\n \"import\": \"./dist/config.js\"\n },\n \"./declarations\": {\n \"types\": \"./dist/declarations.d.ts\",\n \"import\": \"./dist/declarations.js\"\n },\n \"./vite-react\": {\n \"types\": \"./dist/vite-react.d.ts\",\n \"import\": \"./dist/vite-react.js\"\n }\n },\n \"peerDependencies\": {\n \"react\": \"^18.2.0 || ^19.0.0\",\n \"vue\": \"^3.3.0\",\n \"@vitejs/plugin-react\": \"^6.1.1\"\n },\n \"peerDependenciesMeta\": {\n \"react\": {\n \"optional\": true\n },\n \"vue\": {\n \"optional\": true\n },\n \"@vitejs/plugin-react\": {\n \"optional\": true\n }\n },\n \"types\": \"./dist/index.d.ts\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"module\": \"./dist/index.js\",\n \"scripts\": {\n \"build\": \"node ../../scripts/generate-runtime-helper.mjs && vite build && vite build --config vite.plugin.config.ts && node scripts/prepare-core.mjs\",\n \"typecheck\": \"tsc --noEmit -p tsconfig.json\",\n \"prepack\": \"pnpm run build\",\n \"test:unit\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"test:package\": \"node tests/consumer.mjs\",\n \"test:size\": \"node tests/bundle-size.mjs\",\n \"test:browser\": \"playwright test\",\n \"benchmark\": \"node benchmarks/compiler.mjs\",\n \"test\": \"pnpm run test:unit\",\n \"benchmark:branching\": \"node benchmarks/branching.mjs\",\n \"benchmark:enum-patterns\": \"node benchmarks/enum-patterns.mjs\",\n \"benchmark:runtime\": \"node benchmarks/runtime-helpers.mjs\",\n \"benchmark:if-bindings\": \"node benchmarks/if-bindings.mjs\"\n },\n \"devDependencies\": {\n \"vite\": \"catalog:\",\n \"vite-plugin-dts\": \"^5.1.2\",\n \"@types/node\": \"catalog:\",\n \"@vitejs/plugin-react\": \"catalog:\",\n \"vitest\": \"catalog:\",\n \"@vitest/coverage-v8\": \"catalog:\",\n \"@rspack/core\": \"catalog:\",\n \"@types/react\": \"catalog:\",\n \"@types/react-dom\": \"catalog:\",\n \"@vue/server-renderer\": \"catalog:\",\n \"esbuild\": \"catalog:\",\n \"react\": \"catalog:\",\n \"react-dom\": \"catalog:\",\n \"rollup\": \"catalog:\",\n \"vue\": \"catalog:\",\n \"webpack\": \"catalog:\",\n \"@playwright/test\": \"catalog:\",\n \"@swiftuijs/twill-runtime\": \"workspace:*\"\n }\n}\n","import ts from 'typescript';\nimport metadata from '../package.json';\nimport { TwillProject } from './project.js';\nimport { isTwillFile } from './compiler.js';\n\n/** Shareable diagnostics without source contents or environment-variable values. */\nexport function inspectProject(project: TwillProject, filename?: string) {\n const started = performance.now();\n const diagnostics = project.diagnostics(filename);\n const files = project.sourceFiles();\n return {\n twillVersion: metadata.version,\n typescriptVersion: ts.version,\n nodeVersion: process.version,\n root: project.root,\n configFiles: project.configFiles,\n compilerOptions: project.compilerOptions,\n files: {\n total: files.length,\n twill: files.filter(isTwillFile).length,\n native: files.filter((file) => !isTwillFile(file)).length,\n },\n sourceFiles: files,\n diagnostics,\n diagnosticTimeMs: performance.now() - started,\n ok: !diagnostics.some((diagnostic) => diagnostic.category === 'error'),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACMA,SAAgB,eAAe,SAAuB,UAAmB;CACvE,MAAM,UAAU,YAAY,IAAI;CAChC,MAAM,cAAc,QAAQ,YAAY,QAAQ;CAChD,MAAM,QAAQ,QAAQ,YAAY;CAClC,OAAO;EACL,cAAcA,gBAAS;EACvB,mBAAmB,GAAG;EACtB,aAAa,QAAQ;EACrB,MAAM,QAAQ;EACd,aAAa,QAAQ;EACrB,iBAAiB,QAAQ;EACzB,OAAO;GACL,OAAO,MAAM;GACb,OAAO,MAAM,OAAO,WAAW,CAAC,CAAC;GACjC,QAAQ,MAAM,QAAQ,SAAS,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;EACrD;EACA,aAAa;EACb;EACA,kBAAkB,YAAY,IAAI,IAAI;EACtC,IAAI,CAAC,YAAY,MAAM,eAAe,WAAW,aAAa,OAAO;CACvE;AACF"}
|
package/dist/editor.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface CompletionRequest {
|
|
|
17
17
|
export declare class TwillEditor {
|
|
18
18
|
readonly project: TwillProject;
|
|
19
19
|
private attributeCache;
|
|
20
|
+
private descriptorCache;
|
|
20
21
|
constructor(project: TwillProject);
|
|
21
22
|
private sourceFile;
|
|
22
23
|
private attributes;
|
|
@@ -43,6 +44,7 @@ export declare class TwillEditor {
|
|
|
43
44
|
/** Read-only navigation must also exclude generated helpers and duplicate JSX tags. */
|
|
44
45
|
referenceGroups(filename: string, position: number): ts.ReferencedSymbol[] | undefined;
|
|
45
46
|
references(filename: string, position: number): ts.ReferencedSymbolEntry[] | undefined;
|
|
47
|
+
private descriptorSymbols;
|
|
46
48
|
renameInfo(filename: string, position: number): ts.RenameInfo;
|
|
47
49
|
renameLocations(filename: string, position: number, preferences?: ts.UserPreferences | boolean): ts.RenameLocation[] | undefined;
|
|
48
50
|
rename(filename: string, position: number, name: string, preferences?: ts.UserPreferences | boolean): SourceEdit[] | undefined;
|
package/dist/editor.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as isTwillFile } from "./extensions-B1xTkoYP.js";
|
|
2
2
|
import { sourceFilename, virtualFilename } from "./project.js";
|
|
3
3
|
import ts from "typescript";
|
|
4
4
|
//#region src/editor.ts
|
|
@@ -6,6 +6,7 @@ import ts from "typescript";
|
|
|
6
6
|
var TwillEditor = class {
|
|
7
7
|
project;
|
|
8
8
|
attributeCache = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
descriptorCache = /* @__PURE__ */ new WeakMap();
|
|
9
10
|
constructor(project) {
|
|
10
11
|
this.project = project;
|
|
11
12
|
}
|
|
@@ -74,10 +75,11 @@ var TwillEditor = class {
|
|
|
74
75
|
const source = this.project.text(filename);
|
|
75
76
|
if (source === void 0) return void 0;
|
|
76
77
|
if (!isTwillFile(filename)) return span.start >= 0 && span.start + span.length <= source.length ? span : void 0;
|
|
77
|
-
const
|
|
78
|
+
const transformed = this.project.transformed(filename);
|
|
79
|
+
const generated = transformed?.code;
|
|
78
80
|
if (generated === void 0) return void 0;
|
|
79
81
|
const start = this.project.toOriginalOffset(filename, span.start);
|
|
80
|
-
if (start < 0 || start + span.length > source.length || this.project.toGeneratedOffset(filename, start) !== span.start || source.slice(start, start + span.length) !== generated.slice(span.start, span.start + span.length)) return void 0;
|
|
82
|
+
if (start < 0 || start + span.length > source.length || this.project.toGeneratedOffset(filename, start) !== span.start && !transformed.enumCopies.some((copy) => span.start >= copy.generatedStart && span.start + span.length <= copy.generatedStart + copy.length && start === copy.sourceStart + span.start - copy.generatedStart || start >= copy.sourceStart && start + span.length <= copy.sourceStart + copy.length && this.project.toOriginalOffset(filename, span.start + span.length - 1) === start + span.length - 1) || source.slice(start, start + span.length) !== generated.slice(span.start, span.start + span.length)) return void 0;
|
|
81
83
|
return {
|
|
82
84
|
start,
|
|
83
85
|
length: span.length
|
|
@@ -165,8 +167,77 @@ var TwillEditor = class {
|
|
|
165
167
|
references(filename, position) {
|
|
166
168
|
return this.referenceGroups(filename, position)?.flatMap((group) => group.references);
|
|
167
169
|
}
|
|
170
|
+
descriptorSymbols(program) {
|
|
171
|
+
const cached = this.descriptorCache.get(program);
|
|
172
|
+
if (cached) return cached;
|
|
173
|
+
const symbols = /* @__PURE__ */ new Set();
|
|
174
|
+
const checker = program.getTypeChecker();
|
|
175
|
+
for (const file of program.getSourceFiles()) {
|
|
176
|
+
const original = sourceFilename(file.fileName);
|
|
177
|
+
if (!isTwillFile(original)) continue;
|
|
178
|
+
let patterns;
|
|
179
|
+
try {
|
|
180
|
+
patterns = this.project.transformed(original)?.enumPatterns;
|
|
181
|
+
} catch {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (!patterns?.length) continue;
|
|
185
|
+
const offsets = new Set(patterns.map((pattern) => this.project.toGeneratedOffset(original, pattern.reference.property.start)));
|
|
186
|
+
const visit = (node) => {
|
|
187
|
+
if (ts.isIdentifier(node) && offsets.has(node.getStart())) {
|
|
188
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
189
|
+
if (symbol) for (const root of checker.getRootSymbols(symbol)) symbols.add(root);
|
|
190
|
+
}
|
|
191
|
+
ts.forEachChild(node, visit);
|
|
192
|
+
};
|
|
193
|
+
visit(file);
|
|
194
|
+
}
|
|
195
|
+
this.descriptorCache.set(program, symbols);
|
|
196
|
+
return symbols;
|
|
197
|
+
}
|
|
168
198
|
renameInfo(filename, position) {
|
|
169
|
-
const
|
|
199
|
+
const offset = this.project.toGeneratedOffset(filename, position);
|
|
200
|
+
const definitions = this.project.service.getDefinitionAtPosition(virtualFilename(filename), offset);
|
|
201
|
+
const program = this.project.service.getProgram();
|
|
202
|
+
const descriptors = this.descriptorSymbols(program);
|
|
203
|
+
for (const definition of definitions ?? []) {
|
|
204
|
+
const file = sourceFilename(definition.fileName);
|
|
205
|
+
const definitionFile = this.sourceFile(file);
|
|
206
|
+
let descriptor = false;
|
|
207
|
+
const visitDefinition = (node) => {
|
|
208
|
+
if (definition.textSpan.start < node.getStart() || definition.textSpan.start >= node.end) return;
|
|
209
|
+
if (ts.isIdentifier(node) || ts.isStringLiteral(node)) {
|
|
210
|
+
const symbol = program.getTypeChecker().getSymbolAtLocation(node);
|
|
211
|
+
descriptor = !!symbol && program.getTypeChecker().getRootSymbols(symbol).some((root) => descriptors.has(root));
|
|
212
|
+
} else ts.forEachChild(node, visitDefinition);
|
|
213
|
+
};
|
|
214
|
+
if (descriptors.size && definitionFile) visitDefinition(definitionFile);
|
|
215
|
+
if (descriptor) return {
|
|
216
|
+
canRename: false,
|
|
217
|
+
localizedErrorMessage: "Renaming an enum-pattern case descriptor requires linked discriminator edits and is not supported yet."
|
|
218
|
+
};
|
|
219
|
+
const declarations = this.project.transformed(file)?.associatedEnums;
|
|
220
|
+
if (!declarations?.length) continue;
|
|
221
|
+
const sourceFile = this.sourceFile(file);
|
|
222
|
+
let generatedEnum = false;
|
|
223
|
+
const visit = (node) => {
|
|
224
|
+
if (definition.textSpan.start < node.getStart() || definition.textSpan.start >= node.end) return;
|
|
225
|
+
if ((ts.isTypeAliasDeclaration(node) || ts.isVariableDeclaration(node)) && ts.isIdentifier(node.name)) {
|
|
226
|
+
const start = this.project.toOriginalOffset(file, node.name.getStart());
|
|
227
|
+
if (declarations.some((declaration) => declaration.id.start === start)) {
|
|
228
|
+
generatedEnum = true;
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
ts.forEachChild(node, visit);
|
|
233
|
+
};
|
|
234
|
+
if (sourceFile) visit(sourceFile);
|
|
235
|
+
if (generatedEnum) return {
|
|
236
|
+
canRename: false,
|
|
237
|
+
localizedErrorMessage: "Renaming associated-value enum declarations, cases, payload fields and type parameters is not supported yet."
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
const info = this.project.service.getRenameInfo(virtualFilename(filename), offset, { allowRenameOfImportPath: false });
|
|
170
241
|
if (!info.canRename) return info;
|
|
171
242
|
const span = this.mapSpan(filename, info.triggerSpan);
|
|
172
243
|
return span ? {
|
package/dist/editor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.js","names":[],"sources":["../src/editor.ts"],"sourcesContent":["import ts from 'typescript';\nimport { TwillProject, sourceFilename, virtualFilename } from './project.js';\nimport { isTwillFile } from './compiler.js';\n\nexport interface SourceEdit {\n filename: string;\n span: ts.TextSpan;\n newText: string;\n}\n\nexport interface CompletionRequest {\n offset: number;\n info: ts.CompletionInfo | undefined;\n props?: { start: number; end: number };\n}\n\n/** Shared semantic requests and conservative source edits for both editor hosts. */\nexport class TwillEditor {\n private attributeCache = new WeakMap<ts.SourceFile, ts.JsxAttribute[]>();\n constructor(readonly project: TwillProject) {}\n\n private sourceFile(filename: string) {\n return this.project.service.getProgram()?.getSourceFile(virtualFilename(filename));\n }\n\n private attributes(filename: string) {\n const file = this.sourceFile(filename);\n if (!file) return [];\n const cached = this.attributeCache.get(file);\n if (cached) return cached;\n const result: ts.JsxAttribute[] = [];\n const visit = (node: ts.Node) => {\n if (ts.isJsxAttribute(node)) result.push(node);\n ts.forEachChild(node, visit);\n };\n visit(file);\n this.attributeCache.set(file, result);\n return result;\n }\n\n completionLocation(filename: string, position: number) {\n let offset = this.project.toGeneratedOffset(filename, position);\n // A repaired member name and generated arm punctuation can share the same\n // original boundary. Anchor requests at the source-backed dot instead.\n const prefix = this.project.text(filename)?.slice(0, position);\n const member = prefix?.match(/\\.([\\p{ID_Continue}$\\u200c\\u200d]*)$/u);\n const missingMember = prefix?.match(/\\.\\s*$/);\n if (member) offset = this.project.toGeneratedOffset(filename, member.index!) + member[0].length;\n else if (missingMember)\n offset = this.project.toGeneratedOffset(filename, missingMember.index!) + 1;\n let props: CompletionRequest['props'];\n const metadata = this.project.transformed(filename)?.componentProps;\n const property = metadata\n ?.flatMap((object) => object.properties)\n .find((item) => item.shorthand && position >= item.start && position <= item.end);\n if (property) {\n const attribute = this.attributes(filename).find(\n (item) =>\n item.name.getText() === property.name &&\n item.initializer &&\n ts.isJsxExpression(item.initializer) &&\n item.initializer.expression &&\n this.project.toOriginalOffset(filename, item.initializer.expression.getStart()) ===\n property.start,\n );\n if (attribute) {\n offset = attribute.name.getStart() + position - property.start;\n props = { start: property.start, end: property.end };\n }\n } else if (\n metadata?.some((object) => position > object.start && position < object.end) &&\n !this.attributes(filename).some(\n (attribute) => offset >= attribute.name.end && offset <= attribute.end,\n )\n ) {\n // Empty objects and gaps between properties already map to JSX attribute\n // positions. Only classify requests that TS identifies as member lists.\n props = { start: position, end: position };\n }\n return { offset, props };\n }\n\n completions(filename: string, position: number, preferences: ts.UserPreferences = {}) {\n let { offset, props } = this.completionLocation(filename, position);\n const info = this.project.service.getCompletionsAtPosition(virtualFilename(filename), offset, {\n includeCompletionsForModuleExports: true,\n includeCompletionsWithInsertText: true,\n ...preferences,\n });\n if (props && !info?.isMemberCompletion) props = undefined;\n return { offset, info, props } satisfies CompletionRequest;\n }\n\n /** Never stretch a generated edit across lowered punctuation or helper code. */\n mapSpan(filename: string, span: ts.TextSpan): ts.TextSpan | undefined {\n filename = sourceFilename(filename);\n const source = this.project.text(filename);\n if (source === undefined) return undefined;\n if (!isTwillFile(filename))\n return span.start >= 0 && span.start + span.length <= source.length ? span : undefined;\n const generated = this.project.transformed(filename)?.code;\n if (generated === undefined) return undefined;\n const start = this.project.toOriginalOffset(filename, span.start);\n if (\n start < 0 ||\n start + span.length > source.length ||\n this.project.toGeneratedOffset(filename, start) !== span.start ||\n source.slice(start, start + span.length) !==\n generated.slice(span.start, span.start + span.length)\n )\n return undefined;\n return { start, length: span.length };\n }\n\n mapChanges(changes: readonly ts.FileTextChanges[]): SourceEdit[] | undefined {\n const edits: SourceEdit[] = [];\n for (const file of changes) {\n if (file.isNewFile) return undefined;\n const filename = sourceFilename(file.fileName);\n for (const change of file.textChanges) {\n let span = this.mapSpan(filename, change.span);\n // Inferred JSX runtime pragmas can precede the first source token.\n // A fresh import can safely be inserted before the original module.\n if (!span && change.span.length === 0 && /^\\s*import\\b/.test(change.newText)) {\n const firstStatement = this.sourceFile(filename)?.statements[0];\n if (change.span.start <= (firstStatement?.getStart() ?? 0))\n span = { start: 0, length: 0 };\n }\n if (!span) return undefined;\n edits.push({ filename, span, newText: this.importText(change.newText) });\n }\n }\n return edits;\n }\n\n private importText(text: string) {\n // Edit only module literals, never user strings in an unrelated code fix.\n const file = ts.createSourceFile('edits.ts', text, ts.ScriptTarget.Latest, true);\n const replacements: { start: number; end: number; text: string }[] = [];\n for (const statement of file.statements) {\n if (\n (ts.isImportDeclaration(statement) || ts.isExportDeclaration(statement)) &&\n statement.moduleSpecifier &&\n ts.isStringLiteral(statement.moduleSpecifier)\n ) {\n const literal = statement.moduleSpecifier;\n const value = sourceFilename(literal.text);\n if (value !== literal.text)\n replacements.push({ start: literal.getStart() + 1, end: literal.end - 1, text: value });\n }\n }\n for (const replacement of replacements.reverse())\n text = text.slice(0, replacement.start) + replacement.text + text.slice(replacement.end);\n return text;\n }\n\n organizeImports(filename: string, mode = ts.OrganizeImportsMode.All) {\n return this.mapChanges(\n this.project.service.organizeImports(\n { type: 'file', fileName: virtualFilename(filename), mode },\n {},\n {},\n ),\n );\n }\n\n /** Read-only navigation must also exclude generated helpers and duplicate JSX tags. */\n referenceGroups(filename: string, position: number): ts.ReferencedSymbol[] | undefined {\n const groups = this.project.service.findReferences(\n virtualFilename(filename),\n this.project.toGeneratedOffset(filename, position),\n );\n const mapped = <T extends ts.DocumentSpan>(entry: T): T | undefined => {\n const fileName = sourceFilename(entry.fileName);\n const textSpan = this.mapSpan(fileName, entry.textSpan);\n if (!textSpan) return undefined;\n const contextSpan = entry.contextSpan && this.mapSpan(fileName, entry.contextSpan);\n return { ...entry, fileName, textSpan, contextSpan };\n };\n return groups?.flatMap((group) => {\n const definition = mapped(group.definition);\n if (!definition) return [];\n const seen = new Set<string>();\n const references = group.references.flatMap((reference) => {\n const entry = mapped(reference);\n if (!entry) return [];\n // Some TS versions omit isDefinition from findReferences results.\n // Preserve supplied flags; otherwise compare the source-backed span\n // with this symbol group's definition for includeDeclaration requests.\n entry.isDefinition ??=\n entry.fileName === definition.fileName &&\n entry.textSpan.start === definition.textSpan.start &&\n entry.textSpan.length === definition.textSpan.length;\n const key = `${entry.fileName}:${entry.textSpan.start}:${entry.textSpan.length}`;\n if (seen.has(key)) return [];\n seen.add(key);\n return [entry];\n });\n return [{ definition, references }];\n });\n }\n\n references(filename: string, position: number) {\n return this.referenceGroups(filename, position)?.flatMap((group) => group.references);\n }\n\n renameInfo(filename: string, position: number): ts.RenameInfo {\n const info = this.project.service.getRenameInfo(\n virtualFilename(filename),\n this.project.toGeneratedOffset(filename, position),\n { allowRenameOfImportPath: false },\n );\n if (!info.canRename) return info;\n const span = this.mapSpan(filename, info.triggerSpan);\n return span\n ? { ...info, triggerSpan: span }\n : {\n canRename: false,\n localizedErrorMessage: 'This generated symbol cannot be renamed in Twill source.',\n };\n }\n\n renameLocations(\n filename: string,\n position: number,\n preferences: ts.UserPreferences | boolean = true,\n ) {\n const info = this.renameInfo(filename, position);\n if (!info.canRename) return undefined;\n const locations = this.project.service.findRenameLocations(\n virtualFilename(filename),\n this.project.toGeneratedOffset(filename, position),\n false,\n false,\n typeof preferences === 'boolean'\n ? { providePrefixAndSuffixTextForRename: preferences }\n : preferences,\n );\n if (!locations) return undefined;\n const result: ts.RenameLocation[] = [];\n for (const location of locations) {\n const file = sourceFilename(location.fileName);\n let span = this.mapSpan(file, location.textSpan);\n let prefixText = location.prefixText;\n let suffixText = location.suffixText;\n if (isTwillFile(file)) {\n const attribute = this.attributes(file).find(\n (item) =>\n item.name.getStart() === location.textSpan.start &&\n item.initializer &&\n ts.isJsxExpression(item.initializer) &&\n item.initializer.expression,\n );\n if (attribute && attribute.initializer && ts.isJsxExpression(attribute.initializer)) {\n const original = this.project.toOriginalOffset(\n file,\n attribute.initializer.expression!.getStart(),\n );\n const property = this.project\n .transformed(file)\n ?.componentProps.flatMap((object) => object.properties)\n .find(\n (item) =>\n item.name === attribute.name.getText() &&\n (item.shorthand\n ? item.start === original\n : item.start === this.project.toOriginalOffset(file, attribute.name.getStart())),\n );\n if (property) {\n span = { start: property.start, length: property.end - property.start };\n if (property.shorthand) suffixText = `: ${property.name}`;\n else {\n const quote = this.project.text(file)?.[property.start];\n if (quote === '\"' || quote === \"'\") {\n prefixText = quote;\n suffixText = quote;\n }\n }\n }\n } else if (span) {\n const property = this.project\n .transformed(file)\n ?.componentProps.flatMap((object) => object.properties)\n .find((item) => item.shorthand && item.start === span!.start);\n if (property) prefixText = `${property.name}: `;\n }\n }\n if (!span) {\n const generated = this.project.transformed(file)?.code;\n const start = this.project.toOriginalOffset(file, location.textSpan.start);\n if (\n generated &&\n this.project.text(file)?.slice(start, start + location.textSpan.length) !==\n generated.slice(\n location.textSpan.start,\n location.textSpan.start + location.textSpan.length,\n )\n )\n continue; // A compiler-inserted guard/defer reference is regenerated.\n // Generated closing JSX tags duplicate a source component reference;\n // they have no independent source occurrence to edit.\n const sf = this.sourceFile(file);\n let closing = false;\n const visit = (node: ts.Node) => {\n if (\n ts.isJsxClosingElement(node) &&\n location.textSpan.start >= node.tagName.getStart() &&\n location.textSpan.start < node.tagName.end\n )\n closing = true;\n else if (\n location.textSpan.start >= node.getFullStart() &&\n location.textSpan.start < node.end\n )\n ts.forEachChild(node, visit);\n };\n if (sf) visit(sf);\n if (closing) continue;\n return undefined;\n }\n result.push({\n ...location,\n fileName: file,\n textSpan: span,\n prefixText,\n suffixText,\n contextSpan: location.contextSpan ? this.mapSpan(file, location.contextSpan) : undefined,\n });\n }\n return result.filter(\n (item, index) =>\n result.findIndex(\n (other) =>\n item.fileName === other.fileName &&\n item.textSpan.start === other.textSpan.start &&\n item.textSpan.length === other.textSpan.length,\n ) === index,\n );\n }\n\n rename(\n filename: string,\n position: number,\n name: string,\n preferences: ts.UserPreferences | boolean = true,\n ): SourceEdit[] | undefined {\n const scanner = ts.createScanner(\n ts.ScriptTarget.Latest,\n false,\n ts.LanguageVariant.Standard,\n name,\n );\n if (\n scanner.scan() !== ts.SyntaxKind.Identifier ||\n scanner.scan() !== ts.SyntaxKind.EndOfFileToken\n )\n return undefined;\n return this.renameLocations(filename, position, preferences)?.map((location) => ({\n filename: location.fileName,\n span: location.textSpan,\n newText: (location.prefixText ?? '') + name + (location.suffixText ?? ''),\n }));\n }\n\n fixes(filename: string, start: number, end: number, codes: readonly number[]) {\n return this.project.service\n .getCodeFixesAtPosition(\n virtualFilename(filename),\n this.project.toGeneratedOffset(filename, start),\n this.project.toGeneratedOffset(filename, end),\n codes,\n {},\n {},\n )\n .flatMap((fix) => {\n const edits = this.mapChanges(fix.changes);\n return edits?.length && !fix.commands?.length\n ? [{ description: fix.description, edits }]\n : [];\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"editor.js","names":[],"sources":["../src/editor.ts"],"sourcesContent":["import ts from 'typescript';\nimport { TwillProject, sourceFilename, virtualFilename } from './project.js';\nimport { isTwillFile, type TransformResult } from './compiler.js';\n\nexport interface SourceEdit {\n filename: string;\n span: ts.TextSpan;\n newText: string;\n}\n\nexport interface CompletionRequest {\n offset: number;\n info: ts.CompletionInfo | undefined;\n props?: { start: number; end: number };\n}\n\n/** Shared semantic requests and conservative source edits for both editor hosts. */\nexport class TwillEditor {\n private attributeCache = new WeakMap<ts.SourceFile, ts.JsxAttribute[]>();\n private descriptorCache = new WeakMap<ts.Program, Set<ts.Symbol>>();\n constructor(readonly project: TwillProject) {}\n\n private sourceFile(filename: string) {\n return this.project.service.getProgram()?.getSourceFile(virtualFilename(filename));\n }\n\n private attributes(filename: string) {\n const file = this.sourceFile(filename);\n if (!file) return [];\n const cached = this.attributeCache.get(file);\n if (cached) return cached;\n const result: ts.JsxAttribute[] = [];\n const visit = (node: ts.Node) => {\n if (ts.isJsxAttribute(node)) result.push(node);\n ts.forEachChild(node, visit);\n };\n visit(file);\n this.attributeCache.set(file, result);\n return result;\n }\n\n completionLocation(filename: string, position: number) {\n let offset = this.project.toGeneratedOffset(filename, position);\n // A repaired member name and generated arm punctuation can share the same\n // original boundary. Anchor requests at the source-backed dot instead.\n const prefix = this.project.text(filename)?.slice(0, position);\n const member = prefix?.match(/\\.([\\p{ID_Continue}$\\u200c\\u200d]*)$/u);\n const missingMember = prefix?.match(/\\.\\s*$/);\n if (member) offset = this.project.toGeneratedOffset(filename, member.index!) + member[0].length;\n else if (missingMember)\n offset = this.project.toGeneratedOffset(filename, missingMember.index!) + 1;\n let props: CompletionRequest['props'];\n const metadata = this.project.transformed(filename)?.componentProps;\n const property = metadata\n ?.flatMap((object) => object.properties)\n .find((item) => item.shorthand && position >= item.start && position <= item.end);\n if (property) {\n const attribute = this.attributes(filename).find(\n (item) =>\n item.name.getText() === property.name &&\n item.initializer &&\n ts.isJsxExpression(item.initializer) &&\n item.initializer.expression &&\n this.project.toOriginalOffset(filename, item.initializer.expression.getStart()) ===\n property.start,\n );\n if (attribute) {\n offset = attribute.name.getStart() + position - property.start;\n props = { start: property.start, end: property.end };\n }\n } else if (\n metadata?.some((object) => position > object.start && position < object.end) &&\n !this.attributes(filename).some(\n (attribute) => offset >= attribute.name.end && offset <= attribute.end,\n )\n ) {\n // Empty objects and gaps between properties already map to JSX attribute\n // positions. Only classify requests that TS identifies as member lists.\n props = { start: position, end: position };\n }\n return { offset, props };\n }\n\n completions(filename: string, position: number, preferences: ts.UserPreferences = {}) {\n let { offset, props } = this.completionLocation(filename, position);\n const info = this.project.service.getCompletionsAtPosition(virtualFilename(filename), offset, {\n includeCompletionsForModuleExports: true,\n includeCompletionsWithInsertText: true,\n ...preferences,\n });\n if (props && !info?.isMemberCompletion) props = undefined;\n return { offset, info, props } satisfies CompletionRequest;\n }\n\n /** Never stretch a generated edit across lowered punctuation or helper code. */\n mapSpan(filename: string, span: ts.TextSpan): ts.TextSpan | undefined {\n filename = sourceFilename(filename);\n const source = this.project.text(filename);\n if (source === undefined) return undefined;\n if (!isTwillFile(filename))\n return span.start >= 0 && span.start + span.length <= source.length ? span : undefined;\n const transformed = this.project.transformed(filename);\n const generated = transformed?.code;\n if (generated === undefined) return undefined;\n const start = this.project.toOriginalOffset(filename, span.start);\n if (\n start < 0 ||\n start + span.length > source.length ||\n (this.project.toGeneratedOffset(filename, start) !== span.start &&\n !transformed!.enumCopies.some(\n (copy) =>\n (span.start >= copy.generatedStart &&\n span.start + span.length <= copy.generatedStart + copy.length &&\n start === copy.sourceStart + span.start - copy.generatedStart) ||\n (start >= copy.sourceStart &&\n start + span.length <= copy.sourceStart + copy.length &&\n this.project.toOriginalOffset(filename, span.start + span.length - 1) ===\n start + span.length - 1),\n )) ||\n source.slice(start, start + span.length) !==\n generated.slice(span.start, span.start + span.length)\n )\n return undefined;\n return { start, length: span.length };\n }\n\n mapChanges(changes: readonly ts.FileTextChanges[]): SourceEdit[] | undefined {\n const edits: SourceEdit[] = [];\n for (const file of changes) {\n if (file.isNewFile) return undefined;\n const filename = sourceFilename(file.fileName);\n for (const change of file.textChanges) {\n let span = this.mapSpan(filename, change.span);\n // Inferred JSX runtime pragmas can precede the first source token.\n // A fresh import can safely be inserted before the original module.\n if (!span && change.span.length === 0 && /^\\s*import\\b/.test(change.newText)) {\n const firstStatement = this.sourceFile(filename)?.statements[0];\n if (change.span.start <= (firstStatement?.getStart() ?? 0))\n span = { start: 0, length: 0 };\n }\n if (!span) return undefined;\n edits.push({ filename, span, newText: this.importText(change.newText) });\n }\n }\n return edits;\n }\n\n private importText(text: string) {\n // Edit only module literals, never user strings in an unrelated code fix.\n const file = ts.createSourceFile('edits.ts', text, ts.ScriptTarget.Latest, true);\n const replacements: { start: number; end: number; text: string }[] = [];\n for (const statement of file.statements) {\n if (\n (ts.isImportDeclaration(statement) || ts.isExportDeclaration(statement)) &&\n statement.moduleSpecifier &&\n ts.isStringLiteral(statement.moduleSpecifier)\n ) {\n const literal = statement.moduleSpecifier;\n const value = sourceFilename(literal.text);\n if (value !== literal.text)\n replacements.push({ start: literal.getStart() + 1, end: literal.end - 1, text: value });\n }\n }\n for (const replacement of replacements.reverse())\n text = text.slice(0, replacement.start) + replacement.text + text.slice(replacement.end);\n return text;\n }\n\n organizeImports(filename: string, mode = ts.OrganizeImportsMode.All) {\n return this.mapChanges(\n this.project.service.organizeImports(\n { type: 'file', fileName: virtualFilename(filename), mode },\n {},\n {},\n ),\n );\n }\n\n /** Read-only navigation must also exclude generated helpers and duplicate JSX tags. */\n referenceGroups(filename: string, position: number): ts.ReferencedSymbol[] | undefined {\n const groups = this.project.service.findReferences(\n virtualFilename(filename),\n this.project.toGeneratedOffset(filename, position),\n );\n const mapped = <T extends ts.DocumentSpan>(entry: T): T | undefined => {\n const fileName = sourceFilename(entry.fileName);\n const textSpan = this.mapSpan(fileName, entry.textSpan);\n if (!textSpan) return undefined;\n const contextSpan = entry.contextSpan && this.mapSpan(fileName, entry.contextSpan);\n return { ...entry, fileName, textSpan, contextSpan };\n };\n return groups?.flatMap((group) => {\n const definition = mapped(group.definition);\n if (!definition) return [];\n const seen = new Set<string>();\n const references = group.references.flatMap((reference) => {\n const entry = mapped(reference);\n if (!entry) return [];\n // Some TS versions omit isDefinition from findReferences results.\n // Preserve supplied flags; otherwise compare the source-backed span\n // with this symbol group's definition for includeDeclaration requests.\n entry.isDefinition ??=\n entry.fileName === definition.fileName &&\n entry.textSpan.start === definition.textSpan.start &&\n entry.textSpan.length === definition.textSpan.length;\n const key = `${entry.fileName}:${entry.textSpan.start}:${entry.textSpan.length}`;\n if (seen.has(key)) return [];\n seen.add(key);\n return [entry];\n });\n return [{ definition, references }];\n });\n }\n\n references(filename: string, position: number) {\n return this.referenceGroups(filename, position)?.flatMap((group) => group.references);\n }\n\n private descriptorSymbols(program: ts.Program) {\n const cached = this.descriptorCache.get(program);\n if (cached) return cached;\n const symbols = new Set<ts.Symbol>();\n const checker = program.getTypeChecker();\n for (const file of program.getSourceFiles()) {\n const original = sourceFilename(file.fileName);\n if (!isTwillFile(original)) continue;\n let patterns: TransformResult['enumPatterns'] | undefined;\n try {\n patterns = this.project.transformed(original)?.enumPatterns;\n } catch {\n // One malformed document must not disable safe edits in other files.\n // Strict diagnostics and mapChanges still reject its unmappable edits.\n continue;\n }\n if (!patterns?.length) continue;\n const offsets = new Set(\n patterns.map((pattern) =>\n this.project.toGeneratedOffset(original, pattern.reference.property.start),\n ),\n );\n // Index each source once, rather than traversing it for every arm.\n // Program identity invalidates the cached symbols on any source edit.\n const visit = (node: ts.Node) => {\n if (ts.isIdentifier(node) && offsets.has(node.getStart())) {\n const symbol = checker.getSymbolAtLocation(node);\n if (symbol) for (const root of checker.getRootSymbols(symbol)) symbols.add(root);\n }\n ts.forEachChild(node, visit);\n };\n visit(file);\n }\n this.descriptorCache.set(program, symbols);\n return symbols;\n }\n\n renameInfo(filename: string, position: number): ts.RenameInfo {\n const offset = this.project.toGeneratedOffset(filename, position);\n const definitions = this.project.service.getDefinitionAtPosition(\n virtualFilename(filename),\n offset,\n );\n const program = this.project.service.getProgram()!;\n const descriptors = this.descriptorSymbols(program);\n for (const definition of definitions ?? []) {\n const file = sourceFilename(definition.fileName);\n const definitionFile = this.sourceFile(file);\n let descriptor = false;\n const visitDefinition = (node: ts.Node) => {\n if (definition.textSpan.start < node.getStart() || definition.textSpan.start >= node.end)\n return;\n if (ts.isIdentifier(node) || ts.isStringLiteral(node)) {\n const symbol = program.getTypeChecker().getSymbolAtLocation(node);\n descriptor =\n !!symbol &&\n program\n .getTypeChecker()\n .getRootSymbols(symbol)\n .some((root) => descriptors.has(root));\n } else ts.forEachChild(node, visitDefinition);\n };\n if (descriptors.size && definitionFile) visitDefinition(definitionFile);\n if (descriptor)\n return {\n canRename: false,\n localizedErrorMessage:\n 'Renaming an enum-pattern case descriptor requires linked discriminator edits and is not supported yet.',\n };\n const declarations = this.project.transformed(file)?.associatedEnums;\n if (!declarations?.length) continue;\n const sourceFile = this.sourceFile(file);\n let generatedEnum = false;\n const visit = (node: ts.Node) => {\n if (definition.textSpan.start < node.getStart() || definition.textSpan.start >= node.end)\n return;\n if (\n (ts.isTypeAliasDeclaration(node) || ts.isVariableDeclaration(node)) &&\n ts.isIdentifier(node.name)\n ) {\n const start = this.project.toOriginalOffset(file, node.name.getStart());\n if (declarations.some((declaration) => declaration.id.start === start)) {\n generatedEnum = true;\n return;\n }\n }\n ts.forEachChild(node, visit);\n };\n if (sourceFile) visit(sourceFile);\n if (generatedEnum)\n return {\n canRename: false,\n localizedErrorMessage:\n 'Renaming associated-value enum declarations, cases, payload fields and type parameters is not supported yet.',\n };\n }\n const info = this.project.service.getRenameInfo(virtualFilename(filename), offset, {\n allowRenameOfImportPath: false,\n });\n if (!info.canRename) return info;\n const span = this.mapSpan(filename, info.triggerSpan);\n return span\n ? { ...info, triggerSpan: span }\n : {\n canRename: false,\n localizedErrorMessage: 'This generated symbol cannot be renamed in Twill source.',\n };\n }\n\n renameLocations(\n filename: string,\n position: number,\n preferences: ts.UserPreferences | boolean = true,\n ) {\n const info = this.renameInfo(filename, position);\n if (!info.canRename) return undefined;\n const locations = this.project.service.findRenameLocations(\n virtualFilename(filename),\n this.project.toGeneratedOffset(filename, position),\n false,\n false,\n typeof preferences === 'boolean'\n ? { providePrefixAndSuffixTextForRename: preferences }\n : preferences,\n );\n if (!locations) return undefined;\n const result: ts.RenameLocation[] = [];\n for (const location of locations) {\n const file = sourceFilename(location.fileName);\n let span = this.mapSpan(file, location.textSpan);\n let prefixText = location.prefixText;\n let suffixText = location.suffixText;\n if (isTwillFile(file)) {\n const attribute = this.attributes(file).find(\n (item) =>\n item.name.getStart() === location.textSpan.start &&\n item.initializer &&\n ts.isJsxExpression(item.initializer) &&\n item.initializer.expression,\n );\n if (attribute && attribute.initializer && ts.isJsxExpression(attribute.initializer)) {\n const original = this.project.toOriginalOffset(\n file,\n attribute.initializer.expression!.getStart(),\n );\n const property = this.project\n .transformed(file)\n ?.componentProps.flatMap((object) => object.properties)\n .find(\n (item) =>\n item.name === attribute.name.getText() &&\n (item.shorthand\n ? item.start === original\n : item.start === this.project.toOriginalOffset(file, attribute.name.getStart())),\n );\n if (property) {\n span = { start: property.start, length: property.end - property.start };\n if (property.shorthand) suffixText = `: ${property.name}`;\n else {\n const quote = this.project.text(file)?.[property.start];\n if (quote === '\"' || quote === \"'\") {\n prefixText = quote;\n suffixText = quote;\n }\n }\n }\n } else if (span) {\n const property = this.project\n .transformed(file)\n ?.componentProps.flatMap((object) => object.properties)\n .find((item) => item.shorthand && item.start === span!.start);\n if (property) prefixText = `${property.name}: `;\n }\n }\n if (!span) {\n const generated = this.project.transformed(file)?.code;\n const start = this.project.toOriginalOffset(file, location.textSpan.start);\n if (\n generated &&\n this.project.text(file)?.slice(start, start + location.textSpan.length) !==\n generated.slice(\n location.textSpan.start,\n location.textSpan.start + location.textSpan.length,\n )\n )\n continue; // A compiler-inserted guard/defer reference is regenerated.\n // Generated closing JSX tags duplicate a source component reference;\n // they have no independent source occurrence to edit.\n const sf = this.sourceFile(file);\n let closing = false;\n const visit = (node: ts.Node) => {\n if (\n ts.isJsxClosingElement(node) &&\n location.textSpan.start >= node.tagName.getStart() &&\n location.textSpan.start < node.tagName.end\n )\n closing = true;\n else if (\n location.textSpan.start >= node.getFullStart() &&\n location.textSpan.start < node.end\n )\n ts.forEachChild(node, visit);\n };\n if (sf) visit(sf);\n if (closing) continue;\n return undefined;\n }\n result.push({\n ...location,\n fileName: file,\n textSpan: span,\n prefixText,\n suffixText,\n contextSpan: location.contextSpan ? this.mapSpan(file, location.contextSpan) : undefined,\n });\n }\n return result.filter(\n (item, index) =>\n result.findIndex(\n (other) =>\n item.fileName === other.fileName &&\n item.textSpan.start === other.textSpan.start &&\n item.textSpan.length === other.textSpan.length,\n ) === index,\n );\n }\n\n rename(\n filename: string,\n position: number,\n name: string,\n preferences: ts.UserPreferences | boolean = true,\n ): SourceEdit[] | undefined {\n const scanner = ts.createScanner(\n ts.ScriptTarget.Latest,\n false,\n ts.LanguageVariant.Standard,\n name,\n );\n if (\n scanner.scan() !== ts.SyntaxKind.Identifier ||\n scanner.scan() !== ts.SyntaxKind.EndOfFileToken\n )\n return undefined;\n return this.renameLocations(filename, position, preferences)?.map((location) => ({\n filename: location.fileName,\n span: location.textSpan,\n newText: (location.prefixText ?? '') + name + (location.suffixText ?? ''),\n }));\n }\n\n fixes(filename: string, start: number, end: number, codes: readonly number[]) {\n return this.project.service\n .getCodeFixesAtPosition(\n virtualFilename(filename),\n this.project.toGeneratedOffset(filename, start),\n this.project.toGeneratedOffset(filename, end),\n codes,\n {},\n {},\n )\n .flatMap((fix) => {\n const edits = this.mapChanges(fix.changes);\n return edits?.length && !fix.commands?.length\n ? [{ description: fix.description, edits }]\n : [];\n });\n }\n}\n"],"mappings":";;;;;AAiBA,IAAa,cAAb,MAAyB;CAGF;CAFrB,iCAAyB,IAAI,QAA0C;CACvE,kCAA0B,IAAI,QAAoC;CAClE,YAAY,SAAgC;EAAvB,KAAA,UAAA;CAAwB;CAE7C,WAAmB,UAAkB;EACnC,OAAO,KAAK,QAAQ,QAAQ,WAAW,CAAC,EAAE,cAAc,gBAAgB,QAAQ,CAAC;CACnF;CAEA,WAAmB,UAAkB;EACnC,MAAM,OAAO,KAAK,WAAW,QAAQ;EACrC,IAAI,CAAC,MAAM,OAAO,CAAC;EACnB,MAAM,SAAS,KAAK,eAAe,IAAI,IAAI;EAC3C,IAAI,QAAQ,OAAO;EACnB,MAAM,SAA4B,CAAC;EACnC,MAAM,SAAS,SAAkB;GAC/B,IAAI,GAAG,eAAe,IAAI,GAAG,OAAO,KAAK,IAAI;GAC7C,GAAG,aAAa,MAAM,KAAK;EAC7B;EACA,MAAM,IAAI;EACV,KAAK,eAAe,IAAI,MAAM,MAAM;EACpC,OAAO;CACT;CAEA,mBAAmB,UAAkB,UAAkB;EACrD,IAAI,SAAS,KAAK,QAAQ,kBAAkB,UAAU,QAAQ;EAG9D,MAAM,SAAS,KAAK,QAAQ,KAAK,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ;EAC7D,MAAM,SAAS,QAAQ,MAAM,uCAAuC;EACpE,MAAM,gBAAgB,QAAQ,MAAM,QAAQ;EAC5C,IAAI,QAAQ,SAAS,KAAK,QAAQ,kBAAkB,UAAU,OAAO,KAAM,IAAI,OAAO,EAAE,CAAC;OACpF,IAAI,eACP,SAAS,KAAK,QAAQ,kBAAkB,UAAU,cAAc,KAAM,IAAI;EAC5E,IAAI;EACJ,MAAM,WAAW,KAAK,QAAQ,YAAY,QAAQ,CAAC,EAAE;EACrD,MAAM,WAAW,UACb,SAAS,WAAW,OAAO,UAAU,CAAC,CACvC,MAAM,SAAS,KAAK,aAAa,YAAY,KAAK,SAAS,YAAY,KAAK,GAAG;EAClF,IAAI,UAAU;GACZ,MAAM,YAAY,KAAK,WAAW,QAAQ,CAAC,CAAC,MACzC,SACC,KAAK,KAAK,QAAQ,MAAM,SAAS,QACjC,KAAK,eACL,GAAG,gBAAgB,KAAK,WAAW,KACnC,KAAK,YAAY,cACjB,KAAK,QAAQ,iBAAiB,UAAU,KAAK,YAAY,WAAW,SAAS,CAAC,MAC5E,SAAS,KACf;GACA,IAAI,WAAW;IACb,SAAS,UAAU,KAAK,SAAS,IAAI,WAAW,SAAS;IACzD,QAAQ;KAAE,OAAO,SAAS;KAAO,KAAK,SAAS;IAAI;GACrD;EACF,OAAO,IACL,UAAU,MAAM,WAAW,WAAW,OAAO,SAAS,WAAW,OAAO,GAAG,KAC3E,CAAC,KAAK,WAAW,QAAQ,CAAC,CAAC,MACxB,cAAc,UAAU,UAAU,KAAK,OAAO,UAAU,UAAU,GACrE,GAIA,QAAQ;GAAE,OAAO;GAAU,KAAK;EAAS;EAE3C,OAAO;GAAE;GAAQ;EAAM;CACzB;CAEA,YAAY,UAAkB,UAAkB,cAAkC,CAAC,GAAG;EACpF,IAAI,EAAE,QAAQ,UAAU,KAAK,mBAAmB,UAAU,QAAQ;EAClE,MAAM,OAAO,KAAK,QAAQ,QAAQ,yBAAyB,gBAAgB,QAAQ,GAAG,QAAQ;GAC5F,oCAAoC;GACpC,kCAAkC;GAClC,GAAG;EACL,CAAC;EACD,IAAI,SAAS,CAAC,MAAM,oBAAoB,QAAQ,KAAA;EAChD,OAAO;GAAE;GAAQ;GAAM;EAAM;CAC/B;;CAGA,QAAQ,UAAkB,MAA4C;EACpE,WAAW,eAAe,QAAQ;EAClC,MAAM,SAAS,KAAK,QAAQ,KAAK,QAAQ;EACzC,IAAI,WAAW,KAAA,GAAW,OAAO,KAAA;EACjC,IAAI,CAAC,YAAY,QAAQ,GACvB,OAAO,KAAK,SAAS,KAAK,KAAK,QAAQ,KAAK,UAAU,OAAO,SAAS,OAAO,KAAA;EAC/E,MAAM,cAAc,KAAK,QAAQ,YAAY,QAAQ;EACrD,MAAM,YAAY,aAAa;EAC/B,IAAI,cAAc,KAAA,GAAW,OAAO,KAAA;EACpC,MAAM,QAAQ,KAAK,QAAQ,iBAAiB,UAAU,KAAK,KAAK;EAChE,IACE,QAAQ,KACR,QAAQ,KAAK,SAAS,OAAO,UAC5B,KAAK,QAAQ,kBAAkB,UAAU,KAAK,MAAM,KAAK,SACxD,CAAC,YAAa,WAAW,MACtB,SACE,KAAK,SAAS,KAAK,kBAClB,KAAK,QAAQ,KAAK,UAAU,KAAK,iBAAiB,KAAK,UACvD,UAAU,KAAK,cAAc,KAAK,QAAQ,KAAK,kBAChD,SAAS,KAAK,eACb,QAAQ,KAAK,UAAU,KAAK,cAAc,KAAK,UAC/C,KAAK,QAAQ,iBAAiB,UAAU,KAAK,QAAQ,KAAK,SAAS,CAAC,MAClE,QAAQ,KAAK,SAAS,CAC9B,KACF,OAAO,MAAM,OAAO,QAAQ,KAAK,MAAM,MACrC,UAAU,MAAM,KAAK,OAAO,KAAK,QAAQ,KAAK,MAAM,GAEtD,OAAO,KAAA;EACT,OAAO;GAAE;GAAO,QAAQ,KAAK;EAAO;CACtC;CAEA,WAAW,SAAkE;EAC3E,MAAM,QAAsB,CAAC;EAC7B,KAAK,MAAM,QAAQ,SAAS;GAC1B,IAAI,KAAK,WAAW,OAAO,KAAA;GAC3B,MAAM,WAAW,eAAe,KAAK,QAAQ;GAC7C,KAAK,MAAM,UAAU,KAAK,aAAa;IACrC,IAAI,OAAO,KAAK,QAAQ,UAAU,OAAO,IAAI;IAG7C,IAAI,CAAC,QAAQ,OAAO,KAAK,WAAW,KAAK,eAAe,KAAK,OAAO,OAAO,GAAG;KAC5E,MAAM,iBAAiB,KAAK,WAAW,QAAQ,CAAC,EAAE,WAAW;KAC7D,IAAI,OAAO,KAAK,UAAU,gBAAgB,SAAS,KAAK,IACtD,OAAO;MAAE,OAAO;MAAG,QAAQ;KAAE;IACjC;IACA,IAAI,CAAC,MAAM,OAAO,KAAA;IAClB,MAAM,KAAK;KAAE;KAAU;KAAM,SAAS,KAAK,WAAW,OAAO,OAAO;IAAE,CAAC;GACzE;EACF;EACA,OAAO;CACT;CAEA,WAAmB,MAAc;EAE/B,MAAM,OAAO,GAAG,iBAAiB,YAAY,MAAM,GAAG,aAAa,QAAQ,IAAI;EAC/E,MAAM,eAA+D,CAAC;EACtE,KAAK,MAAM,aAAa,KAAK,YAC3B,KACG,GAAG,oBAAoB,SAAS,KAAK,GAAG,oBAAoB,SAAS,MACtE,UAAU,mBACV,GAAG,gBAAgB,UAAU,eAAe,GAC5C;GACA,MAAM,UAAU,UAAU;GAC1B,MAAM,QAAQ,eAAe,QAAQ,IAAI;GACzC,IAAI,UAAU,QAAQ,MACpB,aAAa,KAAK;IAAE,OAAO,QAAQ,SAAS,IAAI;IAAG,KAAK,QAAQ,MAAM;IAAG,MAAM;GAAM,CAAC;EAC1F;EAEF,KAAK,MAAM,eAAe,aAAa,QAAQ,GAC7C,OAAO,KAAK,MAAM,GAAG,YAAY,KAAK,IAAI,YAAY,OAAO,KAAK,MAAM,YAAY,GAAG;EACzF,OAAO;CACT;CAEA,gBAAgB,UAAkB,OAAO,GAAG,oBAAoB,KAAK;EACnE,OAAO,KAAK,WACV,KAAK,QAAQ,QAAQ,gBACnB;GAAE,MAAM;GAAQ,UAAU,gBAAgB,QAAQ;GAAG;EAAK,GAC1D,CAAC,GACD,CAAC,CACH,CACF;CACF;;CAGA,gBAAgB,UAAkB,UAAqD;EACrF,MAAM,SAAS,KAAK,QAAQ,QAAQ,eAClC,gBAAgB,QAAQ,GACxB,KAAK,QAAQ,kBAAkB,UAAU,QAAQ,CACnD;EACA,MAAM,UAAqC,UAA4B;GACrE,MAAM,WAAW,eAAe,MAAM,QAAQ;GAC9C,MAAM,WAAW,KAAK,QAAQ,UAAU,MAAM,QAAQ;GACtD,IAAI,CAAC,UAAU,OAAO,KAAA;GACtB,MAAM,cAAc,MAAM,eAAe,KAAK,QAAQ,UAAU,MAAM,WAAW;GACjF,OAAO;IAAE,GAAG;IAAO;IAAU;IAAU;GAAY;EACrD;EACA,OAAO,QAAQ,SAAS,UAAU;GAChC,MAAM,aAAa,OAAO,MAAM,UAAU;GAC1C,IAAI,CAAC,YAAY,OAAO,CAAC;GACzB,MAAM,uBAAO,IAAI,IAAY;GAgB7B,OAAO,CAAC;IAAE;IAAY,YAfH,MAAM,WAAW,SAAS,cAAc;KACzD,MAAM,QAAQ,OAAO,SAAS;KAC9B,IAAI,CAAC,OAAO,OAAO,CAAC;KAIpB,MAAM,iBACJ,MAAM,aAAa,WAAW,YAC9B,MAAM,SAAS,UAAU,WAAW,SAAS,SAC7C,MAAM,SAAS,WAAW,WAAW,SAAS;KAChD,MAAM,MAAM,GAAG,MAAM,SAAS,GAAG,MAAM,SAAS,MAAM,GAAG,MAAM,SAAS;KACxE,IAAI,KAAK,IAAI,GAAG,GAAG,OAAO,CAAC;KAC3B,KAAK,IAAI,GAAG;KACZ,OAAO,CAAC,KAAK;IACf,CACsB;GAAW,CAAC;EACpC,CAAC;CACH;CAEA,WAAW,UAAkB,UAAkB;EAC7C,OAAO,KAAK,gBAAgB,UAAU,QAAQ,CAAC,EAAE,SAAS,UAAU,MAAM,UAAU;CACtF;CAEA,kBAA0B,SAAqB;EAC7C,MAAM,SAAS,KAAK,gBAAgB,IAAI,OAAO;EAC/C,IAAI,QAAQ,OAAO;EACnB,MAAM,0BAAU,IAAI,IAAe;EACnC,MAAM,UAAU,QAAQ,eAAe;EACvC,KAAK,MAAM,QAAQ,QAAQ,eAAe,GAAG;GAC3C,MAAM,WAAW,eAAe,KAAK,QAAQ;GAC7C,IAAI,CAAC,YAAY,QAAQ,GAAG;GAC5B,IAAI;GACJ,IAAI;IACF,WAAW,KAAK,QAAQ,YAAY,QAAQ,CAAC,EAAE;GACjD,QAAQ;IAGN;GACF;GACA,IAAI,CAAC,UAAU,QAAQ;GACvB,MAAM,UAAU,IAAI,IAClB,SAAS,KAAK,YACZ,KAAK,QAAQ,kBAAkB,UAAU,QAAQ,UAAU,SAAS,KAAK,CAC3E,CACF;GAGA,MAAM,SAAS,SAAkB;IAC/B,IAAI,GAAG,aAAa,IAAI,KAAK,QAAQ,IAAI,KAAK,SAAS,CAAC,GAAG;KACzD,MAAM,SAAS,QAAQ,oBAAoB,IAAI;KAC/C,IAAI,QAAQ,KAAK,MAAM,QAAQ,QAAQ,eAAe,MAAM,GAAG,QAAQ,IAAI,IAAI;IACjF;IACA,GAAG,aAAa,MAAM,KAAK;GAC7B;GACA,MAAM,IAAI;EACZ;EACA,KAAK,gBAAgB,IAAI,SAAS,OAAO;EACzC,OAAO;CACT;CAEA,WAAW,UAAkB,UAAiC;EAC5D,MAAM,SAAS,KAAK,QAAQ,kBAAkB,UAAU,QAAQ;EAChE,MAAM,cAAc,KAAK,QAAQ,QAAQ,wBACvC,gBAAgB,QAAQ,GACxB,MACF;EACA,MAAM,UAAU,KAAK,QAAQ,QAAQ,WAAW;EAChD,MAAM,cAAc,KAAK,kBAAkB,OAAO;EAClD,KAAK,MAAM,cAAc,eAAe,CAAC,GAAG;GAC1C,MAAM,OAAO,eAAe,WAAW,QAAQ;GAC/C,MAAM,iBAAiB,KAAK,WAAW,IAAI;GAC3C,IAAI,aAAa;GACjB,MAAM,mBAAmB,SAAkB;IACzC,IAAI,WAAW,SAAS,QAAQ,KAAK,SAAS,KAAK,WAAW,SAAS,SAAS,KAAK,KACnF;IACF,IAAI,GAAG,aAAa,IAAI,KAAK,GAAG,gBAAgB,IAAI,GAAG;KACrD,MAAM,SAAS,QAAQ,eAAe,CAAC,CAAC,oBAAoB,IAAI;KAChE,aACE,CAAC,CAAC,UACF,QACG,eAAe,CAAC,CAChB,eAAe,MAAM,CAAC,CACtB,MAAM,SAAS,YAAY,IAAI,IAAI,CAAC;IAC3C,OAAO,GAAG,aAAa,MAAM,eAAe;GAC9C;GACA,IAAI,YAAY,QAAQ,gBAAgB,gBAAgB,cAAc;GACtE,IAAI,YACF,OAAO;IACL,WAAW;IACX,uBACE;GACJ;GACF,MAAM,eAAe,KAAK,QAAQ,YAAY,IAAI,CAAC,EAAE;GACrD,IAAI,CAAC,cAAc,QAAQ;GAC3B,MAAM,aAAa,KAAK,WAAW,IAAI;GACvC,IAAI,gBAAgB;GACpB,MAAM,SAAS,SAAkB;IAC/B,IAAI,WAAW,SAAS,QAAQ,KAAK,SAAS,KAAK,WAAW,SAAS,SAAS,KAAK,KACnF;IACF,KACG,GAAG,uBAAuB,IAAI,KAAK,GAAG,sBAAsB,IAAI,MACjE,GAAG,aAAa,KAAK,IAAI,GACzB;KACA,MAAM,QAAQ,KAAK,QAAQ,iBAAiB,MAAM,KAAK,KAAK,SAAS,CAAC;KACtE,IAAI,aAAa,MAAM,gBAAgB,YAAY,GAAG,UAAU,KAAK,GAAG;MACtE,gBAAgB;MAChB;KACF;IACF;IACA,GAAG,aAAa,MAAM,KAAK;GAC7B;GACA,IAAI,YAAY,MAAM,UAAU;GAChC,IAAI,eACF,OAAO;IACL,WAAW;IACX,uBACE;GACJ;EACJ;EACA,MAAM,OAAO,KAAK,QAAQ,QAAQ,cAAc,gBAAgB,QAAQ,GAAG,QAAQ,EACjF,yBAAyB,MAC3B,CAAC;EACD,IAAI,CAAC,KAAK,WAAW,OAAO;EAC5B,MAAM,OAAO,KAAK,QAAQ,UAAU,KAAK,WAAW;EACpD,OAAO,OACH;GAAE,GAAG;GAAM,aAAa;EAAK,IAC7B;GACE,WAAW;GACX,uBAAuB;EACzB;CACN;CAEA,gBACE,UACA,UACA,cAA4C,MAC5C;EAEA,IAAI,CADS,KAAK,WAAW,UAAU,QAClC,CAAA,CAAK,WAAW,OAAO,KAAA;EAC5B,MAAM,YAAY,KAAK,QAAQ,QAAQ,oBACrC,gBAAgB,QAAQ,GACxB,KAAK,QAAQ,kBAAkB,UAAU,QAAQ,GACjD,OACA,OACA,OAAO,gBAAgB,YACnB,EAAE,qCAAqC,YAAY,IACnD,WACN;EACA,IAAI,CAAC,WAAW,OAAO,KAAA;EACvB,MAAM,SAA8B,CAAC;EACrC,KAAK,MAAM,YAAY,WAAW;GAChC,MAAM,OAAO,eAAe,SAAS,QAAQ;GAC7C,IAAI,OAAO,KAAK,QAAQ,MAAM,SAAS,QAAQ;GAC/C,IAAI,aAAa,SAAS;GAC1B,IAAI,aAAa,SAAS;GAC1B,IAAI,YAAY,IAAI,GAAG;IACrB,MAAM,YAAY,KAAK,WAAW,IAAI,CAAC,CAAC,MACrC,SACC,KAAK,KAAK,SAAS,MAAM,SAAS,SAAS,SAC3C,KAAK,eACL,GAAG,gBAAgB,KAAK,WAAW,KACnC,KAAK,YAAY,UACrB;IACA,IAAI,aAAa,UAAU,eAAe,GAAG,gBAAgB,UAAU,WAAW,GAAG;KACnF,MAAM,WAAW,KAAK,QAAQ,iBAC5B,MACA,UAAU,YAAY,WAAY,SAAS,CAC7C;KACA,MAAM,WAAW,KAAK,QACnB,YAAY,IAAI,CAAC,EAChB,eAAe,SAAS,WAAW,OAAO,UAAU,CAAC,CACtD,MACE,SACC,KAAK,SAAS,UAAU,KAAK,QAAQ,MACpC,KAAK,YACF,KAAK,UAAU,WACf,KAAK,UAAU,KAAK,QAAQ,iBAAiB,MAAM,UAAU,KAAK,SAAS,CAAC,EACpF;KACF,IAAI,UAAU;MACZ,OAAO;OAAE,OAAO,SAAS;OAAO,QAAQ,SAAS,MAAM,SAAS;MAAM;MACtE,IAAI,SAAS,WAAW,aAAa,KAAK,SAAS;WAC9C;OACH,MAAM,QAAQ,KAAK,QAAQ,KAAK,IAAI,CAAC,GAAG,SAAS;OACjD,IAAI,UAAU,QAAO,UAAU,KAAK;QAClC,aAAa;QACb,aAAa;OACf;MACF;KACF;IACF,OAAO,IAAI,MAAM;KACf,MAAM,WAAW,KAAK,QACnB,YAAY,IAAI,CAAC,EAChB,eAAe,SAAS,WAAW,OAAO,UAAU,CAAC,CACtD,MAAM,SAAS,KAAK,aAAa,KAAK,UAAU,KAAM,KAAK;KAC9D,IAAI,UAAU,aAAa,GAAG,SAAS,KAAK;IAC9C;GACF;GACA,IAAI,CAAC,MAAM;IACT,MAAM,YAAY,KAAK,QAAQ,YAAY,IAAI,CAAC,EAAE;IAClD,MAAM,QAAQ,KAAK,QAAQ,iBAAiB,MAAM,SAAS,SAAS,KAAK;IACzE,IACE,aACA,KAAK,QAAQ,KAAK,IAAI,CAAC,EAAE,MAAM,OAAO,QAAQ,SAAS,SAAS,MAAM,MACpE,UAAU,MACR,SAAS,SAAS,OAClB,SAAS,SAAS,QAAQ,SAAS,SAAS,MAC9C,GAEF;IAGF,MAAM,KAAK,KAAK,WAAW,IAAI;IAC/B,IAAI,UAAU;IACd,MAAM,SAAS,SAAkB;KAC/B,IACE,GAAG,oBAAoB,IAAI,KAC3B,SAAS,SAAS,SAAS,KAAK,QAAQ,SAAS,KACjD,SAAS,SAAS,QAAQ,KAAK,QAAQ,KAEvC,UAAU;UACP,IACH,SAAS,SAAS,SAAS,KAAK,aAAa,KAC7C,SAAS,SAAS,QAAQ,KAAK,KAE/B,GAAG,aAAa,MAAM,KAAK;IAC/B;IACA,IAAI,IAAI,MAAM,EAAE;IAChB,IAAI,SAAS;IACb;GACF;GACA,OAAO,KAAK;IACV,GAAG;IACH,UAAU;IACV,UAAU;IACV;IACA;IACA,aAAa,SAAS,cAAc,KAAK,QAAQ,MAAM,SAAS,WAAW,IAAI,KAAA;GACjF,CAAC;EACH;EACA,OAAO,OAAO,QACX,MAAM,UACL,OAAO,WACJ,UACC,KAAK,aAAa,MAAM,YACxB,KAAK,SAAS,UAAU,MAAM,SAAS,SACvC,KAAK,SAAS,WAAW,MAAM,SAAS,MAC5C,MAAM,KACV;CACF;CAEA,OACE,UACA,UACA,MACA,cAA4C,MAClB;EAC1B,MAAM,UAAU,GAAG,cACjB,GAAG,aAAa,QAChB,OACA,GAAG,gBAAgB,UACnB,IACF;EACA,IACE,QAAQ,KAAK,MAAM,GAAG,WAAW,cACjC,QAAQ,KAAK,MAAM,GAAG,WAAW,gBAEjC,OAAO,KAAA;EACT,OAAO,KAAK,gBAAgB,UAAU,UAAU,WAAW,CAAC,EAAE,KAAK,cAAc;GAC/E,UAAU,SAAS;GACnB,MAAM,SAAS;GACf,UAAU,SAAS,cAAc,MAAM,QAAQ,SAAS,cAAc;EACxE,EAAE;CACJ;CAEA,MAAM,UAAkB,OAAe,KAAa,OAA0B;EAC5E,OAAO,KAAK,QAAQ,QACjB,uBACC,gBAAgB,QAAQ,GACxB,KAAK,QAAQ,kBAAkB,UAAU,KAAK,GAC9C,KAAK,QAAQ,kBAAkB,UAAU,GAAG,GAC5C,OACA,CAAC,GACD,CAAC,CACH,CAAC,CACA,SAAS,QAAQ;GAChB,MAAM,QAAQ,KAAK,WAAW,IAAI,OAAO;GACzC,OAAO,OAAO,UAAU,CAAC,IAAI,UAAU,SACnC,CAAC;IAAE,aAAa,IAAI;IAAa;GAAM,CAAC,IACxC,CAAC;EACP,CAAC;CACL;AACF"}
|
package/dist/enums.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { default as MagicString, SourceMap } from 'magic-string';
|
|
2
|
+
type Node = {
|
|
3
|
+
type: string;
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
};
|
|
8
|
+
type Insertion = {
|
|
9
|
+
anchor: number;
|
|
10
|
+
before: boolean;
|
|
11
|
+
text: string;
|
|
12
|
+
copies: {
|
|
13
|
+
start: number;
|
|
14
|
+
sourceStart: number;
|
|
15
|
+
length: number;
|
|
16
|
+
}[];
|
|
17
|
+
};
|
|
18
|
+
export declare function enumTypeParameters(node: Node, branch: Node): Node[];
|
|
19
|
+
/** Tagged records and precise factories; no application runtime is introduced. */
|
|
20
|
+
export declare function lowerEnums(source: string, ast: Node, enums: Node[], code: MagicString): Insertion[];
|
|
21
|
+
/** Generated type copies map to their actual source tokens, including .d.ts maps. */
|
|
22
|
+
export declare function mapEnumCopies(source: string, generated: string, map: SourceMap, insertions: Insertion[]): {
|
|
23
|
+
generatedStart: number;
|
|
24
|
+
sourceStart: number;
|
|
25
|
+
length: number;
|
|
26
|
+
}[];
|
|
27
|
+
export {};
|
package/dist/esbuild.js
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/extensions.ts
|
|
2
|
+
var extensions = [".twill", ".twillx"];
|
|
3
|
+
function isTwillFile(id) {
|
|
4
|
+
return extensions.some((extension) => id.split(/[?#]/, 1)[0].endsWith(extension));
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
export { isTwillFile as n, extensions as t };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=extensions-B1xTkoYP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensions-B1xTkoYP.js","names":[],"sources":["../src/extensions.ts"],"sourcesContent":["export const extensions = ['.twill', '.twillx'] as const;\nexport function isTwillFile(id: string): boolean {\n return extensions.some((extension) => id.split(/[?#]/, 1)[0]!.endsWith(extension));\n}\n"],"mappings":";AAAA,IAAa,aAAa,CAAC,UAAU,SAAS;AAC9C,SAAgB,YAAY,IAAqB;CAC/C,OAAO,WAAW,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAE,SAAS,SAAS,CAAC;AACnF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as extensions } from "./extensions-B1xTkoYP.js";
|
|
2
2
|
import { statSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
//#region src/files.ts
|
|
@@ -43,4 +43,4 @@ function resolveSourceFile(base) {
|
|
|
43
43
|
//#endregion
|
|
44
44
|
export { splitId as a, sourceExtensions as i, needsTypeEmission as n, resolveSourceFile as r, isDependency as t };
|
|
45
45
|
|
|
46
|
-
//# sourceMappingURL=files-
|
|
46
|
+
//# sourceMappingURL=files-BW9geU0_.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files-BW9geU0_.js","names":[],"sources":["../src/files.ts"],"sourcesContent":["import { statSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { extensions } from './extensions.js';\n\nexport const sourceExtensions = [\n '.mjs',\n '.js',\n '.mts',\n '.ts',\n '.jsx',\n '.tsx',\n '.cjs',\n '.cts',\n '.json',\n ...extensions,\n];\nexport function isDependency(filename: string) {\n return /(?:^|[\\\\/])node_modules[\\\\/]/.test(filename);\n}\nexport function needsTypeEmission(filename: string) {\n return /\\.(?:tsx?|mts|jsx)$/.test(filename) && !/\\.d\\.(?:ts|mts)$/.test(filename);\n}\nexport function splitId(id: string): [string, string] {\n const index = id.search(/[?#]/);\n return index < 0 ? [id, ''] : [id.slice(0, index), id.slice(index)];\n}\nexport function resolveSourceFile(base: string): string | undefined {\n const file = (candidate: string) => {\n try {\n return statSync(candidate).isFile();\n } catch (error) {\n if (['ENOENT', 'ENOTDIR'].includes((error as NodeJS.ErrnoException).code ?? '')) return false;\n throw error;\n }\n };\n if (file(base)) return base;\n // Match the native-first order of the Vite resolver. Explicit filenames\n // remain the way to select one of several same-stem source files.\n for (const extension of sourceExtensions) if (file(base + extension)) return base + extension;\n for (const extension of sourceExtensions) {\n const candidate = resolve(base, 'index' + extension);\n if (file(candidate)) return candidate;\n }\n}\n"],"mappings":";;;;AAIA,IAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,GAAG;AACL;AACA,SAAgB,aAAa,UAAkB;CAC7C,OAAO,+BAA+B,KAAK,QAAQ;AACrD;AACA,SAAgB,kBAAkB,UAAkB;CAClD,OAAO,sBAAsB,KAAK,QAAQ,KAAK,CAAC,mBAAmB,KAAK,QAAQ;AAClF;AACA,SAAgB,QAAQ,IAA8B;CACpD,MAAM,QAAQ,GAAG,OAAO,MAAM;CAC9B,OAAO,QAAQ,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,MAAM,GAAG,KAAK,GAAG,GAAG,MAAM,KAAK,CAAC;AACpE;AACA,SAAgB,kBAAkB,MAAkC;CAClE,MAAM,QAAQ,cAAsB;EAClC,IAAI;GACF,OAAO,SAAS,SAAS,CAAC,CAAC,OAAO;EACpC,SAAS,OAAO;GACd,IAAI,CAAC,UAAU,SAAS,CAAC,CAAC,SAAU,MAAgC,QAAQ,EAAE,GAAG,OAAO;GACxF,MAAM;EACR;CACF;CACA,IAAI,KAAK,IAAI,GAAG,OAAO;CAGvB,KAAK,MAAM,aAAa,kBAAkB,IAAI,KAAK,OAAO,SAAS,GAAG,OAAO,OAAO;CACpF,KAAK,MAAM,aAAa,kBAAkB;EACxC,MAAM,YAAY,QAAQ,MAAM,UAAU,SAAS;EACnD,IAAI,KAAK,SAAS,GAAG,OAAO;CAC9B;AACF"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as transform, i as originalPosition, n as generatedPosition, r as inferLanguage, t as TwillSyntaxError } from "./compiler-CbNSBUI2.js";
|
|
2
|
+
import { n as isTwillFile, t as extensions } from "./extensions-B1xTkoYP.js";
|
|
2
3
|
export { TwillSyntaxError, extensions, generatedPosition, inferLanguage, isTwillFile, originalPosition, transform };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { r as loaderConfiguration } from "./configuration-BVMf6Q_j.js";
|
|
2
|
+
import { n as transpileNative, t as transpile } from "./transpile-D8P8Lsbx.js";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
//#region src/loader-compiler.ts
|
|
5
|
+
function compileModule(source, filename, dialect) {
|
|
6
|
+
const { config, observations } = loaderConfiguration(filename);
|
|
7
|
+
const result = dialect ? transpile(source, {
|
|
8
|
+
...config,
|
|
9
|
+
filename
|
|
10
|
+
}, ts.ScriptTarget.ES2022) : transpileNative(source, filename, void 0, void 0, config.jsxImportSource, ts.ScriptTarget.ES2022);
|
|
11
|
+
return {
|
|
12
|
+
source: result.code + "\n//# sourceMappingURL=data:application/json;base64," + Buffer.from(result.map).toString("base64"),
|
|
13
|
+
observations
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { compileModule };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=loader-compiler-D1teTrXw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader-compiler-D1teTrXw.js","names":[],"sources":["../src/loader-compiler.ts"],"sourcesContent":["import ts from 'typescript';\nimport { transpile, transpileNative } from './transpile.js';\nimport { loaderConfiguration } from './configuration.js';\n\nexport function compileModule(source: string, filename: string, dialect: boolean) {\n const { config, observations } = loaderConfiguration(filename);\n const result = dialect\n ? transpile(source, { ...config, filename }, ts.ScriptTarget.ES2022)\n : transpileNative(\n source,\n filename,\n undefined,\n undefined,\n config.jsxImportSource,\n ts.ScriptTarget.ES2022,\n );\n return {\n source:\n result.code +\n '\\n//# sourceMappingURL=data:application/json;base64,' +\n Buffer.from(result.map).toString('base64'),\n observations,\n };\n}\n"],"mappings":";;;;AAIA,SAAgB,cAAc,QAAgB,UAAkB,SAAkB;CAChF,MAAM,EAAE,QAAQ,iBAAiB,oBAAoB,QAAQ;CAC7D,MAAM,SAAS,UACX,UAAU,QAAQ;EAAE,GAAG;EAAQ;CAAS,GAAG,GAAG,aAAa,MAAM,IACjE,gBACE,QACA,UACA,KAAA,GACA,KAAA,GACA,OAAO,iBACP,GAAG,aAAa,MAClB;CACJ,OAAO;EACL,QACE,OAAO,OACP,yDACA,OAAO,KAAK,OAAO,GAAG,CAAC,CAAC,SAAS,QAAQ;EAC3C;CACF;AACF"}
|
package/dist/loader.d.ts
CHANGED
package/dist/loader.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { n as needsTypeEmission, r as resolveSourceFile, t as isDependency } from "./files-
|
|
4
|
-
import {
|
|
5
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
-
import { dirname, resolve as resolve$1 } from "node:path";
|
|
7
|
-
import ts from "typescript";
|
|
1
|
+
import { n as isTwillFile } from "./extensions-B1xTkoYP.js";
|
|
2
|
+
import { i as openCompilationCache } from "./compilation-cache-7SugqJ4n.js";
|
|
3
|
+
import { n as needsTypeEmission, r as resolveSourceFile, t as isDependency } from "./files-BW9geU0_.js";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
8
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
9
6
|
//#region src/loader.ts
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
var entries = /* @__PURE__ */ new Set();
|
|
8
|
+
var cacheEnabled = false;
|
|
9
|
+
var cache;
|
|
10
|
+
var cacheInitialized = false;
|
|
11
|
+
function initialize(data) {
|
|
12
|
+
entries = new Set(data?.entries);
|
|
13
|
+
cacheEnabled = data?.cache === true && process.env.TWILL_CACHE !== "0";
|
|
14
|
+
cache = void 0;
|
|
15
|
+
cacheInitialized = false;
|
|
18
16
|
}
|
|
19
17
|
var resolve = async (specifier, context, nextResolve) => {
|
|
20
18
|
try {
|
|
@@ -35,20 +33,29 @@ var resolve = async (specifier, context, nextResolve) => {
|
|
|
35
33
|
var load = async (url, context, nextLoad) => {
|
|
36
34
|
if (!url.startsWith("file:")) return nextLoad(url, context);
|
|
37
35
|
const filename = fileURLToPath(url);
|
|
38
|
-
const dialect = isTwillFile(filename);
|
|
36
|
+
const dialect = isTwillFile(filename) || entries.has(url);
|
|
39
37
|
if (!dialect && (isDependency(filename) || !needsTypeEmission(filename))) return nextLoad(url, context);
|
|
40
38
|
const source = readFileSync(filename, "utf8");
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
39
|
+
if (cacheEnabled && !cacheInitialized) {
|
|
40
|
+
cache = openCompilationCache();
|
|
41
|
+
cacheInitialized = true;
|
|
42
|
+
}
|
|
43
|
+
const cached = cache?.read(url, source, dialect);
|
|
44
|
+
if (cached !== void 0) return {
|
|
45
|
+
format: "module",
|
|
46
|
+
source: cached,
|
|
47
|
+
shortCircuit: true
|
|
48
|
+
};
|
|
49
|
+
const { compileModule } = await import("./loader-compiler-D1teTrXw.js");
|
|
50
|
+
const result = compileModule(source, filename, dialect);
|
|
51
|
+
cache?.write(url, source, dialect, result.source, result.observations);
|
|
45
52
|
return {
|
|
46
53
|
format: "module",
|
|
47
|
-
source: result.
|
|
54
|
+
source: result.source,
|
|
48
55
|
shortCircuit: true
|
|
49
56
|
};
|
|
50
57
|
};
|
|
51
58
|
//#endregion
|
|
52
|
-
export { load, resolve };
|
|
59
|
+
export { initialize, load, resolve };
|
|
53
60
|
|
|
54
61
|
//# sourceMappingURL=loader.js.map
|