@yuxilabs/storymode-compiler
v0.3.0
Published
Compiler layer for StoryMode AST -> IR
Readme
StoryMode Compiler
Compiler layer for StoryMode AST → IR.
Status: Stable – Backwards compatibility for public APIs and IR shape will be maintained with semantic versioning going forward. (Current Version: 0.3.0)
What It Does
Turns parsed StoryMode ASTs from @yuxilabs/storymode-core (StoryFile, NarrativeFile) into lightweight, analysis‑friendly IR objects with:
- Configurable metadata normalization
- Source map entries (Story/Narrative/Scene/MetadataKey)
- Transform diagnostics (mechanical issues, duplicate scene IDs, metadata collapses)
- Lifecycle hooks (before/after story & narrative compilation)
- Severity overrides per diagnostic code
- Optional WeakMap-based caching for repeated compiles of the same AST
- JSON Schema export for the IR (
IR_SCHEMA) - Parse+compile convenience helpers
Install
npm install @yuxilabs/storymode-compiler @yuxilabs/storymode-coreQuick Start
import { parseStory } from '@yuxilabs/storymode-core';
import { compileStory } from '@yuxilabs/storymode-compiler';
const source = `story MyStory\n@author Alice`;
const parse = parseStory(source);
if (parse.ast) {
const result = compileStory(parse.ast, { normalizeMetadata: 'join', embedCoreVersion: true });
console.log(result.ir, result.diagnostics, result.stats);
}One-Step Parse + Compile
import { parseAndCompileNarrative } from '@yuxilabs/storymode-compiler';
const { parseDiagnostics, compile } = parseAndCompileNarrative('narrative N\nscene Intro');Core Types
See: src/types/ir.ts and src/types/result.ts
interface StoryIR { kind: 'StoryIR'; id: string; metadata: Record<string,string>; sourceMap: NodeSourceMap[]; }
interface NarrativeIR { kind: 'NarrativeIR'; id: string; scenes: SceneIR[]; sourceMap: NodeSourceMap[]; }
interface CompileResult<T> { ir: T | null; diagnostics: Diagnostic[]; stats: CompileStatsBreakdown; }Compile Options
CompileOptions:
{
collectSourceMap?: boolean; // default: true
normalizeMetadata?: 'none'|'first'|'last'|'join';
joinDelimiter?: string; // default: ',' when 'join'
embedCoreVersion?: boolean; // adds storymode-core version into stats.coreVersion
onDiagnostic?: (d: Diagnostic) => void; // streaming callback
strictIds?: boolean; // default: true – empty/dup fatal => ir null
severityOverrides?: Record<string,'error'|'warning'|'info'>; // adjust severities
locale?: 'en' | 'zh'; // diagnostic language (default 'en')
hooks?: {
beforeStory?(ast, options): void;
afterStory?(result, options): void;
beforeNarrative?(ast, options): void;
afterNarrative?(result, options): void;
};
cache?: CompilerCache; // WeakMap-backed caching
}Metadata Normalization Strategies
| Strategy | Behavior |
|----------|----------|
| none | Arrays truncated to first element (info diagnostic) |
| first | Take first element (info) |
| last | Take last element (info) |
| join | Join with joinDelimiter (info) |
Source Map Entries
NodeSourceMap = { kind: string; id?: string; range: { start: { line,column }, end: { line,column }}}
Kinds currently emitted: Story, Narrative, Scene, MetadataKey.
Diagnostics
Compiler-specific codes:
UNEXPECTED_AST_KINDMISSING_STORY_IDMISSING_NARRATIVE_IDEMPTY_SCENE_IDDUP_SCENE_IDMETADATA_VALUE_COLLAPSEDMETADATA_KEY_NORMALIZEDNARRATIVE_NO_SCENES
Use severityOverrides to tune impact (e.g., downgrade DUP_SCENE_ID to a warning for exploratory builds).
Internationalization (English & Chinese)
Diagnostics now support bilingual output. Pass a locale in CompileOptions (default 'en').
compileStory(ast, { locale: 'zh' }); // 所有编译诊断消息将显示为中文
compileNarrative(ast, { locale: 'en' });
import { compilerTranslate, compilerResolveLocale } from '@yuxilabs/storymode-compiler';
// You can also manually translate codes:
const msg = compilerTranslate('MISSING_STORY_ID', 'zh');If a diagnostic code lacks a translation it falls back to the code string.
Caching
import { createCompilerCache, compileStory } from '@yuxilabs/storymode-compiler';
const cache = createCompilerCache();
const first = compileStory(ast, { cache });
const second = compileStory(ast, { cache }); // returns cached objectHooks
compileNarrative(ast, {
hooks: {
beforeNarrative: (a) => console.time(a.id),
afterNarrative: (r) => console.timeEnd(r.ir?.id || 'narrative')
}
});IR Schema
import { IR_SCHEMA } from '@yuxilabs/storymode-compiler';
// Validate externally with AJV, etc.Example: Narrative Duplicate Scene Handling
const result = compileNarrative(narrAst, { strictIds: true });
if (!result.ir) {
// fatal duplicates or missing IDs
}Versioning Guidance
While in 0.x, pin exact minor versions for deterministic behavior:
"@yuxilabs/storymode-compiler": "0.3.0"License
Licensed under the MIT License – see LICENSE for full text.
Copyright (c) 2025 William Sawyerr
