@openuji/speculator 0.2.0 → 0.3.1

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/browser.d.ts CHANGED
@@ -1,33 +1,78 @@
1
1
  import MarkdownIt from 'markdown-it';
2
2
 
3
3
  /**
4
- * Service responsible for processing data-format attributes and markdown content.
4
+ * Strategy interface for converting content based on its format.
5
5
  */
6
- declare class FormatProcessor {
7
- private readonly markdownOptions;
8
- constructor(markdownOptions?: MarkdownOptions);
6
+ interface FormatStrategy {
7
+ convert(content: string): string;
8
+ }
9
+ /**
10
+ * Registry responsible for mapping formats to strategies and processing content.
11
+ */
12
+ declare class FormatRegistry {
13
+ private readonly strategies;
14
+ constructor(markdownOptions?: MarkdownOptions, customStrategies?: Record<string, FormatStrategy>);
9
15
  /**
10
- * Convert content based on the specified format.
16
+ * Register a new strategy for a given format.
11
17
  */
12
- processContent(content: string, format: DataFormat): string;
18
+ register(format: DataFormat, strategy: FormatStrategy): void;
13
19
  /**
14
- * Process an element with a data-format attribute.
20
+ * Convert content based on the specified format.
15
21
  */
16
- process(element: Element, stats: ProcessingStats, warnings: string[]): void;
22
+ processContent(content: string, format: DataFormat): string;
23
+ }
24
+
25
+ declare class StatsTracker {
26
+ private _stats;
27
+ private startTime;
28
+ start(): void;
29
+ stop(): void;
30
+ incrementElements(count?: number): void;
31
+ incrementFiles(count?: number): void;
32
+ incrementMarkdownBlocks(count?: number): void;
33
+ toJSON(): ProcessingStats;
34
+ }
35
+
36
+ interface ProcessorResult {
37
+ content?: string | null;
38
+ error?: string;
39
+ }
40
+ interface ElementProcessor {
41
+ matches(element: Element): boolean;
42
+ process(element: Element, tracker: StatsTracker, warnings: string[]): Promise<ProcessorResult> | ProcessorResult;
17
43
  }
18
44
 
19
45
  /**
20
46
  * Service responsible for handling data-include attributes.
21
47
  */
22
- declare class IncludeProcessor {
48
+ declare class IncludeProcessor implements ElementProcessor {
23
49
  private readonly baseUrl;
24
50
  private readonly fileLoader;
25
- private readonly formatProcessor;
26
- constructor(baseUrl: string | undefined, fileLoader: FileLoader, formatProcessor: FormatProcessor);
27
- process(element: Element, stats: ProcessingStats, warnings: string[]): Promise<void>;
51
+ private readonly formatRegistry;
52
+ constructor(baseUrl: string | undefined, fileLoader: FileLoader, formatRegistry: FormatRegistry);
53
+ matches(element: Element): boolean;
54
+ process(element: Element, tracker: StatsTracker, warnings: string[]): Promise<ProcessorResult>;
28
55
  private resolveFilePath;
29
56
  }
30
57
 
58
+ /**
59
+ * Result returned from {@link FormatProcessor.process}.
60
+ * When `error` is present, `content` will be undefined.
61
+ */
62
+ interface FormatResult extends ProcessorResult {
63
+ content?: string;
64
+ }
65
+ /**
66
+ * Processor responsible for handling elements with a `data-format` attribute.
67
+ * Delegates content conversion to {@link FormatRegistry}.
68
+ */
69
+ declare class FormatProcessor implements ElementProcessor {
70
+ private readonly registry;
71
+ constructor(registry?: FormatRegistry);
72
+ matches(element: Element): boolean;
73
+ process(element: Element, tracker: StatsTracker, _warnings: string[]): FormatResult;
74
+ }
75
+
31
76
  /**
32
77
  * Abstraction over DOM parsing and serialization, allowing custom implementations.
33
78
  */
@@ -56,7 +101,9 @@ interface SpeculatorOptions {
56
101
  postprocess?: PostprocessOptions;
57
102
  includeProcessor?: IncludeProcessor;
58
103
  formatProcessor?: FormatProcessor;
104
+ formatRegistry?: FormatRegistry;
59
105
  htmlRenderer?: HtmlRenderer;
106
+ passes?: PipelinePass[] | ((container: Element) => PipelinePass[]);
60
107
  }
61
108
  /**
62
109
  * File loader function type
@@ -74,9 +121,20 @@ interface MarkdownOptions {
74
121
  smartypants?: boolean;
75
122
  /** Generate header IDs */
76
123
  headerIds?: boolean;
124
+ /** Enable Mermaid diagrams */
125
+ mermaid?: boolean | MermaidConfig;
77
126
  /** Custom renderer extensions */
78
127
  extensions?: Array<MarkdownIt.PluginSimple | [MarkdownIt.PluginWithOptions<any>, any]>;
79
128
  }
129
+ /**
130
+ * Configuration options for the Mermaid markdown plugin
131
+ */
132
+ interface MermaidConfig {
133
+ /** Theme to use when rendering diagrams */
134
+ theme?: string;
135
+ /** Additional Mermaid settings */
136
+ [key: string]: unknown;
137
+ }
80
138
  /**
81
139
  * Processing result for a single element
82
140
  */
@@ -102,9 +160,10 @@ interface ProcessingStats {
102
160
  processingTime: number;
103
161
  }
104
162
  /**
105
- * Supported data formats
163
+ * Supported data formats. Additional formats can be provided by registering
164
+ * custom {@link FormatStrategy} implementations with {@link FormatRegistry}.
106
165
  */
107
- type DataFormat = 'markdown' | 'text' | 'html';
166
+ type DataFormat = 'markdown' | 'text' | 'html' | (string & {});
108
167
  /**
109
168
  * Error thrown during rendering
110
169
  */
@@ -113,8 +172,84 @@ declare class SpeculatorError extends Error {
113
172
  readonly path?: string | undefined;
114
173
  constructor(message: string, element?: Element | undefined, path?: string | undefined);
115
174
  }
175
+ /**
176
+ * Hook invoked after all pipeline passes have run.
177
+ */
178
+ type PostProcessHook = (container: Element, outputs: Partial<Record<OutputArea, unknown>>) => void | Promise<void>;
179
+ /**
180
+ * Result returned after rendering a {@link SpeculatorConfig}.
181
+ */
182
+ interface RenderResult {
183
+ sections: Element[];
184
+ header?: Element;
185
+ sotd?: Element;
186
+ metadata?: Record<string, unknown>;
187
+ pubrules?: Element;
188
+ legal?: Element;
189
+ warnings: string[];
190
+ stats: ProcessingStats;
191
+ toc?: string;
192
+ boilerplate?: string[];
193
+ references?: string;
194
+ }
195
+ /**
196
+ * Full configuration for Speculator combining document areas and processing
197
+ * options.
198
+ */
199
+ interface SpeculatorConfig extends SpeculatorOptions {
200
+ /** Document sections to process */
201
+ sections?: Element[];
202
+ /** Optional document header */
203
+ header?: Element;
204
+ /** Status of This Document section */
205
+ sotd?: Element;
206
+ /** Arbitrary metadata */
207
+ metadata?: Record<string, unknown>;
208
+ /** Pubrules-specific content */
209
+ pubrules?: Element;
210
+ /** Legal boilerplate content */
211
+ legal?: Element;
212
+ /** Hook invoked before any processing begins. */
213
+ preHook?: (container: Element) => void | Promise<void>;
214
+ /** Hook invoked after rendering completes. */
215
+ postHook?: (result: RenderResult) => void | Promise<void>;
216
+ /** Hooks executed after pipeline passes complete. */
217
+ postProcess?: PostProcessHook | PostProcessHook[];
218
+ /** Additional, implementation-specific fields. */
219
+ [key: string]: unknown;
220
+ }
221
+ /**
222
+ * Respec's configuration shape. Used for migrating existing specs to the new
223
+ * {@link SpeculatorConfig}.
224
+ */
225
+ interface RespecConfig extends SpeculatorConfig {
226
+ [key: string]: unknown;
227
+ }
228
+ /**
229
+ * Convert a {@link RespecConfig} object to a {@link SpeculatorConfig}.
230
+ */
231
+ declare function fromRespecConfig(respec: RespecConfig): SpeculatorConfig;
232
+ interface RenderHtmlResult {
233
+ sections: string;
234
+ toc: string;
235
+ header?: string;
236
+ sotd?: string;
237
+ metadata?: Record<string, unknown>;
238
+ pubrules?: string;
239
+ legal?: string;
240
+ warnings: string[];
241
+ stats: ProcessingStats;
242
+ boilerplate?: string[];
243
+ references?: string;
244
+ }
116
245
  type XrefQuery = {
246
+ /** Unique identifier returned with results (internal use). */
247
+ id?: string;
248
+ /** The term to resolve. */
117
249
  term: string;
250
+ /** Optional list of spec shortnames to constrain the search. */
251
+ specs?: string[];
252
+ /** Additional context for the lookup (unused for now). */
118
253
  context?: string;
119
254
  };
120
255
  type XrefResult = {
@@ -123,11 +258,15 @@ type XrefResult = {
123
258
  cite?: string;
124
259
  };
125
260
  interface XrefResolver {
126
- resolveBatch(queries: XrefQuery[], specs?: string[]): Promise<Map<string, XrefResult>>;
261
+ /**
262
+ * Resolve a batch of xref queries. The returned map is keyed by the query's
263
+ * `id` if provided, otherwise by the query term.
264
+ */
265
+ resolveBatch(queries: XrefQuery[]): Promise<Map<string, XrefResult[]>>;
127
266
  }
128
267
  interface XrefOptions {
129
268
  specs?: string[];
130
- resolver?: XrefResolver;
269
+ resolver: XrefResolver;
131
270
  }
132
271
  interface BiblioEntry {
133
272
  id: string;
@@ -149,6 +288,12 @@ interface TocOptions {
149
288
  selector?: string;
150
289
  enabled?: boolean;
151
290
  }
291
+ interface DiagnosticsOptions {
292
+ /** Suppress link warnings within elements having this class. */
293
+ suppressClass?: string;
294
+ /** Enable duplicate-id and missing-href checks (default true). */
295
+ idsAndLinks?: boolean;
296
+ }
152
297
  interface BoilerplateOptions {
153
298
  conformance?: boolean | {
154
299
  title?: string;
@@ -167,29 +312,36 @@ interface BoilerplateOptions {
167
312
  };
168
313
  mount?: 'end' | 'before-references' | 'after-toc';
169
314
  }
170
- interface DiagnosticsOptions {
171
- /** Suppress link warnings within elements having this class. */
172
- suppressClass?: string;
173
- }
174
- interface DiagnosticsOptions {
175
- suppressClass?: string;
176
- /** Enable duplicate-id and missing-href checks (default true). */
177
- idsAndLinks?: boolean;
315
+ interface AssertionsOptions {
316
+ /** Override spec short name (e.g., 'ujse'). Defaults from baseUrl path. */
317
+ spec?: string;
318
+ /** Override version string (e.g., '1.0'). Defaults from baseUrl path. */
319
+ version?: string | number;
178
320
  }
179
321
  interface PostprocessOptions {
180
- xref?: XrefOptions;
181
- biblio?: BiblioOptions;
182
- idl?: IdlOptions;
183
- toc?: TocOptions;
184
- diagnostics?: DiagnosticsOptions;
185
- }
186
- interface PostprocessOptions {
187
- xref?: XrefOptions;
322
+ xref?: XrefOptions | XrefOptions[];
188
323
  biblio?: BiblioOptions;
189
324
  idl?: IdlOptions;
190
325
  toc?: TocOptions;
191
326
  diagnostics?: DiagnosticsOptions;
192
327
  boilerplate?: BoilerplateOptions;
328
+ assertions?: AssertionsOptions;
329
+ }
330
+ type OutputArea = 'idl' | 'xref' | 'references' | 'boilerplate' | 'toc' | 'diagnostics' | 'assertions' | 'metadata' | 'pubrules' | 'legal';
331
+ interface PipelineContext {
332
+ /** Accumulated outputs from earlier passes. */
333
+ outputs: Partial<Record<OutputArea, unknown>>;
334
+ /** Accumulated warnings from executed passes. */
335
+ warnings: string[];
336
+ /** Full configuration for the current render. */
337
+ config: SpeculatorConfig;
338
+ }
339
+ type PipelineNext = () => Promise<void>;
340
+ interface PipelinePass {
341
+ /** Which output area this pass is responsible for. */
342
+ area: OutputArea;
343
+ /** Execute the pass. */
344
+ run(context: PipelineContext, next: PipelineNext): Promise<void>;
193
345
  }
194
346
 
195
347
  /**
@@ -198,21 +350,29 @@ interface PostprocessOptions {
198
350
  declare class Speculator {
199
351
  private readonly includeProcessor;
200
352
  private readonly formatProcessor;
353
+ private readonly formatRegistry;
354
+ private readonly processors;
201
355
  private readonly htmlRenderer;
202
- private readonly postprocessOptions;
356
+ private readonly baseConfig;
357
+ private readonly passFactory;
358
+ private readonly documentBuilder;
359
+ private readonly pipelineRunner;
360
+ private prevConfig;
203
361
  constructor(options?: SpeculatorOptions);
204
362
  /**
205
363
  * Process a single DOM element
206
364
  */
207
- processElement(element: Element): Promise<ProcessingResult>;
365
+ processElement(element: Element, tracker?: StatsTracker): Promise<ProcessingResult>;
366
+ private processNode;
208
367
  /**
209
- * Process an entire document
368
+ * Process an entire document described by a SpeculatorConfig
210
369
  */
211
- renderDocument(container: Element): Promise<ProcessingResult>;
370
+ renderDocument(spec: SpeculatorConfig, configOrOutputs?: SpeculatorConfig | OutputArea[]): Promise<RenderResult>;
371
+ renderSections(inputHtml: string): Promise<RenderResult>;
212
372
  /**
213
373
  * Process HTML string and return processed HTML
214
374
  */
215
- renderHTML(html: string): Promise<string>;
375
+ renderHTML(inputHtml: string): Promise<RenderHtmlResult>;
216
376
  }
217
377
 
218
378
  declare function createMarkdownRenderer(options?: MarkdownOptions): MarkdownIt;
@@ -222,10 +382,12 @@ declare function parseMarkdown(markdown: string, options?: MarkdownOptions, env?
222
382
  * Default file loader for Node.js environments
223
383
  */
224
384
  declare const nodeFileLoader: FileLoader;
385
+
225
386
  /**
226
387
  * Default file loader for browser environments
227
388
  */
228
389
  declare const browserFileLoader: FileLoader;
390
+
229
391
  /**
230
392
  * Creates a file loader that tries multiple loaders in sequence
231
393
  */
@@ -235,4 +397,22 @@ declare function createFallbackFileLoader(loaders: FileLoader[]): FileLoader;
235
397
  */
236
398
  declare function getDefaultFileLoader(): FileLoader;
237
399
 
238
- export { DOMHtmlRenderer, type DataFormat, type FileLoader, FormatProcessor, type HtmlRenderer, IncludeProcessor, type MarkdownOptions, type ProcessingResult, type ProcessingStats, Speculator, SpeculatorError, type SpeculatorOptions, browserFileLoader, createFallbackFileLoader, createMarkdownRenderer, getDefaultFileLoader, nodeFileLoader, parseMarkdown };
400
+ /**
401
+ * Xref resolver that queries the public ReSpec xref database.
402
+ *
403
+ * The fetch implementation is injectable to allow easy testing.
404
+ */
405
+ declare class RespecXrefResolver implements XrefResolver {
406
+ private readonly fetchFn;
407
+ private readonly endpoint;
408
+ constructor(fetchFn?: typeof fetch, endpoint?: string);
409
+ resolveBatch(queries: XrefQuery[]): Promise<Map<string, XrefResult[]>>;
410
+ }
411
+
412
+ interface FieldMapping<T> {
413
+ fields: (keyof T)[];
414
+ outputs: OutputArea[];
415
+ }
416
+ declare function getChangedOutputAreas(oldConfig: SpeculatorConfig | undefined, newConfig: SpeculatorConfig): OutputArea[];
417
+
418
+ export { DOMHtmlRenderer, type DataFormat, type ElementProcessor, type FieldMapping, type FileLoader, FormatProcessor, FormatRegistry, type FormatResult, type FormatStrategy, type HtmlRenderer, IncludeProcessor, type MarkdownOptions, type MermaidConfig, type PostProcessHook, type ProcessingResult, type ProcessingStats, type ProcessorResult, type RenderHtmlResult, type RenderResult, type RespecConfig, RespecXrefResolver, Speculator, type SpeculatorConfig, SpeculatorError, type SpeculatorOptions, StatsTracker, browserFileLoader, createFallbackFileLoader, createMarkdownRenderer, fromRespecConfig, getChangedOutputAreas, getDefaultFileLoader, nodeFileLoader, parseMarkdown };
package/dist/browser.js CHANGED
@@ -1,25 +1,35 @@
1
1
  import {
2
2
  DOMHtmlRenderer,
3
3
  FormatProcessor,
4
+ FormatRegistry,
4
5
  IncludeProcessor,
6
+ RespecXrefResolver,
5
7
  Speculator,
6
8
  SpeculatorError,
9
+ StatsTracker,
7
10
  browserFileLoader,
8
11
  createFallbackFileLoader,
9
12
  createMarkdownRenderer,
13
+ fromRespecConfig,
14
+ getChangedOutputAreas,
10
15
  getDefaultFileLoader,
11
16
  nodeFileLoader,
12
17
  parseMarkdown
13
- } from "./chunk-JAR5PGCK.js";
18
+ } from "./chunk-V4GSFQE7.js";
14
19
  export {
15
20
  DOMHtmlRenderer,
16
21
  FormatProcessor,
22
+ FormatRegistry,
17
23
  IncludeProcessor,
24
+ RespecXrefResolver,
18
25
  Speculator,
19
26
  SpeculatorError,
27
+ StatsTracker,
20
28
  browserFileLoader,
21
29
  createFallbackFileLoader,
22
30
  createMarkdownRenderer,
31
+ fromRespecConfig,
32
+ getChangedOutputAreas,
23
33
  getDefaultFileLoader,
24
34
  nodeFileLoader,
25
35
  parseMarkdown
@@ -0,0 +1,28 @@
1
+ import {
2
+ Speculator
3
+ } from "./chunk-V4GSFQE7.js";
4
+
5
+ // src/linkedom-html-renderer.ts
6
+ import { DOMParser } from "linkedom";
7
+ var LinkedomHtmlRenderer = class {
8
+ parse(html) {
9
+ const parser = new DOMParser();
10
+ const doc = parser.parseFromString(`<div>${html}</div>`, "text/html");
11
+ return doc.querySelector("div");
12
+ }
13
+ serialize(element) {
14
+ return element.innerHTML;
15
+ }
16
+ };
17
+
18
+ // src/node.ts
19
+ var Speculator2 = class extends Speculator {
20
+ constructor(options = {}) {
21
+ super({ ...options, htmlRenderer: options.htmlRenderer || new LinkedomHtmlRenderer() });
22
+ }
23
+ };
24
+
25
+ export {
26
+ LinkedomHtmlRenderer,
27
+ Speculator2 as Speculator
28
+ };