@rohal12/twee-ts 1.8.0 → 1.10.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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  compile
3
- } from "../chunk-N2OR5KHL.js";
3
+ } from "../chunk-FSZ5FD3P.js";
4
4
 
5
5
  // src/plugins/rollup.ts
6
6
  function tweeTsPlugin(options) {
@@ -2,7 +2,7 @@ import { C as CompileOptions } from '../types-BbEu2Szm.js';
2
2
 
3
3
  /**
4
4
  * Ready-made Vite plugin for twee-ts.
5
- * Watches .tw files and emits compiled HTML.
5
+ * Watches .tw files and emits compiled HTML via incremental compilation.
6
6
  */
7
7
 
8
8
  interface TweeTsVitePluginOptions {
@@ -34,7 +34,14 @@ declare function tweeTsPlugin(options: TweeTsVitePluginOptions): {
34
34
  type: string;
35
35
  }) => void;
36
36
  };
37
- }): void;
37
+ middlewares: {
38
+ use: (fn: (req: {
39
+ url?: string;
40
+ }, res: {
41
+ end: (data: string) => void;
42
+ }, next: () => void) => void) => void;
43
+ };
44
+ }): Promise<void>;
38
45
  handleHotUpdate(ctx: {
39
46
  file: string;
40
47
  server: {
@@ -44,7 +51,7 @@ declare function tweeTsPlugin(options: TweeTsVitePluginOptions): {
44
51
  }) => void;
45
52
  };
46
53
  };
47
- }): void;
54
+ }): Promise<void>;
48
55
  };
49
56
 
50
57
  export { type TweeTsVitePluginOptions, tweeTsPlugin };
@@ -1,42 +1,66 @@
1
1
  import {
2
- compile
3
- } from "../chunk-N2OR5KHL.js";
2
+ compileIncremental
3
+ } from "../chunk-FSZ5FD3P.js";
4
4
 
5
5
  // src/plugins/vite.ts
