@rohal12/twee-ts 1.6.0 → 1.7.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/dist/index.d.cts CHANGED
@@ -261,6 +261,45 @@ interface BrokenLink {
261
261
  */
262
262
  declare function storyInspect(story: Story): StoryMap;
263
263
 
264
+ /**
265
+ * Lint mode: compile + inspect story structure without producing output.
266
+ * Surfaces broken links, dead ends, orphans, and compilation diagnostics.
267
+ */
268
+
269
+ interface LintResult {
270
+ /** Compilation diagnostics (errors and warnings). */
271
+ diagnostics: Diagnostic[];
272
+ /** Compilation statistics. */
273
+ stats: CompileStats;
274
+ /** Story format name from StoryData (e.g. "SugarCube"). */
275
+ formatName: string;
276
+ /** Story format version from StoryData (e.g. "2.37.3"). */
277
+ formatVersion: string;
278
+ /** The configured start passage name. */
279
+ start: string;
280
+ /** Total passage count. */
281
+ passages: number;
282
+ /** Story passage count (excludes StoryData, StoryTitle, scripts, etc.). */
283
+ storyPassages: number;
284
+ /** Info/special passage count. */
285
+ infoPassages: number;
286
+ /** Broken links: link targets that don't exist as passages. */
287
+ brokenLinks: BrokenLink[];
288
+ /** Story passages with no outgoing links. */
289
+ deadEnds: string[];
290
+ /** Story passages that no other passage links to. */
291
+ orphans: string[];
292
+ }
293
+ /**
294
+ * Lint a story: compile without output rendering, then inspect structure.
295
+ * Uses JSON output mode internally to avoid format resolution.
296
+ */
297
+ declare function lint(options: Omit<CompileOptions, 'outputMode'>): Promise<LintResult>;
298
+ /**
299
+ * Format a lint result as a human-readable report string.
300
+ */
301
+ declare function formatLintReport(result: LintResult): string;
302
+
264
303
  /**
265
304
  * Passage helpers and output methods.
266
305
  * Ported from passage.go / passagedata.go.
@@ -373,4 +412,4 @@ declare function resolveRemoteFormat(name: string, version: string, indices?: st
373
412
  /** Discover all cached remote formats. Returns a Map like discoverFormats(). */
374
413
  declare function discoverCachedFormats(): Map<string, StoryFormatInfo>;
375
414
 
376
- export { type BrokenLink, CONFIG_FILENAME, type CompileOptions, type CompileResult, type CompileStats, type CompileToFileOptions, type Diagnostic, type InlineSource, ItemType, type LexerItem, type OutputMode, type Passage, type PassageMetadata, type SFAIndex, type SFAIndexEntry, type SourceInput, type SourceLocation, type Story, type StoryFormatInfo, type StoryMap, TweeLexer, type TweeTsConfig, TweeTsError, type WatchOptions, applyTagAliases, compile, compileToFile, discoverCachedFormats, discoverFormats, fetchAndCacheFormat, fetchDirectFormat, generateIFID, getCacheDir, getFormatSearchDirs, loadConfig, loadConfigFile, parseFormatJSON, parseSemver, parseTwee, resolveRemoteFormat, scaffoldConfig, semverCompare, storyInspect, tweeLexer, validateConfig, validateIFID, watch };
415
+ export { type BrokenLink, CONFIG_FILENAME, type CompileOptions, type CompileResult, type CompileStats, type CompileToFileOptions, type Diagnostic, type InlineSource, ItemType, type LexerItem, type LintResult, type OutputMode, type Passage, type PassageMetadata, type SFAIndex, type SFAIndexEntry, type SourceInput, type SourceLocation, type Story, type StoryFormatInfo, type StoryMap, TweeLexer, type TweeTsConfig, TweeTsError, type WatchOptions, applyTagAliases, compile, compileToFile, discoverCachedFormats, discoverFormats, fetchAndCacheFormat, fetchDirectFormat, formatLintReport, generateIFID, getCacheDir, getFormatSearchDirs, lint, loadConfig, loadConfigFile, parseFormatJSON, parseSemver, parseTwee, resolveRemoteFormat, scaffoldConfig, semverCompare, storyInspect, tweeLexer, validateConfig, validateIFID, watch };
package/dist/index.d.ts CHANGED
@@ -261,6 +261,45 @@ interface BrokenLink {
261
261
  */
262
262
  declare function storyInspect(story: Story): StoryMap;
263
263
 
264
+ /**
265
+ * Lint mode: compile + inspect story structure without producing output.
266
+ * Surfaces broken links, dead ends, orphans, and compilation diagnostics.
267
+ */
268
+
269
+ interface LintResult {
270
+ /** Compilation diagnostics (errors and warnings). */
271
+ diagnostics: Diagnostic[];
272
+ /** Compilation statistics. */
273
+ stats: CompileStats;
274
+ /** Story format name from StoryData (e.g. "SugarCube"). */
275
+ formatName: string;
276
+ /** Story format version from StoryData (e.g. "2.37.3"). */
277
+ formatVersion: string;
278
+ /** The configured start passage name. */
279
+ start: string;
280
+ /** Total passage count. */
281
+ passages: number;
282
+ /** Story passage count (excludes StoryData, StoryTitle, scripts, etc.). */
283
+ storyPassages: number;
284
+ /** Info/special passage count. */
285
+ infoPassages: number;
286
+ /** Broken links: link targets that don't exist as passages. */
287
+ brokenLinks: BrokenLink[];
288
+ /** Story passages with no outgoing links. */
289
+ deadEnds: string[];
290
+ /** Story passages that no other passage links to. */
291
+ orphans: string[];
292
+ }
293
+ /**
294
+ * Lint a story: compile without output rendering, then inspect structure.
295
+ * Uses JSON output mode internally to avoid format resolution.
296
+ */
297
+ declare function lint(options: Omit<CompileOptions, 'outputMode'>): Promise<LintResult>;
298
+ /**
299
+ * Format a lint result as a human-readable report string.
300
+ */
301
+ declare function formatLintReport(result: LintResult): string;
302
+
264
303
  /**
265
304
  * Passage helpers and output methods.
266
305
  * Ported from passage.go / passagedata.go.
@@ -373,4 +412,4 @@ declare function resolveRemoteFormat(name: string, version: string, indices?: st
373
412
  /** Discover all cached remote formats. Returns a Map like discoverFormats(). */
374
413
  declare function discoverCachedFormats(): Map<string, StoryFormatInfo>;
375
414
 
376
- export { type BrokenLink, CONFIG_FILENAME, type CompileOptions, type CompileResult, type CompileStats, type CompileToFileOptions, type Diagnostic, type InlineSource, ItemType, type LexerItem, type OutputMode, type Passage, type PassageMetadata, type SFAIndex, type SFAIndexEntry, type SourceInput, type SourceLocation, type Story, type StoryFormatInfo, type StoryMap, TweeLexer, type TweeTsConfig, TweeTsError, type WatchOptions, applyTagAliases, compile, compileToFile, discoverCachedFormats, discoverFormats, fetchAndCacheFormat, fetchDirectFormat, generateIFID, getCacheDir, getFormatSearchDirs, loadConfig, loadConfigFile, parseFormatJSON, parseSemver, parseTwee, resolveRemoteFormat, scaffoldConfig, semverCompare, storyInspect, tweeLexer, validateConfig, validateIFID, watch };
415
+ export { type BrokenLink, CONFIG_FILENAME, type CompileOptions, type CompileResult, type CompileStats, type CompileToFileOptions, type Diagnostic, type InlineSource, ItemType, type LexerItem, type LintResult, type OutputMode, type Passage, type PassageMetadata, type SFAIndex, type SFAIndexEntry, type SourceInput, type SourceLocation, type Story, type StoryFormatInfo, type StoryMap, TweeLexer, type TweeTsConfig, TweeTsError, type WatchOptions, applyTagAliases, compile, compileToFile, discoverCachedFormats, discoverFormats, fetchAndCacheFormat, fetchDirectFormat, formatLintReport, generateIFID, getCacheDir, getFormatSearchDirs, lint, loadConfig, loadConfigFile, parseFormatJSON, parseSemver, parseTwee, resolveRemoteFormat, scaffoldConfig, semverCompare, storyInspect, tweeLexer, validateConfig, validateIFID, watch };
package/dist/index.js CHANGED
@@ -2386,6 +2386,69 @@ function storyInspect(story) {
2386
2386
  };
2387
2387
  }
2388
2388
 
2389
+ // src/lint.ts
2390
+ async function lint(options) {
2391
+ const result = await compile({ ...options, outputMode: "json" });
2392
+ const map = storyInspect(result.story);
2393
+ return {
2394
+ diagnostics: result.diagnostics,
2395
+ stats: result.stats,
2396
+ formatName: result.story.twine2.format,
2397
+ formatVersion: result.story.twine2.formatVersion,
2398
+ start: map.start,
2399
+ passages: map.passages.length,
2400
+ storyPassages: map.storyPassages.length,
2401
+ infoPassages: map.infoPassages.length,
2402
+ brokenLinks: map.brokenLinks,
2403
+ deadEnds: map.deadEnds,
2404
+ orphans: map.orphans
2405
+ };
2406
+ }
2407
+ function formatLintReport(result) {
2408
+ const lines = [];
2409
+ const formatStr = result.formatName ? `${result.formatName}${result.formatVersion ? " " + result.formatVersion : ""}` : "unknown";
2410
+ lines.push(`Format: ${formatStr}`);
2411
+ lines.push(
2412
+ `Passages: ${result.passages} total (${result.storyPassages} story, ${result.infoPassages} info), ${result.stats.words.toLocaleString()} words, ${result.stats.files.length} files`
2413
+ );
2414
+ lines.push(`Start: ${result.start}`);
2415
+ if (result.brokenLinks.length > 0) {
2416
+ lines.push("");
2417
+ lines.push(`Broken links (${result.brokenLinks.length}):`);
2418
+ for (const link of result.brokenLinks) {
2419
+ lines.push(` ${link.from} -> ${link.to} (passage "${link.to}" does not exist)`);
2420
+ }
2421
+ }
2422
+ if (result.deadEnds.length > 0) {
2423
+ lines.push("");
2424
+ lines.push(`Dead ends (${result.deadEnds.length}): ${result.deadEnds.join(", ")}`);
2425
+ }
2426
+ if (result.orphans.length > 0) {
2427
+ lines.push("");
2428
+ lines.push(`Orphans (${result.orphans.length}): ${result.orphans.join(", ")}`);
2429
+ }
2430
+ const errors = result.diagnostics.filter((d) => d.level === "error");
2431
+ const warnings = result.diagnostics.filter((d) => d.level === "warning");
2432
+ if (errors.length > 0 || warnings.length > 0) {
2433
+ lines.push("");
2434
+ lines.push(`Diagnostics: ${errors.length} error(s), ${warnings.length} warning(s)`);
2435
+ for (const d of errors) {
2436
+ lines.push(` error: ${d.message}`);
2437
+ }
2438
+ for (const d of warnings) {
2439
+ lines.push(` warning: ${d.message}`);
2440
+ }
2441
+ }
2442
+ lines.push("");
2443
+ const hasErrors = errors.length > 0 || result.brokenLinks.length > 0;
2444
+ if (hasErrors) {
2445
+ lines.push("Lint failed.");
2446
+ } else {
2447
+ lines.push("Lint passed.");
2448
+ }
2449
+ return lines.join("\n");
2450
+ }
2451
+
2389
2452
  // src/config.ts
2390
2453
  import { readFileSync as readFileSync4, existsSync as existsSync2 } from "fs";
2391
2454
  import { join as join5 } from "path";
@@ -2497,9 +2560,11 @@ export {
2497
2560
  discoverFormats,
2498
2561
  fetchAndCacheFormat,
2499
2562
  fetchDirectFormat,
2563
+ formatLintReport,
2500
2564
  generateIFID,
2501
2565
  getCacheDir,
2502
2566
  getFormatSearchDirs,
2567
+ lint,
2503
2568
  loadConfig,
2504
2569
  loadConfigFile,
2505
2570
  parseFormatJSON,