@swiftuijs/twill 0.1.2 → 0.2.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 +39 -11
- 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-CuCGz02_.js +172 -0
- package/dist/compilation-cache-CuCGz02_.js.map +1 -0
- package/dist/compilation-cache.d.ts +21 -0
- package/dist/{compiler-Bi9TNOhX.js → compiler-DY1N07np.js} +530 -50
- package/dist/compiler-DY1N07np.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-CTJjSu_h.js +139 -0
- package/dist/configuration-CTJjSu_h.js.map +1 -0
- package/dist/configuration.d.ts +12 -0
- package/dist/defer-helper.d.ts +1 -0
- package/dist/defer.d.ts +1 -1
- 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-DIw9aw5n.js +19 -0
- package/dist/loader-compiler-DIw9aw5n.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-Bks2hxCJ.js} +41 -12
- package/dist/plugin-Bks2hxCJ.js.map +1 -0
- package/dist/project.js +27 -3
- package/dist/project.js.map +1 -1
- 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-DG81yfVs.js} +2 -2
- package/dist/{transpile-DwVekVFM.js.map → transpile-DG81yfVs.js.map} +1 -1
- package/dist/typescript-plugin.cjs +718 -60
- 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
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Twill is a **TypeScript-based language with Swift-inspired syntax extensions**, built by [forth.ink](https://forth.ink). It extends TypeScript and TSX with guards, `defer`, trailing closures and checked switch expressions. Use TypeScript's type system and existing JavaScript libraries; compile to ordinary JavaScript.
|
|
6
6
|
|
|
7
|
-
[Documentation](https://twill.evecalm.com/) · [Why Twill?](https://twill.evecalm.com/why-twill) · [Playground](https://twill.evecalm.com/playground) · [Getting started](https://twill.evecalm.com/getting-started) · [VS Code extension](https://marketplace.visualstudio.com/items?itemName=forth-ink.twill) · [Compatibility](https://twill.evecalm.com/readiness)
|
|
7
|
+
[Documentation](https://twill.evecalm.com/) · [Why Twill?](https://twill.evecalm.com/why-twill) · [Playground](https://twill.evecalm.com/playground) · [Getting started](https://twill.evecalm.com/getting-started) · [AI skill](https://twill.evecalm.com/ai) · [VS Code extension](https://marketplace.visualstudio.com/items?itemName=forth-ink.twill) · [Compatibility](https://twill.evecalm.com/readiness)
|
|
8
8
|
|
|
9
9
|
```twill
|
|
10
10
|
async function readOwned(acquire: () => Promise<TextDocument>) {
|
|
@@ -52,7 +52,7 @@ function describe(outcome: Outcome): string {
|
|
|
52
52
|
}
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Ordinary closures become arrows; guards become branches. Direct-return switch expressions become native switches; other expression
|
|
55
|
+
Ordinary closures become arrows; guards become branches. Direct-return switch expressions become native switches. Twill 0.2.0 also removes the IIFE from standalone identifier initializers; other expression contexts retain it. Inline emission introduces no runtime library. `defer` allocates callbacks and dynamic registrations use a local stack; general component child collection uses arrays. These costs are [documented and measured](https://twill.evecalm.com/performance).
|
|
56
56
|
|
|
57
57
|
| File | Use |
|
|
58
58
|
| ---------------------------- | ----------------------------------------------------------- |
|
|
@@ -68,7 +68,7 @@ Twill and native files can import each other through the build adapters, virtual
|
|
|
68
68
|
|
|
69
69
|
The [playground](https://twill.evecalm.com/playground) runs the actual compiler locally, with live highlighting and generated-source inspection. It does not execute your code or type-check project imports.
|
|
70
70
|
|
|
71
|
-
Install the compiler as a development dependency in your application. It supports Node 20.19+ or 22.12
|
|
71
|
+
Install the compiler as a development dependency in your application. It supports Node 20.19+ or 22.12+. Default inline emission introduces no language runtime dependency into your application bundle. The [optional runtime](https://twill.evecalm.com/runtime) in 0.2.0 shares dynamic synchronous cleanup when explicitly selected.
|
|
72
72
|
|
|
73
73
|
```sh
|
|
74
74
|
pnpm add -D @swiftuijs/twill
|
|
@@ -112,15 +112,31 @@ Independent [examples](https://github.com/swiftuijs/twill/blob/main/examples/REA
|
|
|
112
112
|
|
|
113
113
|
## Packages
|
|
114
114
|
|
|
115
|
+
The compiler includes adapters for your existing bundler:
|
|
116
|
+
|
|
117
|
+
| Host | Adapter import | Native TS/JSX owner |
|
|
118
|
+
| ------- | -------------------------- | ------------------------ |
|
|
119
|
+
| Vite | `@swiftuijs/twill/vite` | Vite |
|
|
120
|
+
| Rollup | `@swiftuijs/twill/rollup` | Twill adapter by default |
|
|
121
|
+
| Webpack | `@swiftuijs/twill/webpack` | Twill adapter by default |
|
|
122
|
+
| Rspack | `@swiftuijs/twill/rspack` | Twill adapter by default |
|
|
123
|
+
| esbuild | `@swiftuijs/twill/esbuild` | esbuild |
|
|
124
|
+
|
|
125
|
+
Use `@swiftuijs/twill/vite-react` for React Fast Refresh. The [build guide](https://twill.evecalm.com/build-tools#adapter-support) records tested host versions, watch/incremental workflows and the 0.2.0 configuration-refresh behavior. Builds remain transpile-only; run `twill check` separately.
|
|
126
|
+
|
|
115
127
|
Install only the tools your project needs. Keep Twill packages on the same release version.
|
|
116
128
|
|
|
117
|
-
| Package | Purpose
|
|
118
|
-
| ---------------------------------------------------------------------------------------- |
|
|
119
|
-
| [`@swiftuijs/twill`](https://www.npmjs.com/package/@swiftuijs/twill) | Compiler, `twill` CLI, checker, build adapters and Node loader
|
|
120
|
-
| [`@swiftuijs/twill-formatter`](https://www.npmjs.com/package/@swiftuijs/twill-formatter) | Prettier plugin and browser-compatible formatting API
|
|
121
|
-
| [`@swiftuijs/twill-linter`](https://www.npmjs.com/package/@swiftuijs/twill-linter) | ESLint flat configurations and source-mapped fixes
|
|
122
|
-
| [`@swiftuijs/twill-export`](https://www.npmjs.com/package/@swiftuijs/twill-export) | Optional `twill export` command for native TS/TSX output
|
|
123
|
-
| [`@swiftuijs/twill-highlight`](https://www.npmjs.com/package/@swiftuijs/twill-highlight) | Browser/SSR Shiki integration and TextMate grammars
|
|
129
|
+
| Package | Purpose |
|
|
130
|
+
| ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
131
|
+
| [`@swiftuijs/twill`](https://www.npmjs.com/package/@swiftuijs/twill) | Compiler, `twill` CLI, checker, build adapters and Node loader |
|
|
132
|
+
| [`@swiftuijs/twill-formatter`](https://www.npmjs.com/package/@swiftuijs/twill-formatter) | Prettier plugin and browser-compatible formatting API |
|
|
133
|
+
| [`@swiftuijs/twill-linter`](https://www.npmjs.com/package/@swiftuijs/twill-linter) | ESLint flat configurations and source-mapped fixes |
|
|
134
|
+
| [`@swiftuijs/twill-export`](https://www.npmjs.com/package/@swiftuijs/twill-export) | Optional `twill export` command for native TS/TSX output |
|
|
135
|
+
| [`@swiftuijs/twill-highlight`](https://www.npmjs.com/package/@swiftuijs/twill-highlight) | Browser/SSR Shiki integration and TextMate grammars |
|
|
136
|
+
| `@swiftuijs/twill-shell` | Native argv execution, bounded output and owned process teardown |
|
|
137
|
+
| `@swiftuijs/twill-runtime` | Optional, versioned synchronous cleanup helpers |
|
|
138
|
+
|
|
139
|
+
The [shell scripting](https://twill.evecalm.com/scripting) toolkit adds `#!/usr/bin/env twill` executable scripts and content-validated startup caching in 0.2.0. Install/import `@swiftuijs/twill-shell` for subprocesses; its Rust engine and eight-platform prebuilds install automatically. Native JS/TS consumers need no compiler. See [performance](https://twill.evecalm.com/performance#rust-shell-backend) for measured warm gains and cold/polling limits.
|
|
124
140
|
|
|
125
141
|
Install the [Twill VS Code extension](https://marketplace.visualstudio.com/items?itemName=forth-ink.twill) from Marketplace, or run `code --install-extension forth-ink.twill`. The extension bundles its editing tools. Your application installs the compiler for builds and whole-project checks. See the [editor guide](https://twill.evecalm.com/tooling) for configuration.
|
|
126
142
|
|
|
@@ -130,9 +146,13 @@ Twill is a useful candidate for nullable workflows, owned resources, typed state
|
|
|
130
146
|
|
|
131
147
|
Representative native/dialect bundles are compared for behavior and byte size; release artifacts have enforced size budgets. Synthetic benchmarks do not establish whole-application speed or team productivity. Profile your actual workload and exercise failure paths. See [compatibility](https://twill.evecalm.com/readiness), [performance](https://twill.evecalm.com/performance) and [gradual adoption](https://twill.evecalm.com/adoption).
|
|
132
148
|
|
|
149
|
+
## AI assistance
|
|
150
|
+
|
|
151
|
+
Install the [official Twill AI skill](https://twill.evecalm.com/ai) with `npx skills add swiftuijs/twill --skill twill`. It guides Codex, Claude Code and other Agent Skills clients through application syntax, resource ownership, integrations and verification while distinguishing released features from source prototypes. The skill does not install the compiler or other project tools.
|
|
152
|
+
|
|
133
153
|
## Contributing
|
|
134
154
|
|
|
135
|
-
The repository is a pnpm workspace with Vite builds. See the [development guide](https://github.com/swiftuijs/twill/blob/main/docs/contributing/tooling.md) for checkout, dependency and build commands. Compiler, formatter, linter, export and
|
|
155
|
+
The repository is a pnpm workspace with Vite builds. See the [development guide](https://github.com/swiftuijs/twill/blob/main/docs/contributing/tooling.md) for checkout, dependency and build commands. Compiler, formatter, linter, export, highlight, optional runtime and shell packages, editor packages, examples and the English documentation site own their code and tests.
|
|
136
156
|
|
|
137
157
|
```sh
|
|
138
158
|
pnpm check
|
|
@@ -142,3 +162,11 @@ pnpm docs:dev
|
|
|
142
162
|
```
|
|
143
163
|
|
|
144
164
|
See [contributing](https://github.com/swiftuijs/twill/blob/main/CONTRIBUTING.md), [architecture](https://github.com/swiftuijs/twill/blob/main/docs/contributing/architecture.md), [language design](https://twill.evecalm.com/language) and [release instructions](https://github.com/swiftuijs/twill/blob/main/docs/contributing/releasing.md). MIT licensed.
|
|
165
|
+
|
|
166
|
+
## Added in 0.2.0
|
|
167
|
+
|
|
168
|
+
Twill 0.2.0 adds `if const value = lookup() { use(value); }` with branch-local nullish bindings and native destructuring. Group trailing calls in initializers, following Swift’s condition boundary. It emits native branches without a helper, closure or optional wrapper. See [syntax](https://twill.evecalm.com/syntax#branch-nullish-bindings) and [RFC 0018](https://github.com/swiftuijs/twill/blob/main/docs/rfcs/0018-optional-branch-bindings.md).
|
|
169
|
+
|
|
170
|
+
Twill 0.2.0 includes associated-value enums and `match` expressions: `match (state) { case State.loaded({ value }): value; default: 0; }`. Named payload bindings and erased factory descriptors compile to native switches without calling factories. Native switch statements retain JS fallthrough; match and switch expressions return one result without fallthrough. Use the coordinated 0.2.0 packages and extension. Compiler, formatter, linter, highlighter, export and editor changes are validated together. See [syntax and compatibility](https://twill.evecalm.com/syntax#match-expressions) and [RFC 0016](https://github.com/swiftuijs/twill/blob/main/docs/rfcs/0016-pattern-matching.md).
|
|
171
|
+
|
|
172
|
+
For Node scripts, Twill 0.2.0 supports `#!/usr/bin/env twill`, `twill script.twill` and `twill run script.twill`, with Swift-inspired guards, callbacks and cleanup. The Node ESM loader remains available through `node --import @swiftuijs/twill/register`. The [shell SDK](https://twill.evecalm.com/scripting) adds native argv execution, bounded output and process ownership without command compilation. It works independently with ordinary JS/TS; scoped streams, pipelines and shell templates remain deferred.
|
package/bin/run.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { resolve, extname } from 'node:path';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { register } from 'node:module';
|
|
4
|
+
import { realpathSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
export async function run(filename, args) {
|
|
7
|
+
const script = resolve(filename);
|
|
8
|
+
const url = pathToFileURL(script).href;
|
|
9
|
+
const native = /^(?:\.[cm]?js|\.[cm]?ts|\.jsx|\.tsx)$/.test(extname(script));
|
|
10
|
+
const entries = native ? [] : [url, pathToFileURL(realpathSync(script)).href];
|
|
11
|
+
process.argv = [process.execPath, script, ...args];
|
|
12
|
+
process.setSourceMapsEnabled(true);
|
|
13
|
+
register('../dist/loader.js', import.meta.url, { data: { entries, cache: true } });
|
|
14
|
+
await import(url);
|
|
15
|
+
}
|
package/bin/twill.mjs
CHANGED
|
@@ -1,12 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
const args = process.argv.slice(2);
|
|
3
|
+
const first = args[0];
|
|
4
|
+
const commands = new Set(['compile', 'check', 'doctor', 'declarations', 'export']);
|
|
5
|
+
if (
|
|
6
|
+
first === 'run' ||
|
|
7
|
+
first === '--' ||
|
|
8
|
+
(first && !first.startsWith('-') && !commands.has(first))
|
|
9
|
+
) {
|
|
10
|
+
const usage = 'Usage: twill [run] <script> [arguments...]';
|
|
11
|
+
if (first === 'run' && (args[1] === '--help' || args[1] === '-h')) {
|
|
12
|
+
console.log(usage);
|
|
13
|
+
} else {
|
|
14
|
+
let index = first === 'run' || first === '--' ? 1 : 0;
|
|
15
|
+
if (first === 'run' && args[index] === '--') index++;
|
|
16
|
+
if (!args[index]) {
|
|
17
|
+
console.error(usage);
|
|
18
|
+
process.exitCode = 1;
|
|
19
|
+
} else {
|
|
20
|
+
const { run } = await import('./run.mjs');
|
|
21
|
+
await run(args[index], args.slice(index + 1));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
} else {
|
|
25
|
+
const { main } = await import('../dist/cli.js');
|
|
26
|
+
main(args)
|
|
27
|
+
.then((code) => {
|
|
28
|
+
process.exitCode = code;
|
|
29
|
+
})
|
|
30
|
+
.catch((error) => {
|
|
31
|
+
console.error(error.message);
|
|
32
|
+
if (error.frame) console.error(error.frame);
|
|
33
|
+
process.exitCode = 1;
|
|
34
|
+
});
|
|
35
|
+
}
|
package/dist/branches.d.ts
CHANGED
|
@@ -6,7 +6,10 @@ type Node = {
|
|
|
6
6
|
end: number;
|
|
7
7
|
[key: string]: any;
|
|
8
8
|
};
|
|
9
|
-
/** Native switches with per-arm scopes
|
|
10
|
-
*
|
|
11
|
-
export declare function lowerSwitchExpressions(source: string, ast: Node, switches: Node[], code: MagicString, language: Language, usedNames: Set<string>,
|
|
9
|
+
/** Native switches with per-arm scopes. Direct returns and standalone variable
|
|
10
|
+
* initializers need no extra function; other expressions keep a lexical IIFE. */
|
|
11
|
+
export declare function lowerSwitchExpressions(source: string, ast: Node, switches: Node[], code: MagicString, language: Language, usedNames: Set<string>, comments: {
|
|
12
|
+
start: number;
|
|
13
|
+
end: number;
|
|
14
|
+
}[], fail: (node: Node, message: string) => never): void;
|
|
12
15
|
export {};
|
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { loadConfig } from "./
|
|
2
|
+
import { a as transform } from "./compiler-DY1N07np.js";
|
|
3
|
+
import { n as loadConfig } from "./configuration-CTJjSu_h.js";
|
|
4
4
|
import { TwillProject } from "./project.js";
|
|
5
5
|
import { inspectProject } from "./doctor.js";
|
|
6
6
|
import { emitDeclarations } from "./declarations.js";
|
|
7
|
-
import { t as transpile } from "./transpile-
|
|
7
|
+
import { t as transpile } from "./transpile-DG81yfVs.js";
|
|
8
8
|
import { createRequire } from "node:module";
|
|
9
9
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { dirname, resolve } from "node:path";
|
|
11
|
-
import { parseArgs } from "node:util";
|
|
12
11
|
import { pathToFileURL } from "node:url";
|
|
12
|
+
import { parseArgs } from "node:util";
|
|
13
13
|
//#region src/cli.ts
|
|
14
14
|
async function main(args = process.argv.slice(2)) {
|
|
15
15
|
const { values, positionals, tokens } = parseArgs({
|
|
@@ -29,6 +29,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
29
29
|
type: "boolean",
|
|
30
30
|
default: false
|
|
31
31
|
},
|
|
32
|
+
runtime: { type: "string" },
|
|
32
33
|
help: {
|
|
33
34
|
type: "boolean",
|
|
34
35
|
short: "h"
|
|
@@ -48,6 +49,10 @@ async function main(args = process.argv.slice(2)) {
|
|
|
48
49
|
}
|
|
49
50
|
});
|
|
50
51
|
const [command, input, ...extra] = positionals;
|
|
52
|
+
if (values.runtime !== void 0) {
|
|
53
|
+
if (!["inline", "external"].includes(values.runtime)) throw new Error("--runtime must be inline or external");
|
|
54
|
+
if (command !== "compile" && !values.help) throw new Error("--runtime is only supported by twill compile; use twill.config.json for project commands");
|
|
55
|
+
}
|
|
51
56
|
if (command === "export") {
|
|
52
57
|
let entry;
|
|
53
58
|
try {
|
|
@@ -62,7 +67,8 @@ async function main(args = process.argv.slice(2)) {
|
|
|
62
67
|
}
|
|
63
68
|
if (values["dry-run"]) throw new Error("--dry-run is only supported by twill export");
|
|
64
69
|
if (values.help || !command) {
|
|
65
|
-
console.log("twill
|
|
70
|
+
console.log("twill <script> [arguments...]\ntwill run <script> [arguments...]");
|
|
71
|
+
console.log("twill compile <file> [-o output.ts] [--js] [--runtime inline|external]\ntwill check [-p tsconfig.json] [--json]\ntwill doctor [-p tsconfig.json] [--json]\ntwill declarations [-p tsconfig.json] [-o dist] [--build] [--json]\ntwill export [-p tsconfig.json] -o ../native-project [--dry-run] [--json]\n\ncompile keeps TypeScript types by default; --js erases types and lowers JSX.\nexport requires the optional @swiftuijs/twill-export package.\nCommands use the optional twill.config.json from the project root.");
|
|
66
72
|
return 0;
|
|
67
73
|
}
|
|
68
74
|
if (extra.length) throw new Error("Unexpected arguments: " + extra.join(" "));
|
|
@@ -107,7 +113,8 @@ async function main(args = process.argv.slice(2)) {
|
|
|
107
113
|
const root = values.project ? dirname(resolve(values.project)) : process.cwd();
|
|
108
114
|
const options = {
|
|
109
115
|
...loadConfig(root, values.project ? resolve(values.project) : void 0),
|
|
110
|
-
filename
|
|
116
|
+
filename,
|
|
117
|
+
...values.runtime === void 0 ? {} : { runtime: values.runtime }
|
|
111
118
|
};
|
|
112
119
|
const source = readFileSync(filename, "utf8");
|
|
113
120
|
const result = values.js ? transpile(source, options) : transform(source, options);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["import { readFileSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { resolve, dirname } from 'node:path';\nimport { parseArgs } from 'node:util';\nimport { createRequire } from 'node:module';\nimport { pathToFileURL } from 'node:url';\nimport { transform } from './compiler.js';\nimport { transpile } from './transpile.js';\nimport { loadConfig } from './config.js';\nimport { TwillProject } from './project.js';\nimport { inspectProject } from './doctor.js';\nimport { emitDeclarations } from './declarations.js';\n\nexport async function main(args = process.argv.slice(2)): Promise<number> {\n const { values, positionals, tokens } = parseArgs({\n args,\n allowPositionals: true,\n tokens: true,\n options: {\n out: { type: 'string', short: 'o' },\n project: { type: 'string', short: 'p' },\n js: { type: 'boolean', default: false },\n help: { type: 'boolean', short: 'h' },\n json: { type: 'boolean', default: false },\n build: { type: 'boolean', default: false },\n 'dry-run': { type: 'boolean', default: false },\n },\n });\n const [command, input, ...extra] = positionals;\n if (command === 'export') {\n // Resolve from the selected project, including under pnpm's isolated\n // dependency layout. Core does not depend on the optional export tool.\n let entry: string;\n try {\n entry = createRequire(resolve(values.project ?? 'package.json')).resolve(\n '@swiftuijs/twill-export/cli',\n );\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND') throw error;\n throw new Error(\n 'twill export requires @swiftuijs/twill-export in your project. Install it with pnpm add -D @swiftuijs/twill-export.',\n { cause: error },\n );\n }\n const exporter = await import(pathToFileURL(entry).href);\n const index = tokens.find((token) => token.kind === 'positional')!.index;\n return exporter.main(args.filter((_, position) => position !== index));\n }\n if (values['dry-run']) throw new Error('--dry-run is only supported by twill export');\n if (values.help || !command) {\n console.log(\n 'twill compile <file> [-o output.ts] [--js]\\ntwill check [-p tsconfig.json] [--json]\\ntwill doctor [-p tsconfig.json] [--json]\\ntwill declarations [-p tsconfig.json] [-o dist] [--build] [--json]\\ntwill export [-p tsconfig.json] -o ../native-project [--dry-run] [--json]\\n\\ncompile keeps TypeScript types by default; --js erases types and lowers JSX.\\nexport requires the optional @swiftuijs/twill-export package.\\nCommands use the optional twill.config.json from the project root.',\n );\n return 0;\n }\n if (extra.length) throw new Error('Unexpected arguments: ' + extra.join(' '));\n if (command === 'declarations') {\n if (input) throw new Error('Use --project <tsconfig.json> with declarations');\n const result = emitDeclarations(resolve(values.project ?? 'tsconfig.json'), {\n outDir: values.out,\n build: values.build,\n });\n if (values.json) console.log(JSON.stringify(result, null, 2));\n else {\n for (const diagnostic of result.diagnostics)\n console.error(\n `${diagnostic.filename ?? 'tsconfig'}:${diagnostic.line}:${diagnostic.column + 1} TS${diagnostic.code}: ${diagnostic.message}`,\n );\n if (!result.diagnostics.some((item) => item.category === 'error'))\n console.log(\n `Emitted ${result.files.length} declaration/map files from ${result.projects.length} projects.`,\n );\n }\n return result.diagnostics.some((item) => item.category === 'error') ? 1 : 0;\n }\n if (command === 'check' || command === 'doctor') {\n if (input) throw new Error('Use --project <tsconfig.json> with ' + command);\n const project = new TwillProject(resolve(values.project ?? 'tsconfig.json'));\n try {\n if (command === 'doctor') {\n const report = inspectProject(project);\n if (values.json) console.log(JSON.stringify(report, null, 2));\n else {\n console.log(\n `Twill ${report.twillVersion} / TypeScript ${report.typescriptVersion} / Node ${report.nodeVersion}`,\n );\n console.log(\n `Project: ${report.root}\\nSources: ${report.files.twill} Twill, ${report.files.native} native\\nDiagnostics: ${report.diagnostics.length} (${report.diagnosticTimeMs.toFixed(1)} ms)`,\n );\n for (const diagnostic of report.diagnostics)\n console.log(\n `${diagnostic.filename ?? 'tsconfig'}:${diagnostic.line}:${diagnostic.column + 1} TS${diagnostic.code}: ${diagnostic.message}`,\n );\n console.log('Use --json to save the complete project report.');\n }\n return report.ok ? 0 : 1;\n }\n const diagnostics = project.diagnostics();\n if (values.json) console.log(JSON.stringify(diagnostics, null, 2));\n else\n for (const diagnostic of diagnostics)\n console.error(\n `${diagnostic.filename ?? 'tsconfig'}:${diagnostic.line}:${diagnostic.column + 1} TS${diagnostic.code}: ${diagnostic.message}`,\n );\n return diagnostics.some((diagnostic) => diagnostic.category === 'error') ? 1 : 0;\n } finally {\n project.dispose();\n }\n }\n if (command !== 'compile' || !input)\n throw new Error('Expected compile <file> or check. Use --help for usage.');\n const filename = resolve(input);\n const root = values.project ? dirname(resolve(values.project)) : process.cwd();\n const options = {\n ...loadConfig(root, values.project ? resolve(values.project) : undefined),\n filename,\n };\n const source = readFileSync(filename, 'utf8');\n const result = values.js ? transpile(source, options) : transform(source, options);\n if (values.out) {\n const output = resolve(values.out);\n if (output === filename) throw new Error('Output must differ from input');\n mkdirSync(dirname(output), { recursive: true });\n writeFileSync(\n output,\n result.code + `\\n//# sourceMappingURL=${output.split(/[\\\\/]/).at(-1)}.map\\n`,\n );\n const map = JSON.parse(result.map.toString());\n map.file = output.split(/[\\\\/]/).at(-1);\n writeFileSync(output + '.map', JSON.stringify(map));\n } else process.stdout.write(result.code + '\\n');\n return 0;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["import { readFileSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { resolve, dirname } from 'node:path';\nimport { parseArgs } from 'node:util';\nimport { createRequire } from 'node:module';\nimport { pathToFileURL } from 'node:url';\nimport { transform, type TransformOptions } from './compiler.js';\nimport { transpile } from './transpile.js';\nimport { loadConfig } from './config.js';\nimport { TwillProject } from './project.js';\nimport { inspectProject } from './doctor.js';\nimport { emitDeclarations } from './declarations.js';\n\nexport async function main(args = process.argv.slice(2)): Promise<number> {\n const { values, positionals, tokens } = parseArgs({\n args,\n allowPositionals: true,\n tokens: true,\n options: {\n out: { type: 'string', short: 'o' },\n project: { type: 'string', short: 'p' },\n js: { type: 'boolean', default: false },\n runtime: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n json: { type: 'boolean', default: false },\n build: { type: 'boolean', default: false },\n 'dry-run': { type: 'boolean', default: false },\n },\n });\n const [command, input, ...extra] = positionals;\n if (values.runtime !== undefined) {\n if (!['inline', 'external'].includes(values.runtime))\n throw new Error('--runtime must be inline or external');\n if (command !== 'compile' && !values.help)\n throw new Error(\n '--runtime is only supported by twill compile; use twill.config.json for project commands',\n );\n }\n if (command === 'export') {\n // Resolve from the selected project, including under pnpm's isolated\n // dependency layout. Core does not depend on the optional export tool.\n let entry: string;\n try {\n entry = createRequire(resolve(values.project ?? 'package.json')).resolve(\n '@swiftuijs/twill-export/cli',\n );\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND') throw error;\n throw new Error(\n 'twill export requires @swiftuijs/twill-export in your project. Install it with pnpm add -D @swiftuijs/twill-export.',\n { cause: error },\n );\n }\n const exporter = await import(pathToFileURL(entry).href);\n const index = tokens.find((token) => token.kind === 'positional')!.index;\n return exporter.main(args.filter((_, position) => position !== index));\n }\n if (values['dry-run']) throw new Error('--dry-run is only supported by twill export');\n if (values.help || !command) {\n console.log('twill <script> [arguments...]\\ntwill run <script> [arguments...]');\n console.log(\n 'twill compile <file> [-o output.ts] [--js] [--runtime inline|external]\\ntwill check [-p tsconfig.json] [--json]\\ntwill doctor [-p tsconfig.json] [--json]\\ntwill declarations [-p tsconfig.json] [-o dist] [--build] [--json]\\ntwill export [-p tsconfig.json] -o ../native-project [--dry-run] [--json]\\n\\ncompile keeps TypeScript types by default; --js erases types and lowers JSX.\\nexport requires the optional @swiftuijs/twill-export package.\\nCommands use the optional twill.config.json from the project root.',\n );\n return 0;\n }\n if (extra.length) throw new Error('Unexpected arguments: ' + extra.join(' '));\n if (command === 'declarations') {\n if (input) throw new Error('Use --project <tsconfig.json> with declarations');\n const result = emitDeclarations(resolve(values.project ?? 'tsconfig.json'), {\n outDir: values.out,\n build: values.build,\n });\n if (values.json) console.log(JSON.stringify(result, null, 2));\n else {\n for (const diagnostic of result.diagnostics)\n console.error(\n `${diagnostic.filename ?? 'tsconfig'}:${diagnostic.line}:${diagnostic.column + 1} TS${diagnostic.code}: ${diagnostic.message}`,\n );\n if (!result.diagnostics.some((item) => item.category === 'error'))\n console.log(\n `Emitted ${result.files.length} declaration/map files from ${result.projects.length} projects.`,\n );\n }\n return result.diagnostics.some((item) => item.category === 'error') ? 1 : 0;\n }\n if (command === 'check' || command === 'doctor') {\n if (input) throw new Error('Use --project <tsconfig.json> with ' + command);\n const project = new TwillProject(resolve(values.project ?? 'tsconfig.json'));\n try {\n if (command === 'doctor') {\n const report = inspectProject(project);\n if (values.json) console.log(JSON.stringify(report, null, 2));\n else {\n console.log(\n `Twill ${report.twillVersion} / TypeScript ${report.typescriptVersion} / Node ${report.nodeVersion}`,\n );\n console.log(\n `Project: ${report.root}\\nSources: ${report.files.twill} Twill, ${report.files.native} native\\nDiagnostics: ${report.diagnostics.length} (${report.diagnosticTimeMs.toFixed(1)} ms)`,\n );\n for (const diagnostic of report.diagnostics)\n console.log(\n `${diagnostic.filename ?? 'tsconfig'}:${diagnostic.line}:${diagnostic.column + 1} TS${diagnostic.code}: ${diagnostic.message}`,\n );\n console.log('Use --json to save the complete project report.');\n }\n return report.ok ? 0 : 1;\n }\n const diagnostics = project.diagnostics();\n if (values.json) console.log(JSON.stringify(diagnostics, null, 2));\n else\n for (const diagnostic of diagnostics)\n console.error(\n `${diagnostic.filename ?? 'tsconfig'}:${diagnostic.line}:${diagnostic.column + 1} TS${diagnostic.code}: ${diagnostic.message}`,\n );\n return diagnostics.some((diagnostic) => diagnostic.category === 'error') ? 1 : 0;\n } finally {\n project.dispose();\n }\n }\n if (command !== 'compile' || !input)\n throw new Error('Expected compile <file> or check. Use --help for usage.');\n const filename = resolve(input);\n const root = values.project ? dirname(resolve(values.project)) : process.cwd();\n const options = {\n ...loadConfig(root, values.project ? resolve(values.project) : undefined),\n filename,\n ...(values.runtime === undefined\n ? {}\n : { runtime: values.runtime as TransformOptions['runtime'] }),\n };\n const source = readFileSync(filename, 'utf8');\n const result = values.js ? transpile(source, options) : transform(source, options);\n if (values.out) {\n const output = resolve(values.out);\n if (output === filename) throw new Error('Output must differ from input');\n mkdirSync(dirname(output), { recursive: true });\n writeFileSync(\n output,\n result.code + `\\n//# sourceMappingURL=${output.split(/[\\\\/]/).at(-1)}.map\\n`,\n );\n const map = JSON.parse(result.map.toString());\n map.file = output.split(/[\\\\/]/).at(-1);\n writeFileSync(output + '.map', JSON.stringify(map));\n } else process.stdout.write(result.code + '\\n');\n return 0;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { closeSync, constants, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
//#region src/compilation-cache.ts
|
|
8
|
+
var limit = 524288;
|
|
9
|
+
var packages = [
|
|
10
|
+
"typescript",
|
|
11
|
+
"acorn",
|
|
12
|
+
"acorn-typescript",
|
|
13
|
+
"acorn-jsx",
|
|
14
|
+
"magic-string",
|
|
15
|
+
"@ampproject/remapping",
|
|
16
|
+
"@jridgewell/trace-mapping"
|
|
17
|
+
];
|
|
18
|
+
var digest = (source) => createHash("sha256").update(source).digest("hex");
|
|
19
|
+
function observe(path, kind) {
|
|
20
|
+
try {
|
|
21
|
+
if (kind === "directory") return statSync(path).isDirectory() ? "directory" : "absent";
|
|
22
|
+
return digest(readFileSync(path));
|
|
23
|
+
} catch (error) {
|
|
24
|
+
return ["ENOENT", "ENOTDIR"].includes(error.code ?? "") ? "absent" : "unavailable";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function observationsMatch(observations) {
|
|
28
|
+
return observations.every(({ path, kind, value }) => {
|
|
29
|
+
const current = observe(path, kind);
|
|
30
|
+
return current !== "unavailable" && current === value;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** Hash actual installed code without evaluating any compiler or dependency module. */
|
|
34
|
+
function toolchainIdentity(location = import.meta.url, names = packages) {
|
|
35
|
+
try {
|
|
36
|
+
const hash = createHash("sha256").update("twill-loader-cache-v1\0" + process.version);
|
|
37
|
+
const add = (path, bytes) => hash.update(JSON.stringify([path, digest(bytes)]));
|
|
38
|
+
const directory = dirname(fileURLToPath(location));
|
|
39
|
+
for (const file of readdirSync(directory).sort()) if (file.endsWith(".js")) add(file, readFileSync(join(directory, file)));
|
|
40
|
+
const seen = /* @__PURE__ */ new Set();
|
|
41
|
+
const visit = (name, from) => {
|
|
42
|
+
const require = createRequire(from);
|
|
43
|
+
let root = dirname(require.resolve(name));
|
|
44
|
+
for (;;) {
|
|
45
|
+
const metadata = join(root, "package.json");
|
|
46
|
+
if (existsSync(metadata) && JSON.parse(readFileSync(metadata, "utf8")).name === name) break;
|
|
47
|
+
const parent = dirname(root);
|
|
48
|
+
if (parent === root) throw new Error("Package metadata unavailable");
|
|
49
|
+
root = parent;
|
|
50
|
+
}
|
|
51
|
+
root = realpathSync(root);
|
|
52
|
+
if (seen.has(root)) return;
|
|
53
|
+
seen.add(root);
|
|
54
|
+
const metadata = join(root, "package.json");
|
|
55
|
+
const value = JSON.parse(readFileSync(metadata, "utf8"));
|
|
56
|
+
add(name, readFileSync(metadata));
|
|
57
|
+
const walk = (folder) => {
|
|
58
|
+
for (const entry of readdirSync(folder, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
59
|
+
const path = join(folder, entry.name);
|
|
60
|
+
if (entry.isSymbolicLink() && statSync(path).isDirectory()) throw new Error("Directory symlink requires uncached compilation");
|
|
61
|
+
if (entry.isDirectory() && entry.name !== "node_modules") walk(path);
|
|
62
|
+
else if (/\.(?:[cm]?js|json)$/.test(entry.name)) add(path.slice(root.length), readFileSync(path));
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
if (name === "typescript") add("typescript/lib/typescript.js", readFileSync(require.resolve(name)));
|
|
66
|
+
else walk(root);
|
|
67
|
+
for (const dependency of Object.keys(value.dependencies ?? {}).sort()) visit(dependency, metadata);
|
|
68
|
+
};
|
|
69
|
+
for (const name of names) visit(name, location);
|
|
70
|
+
return hash.digest("hex");
|
|
71
|
+
} catch {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function safeDirectory(directory) {
|
|
76
|
+
const info = lstatSync(directory);
|
|
77
|
+
if (!info.isDirectory() || info.isSymbolicLink()) return false;
|
|
78
|
+
if (process.platform === "win32") return true;
|
|
79
|
+
const uid = process.getuid();
|
|
80
|
+
if (info.uid !== uid || (info.mode & 63) !== 0) return false;
|
|
81
|
+
let path = realpathSync(directory);
|
|
82
|
+
for (;;) {
|
|
83
|
+
const parent = lstatSync(path);
|
|
84
|
+
if (parent.uid !== uid && parent.uid !== 0) return false;
|
|
85
|
+
if ((parent.mode & 18) !== 0 && (parent.mode & 512) === 0) return false;
|
|
86
|
+
const next = dirname(path);
|
|
87
|
+
if (next === path) return true;
|
|
88
|
+
path = next;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function safeFile(info) {
|
|
92
|
+
return info.isFile() && info.nlink === 1 && info.size <= limit && (process.platform === "win32" || info.uid === process.getuid() && (info.mode & 63) === 0);
|
|
93
|
+
}
|
|
94
|
+
/** Fixed slots bound completed storage; collisions are misses, never shared module results. */
|
|
95
|
+
var CompilationCache = class {
|
|
96
|
+
directory;
|
|
97
|
+
identity;
|
|
98
|
+
constructor(directory, identity) {
|
|
99
|
+
this.directory = directory;
|
|
100
|
+
this.identity = identity;
|
|
101
|
+
}
|
|
102
|
+
key(url, source, dialect) {
|
|
103
|
+
return digest(JSON.stringify([
|
|
104
|
+
this.identity,
|
|
105
|
+
url,
|
|
106
|
+
digest(source),
|
|
107
|
+
dialect,
|
|
108
|
+
"ES2022"
|
|
109
|
+
]));
|
|
110
|
+
}
|
|
111
|
+
slot(url) {
|
|
112
|
+
return join(this.directory, parseInt(digest(url).slice(0, 2), 16) % 128 + ".json");
|
|
113
|
+
}
|
|
114
|
+
read(url, source, dialect) {
|
|
115
|
+
let fd;
|
|
116
|
+
try {
|
|
117
|
+
if (!safeDirectory(this.directory)) return;
|
|
118
|
+
const file = this.slot(url);
|
|
119
|
+
if (lstatSync(file).isSymbolicLink()) return;
|
|
120
|
+
fd = openSync(file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
121
|
+
if (!safeFile(fstatSync(fd))) return;
|
|
122
|
+
const value = JSON.parse(readFileSync(fd, "utf8"));
|
|
123
|
+
if (value.key !== this.key(url, source, dialect) || typeof value.source !== "string" || value.digest !== digest(value.source) || !Array.isArray(value.observations) || !value.observations.every((entry) => entry && typeof entry.path === "string" && isAbsolute(entry.path) && ["file", "directory"].includes(entry.kind) && typeof entry.value === "string") || !observationsMatch(value.observations)) return;
|
|
124
|
+
return value.source;
|
|
125
|
+
} catch {
|
|
126
|
+
return;
|
|
127
|
+
} finally {
|
|
128
|
+
if (fd !== void 0) try {
|
|
129
|
+
closeSync(fd);
|
|
130
|
+
} catch {}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
write(url, source, dialect, emitted, observations) {
|
|
134
|
+
let temporary;
|
|
135
|
+
try {
|
|
136
|
+
const value = JSON.stringify({
|
|
137
|
+
key: this.key(url, source, dialect),
|
|
138
|
+
source: emitted,
|
|
139
|
+
digest: digest(emitted),
|
|
140
|
+
observations
|
|
141
|
+
});
|
|
142
|
+
if (Buffer.byteLength(value) > limit || !safeDirectory(this.directory) || !observationsMatch(observations)) return;
|
|
143
|
+
temporary = join(this.directory, randomUUID() + ".tmp");
|
|
144
|
+
writeFileSync(temporary, value, {
|
|
145
|
+
flag: "wx",
|
|
146
|
+
mode: 384
|
|
147
|
+
});
|
|
148
|
+
renameSync(temporary, this.slot(url));
|
|
149
|
+
} catch {} finally {
|
|
150
|
+
if (temporary !== void 0) try {
|
|
151
|
+
unlinkSync(temporary);
|
|
152
|
+
} catch {}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
function openCompilationCache() {
|
|
157
|
+
try {
|
|
158
|
+
const directory = process.env.TWILL_CACHE_DIR ?? join(homedir(), ".twill", "script-cache-v1");
|
|
159
|
+
if (!isAbsolute(directory)) return;
|
|
160
|
+
mkdirSync(directory, {
|
|
161
|
+
recursive: true,
|
|
162
|
+
mode: 448
|
|
163
|
+
});
|
|
164
|
+
if (!safeDirectory(directory)) return;
|
|
165
|
+
const identity = toolchainIdentity();
|
|
166
|
+
if (identity) return new CompilationCache(resolve(directory), identity);
|
|
167
|
+
} catch {}
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
170
|
+
export { observe as n, openCompilationCache as r, digest as t };
|
|
171
|
+
|
|
172
|
+
//# sourceMappingURL=compilation-cache-CuCGz02_.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compilation-cache-CuCGz02_.js","names":[],"sources":["../src/compilation-cache.ts"],"sourcesContent":["import {\n closeSync,\n constants,\n existsSync,\n fstatSync,\n lstatSync,\n mkdirSync,\n openSync,\n readFileSync,\n readdirSync,\n realpathSync,\n statSync,\n renameSync,\n unlinkSync,\n writeFileSync,\n type Stats,\n} from 'node:fs';\nimport { createHash, randomUUID } from 'node:crypto';\nimport { createRequire } from 'node:module';\nimport { homedir } from 'node:os';\nimport { dirname, isAbsolute, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport type ConfigurationObservation = {\n path: string;\n kind: 'file' | 'directory';\n value: string;\n};\nconst limit = 512 * 1024;\nconst packages = [\n 'typescript',\n 'acorn',\n 'acorn-typescript',\n 'acorn-jsx',\n 'magic-string',\n '@ampproject/remapping',\n '@jridgewell/trace-mapping',\n];\nexport const digest = (source: string | Uint8Array) =>\n createHash('sha256').update(source).digest('hex');\n\nexport function observe(path: string, kind: ConfigurationObservation['kind']): string {\n try {\n if (kind === 'directory') return statSync(path).isDirectory() ? 'directory' : 'absent';\n return digest(readFileSync(path));\n } catch (error) {\n return ['ENOENT', 'ENOTDIR'].includes((error as NodeJS.ErrnoException).code ?? '')\n ? 'absent'\n : 'unavailable';\n }\n}\nexport function observationsMatch(observations: ConfigurationObservation[]): boolean {\n return observations.every(({ path, kind, value }) => {\n const current = observe(path, kind);\n return current !== 'unavailable' && current === value;\n });\n}\n\n/** Hash actual installed code without evaluating any compiler or dependency module. */\nexport function toolchainIdentity(\n location = import.meta.url,\n names = packages,\n): string | undefined {\n try {\n const hash = createHash('sha256').update('twill-loader-cache-v1\\0' + process.version);\n const add = (path: string, bytes: Uint8Array) =>\n hash.update(JSON.stringify([path, digest(bytes)]));\n const directory = dirname(fileURLToPath(location));\n for (const file of readdirSync(directory).sort())\n if (file.endsWith('.js')) add(file, readFileSync(join(directory, file)));\n const seen = new Set<string>();\n const visit = (name: string, from: string) => {\n const require = createRequire(from);\n let root = dirname(require.resolve(name));\n for (;;) {\n const metadata = join(root, 'package.json');\n if (existsSync(metadata) && JSON.parse(readFileSync(metadata, 'utf8')).name === name) break;\n const parent = dirname(root);\n if (parent === root) throw new Error('Package metadata unavailable');\n root = parent;\n }\n root = realpathSync(root);\n if (seen.has(root)) return;\n seen.add(root);\n const metadata = join(root, 'package.json');\n const value = JSON.parse(readFileSync(metadata, 'utf8'));\n add(name, readFileSync(metadata));\n const walk = (folder: string) => {\n for (const entry of readdirSync(folder, { withFileTypes: true }).sort((a, b) =>\n a.name.localeCompare(b.name),\n )) {\n const path = join(folder, entry.name);\n if (entry.isSymbolicLink() && statSync(path).isDirectory())\n throw new Error('Directory symlink requires uncached compilation');\n if (entry.isDirectory() && entry.name !== 'node_modules') walk(path);\n else if (/\\.(?:[cm]?js|json)$/.test(entry.name))\n add(path.slice(root.length), readFileSync(path));\n }\n };\n // TypeScript emission/configuration executes this single compiler bundle;\n // hashing its CLI/server copies would add unrelated cold-start work.\n if (name === 'typescript')\n add('typescript/lib/typescript.js', readFileSync(require.resolve(name)));\n else walk(root);\n for (const dependency of Object.keys(value.dependencies ?? {}).sort())\n visit(dependency, metadata);\n };\n for (const name of names) visit(name, location);\n return hash.digest('hex');\n } catch {\n return undefined;\n }\n}\n\nfunction safeDirectory(directory: string): boolean {\n const info = lstatSync(directory);\n if (!info.isDirectory() || info.isSymbolicLink()) return false;\n if (process.platform === 'win32') return true; // User-selected/profile ACL, not a POSIX mode claim.\n const uid = process.getuid!();\n if (info.uid !== uid || (info.mode & 0o077) !== 0) return false;\n let path = realpathSync(directory);\n for (;;) {\n const parent = lstatSync(path);\n if (parent.uid !== uid && parent.uid !== 0) return false;\n if ((parent.mode & 0o022) !== 0 && (parent.mode & 0o1000) === 0) return false;\n const next = dirname(path);\n if (next === path) return true;\n path = next;\n }\n}\nfunction safeFile(info: Stats): boolean {\n return (\n info.isFile() &&\n info.nlink === 1 &&\n info.size <= limit &&\n (process.platform === 'win32' || (info.uid === process.getuid!() && (info.mode & 0o077) === 0))\n );\n}\n\n/** Fixed slots bound completed storage; collisions are misses, never shared module results. */\nexport class CompilationCache {\n constructor(\n private readonly directory: string,\n private readonly identity: string,\n ) {}\n\n private key(url: string, source: string, dialect: boolean) {\n return digest(JSON.stringify([this.identity, url, digest(source), dialect, 'ES2022']));\n }\n private slot(url: string) {\n return join(this.directory, (parseInt(digest(url).slice(0, 2), 16) % 128) + '.json');\n }\n read(url: string, source: string, dialect: boolean): string | undefined {\n let fd: number | undefined;\n try {\n if (!safeDirectory(this.directory)) return;\n const file = this.slot(url);\n if (lstatSync(file).isSymbolicLink()) return;\n fd = openSync(file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));\n if (!safeFile(fstatSync(fd))) return;\n const value = JSON.parse(readFileSync(fd, 'utf8'));\n if (\n value.key !== this.key(url, source, dialect) ||\n typeof value.source !== 'string' ||\n value.digest !== digest(value.source) ||\n !Array.isArray(value.observations) ||\n !value.observations.every(\n (entry: ConfigurationObservation) =>\n entry &&\n typeof entry.path === 'string' &&\n isAbsolute(entry.path) &&\n ['file', 'directory'].includes(entry.kind) &&\n typeof entry.value === 'string',\n ) ||\n !observationsMatch(value.observations)\n )\n return;\n return value.source;\n } catch {\n return;\n } finally {\n if (fd !== undefined) {\n try {\n closeSync(fd);\n } catch {\n /* Cache cleanup is optional too. */\n }\n }\n }\n }\n write(\n url: string,\n source: string,\n dialect: boolean,\n emitted: string,\n observations: ConfigurationObservation[],\n ): void {\n let temporary: string | undefined;\n try {\n const value = JSON.stringify({\n key: this.key(url, source, dialect),\n source: emitted,\n digest: digest(emitted),\n observations,\n });\n if (\n Buffer.byteLength(value) > limit ||\n !safeDirectory(this.directory) ||\n !observationsMatch(observations)\n )\n return;\n temporary = join(this.directory, randomUUID() + '.tmp');\n writeFileSync(temporary, value, { flag: 'wx', mode: 0o600 });\n renameSync(temporary, this.slot(url));\n } catch {\n // An executable cache is optional; its failure never changes script behavior.\n } finally {\n if (temporary !== undefined) {\n try {\n unlinkSync(temporary);\n } catch {\n // Renamed, concurrently removed, or inaccessible; never replace the program's result.\n }\n }\n }\n }\n}\n\nexport function openCompilationCache(): CompilationCache | undefined {\n try {\n const directory = process.env.TWILL_CACHE_DIR ?? join(homedir(), '.twill', 'script-cache-v1');\n if (!isAbsolute(directory)) return;\n mkdirSync(directory, { recursive: true, mode: 0o700 });\n if (!safeDirectory(directory)) return;\n const identity = toolchainIdentity();\n if (identity) return new CompilationCache(resolve(directory), identity);\n } catch {\n // Permissions, unsupported environment or unavailable identity: compile normally.\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type ConfigurationObservation = {
|
|
2
|
+
path: string;
|
|
3
|
+
kind: 'file' | 'directory';
|
|
4
|
+
value: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const digest: (source: string | Uint8Array) => string;
|
|
7
|
+
export declare function observe(path: string, kind: ConfigurationObservation['kind']): string;
|
|
8
|
+
export declare function observationsMatch(observations: ConfigurationObservation[]): boolean;
|
|
9
|
+
/** Hash actual installed code without evaluating any compiler or dependency module. */
|
|
10
|
+
export declare function toolchainIdentity(location?: string, names?: string[]): string | undefined;
|
|
11
|
+
/** Fixed slots bound completed storage; collisions are misses, never shared module results. */
|
|
12
|
+
export declare class CompilationCache {
|
|
13
|
+
private readonly directory;
|
|
14
|
+
private readonly identity;
|
|
15
|
+
constructor(directory: string, identity: string);
|
|
16
|
+
private key;
|
|
17
|
+
private slot;
|
|
18
|
+
read(url: string, source: string, dialect: boolean): string | undefined;
|
|
19
|
+
write(url: string, source: string, dialect: boolean, emitted: string, observations: ConfigurationObservation[]): void;
|
|
20
|
+
}
|
|
21
|
+
export declare function openCompilationCache(): CompilationCache | undefined;
|