@swiftuijs/twill-export 0.2.0 → 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 +4 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -6
package/README.md
CHANGED
|
@@ -51,3 +51,7 @@ Twill 0.2.0 adds `if const value = lookup() { use(value); }` with branch-local n
|
|
|
51
51
|
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).
|
|
52
52
|
|
|
53
53
|
The optional `runtime: "external"` compiler mode in 0.2.0 is preserved during export. Its native sources retain the versioned `@swiftuijs/twill-runtime` helper import; install that production dependency in the destination. Default inline export stays self-contained. Export does not copy dependencies or rewrite package manifests. See [runtime modes](https://twill.evecalm.com/runtime).
|
|
54
|
+
|
|
55
|
+
## Development
|
|
56
|
+
|
|
57
|
+
This package's implementation uses Twill and emits ordinary JavaScript. Build and check a checkout with the workspace tools; see [developing tooling in Twill](https://github.com/swiftuijs/twill/blob/main/docs/contributing/dogfooding.md) for bootstrap and contribution instructions.
|
package/dist/cli.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","mappings":"AAIA,wBAAsB,IAAI,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,MAAM,CAAC","names":[],"ignoreList":[],"sources":["../src/cli.twill"],"sourcesContent":["import { parseArgs } from 'node:util';\nimport { resolve } from 'node:path';\nimport { exportProject } from './index.twill';\n\nexport async function main(args = process.argv.slice(2)): Promise<number> {\n const { values, positionals } = parseArgs({\n args,\n options: {\n project: { type: 'string', short: 'p' },\n out: { type: 'string', short: 'o' },\n 'dry-run': { type: 'boolean', default: false },\n json: { type: 'boolean', default: false },\n help: { type: 'boolean', short: 'h' },\n },\n });\n if (values.help) {\n console.log(\n 'twill export [-p tsconfig.json] -o ../native-project [--dry-run] [--json]\\nExports checked sources into a new directory outside the input project. Originals remain intact.',\n );\n return 0;\n }\n guard positionals.length === 0 && values.out else {\n throw new Error('Specify --out <new directory>. Use --help for usage.');\n }\n const result = await exportProject(resolve(values.project ?? 'tsconfig.json'), {\n outDir: resolve(values.out),\n dryRun: values['dry-run'],\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 `${result.written ? 'Exported' : 'Planned'} ${result.files.length} files; native config: ${result.tsconfig}`,\n );\n }\n return result.diagnostics.some((item) => item.category === 'error') ? 1 : 0;\n}\n"]}
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { exportProject } from "./index.js";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
|
-
//#region src/cli.
|
|
4
|
+
//#region src/cli.twill
|
|
5
5
|
async function main(args = process.argv.slice(2)) {
|
|
6
6
|
const { values, positionals } = parseArgs({
|
|
7
7
|
args,
|
|
@@ -32,7 +32,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
32
32
|
console.log("twill export [-p tsconfig.json] -o ../native-project [--dry-run] [--json]\nExports checked sources into a new directory outside the input project. Originals remain intact.");
|
|
33
33
|
return 0;
|
|
34
34
|
}
|
|
35
|
-
if (positionals.length
|
|
35
|
+
if (!(positionals.length === 0 && values.out)) throw new Error("Specify --out <new directory>. Use --help for usage.");
|
|
36
36
|
const result = await exportProject(resolve(values.project ?? "tsconfig.json"), {
|
|
37
37
|
outDir: resolve(values.out),
|
|
38
38
|
dryRun: values["dry-run"]
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.twill"],"sourcesContent":["import { parseArgs } from 'node:util';\nimport { resolve } from 'node:path';\nimport { exportProject } from './index.twill';\n\nexport async function main(args = process.argv.slice(2)): Promise<number> {\n const { values, positionals } = parseArgs({\n args,\n options: {\n project: { type: 'string', short: 'p' },\n out: { type: 'string', short: 'o' },\n 'dry-run': { type: 'boolean', default: false },\n json: { type: 'boolean', default: false },\n help: { type: 'boolean', short: 'h' },\n },\n });\n if (values.help) {\n console.log(\n 'twill export [-p tsconfig.json] -o ../native-project [--dry-run] [--json]\\nExports checked sources into a new directory outside the input project. Originals remain intact.',\n );\n return 0;\n }\n guard positionals.length === 0 && values.out else {\n throw new Error('Specify --out <new directory>. Use --help for usage.');\n }\n const result = await exportProject(resolve(values.project ?? 'tsconfig.json'), {\n outDir: resolve(values.out),\n dryRun: values['dry-run'],\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 `${result.written ? 'Exported' : 'Planned'} ${result.files.length} files; native config: ${result.tsconfig}`,\n );\n }\n return result.diagnostics.some((item) => item.category === 'error') ? 1 : 0;\n}\n"],"mappings":";;;;AAIA,eAAsB,KAAK,OAAO,QAAQ,KAAK,MAAM,CAAC,GAAC;CACrD,MAAM,EAAE,QAAQ,gBAAgB,UAAU;EACxC;EACA,SAAS;GACP,SAAS;IAAE,MAAM;IAAU,OAAO;GAAG;GACrC,KAAK;IAAE,MAAM;IAAU,OAAO;GAAG;GACjC,WAAW;IAAE,MAAM;IAAW,SAAS;GAAK;GAC5C,MAAM;IAAE,MAAM;IAAW,SAAS;GAAK;GACvC,MAAM;IAAE,MAAM;IAAW,OAAO;GAAG;EACpC;CACF,CAAA;CACD,IAAI,OAAO,MAAM;EACf,QAAQ,IACN,6KAA6K;EAE/K,OAAO;CACT;CACA,IAAA,EAAM,YAAY,WAAW,KAAK,OAAO,MACvC,MAAM,IAAI,MAAM,sDAAsD;CAExE,MAAM,SAAS,MAAM,cAAc,QAAQ,OAAO,WAAW,eAAe,GAAG;EAC7E,QAAQ,QAAQ,OAAO,GAAG;EAC1B,QAAQ,OAAO;CAChB,CAAA;CACD,IAAI,OAAO,MAAM,QAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;MACvD;EACH,KAAK,MAAM,cAAc,OAAO,aAC9B,QAAQ,MACN,GAAG,WAAW,YAAY,WAAU,GAAI,WAAW,KAAI,GAAI,WAAW,SAAS,EAAC,KAAM,WAAW,KAAI,IAAK,WAAW,SAAS;EAElI,IAAI,CAAC,OAAO,YAAY,MAAM,SAAS,KAAK,aAAa,OAAO,GAC9D,QAAQ,IACN,GAAG,OAAO,UAAU,aAAa,UAAS,GAAI,OAAO,MAAM,OAAM,yBAA0B,OAAO,UAAU;CAElH;CACA,OAAO,OAAO,YAAY,MAAM,SAAS,KAAK,aAAa,OAAO,IAAI,IAAI;AAC5E"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ProjectDiagnostic } from '@swiftuijs/twill/project';
|
|
1
|
+
import type { ProjectDiagnostic } from '@swiftuijs/twill/project';
|
|
2
2
|
export interface ExportOptions {
|
|
3
3
|
outDir: string;
|
|
4
4
|
dryRun?: boolean;
|
|
@@ -19,3 +19,4 @@ export interface ExportResult {
|
|
|
19
19
|
/** Export checked source files, not application dependencies or bundler configuration.
|
|
20
20
|
* Preflight finishes before creating an exclusively owned destination directory. */
|
|
21
21
|
export declare function exportProject(tsconfig: string, options: ExportOptions): Promise<ExportResult>;
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B;AAYjE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM;IACd,MAAM,CAAC,EAAE,OAAO;;AAElB,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;IACd,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,OAAO;;AAEtC,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM;IAClB,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,MAAM;IAChB,KAAK,EAAE,UAAU,EAAE;IACnB,WAAW,EAAE,iBAAiB,EAAE;IAChC,OAAO,EAAE,OAAO;;AAyBlB;;AAEA,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC","names":[],"ignoreList":[],"sources":["../src/index.twill"],"sourcesContent":["import ts from 'typescript';\nimport MagicString from 'magic-string';\nimport { TwillProject, isDependency, sourceFilename } from '@swiftuijs/twill/project';\nimport { isTwillFile } from '@swiftuijs/twill';\nimport { formatGenerated } from '@swiftuijs/twill-formatter';\nimport type { ProjectDiagnostic } from '@swiftuijs/twill/project';\nimport {\n readFileSync,\n realpathSync,\n lstatSync,\n statSync,\n mkdirSync,\n writeFileSync,\n rmSync,\n} from 'node:fs';\nimport { resolve, relative, dirname, isAbsolute, basename, join } from 'node:path';\n\nexport interface ExportOptions {\n outDir: string;\n dryRun?: boolean;\n}\nexport interface ExportFile {\n source: string;\n output: string;\n kind: 'dialect' | 'native' | 'asset';\n}\nexport interface ExportResult {\n sourceRoot: string;\n outDir: string;\n tsconfig: string;\n files: ExportFile[];\n diagnostics: ProjectDiagnostic[];\n written: boolean;\n}\nconst nativeName = (name: string) => name.replace(/\\.twillx$/, '.tsx').replace(/\\.twill$/, '.ts');\nconst portable = (path: string) => path.replaceAll('\\\\', '/');\nconst inside = (root: string, path: string) => {\n const name = relative(root, path);\n return (\n !isAbsolute(name) &&\n name !== '..' &&\n !name.startsWith('..' + (process.platform === 'win32' ? '\\\\' : '/'))\n );\n};\nfunction exists(path: string) {\n try {\n lstatSync(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw error;\n }\n}\nfunction canonical(path: string): string {\n return exists(path) ? realpathSync(path) : join(canonical(dirname(path)), basename(path));\n}\n\n/** Export checked source files, not application dependencies or bundler configuration.\n * Preflight finishes before creating an exclusively owned destination directory. */\nexport async function exportProject(\n tsconfig: string,\n options: ExportOptions,\n): Promise<ExportResult> {\n tsconfig = resolve(tsconfig);\n const root = dirname(tsconfig);\n const out = resolve(options.outDir);\n const realRoot = realpathSync(root);\n const realOut = canonical(out);\n if (\n inside(root, out) ||\n inside(out, root) ||\n inside(realRoot, realOut) ||\n inside(realOut, realRoot)\n )\n throw new Error('Export directory must be outside the source project and cannot contain it.');\n if (exists(out)) throw new Error(`Export directory already exists: ${out}`);\n const result: ExportResult = {\n sourceRoot: root,\n outDir: out,\n tsconfig: join(out, 'tsconfig.json'),\n files: [],\n diagnostics: [],\n written: false,\n };\n const project = new TwillProject(tsconfig);\n try {\n result.diagnostics = project.diagnostics();\n if (result.diagnostics.some((item) => item.category === 'error')) return result;\n const parsed = ts.getParsedCommandLineOfConfigFile(\n tsconfig,\n {},\n { ...ts.sys, onUnRecoverableConfigFileDiagnostic() {} },\n );\n const raw = ts.readConfigFile(tsconfig, ts.sys.readFile).config;\n if (!parsed || !raw) throw new Error(`Could not read export configuration: ${tsconfig}`);\n if (parsed.options.paths && !parsed.options.baseUrl && !raw.compilerOptions?.paths)\n throw new Error('Inherited path aliases need an explicit baseUrl for source export.');\n const content = new Map<string, string | Buffer>();\n const targets = new Map<string, string>();\n const names = new Set<string>(['tsconfig.json']);\n const moduleSources = new Map<string, string>();\n const sources = new Set([\n ...project.sourceFiles(),\n ...(project.service.getProgram()?.getSourceFiles() ?? [])\n .filter(\n (file) => !isDependency(file.fileName) && inside(root, sourceFilename(file.fileName)),\n )\n .map((file) => sourceFilename(file.fileName)),\n ]);\n const register = (source: string, kind: ExportFile['kind']) => {\n source = resolve(source);\n if (!inside(root, source) || !inside(realRoot, realpathSync(source)))\n throw new Error(`Source is outside the export project: ${source}`);\n const name = portable(nativeName(relative(root, source)));\n // Reject names that would collide on a case-insensitive filesystem too.\n const key = name.toLowerCase();\n const output = join(out, name);\n if (targets.has(source)) return targets.get(source)!;\n if (names.has(key)) throw new Error(`Native output filename collision: ${name}`);\n if (kind !== 'asset') {\n const stem = key.replace(/\\.[cm]?[jt]sx?$/, '');\n const previous = moduleSources.get(stem);\n if (previous && (isTwillFile(source) || isTwillFile(previous)))\n throw new Error(`Native output module resolution collision: ${name}`);\n moduleSources.set(stem, source);\n }\n names.add(key);\n targets.set(source, output);\n result.files.push({ source, output, kind });\n return output;\n };\n for (const source of [...sources].sort())\n register(\n source,\n isTwillFile(source) ? 'dialect' : /\\.[cm]?[jt]sx?$/.test(source) ? 'native' : 'asset',\n );\n for (let index = 0; index < result.files.length; index++) {\n const entry = result.files[index]!;\n if (entry.kind === 'asset') {\n content.set(entry.output, readFileSync(entry.source));\n continue;\n }\n const source = project.transformed(entry.source)?.code ?? project.text(entry.source)!;\n const file = ts.createSourceFile(entry.output, source, ts.ScriptTarget.Latest, true);\n const edits = new MagicString(source);\n const rewrite = (literal: ts.StringLiteralLike) => {\n const boundary = literal.text.search(/[?#]/);\n const path = boundary < 0 ? literal.text : literal.text.slice(0, boundary);\n const suffix = boundary < 0 ? '' : literal.text.slice(boundary);\n if (!path?.startsWith('.')) {\n if (isTwillFile(path))\n throw new Error(\n 'Aliased dialect extension imports need relative paths before source export.',\n );\n return;\n }\n const target = resolve(dirname(entry.source), path);\n if (exists(target) && statSync(target).isFile() && !targets.has(target)) {\n if (/\\.[cm]?[jt]sx?$|\\.twillx?$/.test(target))\n throw new Error(`Imported source is missing from the checked graph: ${target}`);\n register(target, 'asset');\n }\n if (isTwillFile(path)) {\n const output = targets.get(target);\n if (!output)\n throw new Error(`Dialect import is missing from the export graph: ${literal.text}`);\n let value = portable(relative(dirname(entry.output), output));\n if (!value.startsWith('.')) value = './' + value;\n edits.overwrite(literal.getStart(file), literal.end, JSON.stringify(value + suffix));\n }\n };\n const visit = (node: ts.Node) => {\n if (\n (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&\n node.moduleSpecifier &&\n ts.isStringLiteral(node.moduleSpecifier)\n )\n rewrite(node.moduleSpecifier);\n else if (\n ts.isImportTypeNode(node) &&\n ts.isLiteralTypeNode(node.argument) &&\n ts.isStringLiteral(node.argument.literal)\n )\n rewrite(node.argument.literal);\n else if (\n ts.isExternalModuleReference(node) &&\n node.expression &&\n ts.isStringLiteral(node.expression)\n )\n rewrite(node.expression);\n else if (\n ts.isCallExpression(node) &&\n node.expression.kind === ts.SyntaxKind.ImportKeyword\n ) {\n const argument = node.arguments[0];\n if (!argument || !ts.isStringLiteralLike(argument))\n throw new Error(\n 'Computed dynamic imports need explicit module paths before source export.',\n );\n rewrite(argument);\n } else if (\n ts.isCallExpression(node) &&\n ts.isIdentifier(node.expression) &&\n node.expression.text === 'require' &&\n node.arguments.some(\n (argument) =>\n ts.isStringLiteralLike(argument) && /\\.twillx?(?:[?#]|$)/.test(argument.text),\n )\n )\n throw new Error(\n 'CommonJS dialect imports need conversion to ES module imports before source export.',\n );\n else if (\n ts.isCallExpression(node) &&\n ts.isPropertyAccessExpression(node.expression) &&\n ts.isMetaProperty(node.expression.expression) &&\n node.expression.name.text.startsWith('glob') &&\n node.arguments.some(\n (argument) => ts.isStringLiteralLike(argument) && argument.text.includes('.twill'),\n )\n )\n throw new Error('Dialect import globs need explicit module paths before source export.');\n ts.forEachChild(node, visit);\n };\n visit(file);\n content.set(\n entry.output,\n entry.kind === 'dialect'\n ? await formatGenerated(edits.toString(), { filepath: entry.output })\n : edits.toString(),\n );\n }\n const compilerOptions: Record<string, any> = {\n ...parsed.options,\n noEmit: true,\n allowJs: true,\n allowImportingTsExtensions: true,\n };\n for (const [key, values] of [\n ['target', ts.ScriptTarget],\n ['module', ts.ModuleKind],\n ['moduleResolution', ts.ModuleResolutionKind],\n ['moduleDetection', ts.ModuleDetectionKind],\n ['newLine', ts.NewLineKind],\n ] as const)\n if (typeof compilerOptions[key] === 'number')\n compilerOptions[key] = values[compilerOptions[key]];\n if (parsed.options.jsx !== undefined)\n compilerOptions.jsx = (\n {\n [ts.JsxEmit.Preserve]: 'preserve',\n [ts.JsxEmit.React]: 'react',\n [ts.JsxEmit.ReactNative]: 'react-native',\n [ts.JsxEmit.ReactJSX]: 'react-jsx',\n [ts.JsxEmit.ReactJSXDev]: 'react-jsxdev',\n } as Record<number, string>\n )[parsed.options.jsx];\n if (parsed.options.lib)\n compilerOptions.lib = parsed.options.lib.map((name) =>\n name.replace(/^lib\\.(.*)\\.d\\.ts$/, '$1'),\n );\n if (parsed.options.newLine !== undefined)\n compilerOptions.newLine = parsed.options.newLine === ts.NewLineKind.LineFeed ? 'lf' : 'crlf';\n if (compilerOptions.plugins)\n compilerOptions.plugins = compilerOptions.plugins.filter(\n (plugin: { name: string }) =>\n !['@swiftuijs/twill', '@swiftuijs/twill-vscode-tsserver'].includes(plugin.name),\n );\n // The result is an independent checking config, with flattened inheritance.\n for (const key of [\n 'configFile',\n 'configFilePath',\n 'pathsBasePath',\n 'outDir',\n 'declarationDir',\n 'tsBuildInfoFile',\n 'incremental',\n 'composite',\n ])\n delete compilerOptions[key];\n for (const key of ['baseUrl', 'rootDir', 'rootDirs', 'typeRoots'] as const) {\n const value = parsed.options[key];\n if (value === undefined) continue;\n const rebase = (path: string) => {\n if (!inside(root, path))\n throw new Error(`Compiler option ${key} points outside the export project: ${path}`);\n return portable(relative(root, path)) || '.';\n };\n compilerOptions[key] = Array.isArray(value) ? value.map(rebase) : rebase(value);\n }\n if (compilerOptions.paths)\n compilerOptions.paths = Object.fromEntries(\n Object.entries(compilerOptions.paths as Record<string, string[]>).map(([key, values]) => [\n key,\n values.map(nativeName),\n ]),\n );\n const config = {\n compilerOptions,\n files: result.files\n .filter((file) => file.kind !== 'asset')\n .map((file) => portable(relative(out, file.output))),\n };\n content.set(result.tsconfig, JSON.stringify(config, null, 2) + '\\n');\n if (!options.dryRun) {\n mkdirSync(dirname(out), { recursive: true });\n mkdirSync(out); // Exclusive claim: never overwrite another directory.\n try {\n for (const [filename, text] of content) {\n mkdirSync(dirname(filename), { recursive: true });\n writeFileSync(filename, text, { flag: 'wx' });\n }\n } catch (error) {\n rmSync(out, { recursive: true, force: true });\n throw error;\n }\n result.written = true;\n }\n return result;\n } finally {\n project.dispose();\n }\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { isTwillFile } from "@swiftuijs/twill";
|
|
|
5
5
|
import { formatGenerated } from "@swiftuijs/twill-formatter";
|
|
6
6
|
import { lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
8
|
-
//#region src/index.
|
|
8
|
+
//#region src/index.twill
|
|
9
9
|
var nativeName = (name) => name.replace(/\.twillx$/, ".tsx").replace(/\.twill$/, ".ts");
|
|
10
10
|
var portable = (path) => path.replaceAll("\\", "/");
|
|
11
11
|
var inside = (root, path) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import ts from 'typescript';\nimport MagicString from 'magic-string';\nimport { TwillProject, isDependency, sourceFilename } from '@swiftuijs/twill/project';\nimport { isTwillFile } from '@swiftuijs/twill';\nimport { formatGenerated } from '@swiftuijs/twill-formatter';\nimport type { ProjectDiagnostic } from '@swiftuijs/twill/project';\nimport {\n readFileSync,\n realpathSync,\n lstatSync,\n statSync,\n mkdirSync,\n writeFileSync,\n rmSync,\n} from 'node:fs';\nimport { resolve, relative, dirname, isAbsolute, basename, join } from 'node:path';\n\nexport interface ExportOptions {\n outDir: string;\n dryRun?: boolean;\n}\nexport interface ExportFile {\n source: string;\n output: string;\n kind: 'dialect' | 'native' | 'asset';\n}\nexport interface ExportResult {\n sourceRoot: string;\n outDir: string;\n tsconfig: string;\n files: ExportFile[];\n diagnostics: ProjectDiagnostic[];\n written: boolean;\n}\nconst nativeName = (name: string) => name.replace(/\\.twillx$/, '.tsx').replace(/\\.twill$/, '.ts');\nconst portable = (path: string) => path.replaceAll('\\\\', '/');\nconst inside = (root: string, path: string) => {\n const name = relative(root, path);\n return (\n !isAbsolute(name) &&\n name !== '..' &&\n !name.startsWith('..' + (process.platform === 'win32' ? '\\\\' : '/'))\n );\n};\nfunction exists(path: string) {\n try {\n lstatSync(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw error;\n }\n}\nfunction canonical(path: string): string {\n return exists(path) ? realpathSync(path) : join(canonical(dirname(path)), basename(path));\n}\n\n/** Export checked source files, not application dependencies or bundler configuration.\n * Preflight finishes before creating an exclusively owned destination directory. */\nexport async function exportProject(\n tsconfig: string,\n options: ExportOptions,\n): Promise<ExportResult> {\n tsconfig = resolve(tsconfig);\n const root = dirname(tsconfig);\n const out = resolve(options.outDir);\n const realRoot = realpathSync(root);\n const realOut = canonical(out);\n if (\n inside(root, out) ||\n inside(out, root) ||\n inside(realRoot, realOut) ||\n inside(realOut, realRoot)\n )\n throw new Error('Export directory must be outside the source project and cannot contain it.');\n if (exists(out)) throw new Error(`Export directory already exists: ${out}`);\n const result: ExportResult = {\n sourceRoot: root,\n outDir: out,\n tsconfig: join(out, 'tsconfig.json'),\n files: [],\n diagnostics: [],\n written: false,\n };\n const project = new TwillProject(tsconfig);\n try {\n result.diagnostics = project.diagnostics();\n if (result.diagnostics.some((item) => item.category === 'error')) return result;\n const parsed = ts.getParsedCommandLineOfConfigFile(\n tsconfig,\n {},\n { ...ts.sys, onUnRecoverableConfigFileDiagnostic() {} },\n );\n const raw = ts.readConfigFile(tsconfig, ts.sys.readFile).config;\n if (!parsed || !raw) throw new Error(`Could not read export configuration: ${tsconfig}`);\n if (parsed.options.paths && !parsed.options.baseUrl && !raw.compilerOptions?.paths)\n throw new Error('Inherited path aliases need an explicit baseUrl for source export.');\n const content = new Map<string, string | Buffer>();\n const targets = new Map<string, string>();\n const names = new Set<string>(['tsconfig.json']);\n const moduleSources = new Map<string, string>();\n const sources = new Set([\n ...project.sourceFiles(),\n ...(project.service.getProgram()?.getSourceFiles() ?? [])\n .filter(\n (file) => !isDependency(file.fileName) && inside(root, sourceFilename(file.fileName)),\n )\n .map((file) => sourceFilename(file.fileName)),\n ]);\n const register = (source: string, kind: ExportFile['kind']) => {\n source = resolve(source);\n if (!inside(root, source) || !inside(realRoot, realpathSync(source)))\n throw new Error(`Source is outside the export project: ${source}`);\n const name = portable(nativeName(relative(root, source)));\n // Reject names that would collide on a case-insensitive filesystem too.\n const key = name.toLowerCase();\n const output = join(out, name);\n if (targets.has(source)) return targets.get(source)!;\n if (names.has(key)) throw new Error(`Native output filename collision: ${name}`);\n if (kind !== 'asset') {\n const stem = key.replace(/\\.[cm]?[jt]sx?$/, '');\n const previous = moduleSources.get(stem);\n if (previous && (isTwillFile(source) || isTwillFile(previous)))\n throw new Error(`Native output module resolution collision: ${name}`);\n moduleSources.set(stem, source);\n }\n names.add(key);\n targets.set(source, output);\n result.files.push({ source, output, kind });\n return output;\n };\n for (const source of [...sources].sort())\n register(\n source,\n isTwillFile(source) ? 'dialect' : /\\.[cm]?[jt]sx?$/.test(source) ? 'native' : 'asset',\n );\n for (let index = 0; index < result.files.length; index++) {\n const entry = result.files[index]!;\n if (entry.kind === 'asset') {\n content.set(entry.output, readFileSync(entry.source));\n continue;\n }\n const source = project.transformed(entry.source)?.code ?? project.text(entry.source)!;\n const file = ts.createSourceFile(entry.output, source, ts.ScriptTarget.Latest, true);\n const edits = new MagicString(source);\n const rewrite = (literal: ts.StringLiteralLike) => {\n const boundary = literal.text.search(/[?#]/);\n const path = boundary < 0 ? literal.text : literal.text.slice(0, boundary);\n const suffix = boundary < 0 ? '' : literal.text.slice(boundary);\n if (!path?.startsWith('.')) {\n if (isTwillFile(path))\n throw new Error(\n 'Aliased dialect extension imports need relative paths before source export.',\n );\n return;\n }\n const target = resolve(dirname(entry.source), path);\n if (exists(target) && statSync(target).isFile() && !targets.has(target)) {\n if (/\\.[cm]?[jt]sx?$|\\.twillx?$/.test(target))\n throw new Error(`Imported source is missing from the checked graph: ${target}`);\n register(target, 'asset');\n }\n if (isTwillFile(path)) {\n const output = targets.get(target);\n if (!output)\n throw new Error(`Dialect import is missing from the export graph: ${literal.text}`);\n let value = portable(relative(dirname(entry.output), output));\n if (!value.startsWith('.')) value = './' + value;\n edits.overwrite(literal.getStart(file), literal.end, JSON.stringify(value + suffix));\n }\n };\n const visit = (node: ts.Node) => {\n if (\n (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&\n node.moduleSpecifier &&\n ts.isStringLiteral(node.moduleSpecifier)\n )\n rewrite(node.moduleSpecifier);\n else if (\n ts.isImportTypeNode(node) &&\n ts.isLiteralTypeNode(node.argument) &&\n ts.isStringLiteral(node.argument.literal)\n )\n rewrite(node.argument.literal);\n else if (\n ts.isExternalModuleReference(node) &&\n node.expression &&\n ts.isStringLiteral(node.expression)\n )\n rewrite(node.expression);\n else if (\n ts.isCallExpression(node) &&\n node.expression.kind === ts.SyntaxKind.ImportKeyword\n ) {\n const argument = node.arguments[0];\n if (!argument || !ts.isStringLiteralLike(argument))\n throw new Error(\n 'Computed dynamic imports need explicit module paths before source export.',\n );\n rewrite(argument);\n } else if (\n ts.isCallExpression(node) &&\n ts.isIdentifier(node.expression) &&\n node.expression.text === 'require' &&\n node.arguments.some(\n (argument) =>\n ts.isStringLiteralLike(argument) && /\\.twillx?(?:[?#]|$)/.test(argument.text),\n )\n )\n throw new Error(\n 'CommonJS dialect imports need conversion to ES module imports before source export.',\n );\n else if (\n ts.isCallExpression(node) &&\n ts.isPropertyAccessExpression(node.expression) &&\n ts.isMetaProperty(node.expression.expression) &&\n node.expression.name.text.startsWith('glob') &&\n node.arguments.some(\n (argument) => ts.isStringLiteralLike(argument) && argument.text.includes('.twill'),\n )\n )\n throw new Error('Dialect import globs need explicit module paths before source export.');\n ts.forEachChild(node, visit);\n };\n visit(file);\n content.set(\n entry.output,\n entry.kind === 'dialect'\n ? await formatGenerated(edits.toString(), { filepath: entry.output })\n : edits.toString(),\n );\n }\n const compilerOptions: Record<string, any> = {\n ...parsed.options,\n noEmit: true,\n allowJs: true,\n allowImportingTsExtensions: true,\n };\n for (const [key, values] of [\n ['target', ts.ScriptTarget],\n ['module', ts.ModuleKind],\n ['moduleResolution', ts.ModuleResolutionKind],\n ['moduleDetection', ts.ModuleDetectionKind],\n ['newLine', ts.NewLineKind],\n ] as const)\n if (typeof compilerOptions[key] === 'number')\n compilerOptions[key] = values[compilerOptions[key]];\n if (parsed.options.jsx !== undefined)\n compilerOptions.jsx = (\n {\n [ts.JsxEmit.Preserve]: 'preserve',\n [ts.JsxEmit.React]: 'react',\n [ts.JsxEmit.ReactNative]: 'react-native',\n [ts.JsxEmit.ReactJSX]: 'react-jsx',\n [ts.JsxEmit.ReactJSXDev]: 'react-jsxdev',\n } as Record<number, string>\n )[parsed.options.jsx];\n if (parsed.options.lib)\n compilerOptions.lib = parsed.options.lib.map((name) =>\n name.replace(/^lib\\.(.*)\\.d\\.ts$/, '$1'),\n );\n if (parsed.options.newLine !== undefined)\n compilerOptions.newLine = parsed.options.newLine === ts.NewLineKind.LineFeed ? 'lf' : 'crlf';\n if (compilerOptions.plugins)\n compilerOptions.plugins = compilerOptions.plugins.filter(\n (plugin: { name: string }) =>\n !['@swiftuijs/twill', '@swiftuijs/twill-vscode-tsserver'].includes(plugin.name),\n );\n // The result is an independent checking config, with flattened inheritance.\n for (const key of [\n 'configFile',\n 'configFilePath',\n 'pathsBasePath',\n 'outDir',\n 'declarationDir',\n 'tsBuildInfoFile',\n 'incremental',\n 'composite',\n ])\n delete compilerOptions[key];\n for (const key of ['baseUrl', 'rootDir', 'rootDirs', 'typeRoots'] as const) {\n const value = parsed.options[key];\n if (value === undefined) continue;\n const rebase = (path: string) => {\n if (!inside(root, path))\n throw new Error(`Compiler option ${key} points outside the export project: ${path}`);\n return portable(relative(root, path)) || '.';\n };\n compilerOptions[key] = Array.isArray(value) ? value.map(rebase) : rebase(value);\n }\n if (compilerOptions.paths)\n compilerOptions.paths = Object.fromEntries(\n Object.entries(compilerOptions.paths as Record<string, string[]>).map(([key, values]) => [\n key,\n values.map(nativeName),\n ]),\n );\n const config = {\n compilerOptions,\n files: result.files\n .filter((file) => file.kind !== 'asset')\n .map((file) => portable(relative(out, file.output))),\n };\n content.set(result.tsconfig, JSON.stringify(config, null, 2) + '\\n');\n if (!options.dryRun) {\n mkdirSync(dirname(out), { recursive: true });\n mkdirSync(out); // Exclusive claim: never overwrite another directory.\n try {\n for (const [filename, text] of content) {\n mkdirSync(dirname(filename), { recursive: true });\n writeFileSync(filename, text, { flag: 'wx' });\n }\n } catch (error) {\n rmSync(out, { recursive: true, force: true });\n throw error;\n }\n result.written = true;\n }\n return result;\n } finally {\n project.dispose();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.twill"],"sourcesContent":["import ts from 'typescript';\nimport MagicString from 'magic-string';\nimport { TwillProject, isDependency, sourceFilename } from '@swiftuijs/twill/project';\nimport { isTwillFile } from '@swiftuijs/twill';\nimport { formatGenerated } from '@swiftuijs/twill-formatter';\nimport type { ProjectDiagnostic } from '@swiftuijs/twill/project';\nimport {\n readFileSync,\n realpathSync,\n lstatSync,\n statSync,\n mkdirSync,\n writeFileSync,\n rmSync,\n} from 'node:fs';\nimport { resolve, relative, dirname, isAbsolute, basename, join } from 'node:path';\n\nexport interface ExportOptions {\n outDir: string;\n dryRun?: boolean;\n}\nexport interface ExportFile {\n source: string;\n output: string;\n kind: 'dialect' | 'native' | 'asset';\n}\nexport interface ExportResult {\n sourceRoot: string;\n outDir: string;\n tsconfig: string;\n files: ExportFile[];\n diagnostics: ProjectDiagnostic[];\n written: boolean;\n}\nconst nativeName = (name: string) => name.replace(/\\.twillx$/, '.tsx').replace(/\\.twill$/, '.ts');\nconst portable = (path: string) => path.replaceAll('\\\\', '/');\nconst inside = (root: string, path: string) => {\n const name = relative(root, path);\n return (\n !isAbsolute(name) &&\n name !== '..' &&\n !name.startsWith('..' + (process.platform === 'win32' ? '\\\\' : '/'))\n );\n};\nfunction exists(path: string) {\n try {\n lstatSync(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw error;\n }\n}\nfunction canonical(path: string): string {\n return exists(path) ? realpathSync(path) : join(canonical(dirname(path)), basename(path));\n}\n\n/** Export checked source files, not application dependencies or bundler configuration.\n * Preflight finishes before creating an exclusively owned destination directory. */\nexport async function exportProject(\n tsconfig: string,\n options: ExportOptions,\n): Promise<ExportResult> {\n tsconfig = resolve(tsconfig);\n const root = dirname(tsconfig);\n const out = resolve(options.outDir);\n const realRoot = realpathSync(root);\n const realOut = canonical(out);\n if (\n inside(root, out) ||\n inside(out, root) ||\n inside(realRoot, realOut) ||\n inside(realOut, realRoot)\n )\n throw new Error('Export directory must be outside the source project and cannot contain it.');\n if (exists(out)) throw new Error(`Export directory already exists: ${out}`);\n const result: ExportResult = {\n sourceRoot: root,\n outDir: out,\n tsconfig: join(out, 'tsconfig.json'),\n files: [],\n diagnostics: [],\n written: false,\n };\n const project = new TwillProject(tsconfig);\n try {\n result.diagnostics = project.diagnostics();\n if (result.diagnostics.some((item) => item.category === 'error')) return result;\n const parsed = ts.getParsedCommandLineOfConfigFile(\n tsconfig,\n {},\n { ...ts.sys, onUnRecoverableConfigFileDiagnostic() {} },\n );\n const raw = ts.readConfigFile(tsconfig, ts.sys.readFile).config;\n if (!parsed || !raw) throw new Error(`Could not read export configuration: ${tsconfig}`);\n if (parsed.options.paths && !parsed.options.baseUrl && !raw.compilerOptions?.paths)\n throw new Error('Inherited path aliases need an explicit baseUrl for source export.');\n const content = new Map<string, string | Buffer>();\n const targets = new Map<string, string>();\n const names = new Set<string>(['tsconfig.json']);\n const moduleSources = new Map<string, string>();\n const sources = new Set([\n ...project.sourceFiles(),\n ...(project.service.getProgram()?.getSourceFiles() ?? [])\n .filter(\n (file) => !isDependency(file.fileName) && inside(root, sourceFilename(file.fileName)),\n )\n .map((file) => sourceFilename(file.fileName)),\n ]);\n const register = (source: string, kind: ExportFile['kind']) => {\n source = resolve(source);\n if (!inside(root, source) || !inside(realRoot, realpathSync(source)))\n throw new Error(`Source is outside the export project: ${source}`);\n const name = portable(nativeName(relative(root, source)));\n // Reject names that would collide on a case-insensitive filesystem too.\n const key = name.toLowerCase();\n const output = join(out, name);\n if (targets.has(source)) return targets.get(source)!;\n if (names.has(key)) throw new Error(`Native output filename collision: ${name}`);\n if (kind !== 'asset') {\n const stem = key.replace(/\\.[cm]?[jt]sx?$/, '');\n const previous = moduleSources.get(stem);\n if (previous && (isTwillFile(source) || isTwillFile(previous)))\n throw new Error(`Native output module resolution collision: ${name}`);\n moduleSources.set(stem, source);\n }\n names.add(key);\n targets.set(source, output);\n result.files.push({ source, output, kind });\n return output;\n };\n for (const source of [...sources].sort())\n register(\n source,\n isTwillFile(source) ? 'dialect' : /\\.[cm]?[jt]sx?$/.test(source) ? 'native' : 'asset',\n );\n for (let index = 0; index < result.files.length; index++) {\n const entry = result.files[index]!;\n if (entry.kind === 'asset') {\n content.set(entry.output, readFileSync(entry.source));\n continue;\n }\n const source = project.transformed(entry.source)?.code ?? project.text(entry.source)!;\n const file = ts.createSourceFile(entry.output, source, ts.ScriptTarget.Latest, true);\n const edits = new MagicString(source);\n const rewrite = (literal: ts.StringLiteralLike) => {\n const boundary = literal.text.search(/[?#]/);\n const path = boundary < 0 ? literal.text : literal.text.slice(0, boundary);\n const suffix = boundary < 0 ? '' : literal.text.slice(boundary);\n if (!path?.startsWith('.')) {\n if (isTwillFile(path))\n throw new Error(\n 'Aliased dialect extension imports need relative paths before source export.',\n );\n return;\n }\n const target = resolve(dirname(entry.source), path);\n if (exists(target) && statSync(target).isFile() && !targets.has(target)) {\n if (/\\.[cm]?[jt]sx?$|\\.twillx?$/.test(target))\n throw new Error(`Imported source is missing from the checked graph: ${target}`);\n register(target, 'asset');\n }\n if (isTwillFile(path)) {\n const output = targets.get(target);\n if (!output)\n throw new Error(`Dialect import is missing from the export graph: ${literal.text}`);\n let value = portable(relative(dirname(entry.output), output));\n if (!value.startsWith('.')) value = './' + value;\n edits.overwrite(literal.getStart(file), literal.end, JSON.stringify(value + suffix));\n }\n };\n const visit = (node: ts.Node) => {\n if (\n (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&\n node.moduleSpecifier &&\n ts.isStringLiteral(node.moduleSpecifier)\n )\n rewrite(node.moduleSpecifier);\n else if (\n ts.isImportTypeNode(node) &&\n ts.isLiteralTypeNode(node.argument) &&\n ts.isStringLiteral(node.argument.literal)\n )\n rewrite(node.argument.literal);\n else if (\n ts.isExternalModuleReference(node) &&\n node.expression &&\n ts.isStringLiteral(node.expression)\n )\n rewrite(node.expression);\n else if (\n ts.isCallExpression(node) &&\n node.expression.kind === ts.SyntaxKind.ImportKeyword\n ) {\n const argument = node.arguments[0];\n if (!argument || !ts.isStringLiteralLike(argument))\n throw new Error(\n 'Computed dynamic imports need explicit module paths before source export.',\n );\n rewrite(argument);\n } else if (\n ts.isCallExpression(node) &&\n ts.isIdentifier(node.expression) &&\n node.expression.text === 'require' &&\n node.arguments.some(\n (argument) =>\n ts.isStringLiteralLike(argument) && /\\.twillx?(?:[?#]|$)/.test(argument.text),\n )\n )\n throw new Error(\n 'CommonJS dialect imports need conversion to ES module imports before source export.',\n );\n else if (\n ts.isCallExpression(node) &&\n ts.isPropertyAccessExpression(node.expression) &&\n ts.isMetaProperty(node.expression.expression) &&\n node.expression.name.text.startsWith('glob') &&\n node.arguments.some(\n (argument) => ts.isStringLiteralLike(argument) && argument.text.includes('.twill'),\n )\n )\n throw new Error('Dialect import globs need explicit module paths before source export.');\n ts.forEachChild(node, visit);\n };\n visit(file);\n content.set(\n entry.output,\n entry.kind === 'dialect'\n ? await formatGenerated(edits.toString(), { filepath: entry.output })\n : edits.toString(),\n );\n }\n const compilerOptions: Record<string, any> = {\n ...parsed.options,\n noEmit: true,\n allowJs: true,\n allowImportingTsExtensions: true,\n };\n for (const [key, values] of [\n ['target', ts.ScriptTarget],\n ['module', ts.ModuleKind],\n ['moduleResolution', ts.ModuleResolutionKind],\n ['moduleDetection', ts.ModuleDetectionKind],\n ['newLine', ts.NewLineKind],\n ] as const)\n if (typeof compilerOptions[key] === 'number')\n compilerOptions[key] = values[compilerOptions[key]];\n if (parsed.options.jsx !== undefined)\n compilerOptions.jsx = (\n {\n [ts.JsxEmit.Preserve]: 'preserve',\n [ts.JsxEmit.React]: 'react',\n [ts.JsxEmit.ReactNative]: 'react-native',\n [ts.JsxEmit.ReactJSX]: 'react-jsx',\n [ts.JsxEmit.ReactJSXDev]: 'react-jsxdev',\n } as Record<number, string>\n )[parsed.options.jsx];\n if (parsed.options.lib)\n compilerOptions.lib = parsed.options.lib.map((name) =>\n name.replace(/^lib\\.(.*)\\.d\\.ts$/, '$1'),\n );\n if (parsed.options.newLine !== undefined)\n compilerOptions.newLine = parsed.options.newLine === ts.NewLineKind.LineFeed ? 'lf' : 'crlf';\n if (compilerOptions.plugins)\n compilerOptions.plugins = compilerOptions.plugins.filter(\n (plugin: { name: string }) =>\n !['@swiftuijs/twill', '@swiftuijs/twill-vscode-tsserver'].includes(plugin.name),\n );\n // The result is an independent checking config, with flattened inheritance.\n for (const key of [\n 'configFile',\n 'configFilePath',\n 'pathsBasePath',\n 'outDir',\n 'declarationDir',\n 'tsBuildInfoFile',\n 'incremental',\n 'composite',\n ])\n delete compilerOptions[key];\n for (const key of ['baseUrl', 'rootDir', 'rootDirs', 'typeRoots'] as const) {\n const value = parsed.options[key];\n if (value === undefined) continue;\n const rebase = (path: string) => {\n if (!inside(root, path))\n throw new Error(`Compiler option ${key} points outside the export project: ${path}`);\n return portable(relative(root, path)) || '.';\n };\n compilerOptions[key] = Array.isArray(value) ? value.map(rebase) : rebase(value);\n }\n if (compilerOptions.paths)\n compilerOptions.paths = Object.fromEntries(\n Object.entries(compilerOptions.paths as Record<string, string[]>).map(([key, values]) => [\n key,\n values.map(nativeName),\n ]),\n );\n const config = {\n compilerOptions,\n files: result.files\n .filter((file) => file.kind !== 'asset')\n .map((file) => portable(relative(out, file.output))),\n };\n content.set(result.tsconfig, JSON.stringify(config, null, 2) + '\\n');\n if (!options.dryRun) {\n mkdirSync(dirname(out), { recursive: true });\n mkdirSync(out); // Exclusive claim: never overwrite another directory.\n try {\n for (const [filename, text] of content) {\n mkdirSync(dirname(filename), { recursive: true });\n writeFileSync(filename, text, { flag: 'wx' });\n }\n } catch (error) {\n rmSync(out, { recursive: true, force: true });\n throw error;\n }\n result.written = true;\n }\n return result;\n } finally {\n project.dispose();\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swiftuijs/twill-export",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Export a checked Twill source project to formatted native TypeScript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,12 +39,11 @@
|
|
|
39
39
|
"prettier": "^3.9.9",
|
|
40
40
|
"typescript": "5.9.3",
|
|
41
41
|
"magic-string": "^1.4.2",
|
|
42
|
-
"@swiftuijs/twill": "0.
|
|
43
|
-
"@swiftuijs/twill-formatter": "0.
|
|
42
|
+
"@swiftuijs/twill": "0.3.0",
|
|
43
|
+
"@swiftuijs/twill-formatter": "0.3.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"vite": "^8.3.2",
|
|
47
|
-
"vite-plugin-dts": "^5.1.2",
|
|
48
47
|
"@types/node": "^26.6.4",
|
|
49
48
|
"vitest": "^5.0.3",
|
|
50
49
|
"@vitest/coverage-v8": "^5.0.3"
|
|
@@ -59,8 +58,8 @@
|
|
|
59
58
|
"source-export"
|
|
60
59
|
],
|
|
61
60
|
"scripts": {
|
|
62
|
-
"build": "vite build",
|
|
63
|
-
"typecheck": "
|
|
61
|
+
"build": "vite build && twill declarations -p tsconfig.build.json -o dist",
|
|
62
|
+
"typecheck": "twill check -p tsconfig.json",
|
|
64
63
|
"test:unit": "vitest run",
|
|
65
64
|
"test:watch": "vitest",
|
|
66
65
|
"test:coverage": "vitest run --coverage",
|