6
+ function isTweeFile(file) {
7
+ return file.endsWith(".tw") || file.endsWith(".twee");
8
+ }
9
+ function getCompileOptions(options) {
10
+ return {
11
+ sources: options.sources,
12
+ formatId: options.format,
13
+ ...options.compileOptions
14
+ };
15
+ }
16
+ function logDiagnostics(diagnostics) {
17
+ for (const d of diagnostics) {
18
+ if (d.level === "warning") {
19
+ console.warn(`[twee-ts] ${d.message}`);
20
+ } else {
21
+ console.error(`[twee-ts] ${d.message}`);
22
+ }
23
+ }
24
+ }
6
25
  function tweeTsPlugin(options) {
7
26
  const outputFilename = options.outputFilename ?? "index.html";
27
+ const cache = /* @__PURE__ */ new Map();
28
+ let compiledHtml = "";
8
29
  return {
9
30
  name: "twee-ts",
10
31
  async buildStart() {
11
32
  },
12
33
  async generateBundle() {
13
- const result = await compile({
14
- sources: options.sources,
15
- formatId: options.format,
16
- ...options.compileOptions
17
- });
34
+ const result = await compileIncremental(getCompileOptions(options), cache);
18
35
  this.emitFile({
19
36
  type: "asset",
20
37
  fileName: outputFilename,
21
38
  source: result.output
22
39
  });
23
- for (const d of result.diagnostics) {
24
- if (d.level === "warning") {
25
- console.warn(`[twee-ts] ${d.message}`);
26
- } else {
27
- console.error(`[twee-ts] ${d.message}`);
28
- }
29
- }
40
+ logDiagnostics(result.diagnostics);
30
41
  },
31
- configureServer(server) {
42
+ async configureServer(server) {
32
43
  for (const source of options.sources) {
33
44
  server.watcher.add(source);
34
45
  }
46
+ const result = await compileIncremental(getCompileOptions(options), cache);
47
+ compiledHtml = result.output;
48
+ logDiagnostics(result.diagnostics);
49
+ const servePath = outputFilename === "index.html" ? "/" : `/${outputFilename}`;
50
+ server.middlewares.use((req, res, next) => {
51
+ if (req.url === servePath || servePath === "/" && req.url === "/index.html") {
52
+ res.end(compiledHtml);
53
+ return;
54
+ }
55
+ next();
56
+ });
35
57
  },
36
- handleHotUpdate(ctx) {
37
- if (ctx.file.endsWith(".tw") || ctx.file.endsWith(".twee")) {
38
- ctx.server.ws.send({ type: "full-reload" });
39
- }
58
+ async handleHotUpdate(ctx) {
59
+ if (!isTweeFile(ctx.file)) return;
60
+ const result = await compileIncremental(getCompileOptions(options), cache, /* @__PURE__ */ new Set([ctx.file]));
61
+ compiledHtml = result.output;
62
+ logDiagnostics(result.diagnostics);
63
+ ctx.server.ws.send({ type: "full-reload" });
40
64
  }
41
65
  };
42
66
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/plugins/vite.ts"],"sourcesContent":["/**\n * Ready-made Vite plugin for twee-ts.\n * Watches .tw files and emits compiled HTML.\n */\nimport type { CompileOptions } from '../types.js';\nimport { compile } from '../compiler.js';\n\nexport interface TweeTsVitePluginOptions {\n /** Source directories/files to compile. */\n sources: string[];\n /** Story format ID. */\n format?: string;\n /** Output filename in build output. Default: 'index.html'. */\n outputFilename?: string;\n /** Additional compile options. */\n compileOptions?: Partial<CompileOptions>;\n}\n\nexport function tweeTsPlugin(options: TweeTsVitePluginOptions) {\n const outputFilename = options.outputFilename ?? 'index.html';\n\n return {\n name: 'twee-ts',\n\n async buildStart() {\n // No-op: compilation happens in generateBundle\n },\n\n async generateBundle(this: { emitFile: (opts: { type: string; fileName: string; source: string }) => void }) {\n const result = await compile({\n sources: options.sources,\n formatId: options.format,\n ...options.compileOptions,\n });\n\n this.emitFile({\n type: 'asset',\n fileName: outputFilename,\n source: result.output,\n });\n\n for (const d of result.diagnostics) {\n if (d.level === 'warning') {\n console.warn(`[twee-ts] ${d.message}`);\n } else {\n console.error(`[twee-ts] ${d.message}`);\n }\n }\n },\n\n configureServer(server: {\n watcher: { add: (path: string) => void };\n ws: { send: (data: { type: string }) => void };\n }) {\n for (const source of options.sources) {\n server.watcher.add(source);\n }\n },\n\n handleHotUpdate(ctx: { file: string; server: { ws: { send: (data: { type: string }) => void } } }) {\n if (ctx.file.endsWith('.tw') || ctx.file.endsWith('.twee')) {\n ctx.server.ws.send({ type: 'full-reload' });\n }\n },\n };\n}\n"],"mappings":";;;;;AAkBO,SAAS,aAAa,SAAkC;AAC7D,QAAM,iBAAiB,QAAQ,kBAAkB;AAEjD,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,MAAM,aAAa;AAAA,IAEnB;AAAA,IAEA,MAAM,iBAAuG;AAC3G,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,SAAS,QAAQ;AAAA,QACjB,UAAU,QAAQ;AAAA,QAClB,GAAG,QAAQ;AAAA,MACb,CAAC;AAED,WAAK,SAAS;AAAA,QACZ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ,OAAO;AAAA,MACjB,CAAC;AAED,iBAAW,KAAK,OAAO,aAAa;AAClC,YAAI,EAAE,UAAU,WAAW;AACzB,kBAAQ,KAAK,aAAa,EAAE,OAAO,EAAE;AAAA,QACvC,OAAO;AACL,kBAAQ,MAAM,aAAa,EAAE,OAAO,EAAE;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAAA,IAEA,gBAAgB,QAGb;AACD,iBAAW,UAAU,QAAQ,SAAS;AACpC,eAAO,QAAQ,IAAI,MAAM;AAAA,MAC3B;AAAA,IACF;AAAA,IAEA,gBAAgB,KAAmF;AACjG,UAAI,IAAI,KAAK,SAAS,KAAK,KAAK,IAAI,KAAK,SAAS,OAAO,GAAG;AAC1D,YAAI,OAAO,GAAG,KAAK,EAAE,MAAM,cAAc,CAAC;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/plugins/vite.ts"],"sourcesContent":["/**\n * Ready-made Vite plugin for twee-ts.\n * Watches .tw files and emits compiled HTML via incremental compilation.\n */\nimport type { CompileOptions, FileCacheEntry } from '../types.js';\nimport { compileIncremental } from '../compiler.js';\n\nexport interface TweeTsVitePluginOptions {\n /** Source directories/files to compile. */\n sources: string[];\n /** Story format ID. */\n format?: string;\n /** Output filename in build output. Default: 'index.html'. */\n outputFilename?: string;\n /** Additional compile options. */\n compileOptions?: Partial<CompileOptions>;\n}\n\nfunction isTweeFile(file: string): boolean {\n return file.endsWith('.tw') || file.endsWith('.twee');\n}\n\nfunction getCompileOptions(options: TweeTsVitePluginOptions): CompileOptions {\n return {\n sources: options.sources,\n formatId: options.format,\n ...options.compileOptions,\n };\n}\n\nfunction logDiagnostics(diagnostics: ReadonlyArray<{ level: string; message: string }>) {\n for (const d of diagnostics) {\n if (d.level === 'warning') {\n console.warn(`[twee-ts] ${d.message}`);\n } else {\n console.error(`[twee-ts] ${d.message}`);\n }\n }\n}\n\nexport function tweeTsPlugin(options: TweeTsVitePluginOptions) {\n const outputFilename = options.outputFilename ?? 'index.html';\n const cache = new Map<string, FileCacheEntry>();\n let compiledHtml = '';\n\n return {\n name: 'twee-ts',\n\n async buildStart() {\n // No-op: compilation happens in generateBundle (build) or configureServer (dev)\n },\n\n async generateBundle(this: { emitFile: (opts: { type: string; fileName: string; source: string }) => void }) {\n const result = await compileIncremental(getCompileOptions(options), cache);\n\n this.emitFile({\n type: 'asset',\n fileName: outputFilename,\n source: result.output,\n });\n\n logDiagnostics(result.diagnostics);\n },\n\n async configureServer(server: {\n watcher: { add: (path: string) => void };\n ws: { send: (data: { type: string }) => void };\n middlewares: {\n use: (fn: (req: { url?: string }, res: { end: (data: string) => void }, next: () => void) => void) => void;\n };\n }) {\n for (const source of options.sources) {\n server.watcher.add(source);\n }\n\n // Initial compile\n const result = await compileIncremental(getCompileOptions(options), cache);\n compiledHtml = result.output;\n logDiagnostics(result.diagnostics);\n\n // Serve compiled HTML for requests to / or the output filename\n const servePath = outputFilename === 'index.html' ? '/' : `/${outputFilename}`;\n server.middlewares.use((req, res, next) => {\n if (req.url === servePath || (servePath === '/' && req.url === '/index.html')) {\n res.end(compiledHtml);\n return;\n }\n next();\n });\n },\n\n async handleHotUpdate(ctx: { file: string; server: { ws: { send: (data: { type: string }) => void } } }) {\n if (!isTweeFile(ctx.file)) return;\n\n const result = await compileIncremental(getCompileOptions(options), cache, new Set([ctx.file]));\n compiledHtml = result.output;\n logDiagnostics(result.diagnostics);\n\n ctx.server.ws.send({ type: 'full-reload' });\n },\n };\n}\n"],"mappings":";;;;;AAkBA,SAAS,WAAW,MAAuB;AACzC,SAAO,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,OAAO;AACtD;AAEA,SAAS,kBAAkB,SAAkD;AAC3E,SAAO;AAAA,IACL,SAAS,QAAQ;AAAA,IACjB,UAAU,QAAQ;AAAA,IAClB,GAAG,QAAQ;AAAA,EACb;AACF;AAEA,SAAS,eAAe,aAAgE;AACtF,aAAW,KAAK,aAAa;AAC3B,QAAI,EAAE,UAAU,WAAW;AACzB,cAAQ,KAAK,aAAa,EAAE,OAAO,EAAE;AAAA,IACvC,OAAO;AACL,cAAQ,MAAM,aAAa,EAAE,OAAO,EAAE;AAAA,IACxC;AAAA,EACF;AACF;AAEO,SAAS,aAAa,SAAkC;AAC7D,QAAM,iBAAiB,QAAQ,kBAAkB;AACjD,QAAM,QAAQ,oBAAI,IAA4B;AAC9C,MAAI,eAAe;AAEnB,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,MAAM,aAAa;AAAA,IAEnB;AAAA,IAEA,MAAM,iBAAuG;AAC3G,YAAM,SAAS,MAAM,mBAAmB,kBAAkB,OAAO,GAAG,KAAK;AAEzE,WAAK,SAAS;AAAA,QACZ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ,OAAO;AAAA,MACjB,CAAC;AAED,qBAAe,OAAO,WAAW;AAAA,IACnC;AAAA,IAEA,MAAM,gBAAgB,QAMnB;AACD,iBAAW,UAAU,QAAQ,SAAS;AACpC,eAAO,QAAQ,IAAI,MAAM;AAAA,MAC3B;AAGA,YAAM,SAAS,MAAM,mBAAmB,kBAAkB,OAAO,GAAG,KAAK;AACzE,qBAAe,OAAO;AACtB,qBAAe,OAAO,WAAW;AAGjC,YAAM,YAAY,mBAAmB,eAAe,MAAM,IAAI,cAAc;AAC5E,aAAO,YAAY,IAAI,CAAC,KAAK,KAAK,SAAS;AACzC,YAAI,IAAI,QAAQ,aAAc,cAAc,OAAO,IAAI,QAAQ,eAAgB;AAC7E,cAAI,IAAI,YAAY;AACpB;AAAA,QACF;AACA,aAAK;AAAA,MACP,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,gBAAgB,KAAmF;AACvG,UAAI,CAAC,WAAW,IAAI,IAAI,EAAG;AAE3B,YAAM,SAAS,MAAM,mBAAmB,kBAAkB,OAAO,GAAG,OAAO,oBAAI,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;AAC9F,qBAAe,OAAO;AACtB,qBAAe,OAAO,WAAW;AAEjC,UAAI,OAAO,GAAG,KAAK,EAAE,MAAM,cAAc,CAAC;AAAA,IAC5C;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rohal12/twee-ts",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "description": "TypeScript Twee-to-HTML compiler — a complete reimplementation of Tweego",
5
5
  "type": "module",
6
6
  "license": "Unlicense",
@@ -43,11 +43,13 @@
43
43
  "twee-ts": "./dist/bin/twee-ts.js"
44
44
  },
45
45
  "files": [
46
- "dist"
46
+ "dist",
47
+ "schemas"
47
48
  ],
48
49
  "scripts": {
49
50
  "build": "tsup",
50
51
  "test": "vitest run",
52
+ "test:coverage": "vitest run --coverage",
51
53
  "test:watch": "vitest",
52
54
  "typecheck": "tsc --noEmit",
53
55
  "prepublishOnly": "pnpm run typecheck && pnpm test && pnpm run build",
@@ -63,6 +65,7 @@
63
65
  },
64
66
  "devDependencies": {
65
67
  "@types/node": "^25.3.3",
68
+ "@vitest/coverage-v8": "^4.0.18",
66
69
  "prettier": "^3.8.1",
67
70
  "tsup": "^8.4.0",
68
71
  "tsx": "^4.21.0",
@@ -0,0 +1,97 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://unpkg.com/@rohal12/twee-ts/schemas/twee-ts.config.schema.json",
4
+ "title": "twee-ts Configuration",
5
+ "description": "Configuration file for twee-ts, a TypeScript Twee-to-HTML compiler.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "$schema": {
10
+ "type": "string",
11
+ "description": "JSON Schema reference for editor support."
12
+ },
13
+ "sources": {
14
+ "type": "array",
15
+ "items": { "type": "string" },
16
+ "description": "Files or directories to compile."
17
+ },
18
+ "output": {
19
+ "type": "string",
20
+ "description": "Output file path."
21
+ },
22
+ "outputMode": {
23
+ "type": "string",
24
+ "enum": ["html", "twee3", "twee1", "twine2-archive", "twine1-archive", "json"],
25
+ "default": "html",
26
+ "description": "Output mode."
27
+ },
28
+ "formatId": {
29
+ "type": "string",
30
+ "description": "Story format directory ID (e.g. 'sugarcube-2')."
31
+ },
32
+ "startPassage": {
33
+ "type": "string",
34
+ "description": "Name of the starting passage.",
35
+ "default": "Start"
36
+ },
37
+ "formatPaths": {
38
+ "type": "array",
39
+ "items": { "type": "string" },
40
+ "description": "Extra directories to search for story formats."
41
+ },
42
+ "formatIndices": {
43
+ "type": "array",
44
+ "items": { "type": "string" },
45
+ "description": "URLs to SFA-compatible index.json files for remote format lookup."
46
+ },
47
+ "formatUrls": {
48
+ "type": "array",
49
+ "items": { "type": "string" },
50
+ "description": "Direct URLs to format.js files."
51
+ },
52
+ "useTweegoPath": {
53
+ "type": "boolean",
54
+ "default": true,
55
+ "description": "Also search TWEEGO_PATH env for formats."
56
+ },
57
+ "modules": {
58
+ "type": "array",
59
+ "items": { "type": "string" },
60
+ "description": "Module files to inject into <head>."
61
+ },
62
+ "headFile": {
63
+ "type": "string",
64
+ "description": "Raw HTML file to append to <head>."
65
+ },
66
+ "trim": {
67
+ "type": "boolean",
68
+ "default": true,
69
+ "description": "Trim passage whitespace."
70
+ },
71
+ "twee2Compat": {
72
+ "type": "boolean",
73
+ "default": false,
74
+ "description": "Twee2 compatibility mode."
75
+ },
76
+ "testMode": {
77
+ "type": "boolean",
78
+ "default": false,
79
+ "description": "Enable debug/test mode option."
80
+ },
81
+ "noRemote": {
82
+ "type": "boolean",
83
+ "default": false,
84
+ "description": "Disable remote format fetching."
85
+ },
86
+ "tagAliases": {
87
+ "type": "object",
88
+ "additionalProperties": { "type": "string" },
89
+ "description": "Map alias tags to canonical special tags (e.g. { \"library\": \"script\" })."
90
+ },
91
+ "sourceInfo": {
92
+ "type": "boolean",
93
+ "default": false,
94
+ "description": "Emit source file and line as data- attributes on passage elements."
95
+ }
96
+ }
97
+ }