@topik/content 0.1.0-alpha.6 → 0.1.0-alpha.7

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.mts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Code, Node, Root, RootContent } from "mdast";
2
- //#region src/expressions.d.ts
3
2
  /** The deliberately small expression language accepted in authored conditionals. */
4
3
  type Expression = {
5
4
  type: "literal";
@@ -12,8 +11,6 @@ type Expression = {
12
11
  name: "equals" | "and" | "or" | "not";
13
12
  args: Expression[];
14
13
  };
15
- //#endregion
16
- //#region src/code-presentation.d.ts
17
14
  /** Bounds are independent of ordinary, unpresented code admission. */
18
15
  export declare const CODE_PRESENTATION_LIMITS: Readonly<{
19
16
  metadataLength: 16384;
@@ -42,8 +39,6 @@ interface CodePresentationEffectiveOptions extends CodePresentationOptions {
42
39
  wrap: boolean;
43
40
  }
44
41
  export declare function effectiveCodePresentationOptions(options: CodePresentationOptions): CodePresentationEffectiveOptions;
45
- //#endregion
46
- //#region src/model.d.ts
47
42
  type Scalar = string | number | boolean;
48
43
  /** Unevaluated text with an explicit distinction between literals and references. */
49
44
  type TextTemplate = {
@@ -131,8 +126,6 @@ type ParseResult = {
131
126
  diagnostics: Diagnostic[];
132
127
  source: string;
133
128
  };
134
- //#endregion
135
- //#region src/extensions/native.d.ts
136
129
  declare const nativeComponents: {
137
130
  readonly codeBlock: {
138
131
  readonly name: "codeBlock";
@@ -237,8 +230,6 @@ declare const nativeComponents: {
237
230
  readonly description: "A header cell inside a Markdown table.";
238
231
  };
239
232
  };
240
- //#endregion
241
- //#region src/registry.d.ts
242
233
  export declare const TOPIK_CONTENT_SCHEMA_VERSION = "0.2.2";
243
234
  export declare const CALLOUT_VARIANTS: readonly ["info", "tip", "warning", "danger"];
244
235
  export declare const BADGE_VARIANTS: readonly ["neutral", "info", "success", "warning", "danger"];
@@ -363,41 +354,25 @@ export declare const topikComponents: Record<keyof typeof authoredComponents | k
363
354
  type TopikComponentName = keyof typeof topikComponents;
364
355
  /** Defaults are for reading/rendering; authored absence stays unchanged. */
365
356
  export declare function getEffectiveProps(component: Pick<Component, "name" | "props">, registry?: Registry): Record<string, AuthoredAttributeValue>;
366
- //#endregion
367
- //#region src/validation.d.ts
368
357
  export declare function validateDocument(document: ContentDocument, registry?: Registry): Diagnostic[];
369
- //#endregion
370
- //#region src/document-meaning.d.ts
371
358
  /** Compare admitted authoring trees, retaining explicit heading IDs and every authored branch.
372
359
  * Source positions, cosmetic spelling and derived metadata do not affect equality.
373
360
  * This compares meaning; it does not validate arbitrary caller-constructed trees.
374
361
  */
375
362
  export declare function sameDocumentMeaning(left: ContentDocument, right: ContentDocument): boolean;
376
- //#endregion
377
- //#region src/parser.d.ts
378
363
  export declare const FORMAT_VERSION = 1;
379
- //#endregion
380
- //#region src/writer.d.ts
381
364
  export declare function writeDocument(document: ContentDocument, registry?: Registry, formatVersion?: number): string;
382
- //#endregion
383
- //#region src/markdown.d.ts
384
365
  export declare function parseDocument(source: string, registry?: Registry, formatVersion?: number): ParseResult;
385
366
  export declare function formatDocument(source: string, registry?: Registry): ParseResult & {
386
367
  formatted?: string;
387
368
  };
388
- //#endregion
389
- //#region src/assets.d.ts
390
369
  /** Rewrite asset definitions once, preserving reference identity and unrelated navigation. */
391
370
  export declare function rewriteAssets(document: ContentDocument, replace: (url: string) => string | undefined, registry?: Registry): ContentDocument;
392
- //#endregion
393
- //#region src/evaluate.d.ts
394
371
  export declare class ContentEvaluationError extends Error {
395
372
  constructor(message: string);
396
373
  }
397
374
  /** Resolve into a new, writable document; the authored branches remain untouched. */
398
375
  export declare function evaluateDocument(document: ContentDocument, context: Record<string, unknown>, registry?: Registry): ContentDocument;
399
- //#endregion
400
- //#region src/limits.d.ts
401
376
  /** Fixed admission limits, measured in UTF-16 code units and tree nodes. */
402
377
  export declare const CONTENT_LIMITS: Readonly<{
403
378
  sourceLength: 1000000;
@@ -418,8 +393,6 @@ export declare class ContentLimitError extends Error {
418
393
  readonly id = "topik-content-limit";
419
394
  constructor(message: string);
420
395
  }
421
- //#endregion
422
- //#region src/config.d.ts
423
396
  interface TopikContentConfig {
424
397
  /** Additional component schemas. Canonical Topik definitions cannot be replaced. */
425
398
  components?: Record<string, ComponentSchema>;
@@ -432,8 +405,6 @@ interface ResolvedTopikContentConfig {
432
405
  }
433
406
  /** Isolate schemas before validation; runtime variables are read without invoking accessors. */
434
407
  export declare function mergeTopikContentConfig(extension?: TopikContentConfig): ResolvedTopikContentConfig;
435
- //#endregion
436
- //#region src/asset-reference-policy.d.ts
437
408
  export declare const TOPIK_ASSET_REFERENCE_VERSION: "topik-asset-reference-v1";
438
409
  /** Public grammar descriptor. Runtime admission uses an isolated boundary. */
439
410
  export declare const TOPIK_GENERATED_ASSET_NAME_PATTERN: RegExp;
@@ -462,8 +433,6 @@ type TopikAssetReferenceValidation = {
462
433
  };
463
434
  /** Validate the URL-facing portion of topik-asset-reference-v1 without filesystem access. */
464
435
  export declare function validateTopikAssetReference(reference: string): TopikAssetReferenceValidation;
465
- //#endregion
466
- //#region src/asset-references.d.ts
467
436
  interface TopikAssetReferenceSlot {
468
437
  node: "image" | "tag" | "link";
469
438
  tag?: "figure";
@@ -536,8 +505,6 @@ export declare function extractTopikAssetOccurrences(source: string, options?: E
536
505
  export declare function removeInvalidTopikAssetReferences(document: ContentDocument, source?: string, options?: {
537
506
  config?: TopikContentConfig;
538
507
  }): void;
539
- //#endregion
540
- //#region src/content.d.ts
541
508
  type TopikContentNode = ContentDocument;
542
509
  interface ParseTopikContentOptions {
543
510
  /** @deprecated Compatibility-only; use validation/analysis options for diagnostic labels. */
@@ -548,8 +515,6 @@ interface ParseTopikContentOptions {
548
515
  }
549
516
  /** Parse the authoring tree. Use validateTopikContent at publication boundaries. */
550
517
  export declare function parseTopikContent(source: string, options?: ParseTopikContentOptions): ContentDocument;
551
- //#endregion
552
- //#region src/diagnostics.d.ts
553
518
  type TopikContentDiagnosticLevel = "debug" | "info" | "warning" | "error" | "critical";
554
519
  interface ContentValidationIssue {
555
520
  type: string;
@@ -592,16 +557,12 @@ export declare function sanitizeTopikContentDiagnostic(diagnostic: TopikContentD
592
557
  export declare function toTopikContentDiagnostic(error: ContentValidationIssue): TopikContentDiagnostic;
593
558
  /** Convert an untrusted diagnostic location to a browser-compatible safe label. */
594
559
  export declare function sanitizeTopikDiagnosticFile(file: string | undefined): string | undefined;
595
- //#endregion
596
- //#region src/source.d.ts
597
560
  interface ValidateTopikContentOptions {
598
561
  file?: string;
599
562
  config?: TopikContentConfig;
600
563
  /** Accept compiler-produced references at a compiled-output boundary. */
601
564
  allowCompiledAssetReferences?: boolean;
602
565
  }
603
- //#endregion
604
- //#region src/validate.d.ts
605
566
  interface ValidateTopikContentResult {
606
567
  source: string;
607
568
  valid: boolean;
@@ -609,8 +570,6 @@ interface ValidateTopikContentResult {
609
570
  }
610
571
  /** Source admission is the same boundary used by formatting and asset rewriting. */
611
572
  export declare function validateTopikContent(source: string, options?: ValidateTopikContentOptions): ValidateTopikContentResult;
612
- //#endregion
613
- //#region src/format.d.ts
614
573
  interface FormatTopikContentOptions extends ValidateTopikContentOptions {}
615
574
  interface FormatTopikContentSuccess {
616
575
  ok: true;
@@ -628,8 +587,6 @@ interface FormatTopikContentFailure {
628
587
  type FormatTopikContentResult = FormatTopikContentSuccess | FormatTopikContentFailure;
629
588
  /** Validate source before formatting so unsupported input remains an exact opaque handoff. */
630
589
  export declare function formatTopikContent(source: string, options?: FormatTopikContentOptions): FormatTopikContentResult;
631
- //#endregion
632
- //#region src/rewrite.d.ts
633
590
  interface RewriteTopikAssetOccurrencesOptions extends ExtractTopikAssetOccurrencesOptions, ValidateTopikContentOptions {}
634
591
  interface RewriteTopikAssetOccurrencesSuccess {
635
592
  ok: true;
@@ -647,16 +604,12 @@ interface RewriteTopikAssetOccurrencesFailure {
647
604
  }
648
605
  type RewriteTopikAssetOccurrencesResult = RewriteTopikAssetOccurrencesSuccess | RewriteTopikAssetOccurrencesFailure;
649
606
  export declare function rewriteTopikAssetOccurrences(source: string, replace: (occurrence: TopikAssetOccurrence) => string | undefined, options?: RewriteTopikAssetOccurrencesOptions): RewriteTopikAssetOccurrencesResult;
650
- //#endregion
651
- //#region src/headings.d.ts
652
607
  interface TopikHeading {
653
608
  id: string;
654
609
  level: number;
655
610
  title: string;
656
611
  }
657
612
  export declare function assignTopikHeadingIds(document: ContentDocument): TopikHeading[];
658
- //#endregion
659
- //#region src/resource-references.d.ts
660
613
  /** Version of the portable compiled-content resource reference contract. */
661
614
  export declare const TOPIK_RESOURCE_REFERENCE_VERSION: 1;
662
615
  interface TopikResourceReference {
@@ -673,8 +626,6 @@ interface TopikResourceReference {
673
626
  export declare function parseTopikResourceReference(href: string): TopikResourceReference | null;
674
627
  /** Serialize an identity as a canonical ref:// URI; this is not a browser-facing URL. */
675
628
  export declare function serializeTopikResourceReference(reference: TopikResourceReference): string;
676
- //#endregion
677
- //#region src/navigation-rewrite.d.ts
678
629
  interface TopikNavigationReference {
679
630
  href: string;
680
631
  kind: "link" | "card";
@@ -694,8 +645,6 @@ type RewriteTopikNavigationResult = {
694
645
  };
695
646
  /** Rewrite actual navigation references, retaining definitions/scopes and every authored branch. */
696
647
  export declare function rewriteTopikNavigationReferences(source: string, replace: (reference: TopikNavigationReference) => string | undefined, options?: ValidateTopikContentOptions): RewriteTopikNavigationResult;
697
- //#endregion
698
- //#region src/links.d.ts
699
648
  type ValidationError = {
700
649
  id: string;
701
650
  level: "error";
@@ -728,8 +677,6 @@ export declare function validateTopikBrowserHref(value: unknown): ValidationErro
728
677
  export declare function validateTopikNavigationHref(value: unknown): ValidationError[];
729
678
  /** Remove invalid navigation attributes before a renderer can emit a browser-facing URL. */
730
679
  export declare function removeInvalidTopikNavigationReferences(root: ContentDocument): void;
731
- //#endregion
732
- //#region src/render.d.ts
733
680
  /** Framework-independent, serializable output. It contains no executable values. */
734
681
  type RenderableTreeNode = ContentTag | string | number | boolean | null | RenderableTreeNode[];
735
682
  export declare class ContentTag {
@@ -742,8 +689,6 @@ export declare class ContentTag {
742
689
  export declare function isContentTag(value: unknown): value is ContentTag;
743
690
  /** Render a validated authored document through a separate evaluated document. */
744
691
  export declare function transformTopikContent(document: ContentDocument, options?: TopikContentConfig): RenderableTreeNode;
745
- //#endregion
746
- //#region src/compiled.d.ts
747
692
  interface CompiledTopikContent {
748
693
  sourceFormat: "topik";
749
694
  topikSchemaVersion: string;
@@ -752,8 +697,6 @@ interface CompiledTopikContent {
752
697
  renderableTree: RenderableTreeNode;
753
698
  diagnostics: TopikContentDiagnostic[];
754
699
  }
755
- //#endregion
756
- //#region src/compile.d.ts
757
700
  interface CompileTopikContentOptions {
758
701
  file?: string;
759
702
  config?: TopikContentConfig;
@@ -775,9 +718,6 @@ interface CompileTopikContentFailure {
775
718
  type CompileTopikContentResult = CompileTopikContentSuccess | CompileTopikContentFailure;
776
719
  /** Admit source once, including compiled asset references, and produce a reader tree. */
777
720
  export declare function compileTopikContent(source: string, options?: CompileTopikContentOptions): CompileTopikContentResult;
778
- //#endregion
779
- //#region src/index.d.ts
780
721
  export type TopikComponentKind = "block" | "inline";
781
722
  export type TopikAttributeType = "string" | "number" | "boolean" | "enum";
782
- //#endregion
783
723
  export type { AnalyzeTopikContentOptions, AnalyzeTopikContentResult, AttributeDefinition, AuthoredAttributeValue, Branch, ChildConstraint, CodeLineSelection, CodePresentation, CodePresentationEffectiveOptions, CodePresentationOptions, CodeTemplate, CompileTopikContentFailure, CompileTopikContentOptions, CompileTopikContentResult, CompileTopikContentSuccess, CompiledTopikContent, Component, ComponentDefinition, ComponentSchema, Conditional, ContentDocument, Diagnostic, Expression, ExtractTopikAssetOccurrencesOptions, FormatTopikContentFailure, FormatTopikContentOptions, FormatTopikContentResult, FormatTopikContentSuccess, ParseResult, ParseTopikContentOptions, Registry, RenderableTreeNode, ResolvedTopikContentConfig, RewriteTopikAssetOccurrencesFailure, RewriteTopikAssetOccurrencesOptions, RewriteTopikAssetOccurrencesResult, RewriteTopikAssetOccurrencesSuccess, RewriteTopikNavigationResult, Scalar, TextTemplate, TopikAnalyzedHeading, TopikAssetOccurrence, TopikAssetOccurrenceKind, TopikAssetOccurrenceSemantics, TopikAssetReferenceDefinition, TopikAssetReferenceRole, TopikAssetReferenceSlot, TopikAssetReferenceValidation, TopikComponentAttributeDefinition, TopikComponentDefinition, TopikComponentName, TopikContentConfig, TopikContentDiagnostic, TopikContentDiagnosticLevel, TopikContentLink, TopikContentLinkKind, TopikContentNode, TopikGeneratedAssetName, TopikHeading, TopikNavigationReference, TopikResourceReference, ValidateTopikContentOptions, ValidateTopikContentResult, Variable };
package/dist/index.mjs CHANGED
@@ -13,7 +13,7 @@ import { gfmTableFromMarkdown, gfmTableToMarkdown } from "mdast-util-gfm-table";
13
13
  import { gfmTaskListItemFromMarkdown, gfmTaskListItemToMarkdown } from "mdast-util-gfm-task-list-item";
14
14
  import { defaultHandlers, toMarkdown } from "mdast-util-to-markdown";
15
15
  import GithubSlugger from "github-slugger";
16
- //#region src/extensions/accordion.ts
16
+ // src/extensions/accordion.ts
17
17
  const accordionDefinition = {
18
18
  kind: "block",
19
19
  render: "TopikAccordion",
@@ -31,8 +31,7 @@ const accordionDefinition = {
31
31
  },
32
32
  children: "blocks"
33
33
  };
34
- //#endregion
35
- //#region src/extensions/badge.ts
34
+ // src/extensions/badge.ts
36
35
  const badgeDefinition = {
37
36
  kind: "inline",
38
37
  render: "TopikBadge",
@@ -51,8 +50,7 @@ const badgeDefinition = {
51
50
  } },
52
51
  children: "inline"
53
52
  };
54
- //#endregion
55
- //#region src/extensions/callout.ts
53
+ // src/extensions/callout.ts
56
54
  const calloutDefinition = {
57
55
  kind: "block",
58
56
  render: "TopikCallout",
@@ -72,8 +70,7 @@ const calloutDefinition = {
72
70
  },
73
71
  children: "blocks"
74
72
  };
75
- //#endregion
76
- //#region src/extensions/cards.ts
73
+ // src/extensions/cards.ts
77
74
  const cardGridDefinition = {
78
75
  kind: "block",
79
76
  render: "TopikCardGrid",
@@ -109,8 +106,7 @@ const cardDefinition = {
109
106
  children: "blocks",
110
107
  selfClosing: true
111
108
  };
112
- //#endregion
113
- //#region src/extensions/code.ts
109
+ // src/extensions/code.ts
114
110
  const codeGroupDefinition = {
115
111
  kind: "block",
116
112
  render: "TopikCodeGroup",
@@ -146,8 +142,7 @@ const codeTabDefinition = {
146
142
  },
147
143
  allowedParents: ["codeGroup"]
148
144
  };
149
- //#endregion
150
- //#region src/extensions/figure.ts
145
+ // src/extensions/figure.ts
151
146
  const figureDefinition = {
152
147
  kind: "block",
153
148
  render: "TopikFigure",
@@ -184,8 +179,7 @@ const figureDefinition = {
184
179
  },
185
180
  children: "none"
186
181
  };
187
- //#endregion
188
- //#region src/extensions/math.ts
182
+ // src/extensions/math.ts
189
183
  const mathDefinition = {
190
184
  kind: "block",
191
185
  render: "TopikMath",
@@ -210,8 +204,7 @@ const mathInlineDefinition = {
210
204
  } },
211
205
  children: "none"
212
206
  };
213
- //#endregion
214
- //#region src/extensions/native.ts
207
+ // src/extensions/native.ts
215
208
  const nativeComponents = {
216
209
  codeBlock: {
217
210
  name: "codeBlock",
@@ -312,8 +305,7 @@ const nativeComponents = {
312
305
  description: "A header cell inside a Markdown table."
313
306
  }
314
307
  };
315
- //#endregion
316
- //#region src/extensions/quiz.ts
308
+ // src/extensions/quiz.ts
317
309
  const quizDefinition = {
318
310
  kind: "block",
319
311
  render: "TopikQuiz",
@@ -376,8 +368,7 @@ const explanationDefinition = {
376
368
  children: "blocks",
377
369
  allowedParents: ["question"]
378
370
  };
379
- //#endregion
380
- //#region src/extensions/steps.ts
371
+ // src/extensions/steps.ts
381
372
  const stepsDefinition = {
382
373
  kind: "block",
383
374
  render: "TopikSteps",
@@ -399,8 +390,7 @@ const stepDefinition = {
399
390
  children: "blocks",
400
391
  allowedParents: ["steps"]
401
392
  };
402
- //#endregion
403
- //#region src/extensions/tabs.ts
393
+ // src/extensions/tabs.ts
404
394
  const tabsDefinition = {
405
395
  kind: "block",
406
396
  render: "TopikTabs",
@@ -423,8 +413,7 @@ const tabDefinition = {
423
413
  children: "blocks",
424
414
  allowedParents: ["tabs"]
425
415
  };
426
- //#endregion
427
- //#region src/extensions/underline.ts
416
+ // src/extensions/underline.ts
428
417
  const underlineDefinition = {
429
418
  kind: "inline",
430
419
  render: "TopikUnderline",
@@ -432,8 +421,7 @@ const underlineDefinition = {
432
421
  attributes: {},
433
422
  children: "inline"
434
423
  };
435
- //#endregion
436
- //#region src/registry.ts
424
+ // src/registry.ts
437
425
  const TOPIK_CONTENT_SCHEMA_VERSION = "0.2.2";
438
426
  const CALLOUT_VARIANTS = [
439
427
  "info",
@@ -537,8 +525,7 @@ function getEffectiveProps(component, registry = components) {
537
525
  ...component.props
538
526
  };
539
527
  }
540
- //#endregion
541
- //#region src/limits.ts
528
+ // src/limits.ts
542
529
  /** Fixed admission limits, measured in UTF-16 code units and tree nodes. */
543
530
  const CONTENT_LIMITS = Object.freeze({
544
531
  sourceLength: 1e6,
@@ -671,8 +658,7 @@ function assertDataLimits(root, options = {}) {
671
658
  }
672
659
  }
673
660
  }
674
- //#endregion
675
- //#region src/expressions.ts
661
+ // src/expressions.ts
676
662
  const identifier = /^[A-Za-z_][A-Za-z0-9_]*/;
677
663
  const number = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?/;
678
664
  const unsafeKeys$1 = /* @__PURE__ */ new Set([
@@ -823,8 +809,7 @@ function writeExpression(expression) {
823
809
  if (result.length > CONTENT_LIMITS.expressionLength) throw new ContentLimitError(`Content exceeds the expression length limit of ${CONTENT_LIMITS.expressionLength}`);
824
810
  return result;
825
811
  }
826
- //#endregion
827
- //#region src/node-grammar.ts
812
+ // src/node-grammar.ts
828
813
  const blockTypes = /* @__PURE__ */ new Set([
829
814
  "paragraph",
830
815
  "heading",
@@ -887,8 +872,7 @@ function isContentKind(node, kind, registry) {
887
872
  function isInlineParent(node, registry) {
888
873
  return inlineParentTypes.has(node.type) || node.type === "topikComponent" && isContentKind(node, "inline", registry);
889
874
  }
890
- //#endregion
891
- //#region src/node-validation.ts
875
+ // src/node-validation.ts
892
876
  function record(value) {
893
877
  return value !== null && typeof value === "object" && !Array.isArray(value);
894
878
  }
@@ -1053,8 +1037,7 @@ function nodeShapeProblem(value, registry) {
1053
1037
  ].includes(node.referenceType)) return "References require a supported reference type";
1054
1038
  }
1055
1039
  }
1056
- //#endregion
1057
- //#region src/code-presentation.ts
1040
+ // src/code-presentation.ts
1058
1041
  /** Bounds are independent of ordinary, unpresented code admission. */
1059
1042
  const CODE_PRESENTATION_LIMITS = Object.freeze({
1060
1043
  metadataLength: 16384,
@@ -1500,8 +1483,7 @@ function codePresentationProblem(node, seen = /* @__PURE__ */ new Set()) {
1500
1483
  throw error;
1501
1484
  }
1502
1485
  }
1503
- //#endregion
1504
- //#region src/presentation-output.ts
1486
+ // src/presentation-output.ts
1505
1487
  /**
1506
1488
  * Reserve a conservative serialization budget before allocating reader rows.
1507
1489
  * Each text unit can expand to six HTML units; each row reserves 768 units for
@@ -1533,8 +1515,7 @@ function assertCodePresentationOutputLimit(document) {
1533
1515
  for (const child of node.children ?? []) stack.push(child);
1534
1516
  }
1535
1517
  }
1536
- //#endregion
1537
- //#region src/document-index.ts
1518
+ // src/document-index.ts
1538
1519
  function referenceIdentifier(identifier) {
1539
1520
  return identifier.replace(/[\t\n\r ]+/gu, " ").replace(/^ | $/gu, "").toLowerCase().toUpperCase().toLowerCase();
1540
1521
  }
@@ -1598,8 +1579,7 @@ function materializeReferences(document, index = indexDocument(document)) {
1598
1579
  delete resource.referenceType;
1599
1580
  }
1600
1581
  }
1601
- //#endregion
1602
- //#region src/validation.ts
1582
+ // src/validation.ts
1603
1583
  function issue(id, message) {
1604
1584
  return {
1605
1585
  id,
@@ -1839,8 +1819,7 @@ function validateDocumentWithIndex(document, registry) {
1839
1819
  index
1840
1820
  };
1841
1821
  }
1842
- //#endregion
1843
- //#region src/document-meaning.ts
1822
+ // src/document-meaning.ts
1844
1823
  /** Compare admitted authoring trees, retaining explicit heading IDs and every authored branch.
1845
1824
  * Source positions, cosmetic spelling and derived metadata do not affect equality.
1846
1825
  * This compares meaning; it does not validate arbitrary caller-constructed trees.
@@ -1925,8 +1904,7 @@ function equal(left, right) {
1925
1904
  const keys = Object.keys(a);
1926
1905
  return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && equal(a[key], b[key]));
1927
1906
  }
1928
- //#endregion
1929
- //#region src/tag-options.ts
1907
+ // src/tag-options.ts
1930
1908
  /** Parser and writer share the exact registry attribute admission. */
1931
1909
  function tagOptions(registry) {
1932
1910
  return {
@@ -1934,8 +1912,7 @@ function tagOptions(registry) {
1934
1912
  escapedWhitespace: Object.fromEntries(Object.entries(registry).map(([name, definition]) => [name, Object.entries(definition.attributes).filter(([, attribute]) => attribute.type === "string" && attribute.escapedWhitespace).map(([key]) => key)]))
1935
1913
  };
1936
1914
  }
1937
- //#endregion
1938
- //#region src/gfm.ts
1915
+ // src/gfm.ts
1939
1916
  function gfmSyntax() {
1940
1917
  return [
1941
1918
  gfmFootnote(),
@@ -1960,8 +1937,7 @@ function gfmToMarkdown() {
1960
1937
  gfmTaskListItemToMarkdown()
1961
1938
  ] };
1962
1939
  }
1963
- //#endregion
1964
- //#region src/heading-ids.ts
1940
+ // src/heading-ids.ts
1965
1941
  const validId = /^[A-Za-z0-9_.:-]+$/;
1966
1942
  /** An independent inline construct, claimed before generic tag tokenization. */
1967
1943
  function headingIdSyntax() {
@@ -2075,8 +2051,7 @@ function headingIdToMarkdown() {
2075
2051
  }
2076
2052
  } };
2077
2053
  }
2078
- //#endregion
2079
- //#region src/reference-source.ts
2054
+ // src/reference-source.ts
2080
2055
  const references = /* @__PURE__ */ new WeakMap();
2081
2056
  function referenceSourceExtension() {
2082
2057
  return { enter: {
@@ -2131,8 +2106,7 @@ function createReferenceSourceLookup(source, reparse) {
2131
2106
  return match?.url === node.url ? match.reference : "";
2132
2107
  };
2133
2108
  }
2134
- //#endregion
2135
- //#region src/parser-limits.ts
2109
+ // src/parser-limits.ts
2136
2110
  /** Refuse expensive syntax before micromark resolves containers and inline delimiters. */
2137
2111
  function parserLimitSyntax(source) {
2138
2112
  let steps = 0;
@@ -2182,8 +2156,7 @@ function parserLimitSyntax(source) {
2182
2156
  }
2183
2157
  };
2184
2158
  }
2185
- //#endregion
2186
- //#region src/line-endings.ts
2159
+ // src/line-endings.ts
2187
2160
  /** Normalize source syntax, leaving entity-decoded characters and original locations distinct. */
2188
2161
  function normalizeLineEndings(source) {
2189
2162
  const crlfOffsets = [];
@@ -2221,8 +2194,7 @@ function normalizeLineEndings(source) {
2221
2194
  restorePositions
2222
2195
  };
2223
2196
  }
2224
- //#endregion
2225
- //#region src/parser.ts
2197
+ // src/parser.ts
2226
2198
  function declarations(registry) {
2227
2199
  return Object.fromEntries(Object.entries(registry).map(([name, definition]) => [name, { kind: definition.kind }]));
2228
2200
  }
@@ -2420,8 +2392,7 @@ function normalizeTables(root, remainingNodes) {
2420
2392
  }
2421
2393
  walk(root);
2422
2394
  }
2423
- //#endregion
2424
- //#region src/markdown-marks.ts
2395
+ // src/markdown-marks.ts
2425
2396
  /** Choose delimiters before writing so handlers and their lookahead agree. */
2426
2397
  function markWriterExtension(root) {
2427
2398
  const markers = /* @__PURE__ */ new WeakMap();
@@ -2469,12 +2440,10 @@ function markWriterExtension(root) {
2469
2440
  strong: handler("strong")
2470
2441
  } };
2471
2442
  }
2472
- //#endregion
2473
- //#region src/reference-writer.ts
2443
+ // src/reference-writer.ts
2474
2444
  /** Escapes and entities are part of reference identity, not decoded Markdown text. */
2475
- function referenceLabel(node, state) {
2476
- const value = referenceSourceLabel(node);
2477
- return state.stack.includes("tableCell") ? value.replaceAll("|", "\\|") : value;
2445
+ function referenceLabel(node) {
2446
+ return referenceSourceLabel(node);
2478
2447
  }
2479
2448
  function referenceWriterExtension() {
2480
2449
  const reference = (untyped, _parent, state, info) => {
@@ -2488,9 +2457,9 @@ function referenceWriterExtension() {
2488
2457
  after: "]",
2489
2458
  ...tracker.current()
2490
2459
  };
2491
- const text = node.type === "imageReference" ? state.safe(node.alt ?? "", context) : state.containerPhrasing(node, context);
2460
+ const text = node.type === "imageReference" ? state.safe(node.alt ?? "", context).replaceAll("\n", "&#xa;") : state.containerPhrasing(node, context);
2492
2461
  labelExit();
2493
- const label = referenceLabel(node, state);
2462
+ const label = referenceLabel(node);
2494
2463
  exit();
2495
2464
  return `${prefix}${text}]${node.referenceType === "full" || !text || text !== label ? `[${label}]` : node.referenceType === "collapsed" ? "[]" : ""}`;
2496
2465
  };
@@ -2499,8 +2468,7 @@ function referenceWriterExtension() {
2499
2468
  imageReference: Object.assign(reference.bind(null), { peek: () => "!" })
2500
2469
  } };
2501
2470
  }
2502
- //#endregion
2503
- //#region src/resource-writer.ts
2471
+ // src/resource-writer.ts
2504
2472
  const entity = /&(?:#(?:\d{1,7}|x[\da-f]{1,6})|[\da-z]{1,31});/giu;
2505
2473
  /** Escape Markdown syntax, without changing the spelling of ordinary URL bytes. */
2506
2474
  function destination(url, state) {
@@ -2556,7 +2524,7 @@ function resourceWriterExtension() {
2556
2524
  ...info,
2557
2525
  before: "![",
2558
2526
  after: "]"
2559
- });
2527
+ }).replaceAll("\n", "&#xa;");
2560
2528
  labelExit();
2561
2529
  const result = `![${alt}](${destination(node.url, state)}${title(node.title, state)})`;
2562
2530
  exit();
@@ -2565,7 +2533,7 @@ function resourceWriterExtension() {
2565
2533
  const definition = (untyped, _parent, state) => {
2566
2534
  const node = untyped;
2567
2535
  const exit = state.enter("definition");
2568
- const result = `[${referenceLabel(node, state)}]: ${destination(node.url, state)}${title(node.title, state)}`;
2536
+ const result = `[${referenceLabel(node)}]: ${destination(node.url, state)}${title(node.title, state)}`;
2569
2537
  exit();
2570
2538
  return result;
2571
2539
  };
@@ -2577,8 +2545,7 @@ function resourceWriterExtension() {
2577
2545
  definition
2578
2546
  } };
2579
2547
  }
2580
- //#endregion
2581
- //#region src/whitespace-writer.ts
2548
+ // src/whitespace-writer.ts
2582
2549
  function boundaryWhitespaceWriterExtension() {
2583
2550
  return { handlers: { text(node, parent, state, info) {
2584
2551
  if (parent?.type !== "delete" && parent?.type !== "tableCell" && !node.value.includes("\n")) return defaultHandlers.text(node, parent, state, info);
@@ -2606,8 +2573,7 @@ function boundaryWhitespaceWriterExtension() {
2606
2573
  })).join("&#xa;") + after;
2607
2574
  } } };
2608
2575
  }
2609
- //#endregion
2610
- //#region src/code-writer.ts
2576
+ // src/code-writer.ts
2611
2577
  /*!
2612
2578
  * @license MIT
2613
2579
  * Header escaping follows mdast-util-to-markdown's safe utility, with linear
@@ -2737,8 +2703,7 @@ function codeWriterExtension() {
2737
2703
  }
2738
2704
  } } };
2739
2705
  }
2740
- //#endregion
2741
- //#region src/code-presentation-writer.ts
2706
+ // src/code-presentation-writer.ts
2742
2707
  /** Header source has already been encoded for exactly one CommonMark decoding pass. */
2743
2708
  function codePresentationWriterExtension() {
2744
2709
  return { handlers: { topikCodePresentation(node) {
@@ -2759,8 +2724,7 @@ function codePresentationWriterExtension() {
2759
2724
  return scope;
2760
2725
  } } };
2761
2726
  }
2762
- //#endregion
2763
- //#region src/writer.ts
2727
+ // src/writer.ts
2764
2728
  /**
2765
2729
  * Count payload deltas from an empty-template/code skeleton. A cheap source
2766
2730
  * floor refuses obvious overflows before cloning or baseline serialization;
@@ -2999,8 +2963,7 @@ function writeMarkdown(tree, registry) {
2999
2963
  fences: true
3000
2964
  });
3001
2965
  }
3002
- //#endregion
3003
- //#region src/markdown.ts
2966
+ // src/markdown.ts
3004
2967
  function parseDocument(source, registry = components, formatVersion = 1) {
3005
2968
  const result = parseDocumentTree(source, registry, formatVersion);
3006
2969
  return result.document && result.diagnostics.length === 0 ? {
@@ -3032,8 +2995,7 @@ function formatDocument(source, registry = components) {
3032
2995
  };
3033
2996
  }
3034
2997
  }
3035
- //#endregion
3036
- //#region src/assets.ts
2998
+ // src/assets.ts
3037
2999
  /** Rewrite asset definitions once, preserving reference identity and unrelated navigation. */
3038
3000
  function rewriteAssets(document, replace, registry = components) {
3039
3001
  const inputErrors = validateDocument(document, registry);
@@ -3066,8 +3028,7 @@ function rewriteAssets(document, replace, registry = components) {
3066
3028
  if (errors.length) throw new Error(errors.map((error) => error.message).join("; "));
3067
3029
  return cloned;
3068
3030
  }
3069
- //#endregion
3070
- //#region src/traversal.ts
3031
+ // src/traversal.ts
3071
3032
  function walkContent(node, visit, path = []) {
3072
3033
  assertDataLimits(node, { plain: true });
3073
3034
  assertTreeLimits(node);
@@ -3083,8 +3044,7 @@ function plainText(node) {
3083
3044
  if (node.type === "break") return "\n";
3084
3045
  return (node.children ?? []).map(plainText).join("");
3085
3046
  }
3086
- //#endregion
3087
- //#region src/headings.ts
3047
+ // src/headings.ts
3088
3048
  function assignTopikHeadingIds(document) {
3089
3049
  const headings = [];
3090
3050
  walkContent(document, (node) => {
@@ -3114,8 +3074,7 @@ function assignHeadingIds(headings) {
3114
3074
  };
3115
3075
  });
3116
3076
  }
3117
- //#endregion
3118
- //#region src/evaluate.ts
3077
+ // src/evaluate.ts
3119
3078
  var ContentEvaluationError = class extends Error {
3120
3079
  constructor(message) {
3121
3080
  super(message);
@@ -3341,8 +3300,7 @@ function resolveDocument(document, context, registry, includeHeadingIds) {
3341
3300
  }
3342
3301
  return resolved;
3343
3302
  }
3344
- //#endregion
3345
- //#region src/config.ts
3303
+ // src/config.ts
3346
3304
  function plainObject(value) {
3347
3305
  return value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
3348
3306
  }
@@ -3463,16 +3421,14 @@ function mergeTopikContentConfig(extension = {}) {
3463
3421
  variables: cloneSchema(variables)
3464
3422
  };
3465
3423
  }
3466
- //#endregion
3467
- //#region src/content.ts
3424
+ // src/content.ts
3468
3425
  /** Parse the authoring tree. Use validateTopikContent at publication boundaries. */
3469
3426
  function parseTopikContent(source, options = {}) {
3470
3427
  const result = parseDocumentTree(source, mergeTopikContentConfig(options.config).components);
3471
3428
  if (!result.document) throw new Error("Content could not be parsed");
3472
3429
  return result.document;
3473
3430
  }
3474
- //#endregion
3475
- //#region src/asset-reference-policy.ts
3431
+ // src/asset-reference-policy.ts
3476
3432
  const TOPIK_ASSET_REFERENCE_VERSION = "topik-asset-reference-v1";
3477
3433
  const TOPIK_GENERATED_ASSET_NAME_VALIDATOR = /^auto-v1-[a-z2-7]{51}[aq]$/u;
3478
3434
  /** Public grammar descriptor. Runtime admission uses an isolated boundary. */
@@ -3603,8 +3559,7 @@ function containsNonAscii(value) {
3603
3559
  for (const character of value) if ((character.codePointAt(0) ?? 0) > 127) return true;
3604
3560
  return false;
3605
3561
  }
3606
- //#endregion
3607
- //#region src/resource-references.ts
3562
+ // src/resource-references.ts
3608
3563
  /** Version of the portable compiled-content resource reference contract. */
3609
3564
  const TOPIK_RESOURCE_REFERENCE_VERSION = 1;
3610
3565
  const RESOURCE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
@@ -3637,8 +3592,7 @@ function serializeTopikResourceReference(reference) {
3637
3592
  if (!parsed) throw new TypeError("Resource reference is not valid");
3638
3593
  return `ref://${kind}/${parsed.name}${parsed.search}${parsed.hash ? `#${parsed.hash}` : ""}`;
3639
3594
  }
3640
- //#endregion
3641
- //#region src/diagnostics.ts
3595
+ // src/diagnostics.ts
3642
3596
  const TOPIK_LINK_DIAGNOSTIC_MESSAGES = {
3643
3597
  "link-asset-invalid": "Asset link target is not a canonical generated name.",
3644
3598
  "link-asset-navigation-unsupported": "Navigation targets cannot use generated Asset names.",
@@ -3831,8 +3785,7 @@ function safeDiagnosticBasename(file) {
3831
3785
  function isSafeRelativeDiagnosticLabel(value) {
3832
3786
  return /^(?!\.\.?$)[a-z0-9._-]+(?:[\\/][a-z0-9._-]+)*$/iu.test(value);
3833
3787
  }
3834
- //#endregion
3835
- //#region src/links.ts
3788
+ // src/links.ts
3836
3789
  const ALLOWED_SCHEMES = /* @__PURE__ */ new Set([
3837
3790
  "asset",
3838
3791
  "http",
@@ -3964,8 +3917,7 @@ function isNetworkPathReference(value) {
3964
3917
  const isPathSeparator = (character) => character === "/" || character === "\\";
3965
3918
  return isPathSeparator(value[0]) && isPathSeparator(value[1]);
3966
3919
  }
3967
- //#endregion
3968
- //#region src/asset-references.ts
3920
+ // src/asset-references.ts
3969
3921
  /**
3970
3922
  * Closed registry for topik-asset-reference-v1. Extractors never infer a slot from an
3971
3923
  * attribute name and never recursively inspect arbitrary strings.
@@ -4145,8 +4097,7 @@ function removeInvalidTopikAssetReferences(document, source, options = {}) {
4145
4097
  }
4146
4098
  sanitize(document);
4147
4099
  }
4148
- //#endregion
4149
- //#region src/custom-assets.ts
4100
+ // src/custom-assets.ts
4150
4101
  /** Custom assets share URL admission, but do not extend the compiler's closed slot protocol. */
4151
4102
  function validateCustomAssetReferences(document, registry, allowCompiled, index = indexDocument(document)) {
4152
4103
  const issues = [];
@@ -4173,8 +4124,7 @@ function validateCustomAssetReferences(document, registry, allowCompiled, index
4173
4124
  }
4174
4125
  return issues;
4175
4126
  }
4176
- //#endregion
4177
- //#region src/source.ts
4127
+ // src/source.ts
4178
4128
  function writeFailure(source, file) {
4179
4129
  return {
4180
4130
  ok: false,
@@ -4256,8 +4206,7 @@ function prepareSource(source, options = {}) {
4256
4206
  }
4257
4207
  return failure();
4258
4208
  }
4259
- //#endregion
4260
- //#region src/validate.ts
4209
+ // src/validate.ts
4261
4210
  /** Source admission is the same boundary used by formatting and asset rewriting. */
4262
4211
  function validateTopikContent(source, options = {}) {
4263
4212
  const result = prepareSource(source, options);
@@ -4267,8 +4216,7 @@ function validateTopikContent(source, options = {}) {
4267
4216
  errors: result.diagnostics
4268
4217
  };
4269
4218
  }
4270
- //#endregion
4271
- //#region src/format.ts
4219
+ // src/format.ts
4272
4220
  /** Validate source before formatting so unsupported input remains an exact opaque handoff. */
4273
4221
  function formatTopikContent(source, options = {}) {
4274
4222
  const prepared = prepareSource(source, options);
@@ -4296,8 +4244,7 @@ function formatTopikContent(source, options = {}) {
4296
4244
  formatted
4297
4245
  };
4298
4246
  }
4299
- //#endregion
4300
- //#region src/rewrite.ts
4247
+ // src/rewrite.ts
4301
4248
  function rewriteTopikAssetOccurrences(source, replace, options = {}) {
4302
4249
  const prepared = prepareSource(source, options);
4303
4250
  if (!prepared.ok) return prepared;
@@ -4326,8 +4273,7 @@ function rewriteTopikAssetOccurrences(source, replace, options = {}) {
4326
4273
  content
4327
4274
  };
4328
4275
  }
4329
- //#endregion
4330
- //#region src/navigation-rewrite.ts
4276
+ // src/navigation-rewrite.ts
4331
4277
  /** Rewrite actual navigation references, retaining definitions/scopes and every authored branch. */
4332
4278
  function rewriteTopikNavigationReferences(source, replace, options = {}) {
4333
4279
  const prepared = prepareSource(source, options);
@@ -4372,7 +4318,7 @@ function rewriteTopikNavigationReferences(source, replace, options = {}) {
4372
4318
  else node.url = replacement;
4373
4319
  let content;
4374
4320
  try {
4375
- content = writeDocument(prepared.document, prepared.config.components);
4321
+ content = serializeDocument(prepared.document, prepared.config.components);
4376
4322
  } catch {
4377
4323
  return writeFailure(source, options.file);
4378
4324
  }
@@ -4388,8 +4334,7 @@ function rewriteTopikNavigationReferences(source, replace, options = {}) {
4388
4334
  diagnostics: []
4389
4335
  };
4390
4336
  }
4391
- //#endregion
4392
- //#region src/render.ts
4337
+ // src/render.ts
4393
4338
  var ContentTag = class {
4394
4339
  name;
4395
4340
  attributes;
@@ -4486,8 +4431,7 @@ function transformDocument(document, config) {
4486
4431
  }
4487
4432
  return render(resolved);
4488
4433
  }
4489
- //#endregion
4490
- //#region src/compile.ts
4434
+ // src/compile.ts
4491
4435
  /** Admit source once, including compiled asset references, and produce a reader tree. */
4492
4436
  function compileTopikContent(source, options = {}) {
4493
4437
  const prepared = prepareSource(source, {
@@ -4525,5 +4469,4 @@ function compileTopikContent(source, options = {}) {
4525
4469
  };
4526
4470
  }
4527
4471
  }
4528
- //#endregion
4529
4472
  export { BADGE_VARIANTS, CALLOUT_VARIANTS, CODE_PRESENTATION_LIMITS, CONTENT_LIMITS, ContentEvaluationError, ContentLimitError, ContentTag, FORMAT_VERSION, QUIZ_QUESTION_TYPES, TOPIK_ASSET_REFERENCE_VERSION, TOPIK_CONTENT_SCHEMA_VERSION, TOPIK_GENERATED_ASSET_NAME_PATTERN, TOPIK_RESOURCE_REFERENCE_VERSION, analyzeTopikContent, assignTopikHeadingIds, compileTopikContent, components, effectiveCodePresentationOptions, evaluateDocument, extractTopikAssetOccurrences, formatDocument, formatTopikContent, getEffectiveProps, isContentTag, isTopikGeneratedAssetName, mergeTopikContentConfig, parseDocument, parseTopikContent, parseTopikGeneratedAssetName, parseTopikResourceReference, removeInvalidTopikAssetReferences, removeInvalidTopikNavigationReferences, rewriteAssets, rewriteTopikAssetOccurrences, rewriteTopikNavigationReferences, sameDocumentMeaning, sanitizeTopikContentDiagnostic, sanitizeTopikDiagnosticFile, serializeTopikResourceReference, toTopikContentDiagnostic, topikAssetReferenceSlots, topikComponents, topikLinkDiagnosticMessage, transformTopikContent, validateDocument, validateTopikAssetReference, validateTopikBrowserHref, validateTopikContent, validateTopikHref, validateTopikNavigationHref, writeDocument };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topik/content",
3
- "version": "0.1.0-alpha.6",
3
+ "version": "0.1.0-alpha.7",
4
4
  "description": "Declarative Topik content model, Markdown format, validation and rendering",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -20,37 +20,37 @@
20
20
  "access": "public"
21
21
  },
22
22
  "dependencies": {
23
+ "@topik/remark-tags": "0.1.0-alpha.7",
23
24
  "@types/mdast": "^4.0.4",
24
25
  "@types/unist": "^3.0.3",
25
26
  "github-slugger": "^2.0.0",
26
27
  "mdast-util-from-markdown": "^2.1.0",
27
28
  "mdast-util-frontmatter": "^2.0.1",
28
29
  "mdast-util-gfm-footnote": "^2.1.0",
29
- "mdast-util-gfm-strikethrough": "^2.0.0",
30
+ "mdast-util-gfm-strikethrough": "^2.0.1",
30
31
  "mdast-util-gfm-table": "^2.0.0",
31
32
  "mdast-util-gfm-task-list-item": "^2.0.0",
32
- "mdast-util-to-markdown": "^2.1.2",
33
+ "mdast-util-to-markdown": "^2.2.1",
33
34
  "micromark-extension-frontmatter": "^2.0.0",
34
35
  "micromark-extension-gfm-footnote": "^2.1.0",
35
36
  "micromark-extension-gfm-strikethrough": "^2.1.0",
36
37
  "micromark-extension-gfm-table": "^2.1.2",
37
38
  "micromark-extension-gfm-task-list-item": "^2.1.0",
38
- "micromark-util-decode-string": "^2.0.1",
39
- "@topik/remark-tags": "0.1.0-alpha.6"
39
+ "micromark-util-decode-string": "^2.0.1"
40
40
  },
41
41
  "devDependencies": {
42
- "@types/node": "22.20.4",
43
- "@vitest/coverage-v8": "5.0.4",
44
- "micromark-util-types": "^2.0.2",
42
+ "@types/node": "22.20.5",
43
+ "@vitest/coverage-v8": "5.0.5",
44
+ "micromark-util-types": "^2.0.3",
45
45
  "typescript": "^7.0.2",
46
- "vite": "npm:@voidzero-dev/vite-plus-core@1.2.0",
47
- "vite-plus": "1.2.0",
48
- "vitest": "5.0.4"
46
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.4.0",
47
+ "vite-plus": "1.4.0",
48
+ "vitest": "5.0.5"
49
49
  },
50
50
  "devEngines": {
51
51
  "runtime": {
52
52
  "name": "node",
53
- "version": "^22.18.0 || ^24.11.0 || >=26.0.0"
53
+ "version": "^22.23.4 || ^24.11.0 || >=26.0.0"
54
54
  }
55
55
  },
56
56
  "engines": {