@agentshouse/mdmodel 0.1.0-alpha.13 → 0.1.0-alpha.15

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.
Files changed (41) hide show
  1. package/README.md +42 -2
  2. package/dist/definition.d.ts +1 -1
  3. package/dist/definition.d.ts.map +1 -1
  4. package/dist/definition.js +4 -2
  5. package/dist/definition.js.map +1 -1
  6. package/dist/document.js +5 -5
  7. package/dist/document.js.map +1 -1
  8. package/dist/index.d.ts +4 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +2 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/paths.d.ts +2 -1
  13. package/dist/paths.d.ts.map +1 -1
  14. package/dist/paths.js +9 -5
  15. package/dist/paths.js.map +1 -1
  16. package/dist/project.js +3 -3
  17. package/dist/project.js.map +1 -1
  18. package/dist/types.d.ts +12 -0
  19. package/dist/types.d.ts.map +1 -1
  20. package/dist/types.js.map +1 -1
  21. package/dist/validate.d.ts +4 -2
  22. package/dist/validate.d.ts.map +1 -1
  23. package/dist/validate.js +74 -21
  24. package/dist/validate.js.map +1 -1
  25. package/dist/version.d.ts +1 -1
  26. package/dist/version.js +1 -1
  27. package/dist/version.js.map +1 -1
  28. package/fixtures/README.md +11 -5
  29. package/fixtures/cases/external-invalid-model/context.json +1 -0
  30. package/fixtures/cases/external-invalid-model/definitions/schema/task.md +5 -0
  31. package/fixtures/cases/external-invalid-model/expected.json +1 -0
  32. package/fixtures/cases/external-invalid-model/library/note.md +1 -0
  33. package/fixtures/cases/external-unknown-type/context.json +1 -0
  34. package/fixtures/cases/external-unknown-type/definitions/schema/task.md +5 -0
  35. package/fixtures/cases/external-unknown-type/expected.json +1 -0
  36. package/fixtures/cases/external-unknown-type/library/item.md +3 -0
  37. package/fixtures/cases/external-valid/context.json +1 -0
  38. package/fixtures/cases/external-valid/definitions/types/task.md +5 -0
  39. package/fixtures/cases/external-valid/expected.json +1 -0
  40. package/fixtures/cases/external-valid/library/types/task.md +4 -0
  41. package/package.json +1 -1
package/README.md CHANGED
@@ -16,7 +16,7 @@ through either `import` or `require`; browser bundlers consume the same artifact
16
16
  npm install @agentshouse/mdmodel
17
17
  ```
18
18
 
19
- Package releases are published after the User confirms.
19
+ Package releases follow the repository release handoff after merge.
20
20
 
21
21
  ## API
22
22
 
@@ -28,8 +28,12 @@ import {
28
28
  MARKDOWN_SYNTAX_PROFILE,
29
29
  parse,
30
30
  project,
31
+ retarget,
31
32
  serialize,
33
+ target,
32
34
  validate,
35
+ verify,
36
+ verifyDocuments,
33
37
  VERSION,
34
38
  } from '@agentshouse/mdmodel';
35
39
 
@@ -41,6 +45,14 @@ validate(
41
45
  },
42
46
  { binaryTargets: ['assets/figure.png'] },
43
47
  );
48
+ const checked = verify({
49
+ 'model/task.md': '---\ntype: definition\nfields:\n title: { kind: string }\n---\n',
50
+ });
51
+ if (checked.verdict === 'accept') {
52
+ validate({ 'tasks/one.md': '---\ntype: task\ntitle: Ship\n---\n' }, undefined, checked.model);
53
+ const task = checked.model.types.task;
54
+ const titleKind = task?.fields.title?.kind;
55
+ }
44
56
  const parsed = parse(content);
45
57
  if (parsed.ok) {
46
58
  const next = apply(parsed.document, {
@@ -62,7 +74,16 @@ if (parsed.ok) {
62
74
  }
63
75
  ```
64
76
 
65
- `validate(library, context?)` takes the resulting text Library and one
77
+ `verify(definitions)` accepts definition text keyed by canonical definition
78
+ address. It returns a verified model whose `types` expose each MD Type's name,
79
+ address, parsed field specs, and declared sections. A field spec names its
80
+ `kind` and `required` flag; a list carries `of`, an enum carries `values`, and a
81
+ reference carries `to`. `verifyDocuments(definitions)` accepts already parsed
82
+ definition Documents keyed by canonical definition address and yields the same
83
+ verified facts without parsing their content again. A verification refusal names
84
+ `source: 'model'` and the definition address.
85
+
86
+ `validate(library, context?, model?)` takes the resulting text Library and one
66
87
  `ValidationContext` containing `binaryTargets: readonly string[]`. Omitting the
67
88
  context declares no binary targets. Library keys and binary targets use the
68
89
  same collection-relative path namespace; callers supply canonical paths, and
@@ -71,6 +92,10 @@ in typed Documents may resolve to either membership, including relative
71
92
  normalization from the source Document. A binary target supplies no Document
72
93
  or MD Type and cannot satisfy a typed reference, including one to `any`.
73
94
  The existing `any` Document rules are unchanged.
95
+ When `model` is supplied, validation uses only its definitions and treats every
96
+ Library member as content, even when its Path equals a definition address. A
97
+ content refusal then names `source: 'content'` and its Library Path. Without
98
+ `model`, definition Documents under `types/` are read from the Library.
74
99
 
75
100
  A typed Document carries the frontmatter fields its MD type declares, plus
76
101
  `type`, `site`, and `received`; any other field is refused as
@@ -137,6 +162,21 @@ link, one that is empty, a bare fragment, or carries a URL scheme, and one that
137
162
  leaves the collection are not in the inventory. Frontmatter field values,
138
163
  including typed references, are not link destinations and are never enumerated.
139
164
 
165
+ `target(file, href)` is the collection Path one written destination resolves to
166
+ relative to `file`, by the rule `links` and `validate` read: surrounding spaces
167
+ and the `?query` or `#fragment` it carries are not part of that Path. A
168
+ destination that is empty, a bare fragment, carries a URL scheme, starts at `/`,
169
+ or leaves the collection resolves to `null`. It reads a destination written
170
+ anywhere, such as a typed reference field value, which `links` never
171
+ enumerates. `retarget(href, to)` is that destination rewritten to `to`, keeping
172
+ the `?query` or `#fragment` it carried, which is the destination the `link`
173
+ change below writes.
174
+
175
+ ```ts
176
+ target('items/six.md', ' ../projects/atlas.md#overview '); // 'projects/atlas.md'
177
+ retarget(' ../projects/atlas.md#overview ', '../archive/atlas.md'); // '../archive/atlas.md#overview'
178
+ ```
179
+
140
180
  `apply(document, { kind: 'link', href, to })` rewrites every body occurrence of
141
181
  that written destination and changes nothing else, so a caller that moves a Path
142
182
  rewrites its referring Documents without a second Markdown parser. `to` is the
@@ -30,7 +30,7 @@ export type FieldSpec = ScalarSpec | ListSpec;
30
30
  export type SectionSpec = TextSpec | ListSpec;
31
31
  export type Definition = {
32
32
  readonly name: string;
33
- readonly file: string;
33
+ readonly address: string;
34
34
  readonly fields: Readonly<Record<string, FieldSpec>>;
35
35
  readonly sections: Readonly<Record<string, SectionSpec>>;
36
36
  };
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7E,MAAM,MAAM,UAAU,GAClB,QAAQ,GACR;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACzF;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE9C,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CAC1D,CAAC;AAsGF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CA6BrF"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7E,MAAM,MAAM,UAAU,GAClB,QAAQ,GACR;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACzF;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE9C,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CAC1D,CAAC;AAsGF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CA6BrF"}
@@ -16,7 +16,9 @@ function requiredFlag(value) {
16
16
  function stringList(value) {
17
17
  if (!Array.isArray(value) || value.length === 0) return undefined;
18
18
  if (!value.every((item)=>typeof item === 'string' && item !== '')) return undefined;
19
- return value;
19
+ return [
20
+ ...value
21
+ ];
20
22
  }
21
23
  const SCALAR_KINDS = new Set([
22
24
  'text',
@@ -162,7 +164,7 @@ export function readDefinition(file, document) {
162
164
  }
163
165
  return {
164
166
  name,
165
- file,
167
+ address: file,
166
168
  fields,
167
169
  sections
168
170
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/definition.ts"],"sourcesContent":["import { typeNameFromPath } from './paths.js';\nimport { refusal } from './refuse.js';\nimport type { Document, Refusal } from './types.js';\n\nexport type TextSpec = { readonly kind: 'text'; readonly required: boolean };\n\nexport type ScalarSpec =\n | TextSpec\n | { readonly kind: 'string'; readonly required: boolean }\n | { readonly kind: 'number'; readonly required: boolean }\n | { readonly kind: 'date'; readonly required: boolean }\n | { readonly kind: 'enum'; readonly required: boolean; readonly values: readonly string[] }\n | { readonly kind: 'reference'; readonly required: boolean; readonly to: string };\n\nexport type ListSpec = {\n readonly kind: 'list';\n readonly required: boolean;\n readonly of: ScalarSpec;\n};\n\nexport type FieldSpec = ScalarSpec | ListSpec;\n\nexport type SectionSpec = TextSpec | ListSpec;\n\nexport type Definition = {\n readonly name: string;\n readonly file: string;\n readonly fields: Readonly<Record<string, FieldSpec>>;\n readonly sections: Readonly<Record<string, SectionSpec>>;\n};\n\nfunction refuse(file: string, rule: string, location?: string): Refusal {\n return location === undefined ? refusal(file, rule) : refusal(file, rule, { location });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction requiredFlag(value: unknown): boolean | undefined {\n if (value === undefined) return false;\n if (typeof value === 'boolean') return value;\n return undefined;\n}\n\nfunction stringList(value: unknown): string[] | undefined {\n if (!Array.isArray(value) || value.length === 0) return undefined;\n if (!value.every((item) => typeof item === 'string' && item !== '')) return undefined;\n return value;\n}\n\nconst SCALAR_KINDS = new Set(['text', 'string', 'number', 'date', 'enum', 'reference']);\n\nfunction parseScalar(\n file: string,\n location: string,\n spec: Record<string, unknown>,\n required: boolean,\n): ScalarSpec | Refusal {\n const kind = spec.kind;\n if (kind === 'text') return { kind: 'text', required };\n if (kind === 'string') return { kind: 'string', required };\n if (kind === 'number') return { kind: 'number', required };\n if (kind === 'date') return { kind: 'date', required };\n if (kind === 'enum') {\n const values = stringList(spec.values);\n if (values === undefined) return refuse(file, 'definition-enum-values', location);\n return { kind: 'enum', required, values };\n }\n if (kind === 'reference') {\n if (typeof spec.to !== 'string' || spec.to === '')\n return refuse(file, 'definition-reference-to', location);\n return { kind: 'reference', required, to: spec.to };\n }\n return refuse(file, 'definition-field-kind', location);\n}\n\nfunction extraKeys(spec: Record<string, unknown>, allowed: readonly string[]): boolean {\n return Object.keys(spec).some((key) => !allowed.includes(key));\n}\n\nfunction parseList(\n file: string,\n location: string,\n spec: Record<string, unknown>,\n required: boolean,\n malformed: string,\n): ListSpec | Refusal {\n if (typeof spec.of !== 'string' || !SCALAR_KINDS.has(spec.of)) {\n return refuse(file, 'definition-list-of', location);\n }\n const allowed =\n spec.of === 'enum'\n ? ['kind', 'required', 'of', 'values']\n : spec.of === 'reference'\n ? ['kind', 'required', 'of', 'to']\n : ['kind', 'required', 'of'];\n if (extraKeys(spec, allowed)) return refuse(file, malformed, location);\n const inner = parseScalar(file, location, { ...spec, kind: spec.of }, false);\n if ('rule' in inner) return inner;\n return { kind: 'list', required, of: inner };\n}\n\nfunction parseField(file: string, location: string, value: unknown): FieldSpec | Refusal {\n if (!isRecord(value) || typeof value.kind !== 'string')\n return refuse(file, 'definition-field', location);\n const required = requiredFlag(value.required);\n if (required === undefined) return refuse(file, 'definition-field', location);\n if (value.kind === 'list') return parseList(file, location, value, required, 'definition-field');\n const allowed =\n value.kind === 'enum'\n ? ['kind', 'required', 'values']\n : value.kind === 'reference'\n ? ['kind', 'required', 'to']\n : ['kind', 'required'];\n if (extraKeys(value, allowed)) return refuse(file, 'definition-field', location);\n return parseScalar(file, location, value, required);\n}\n\nfunction parseSection(file: string, location: string, value: unknown): SectionSpec | Refusal {\n if (!isRecord(value) || (value.kind !== 'text' && value.kind !== 'list')) {\n return refuse(file, 'definition-section-kind', location);\n }\n const required = requiredFlag(value.required);\n if (required === undefined) return refuse(file, 'definition-section', location);\n if (value.kind === 'list')\n return parseList(file, location, value, required, 'definition-section');\n if (extraKeys(value, ['kind', 'required'])) return refuse(file, 'definition-section', location);\n return { kind: 'text', required };\n}\n\nexport function readDefinition(file: string, document: Document): Definition | Refusal {\n if (document.type !== 'definition') return refuse(file, 'definition-type');\n const name = typeNameFromPath(file);\n if (name === '') return refuse(file, 'definition-type');\n for (const key of Object.keys(document.fields)) {\n if (key !== 'type' && key !== 'fields' && key !== 'sections') {\n return refuse(file, 'definition-shape', key);\n }\n }\n const fieldsValue = document.fields.fields;\n const sectionsValue = document.fields.sections;\n if (fieldsValue !== undefined && !isRecord(fieldsValue))\n return refuse(file, 'definition-fields', 'fields');\n if (sectionsValue !== undefined && !isRecord(sectionsValue)) {\n return refuse(file, 'definition-sections', 'sections');\n }\n const fields: Record<string, FieldSpec> = Object.create(null);\n for (const [fieldName, spec] of Object.entries(fieldsValue ?? {})) {\n const parsed = parseField(file, fieldName, spec);\n if ('rule' in parsed) return parsed;\n fields[fieldName] = parsed;\n }\n const sections: Record<string, SectionSpec> = Object.create(null);\n for (const [sectionName, spec] of Object.entries(sectionsValue ?? {})) {\n const parsed = parseSection(file, sectionName, spec);\n if ('rule' in parsed) return parsed;\n sections[sectionName] = parsed;\n }\n return { name, file, fields, sections };\n}\n"],"names":["typeNameFromPath","refusal","refuse","file","rule","location","undefined","isRecord","value","Array","isArray","requiredFlag","stringList","length","every","item","SCALAR_KINDS","Set","parseScalar","spec","required","kind","values","to","extraKeys","allowed","Object","keys","some","key","includes","parseList","malformed","of","has","inner","parseField","parseSection","readDefinition","document","type","name","fields","fieldsValue","sectionsValue","sections","create","fieldName","entries","parsed","sectionName"],"mappings":"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"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/definition.ts"],"sourcesContent":["import { typeNameFromPath } from './paths.js';\nimport { refusal } from './refuse.js';\nimport type { Document, Refusal } from './types.js';\n\nexport type TextSpec = { readonly kind: 'text'; readonly required: boolean };\n\nexport type ScalarSpec =\n | TextSpec\n | { readonly kind: 'string'; readonly required: boolean }\n | { readonly kind: 'number'; readonly required: boolean }\n | { readonly kind: 'date'; readonly required: boolean }\n | { readonly kind: 'enum'; readonly required: boolean; readonly values: readonly string[] }\n | { readonly kind: 'reference'; readonly required: boolean; readonly to: string };\n\nexport type ListSpec = {\n readonly kind: 'list';\n readonly required: boolean;\n readonly of: ScalarSpec;\n};\n\nexport type FieldSpec = ScalarSpec | ListSpec;\n\nexport type SectionSpec = TextSpec | ListSpec;\n\nexport type Definition = {\n readonly name: string;\n readonly address: string;\n readonly fields: Readonly<Record<string, FieldSpec>>;\n readonly sections: Readonly<Record<string, SectionSpec>>;\n};\n\nfunction refuse(file: string, rule: string, location?: string): Refusal {\n return location === undefined ? refusal(file, rule) : refusal(file, rule, { location });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction requiredFlag(value: unknown): boolean | undefined {\n if (value === undefined) return false;\n if (typeof value === 'boolean') return value;\n return undefined;\n}\n\nfunction stringList(value: unknown): string[] | undefined {\n if (!Array.isArray(value) || value.length === 0) return undefined;\n if (!value.every((item) => typeof item === 'string' && item !== '')) return undefined;\n return [...value];\n}\n\nconst SCALAR_KINDS = new Set(['text', 'string', 'number', 'date', 'enum', 'reference']);\n\nfunction parseScalar(\n file: string,\n location: string,\n spec: Record<string, unknown>,\n required: boolean,\n): ScalarSpec | Refusal {\n const kind = spec.kind;\n if (kind === 'text') return { kind: 'text', required };\n if (kind === 'string') return { kind: 'string', required };\n if (kind === 'number') return { kind: 'number', required };\n if (kind === 'date') return { kind: 'date', required };\n if (kind === 'enum') {\n const values = stringList(spec.values);\n if (values === undefined) return refuse(file, 'definition-enum-values', location);\n return { kind: 'enum', required, values };\n }\n if (kind === 'reference') {\n if (typeof spec.to !== 'string' || spec.to === '')\n return refuse(file, 'definition-reference-to', location);\n return { kind: 'reference', required, to: spec.to };\n }\n return refuse(file, 'definition-field-kind', location);\n}\n\nfunction extraKeys(spec: Record<string, unknown>, allowed: readonly string[]): boolean {\n return Object.keys(spec).some((key) => !allowed.includes(key));\n}\n\nfunction parseList(\n file: string,\n location: string,\n spec: Record<string, unknown>,\n required: boolean,\n malformed: string,\n): ListSpec | Refusal {\n if (typeof spec.of !== 'string' || !SCALAR_KINDS.has(spec.of)) {\n return refuse(file, 'definition-list-of', location);\n }\n const allowed =\n spec.of === 'enum'\n ? ['kind', 'required', 'of', 'values']\n : spec.of === 'reference'\n ? ['kind', 'required', 'of', 'to']\n : ['kind', 'required', 'of'];\n if (extraKeys(spec, allowed)) return refuse(file, malformed, location);\n const inner = parseScalar(file, location, { ...spec, kind: spec.of }, false);\n if ('rule' in inner) return inner;\n return { kind: 'list', required, of: inner };\n}\n\nfunction parseField(file: string, location: string, value: unknown): FieldSpec | Refusal {\n if (!isRecord(value) || typeof value.kind !== 'string')\n return refuse(file, 'definition-field', location);\n const required = requiredFlag(value.required);\n if (required === undefined) return refuse(file, 'definition-field', location);\n if (value.kind === 'list') return parseList(file, location, value, required, 'definition-field');\n const allowed =\n value.kind === 'enum'\n ? ['kind', 'required', 'values']\n : value.kind === 'reference'\n ? ['kind', 'required', 'to']\n : ['kind', 'required'];\n if (extraKeys(value, allowed)) return refuse(file, 'definition-field', location);\n return parseScalar(file, location, value, required);\n}\n\nfunction parseSection(file: string, location: string, value: unknown): SectionSpec | Refusal {\n if (!isRecord(value) || (value.kind !== 'text' && value.kind !== 'list')) {\n return refuse(file, 'definition-section-kind', location);\n }\n const required = requiredFlag(value.required);\n if (required === undefined) return refuse(file, 'definition-section', location);\n if (value.kind === 'list')\n return parseList(file, location, value, required, 'definition-section');\n if (extraKeys(value, ['kind', 'required'])) return refuse(file, 'definition-section', location);\n return { kind: 'text', required };\n}\n\nexport function readDefinition(file: string, document: Document): Definition | Refusal {\n if (document.type !== 'definition') return refuse(file, 'definition-type');\n const name = typeNameFromPath(file);\n if (name === '') return refuse(file, 'definition-type');\n for (const key of Object.keys(document.fields)) {\n if (key !== 'type' && key !== 'fields' && key !== 'sections') {\n return refuse(file, 'definition-shape', key);\n }\n }\n const fieldsValue = document.fields.fields;\n const sectionsValue = document.fields.sections;\n if (fieldsValue !== undefined && !isRecord(fieldsValue))\n return refuse(file, 'definition-fields', 'fields');\n if (sectionsValue !== undefined && !isRecord(sectionsValue)) {\n return refuse(file, 'definition-sections', 'sections');\n }\n const fields: Record<string, FieldSpec> = Object.create(null);\n for (const [fieldName, spec] of Object.entries(fieldsValue ?? {})) {\n const parsed = parseField(file, fieldName, spec);\n if ('rule' in parsed) return parsed;\n fields[fieldName] = parsed;\n }\n const sections: Record<string, SectionSpec> = Object.create(null);\n for (const [sectionName, spec] of Object.entries(sectionsValue ?? {})) {\n const parsed = parseSection(file, sectionName, spec);\n if ('rule' in parsed) return parsed;\n sections[sectionName] = parsed;\n }\n return { name, address: file, fields, sections };\n}\n"],"names":["typeNameFromPath","refusal","refuse","file","rule","location","undefined","isRecord","value","Array","isArray","requiredFlag","stringList","length","every","item","SCALAR_KINDS","Set","parseScalar","spec","required","kind","values","to","extraKeys","allowed","Object","keys","some","key","includes","parseList","malformed","of","has","inner","parseField","parseSection","readDefinition","document","type","name","fields","fieldsValue","sectionsValue","sections","create","fieldName","entries","parsed","sectionName","address"],"mappings":"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"}
package/dist/document.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { hrefOccurrences } from './links.js';
2
- import { classifyHref, hrefSuffix } from './paths.js';
2
+ import { retarget, target } from './paths.js';
3
3
  import { headingSpans, sectionsRecord } from './sections.js';
4
4
  import { refusal } from './refuse.js';
5
5
  import { bodyStartAfterYaml, bodyStartOf, equalValue, extractFrontmatter, jsValue, lineEnding, mapEntry, parseYamlMapping, serializeJs, serializeKey, YamlError } from './yaml.js';
@@ -185,7 +185,7 @@ function applyLink(document, href, to) {
185
185
  outcome: 'stale',
186
186
  document
187
187
  };
188
- const written = to + hrefSuffix(href);
188
+ const written = retarget(href, to);
189
189
  let rewritten = '';
190
190
  let cursor = 0;
191
191
  for (const match of matches){
@@ -213,12 +213,12 @@ export function links(document, file) {
213
213
  const seen = new Set();
214
214
  for (const occurrence of hrefOccurrences(document.content.slice(bodyStartOf(document.content)))){
215
215
  if (seen.has(occurrence.href)) continue;
216
- const resolved = classifyHref(file, occurrence.href);
217
- if (resolved.kind !== 'path') continue;
216
+ const resolved = target(file, occurrence.href);
217
+ if (resolved === null) continue;
218
218
  seen.add(occurrence.href);
219
219
  found.push({
220
220
  href: occurrence.href,
221
- target: resolved.path
221
+ target: resolved
222
222
  });
223
223
  }
224
224
  return found;
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/document.ts"],"sourcesContent":["import { hrefOccurrences } from './links.js';\nimport { classifyHref, hrefSuffix } from './paths.js';\nimport { headingSpans, sectionsRecord } from './sections.js';\nimport { refusal } from './refuse.js';\nimport type { ApplyResult, Change, Document, Link, ParseResult } from './types.js';\nimport {\n bodyStartAfterYaml,\n bodyStartOf,\n equalValue,\n extractFrontmatter,\n jsValue,\n lineEnding,\n mapEntry,\n parseYamlMapping,\n serializeJs,\n serializeKey,\n YamlError,\n type YamlMap,\n} from './yaml.js';\n\ntype Internal = {\n readonly root: YamlMap | null;\n readonly yamlEnd: number;\n readonly bodyStart: number;\n};\n\nconst internals = new WeakMap<Document, Internal>();\n\nfunction refuse(file: string, rule: string, location?: string) {\n return location === undefined ? refusal(file, rule) : refusal(file, rule, { location });\n}\n\nfunction freezeDocument(\n content: string,\n type: string | undefined,\n fields: Record<string, unknown>,\n preamble: string,\n sections: Record<string, string>,\n internal: Internal,\n): Document {\n const document: Document = Object.freeze({\n content,\n type,\n fields: Object.freeze(fields),\n preamble,\n sections: Object.freeze(sections),\n });\n internals.set(document, internal);\n return document;\n}\n\nfunction declaredType(fields: Record<string, unknown>): string | undefined {\n const value = fields.type;\n if (value === undefined || value === null) return undefined;\n if (typeof value !== 'string' || value === '') return undefined;\n return value;\n}\n\nexport function parse(content: string, file = ''): ParseResult {\n const fence = extractFrontmatter(content);\n if (fence.kind === 'none') {\n const spans = headingSpans(content, 0);\n return {\n ok: true,\n document: freezeDocument(\n content,\n undefined,\n {},\n content.slice(0, spans[0]?.headingStart),\n sectionsRecord(spans, content),\n {\n root: null,\n yamlEnd: 0,\n bodyStart: 0,\n },\n ),\n };\n }\n if (fence.kind === 'unclosed') return { ok: false, refusal: refuse(file, 'frontmatter-fence') };\n try {\n const root = parseYamlMapping(content, fence.yamlStart, fence.yamlEnd);\n const fields = jsValue(root);\n if (fields === null || typeof fields !== 'object' || Array.isArray(fields)) {\n return { ok: false, refusal: refuse(file, 'frontmatter-fence') };\n }\n const bodyStart = bodyStartAfterYaml(content, fence.yamlEnd);\n const spans = headingSpans(content, bodyStart);\n const record = fields as Record<string, unknown>;\n return {\n ok: true,\n document: freezeDocument(\n content,\n declaredType(record),\n record,\n content.slice(bodyStart, spans[0]?.headingStart),\n sectionsRecord(spans, content),\n {\n root,\n yamlEnd: fence.yamlEnd,\n bodyStart,\n },\n ),\n };\n } catch (error) {\n if (error instanceof YamlError)\n return { ok: false, refusal: refuse(file, 'frontmatter-fence') };\n throw error;\n }\n}\n\nfunction splice(content: string, start: number, end: number, insert: string): string {\n return content.slice(0, start) + insert + content.slice(end);\n}\n\nfunction applyField(document: Document, name: string, value: unknown, prior: unknown): ApplyResult {\n const internal = internals.get(document);\n if (internal === undefined || internal.root === null) {\n return { outcome: 'refuse', refusal: refuse('', 'frontmatter-fence', name) };\n }\n if (!equalValue(document.fields[name], prior)) {\n return { outcome: 'stale', document };\n }\n let nextContent: string;\n const existing = mapEntry(internal.root, name);\n if (existing !== undefined) {\n nextContent = splice(\n document.content,\n existing.value.start,\n existing.value.end,\n serializeJs(value),\n );\n } else if (document.content[internal.root.start] === '{') {\n nextContent = splice(\n document.content,\n internal.root.end - 1,\n internal.root.end - 1,\n `${internal.root.entries.length === 0 ? '' : ', '}${serializeKey(name)}: ${serializeJs(value)}`,\n );\n } else {\n const nl = lineEnding(document.content);\n const lineStart = document.content.lastIndexOf('\\n', internal.root.start - 1) + 1;\n const indent = document.content.slice(lineStart, internal.root.start);\n const line = `${indent}${serializeKey(name)}: ${serializeJs(value)}${nl}`;\n const before = document.content.slice(0, internal.yamlEnd);\n const prefix = before.endsWith('\\n') || before.endsWith('\\r\\n') ? '' : nl;\n nextContent = splice(document.content, internal.yamlEnd, internal.yamlEnd, `${prefix}${line}`);\n }\n const parsed = parse(nextContent);\n if (!parsed.ok) return { outcome: 'refuse', refusal: parsed.refusal };\n return { outcome: 'applied', document: parsed.document };\n}\n\nfunction applySection(document: Document, name: string, value: string, prior: string): ApplyResult {\n const internal = internals.get(document);\n if (internal === undefined)\n return { outcome: 'refuse', refusal: refuse('', 'required-section', name) };\n const spans = headingSpans(document.content, internal.bodyStart);\n const span = spans.find((item) => item.name === name);\n if (span === undefined)\n return { outcome: 'refuse', refusal: refuse('', 'required-section', name) };\n const current = document.content.slice(span.bodyStart, span.bodyEnd);\n if (current !== prior) return { outcome: 'stale', document };\n const parsed = parse(splice(document.content, span.bodyStart, span.bodyEnd, value));\n if (!parsed.ok) return { outcome: 'refuse', refusal: parsed.refusal };\n return { outcome: 'applied', document: parsed.document };\n}\n\nfunction applyPreamble(document: Document, value: string, prior: string): ApplyResult {\n if (document.preamble !== prior) return { outcome: 'stale', document };\n const start = bodyStartOf(document.content);\n const parsed = parse(splice(document.content, start, start + document.preamble.length, value));\n if (!parsed.ok) return { outcome: 'refuse', refusal: parsed.refusal };\n return { outcome: 'applied', document: parsed.document };\n}\n\nfunction fitsBare(to: string): boolean {\n if (to === '' || to.startsWith('<')) return false;\n let depth = 0;\n for (const character of to) {\n if (/[\\s\\u0000-\\u001f\\u007f]/.test(character)) return false;\n if (character === '(') depth += 1;\n else if (character === ')') {\n if (depth === 0) return false;\n depth -= 1;\n }\n }\n return depth === 0;\n}\n\nfunction fitsBrackets(to: string): boolean {\n return to !== '' && !/[<>\\n\\r]/.test(to);\n}\n\nfunction destinationText(to: string, bracketed: boolean): string | null {\n if (fitsBare(to)) return bracketed && fitsBrackets(to) ? `<${to}>` : to;\n if (fitsBrackets(to)) return `<${to}>`;\n return null;\n}\n\nfunction applyLink(document: Document, href: string, to: string): ApplyResult {\n const content = document.content;\n const bodyStart = bodyStartOf(content);\n const matches = hrefOccurrences(content.slice(bodyStart)).filter(\n (occurrence) => occurrence.href === href,\n );\n if (matches.length === 0) return { outcome: 'stale', document };\n const written = to + hrefSuffix(href);\n let rewritten = '';\n let cursor = 0;\n for (const match of matches) {\n const text = destinationText(written, match.bracketed);\n if (text === null)\n return { outcome: 'refuse', refusal: refuse('', 'unwritable-link', written) };\n rewritten += content.slice(cursor, bodyStart + match.start);\n rewritten += text;\n cursor = bodyStart + match.end;\n }\n const parsed = parse(rewritten + content.slice(cursor));\n if (!parsed.ok) return { outcome: 'refuse', refusal: parsed.refusal };\n return { outcome: 'applied', document: parsed.document };\n}\n\nexport function links(document: Document, file: string): readonly Link[] {\n const found: Link[] = [];\n const seen = new Set<string>();\n for (const occurrence of hrefOccurrences(document.content.slice(bodyStartOf(document.content)))) {\n if (seen.has(occurrence.href)) continue;\n const resolved = classifyHref(file, occurrence.href);\n if (resolved.kind !== 'path') continue;\n seen.add(occurrence.href);\n found.push({ href: occurrence.href, target: resolved.path });\n }\n return found;\n}\n\nexport function apply(document: Document, change: Change): ApplyResult {\n if (change.kind === 'link') return applyLink(document, change.href, change.to);\n if (change.kind === 'preamble') return applyPreamble(document, change.value, change.prior);\n try {\n if (change.kind === 'field')\n return applyField(document, change.name, change.value, change.prior);\n return applySection(document, change.name, change.value, change.prior);\n } catch (error) {\n if (error instanceof YamlError) {\n return { outcome: 'refuse', refusal: refuse('', 'frontmatter-fence', change.name) };\n }\n throw error;\n }\n}\n\nexport function serialize(document: Document): string {\n return document.content;\n}\n\nexport function frontmatter(document: Document): YamlMap | null {\n return internals.get(document)?.root ?? null;\n}\n"],"names":["hrefOccurrences","classifyHref","hrefSuffix","headingSpans","sectionsRecord","refusal","bodyStartAfterYaml","bodyStartOf","equalValue","extractFrontmatter","jsValue","lineEnding","mapEntry","parseYamlMapping","serializeJs","serializeKey","YamlError","internals","WeakMap","refuse","file","rule","location","undefined","freezeDocument","content","type","fields","preamble","sections","internal","document","Object","freeze","set","declaredType","value","parse","fence","kind","spans","ok","slice","headingStart","root","yamlEnd","bodyStart","yamlStart","Array","isArray","record","error","splice","start","end","insert","applyField","name","prior","get","outcome","nextContent","existing","entries","length","nl","lineStart","lastIndexOf","indent","line","before","prefix","endsWith","parsed","applySection","span","find","item","current","bodyEnd","applyPreamble","fitsBare","to","startsWith","depth","character","test","fitsBrackets","destinationText","bracketed","applyLink","href","matches","filter","occurrence","written","rewritten","cursor","match","text","links","found","seen","Set","has","resolved","add","push","target","path","apply","change","serialize","frontmatter"],"mappings":"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"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/document.ts"],"sourcesContent":["import { hrefOccurrences } from './links.js';\nimport { retarget, target } from './paths.js';\nimport { headingSpans, sectionsRecord } from './sections.js';\nimport { refusal } from './refuse.js';\nimport type { ApplyResult, Change, Document, Link, ParseResult } from './types.js';\nimport {\n bodyStartAfterYaml,\n bodyStartOf,\n equalValue,\n extractFrontmatter,\n jsValue,\n lineEnding,\n mapEntry,\n parseYamlMapping,\n serializeJs,\n serializeKey,\n YamlError,\n type YamlMap,\n} from './yaml.js';\n\ntype Internal = {\n readonly root: YamlMap | null;\n readonly yamlEnd: number;\n readonly bodyStart: number;\n};\n\nconst internals = new WeakMap<Document, Internal>();\n\nfunction refuse(file: string, rule: string, location?: string) {\n return location === undefined ? refusal(file, rule) : refusal(file, rule, { location });\n}\n\nfunction freezeDocument(\n content: string,\n type: string | undefined,\n fields: Record<string, unknown>,\n preamble: string,\n sections: Record<string, string>,\n internal: Internal,\n): Document {\n const document: Document = Object.freeze({\n content,\n type,\n fields: Object.freeze(fields),\n preamble,\n sections: Object.freeze(sections),\n });\n internals.set(document, internal);\n return document;\n}\n\nfunction declaredType(fields: Record<string, unknown>): string | undefined {\n const value = fields.type;\n if (value === undefined || value === null) return undefined;\n if (typeof value !== 'string' || value === '') return undefined;\n return value;\n}\n\nexport function parse(content: string, file = ''): ParseResult {\n const fence = extractFrontmatter(content);\n if (fence.kind === 'none') {\n const spans = headingSpans(content, 0);\n return {\n ok: true,\n document: freezeDocument(\n content,\n undefined,\n {},\n content.slice(0, spans[0]?.headingStart),\n sectionsRecord(spans, content),\n {\n root: null,\n yamlEnd: 0,\n bodyStart: 0,\n },\n ),\n };\n }\n if (fence.kind === 'unclosed') return { ok: false, refusal: refuse(file, 'frontmatter-fence') };\n try {\n const root = parseYamlMapping(content, fence.yamlStart, fence.yamlEnd);\n const fields = jsValue(root);\n if (fields === null || typeof fields !== 'object' || Array.isArray(fields)) {\n return { ok: false, refusal: refuse(file, 'frontmatter-fence') };\n }\n const bodyStart = bodyStartAfterYaml(content, fence.yamlEnd);\n const spans = headingSpans(content, bodyStart);\n const record = fields as Record<string, unknown>;\n return {\n ok: true,\n document: freezeDocument(\n content,\n declaredType(record),\n record,\n content.slice(bodyStart, spans[0]?.headingStart),\n sectionsRecord(spans, content),\n {\n root,\n yamlEnd: fence.yamlEnd,\n bodyStart,\n },\n ),\n };\n } catch (error) {\n if (error instanceof YamlError)\n return { ok: false, refusal: refuse(file, 'frontmatter-fence') };\n throw error;\n }\n}\n\nfunction splice(content: string, start: number, end: number, insert: string): string {\n return content.slice(0, start) + insert + content.slice(end);\n}\n\nfunction applyField(document: Document, name: string, value: unknown, prior: unknown): ApplyResult {\n const internal = internals.get(document);\n if (internal === undefined || internal.root === null) {\n return { outcome: 'refuse', refusal: refuse('', 'frontmatter-fence', name) };\n }\n if (!equalValue(document.fields[name], prior)) {\n return { outcome: 'stale', document };\n }\n let nextContent: string;\n const existing = mapEntry(internal.root, name);\n if (existing !== undefined) {\n nextContent = splice(\n document.content,\n existing.value.start,\n existing.value.end,\n serializeJs(value),\n );\n } else if (document.content[internal.root.start] === '{') {\n nextContent = splice(\n document.content,\n internal.root.end - 1,\n internal.root.end - 1,\n `${internal.root.entries.length === 0 ? '' : ', '}${serializeKey(name)}: ${serializeJs(value)}`,\n );\n } else {\n const nl = lineEnding(document.content);\n const lineStart = document.content.lastIndexOf('\\n', internal.root.start - 1) + 1;\n const indent = document.content.slice(lineStart, internal.root.start);\n const line = `${indent}${serializeKey(name)}: ${serializeJs(value)}${nl}`;\n const before = document.content.slice(0, internal.yamlEnd);\n const prefix = before.endsWith('\\n') || before.endsWith('\\r\\n') ? '' : nl;\n nextContent = splice(document.content, internal.yamlEnd, internal.yamlEnd, `${prefix}${line}`);\n }\n const parsed = parse(nextContent);\n if (!parsed.ok) return { outcome: 'refuse', refusal: parsed.refusal };\n return { outcome: 'applied', document: parsed.document };\n}\n\nfunction applySection(document: Document, name: string, value: string, prior: string): ApplyResult {\n const internal = internals.get(document);\n if (internal === undefined)\n return { outcome: 'refuse', refusal: refuse('', 'required-section', name) };\n const spans = headingSpans(document.content, internal.bodyStart);\n const span = spans.find((item) => item.name === name);\n if (span === undefined)\n return { outcome: 'refuse', refusal: refuse('', 'required-section', name) };\n const current = document.content.slice(span.bodyStart, span.bodyEnd);\n if (current !== prior) return { outcome: 'stale', document };\n const parsed = parse(splice(document.content, span.bodyStart, span.bodyEnd, value));\n if (!parsed.ok) return { outcome: 'refuse', refusal: parsed.refusal };\n return { outcome: 'applied', document: parsed.document };\n}\n\nfunction applyPreamble(document: Document, value: string, prior: string): ApplyResult {\n if (document.preamble !== prior) return { outcome: 'stale', document };\n const start = bodyStartOf(document.content);\n const parsed = parse(splice(document.content, start, start + document.preamble.length, value));\n if (!parsed.ok) return { outcome: 'refuse', refusal: parsed.refusal };\n return { outcome: 'applied', document: parsed.document };\n}\n\nfunction fitsBare(to: string): boolean {\n if (to === '' || to.startsWith('<')) return false;\n let depth = 0;\n for (const character of to) {\n if (/[\\s\\u0000-\\u001f\\u007f]/.test(character)) return false;\n if (character === '(') depth += 1;\n else if (character === ')') {\n if (depth === 0) return false;\n depth -= 1;\n }\n }\n return depth === 0;\n}\n\nfunction fitsBrackets(to: string): boolean {\n return to !== '' && !/[<>\\n\\r]/.test(to);\n}\n\nfunction destinationText(to: string, bracketed: boolean): string | null {\n if (fitsBare(to)) return bracketed && fitsBrackets(to) ? `<${to}>` : to;\n if (fitsBrackets(to)) return `<${to}>`;\n return null;\n}\n\nfunction applyLink(document: Document, href: string, to: string): ApplyResult {\n const content = document.content;\n const bodyStart = bodyStartOf(content);\n const matches = hrefOccurrences(content.slice(bodyStart)).filter(\n (occurrence) => occurrence.href === href,\n );\n if (matches.length === 0) return { outcome: 'stale', document };\n const written = retarget(href, to);\n let rewritten = '';\n let cursor = 0;\n for (const match of matches) {\n const text = destinationText(written, match.bracketed);\n if (text === null)\n return { outcome: 'refuse', refusal: refuse('', 'unwritable-link', written) };\n rewritten += content.slice(cursor, bodyStart + match.start);\n rewritten += text;\n cursor = bodyStart + match.end;\n }\n const parsed = parse(rewritten + content.slice(cursor));\n if (!parsed.ok) return { outcome: 'refuse', refusal: parsed.refusal };\n return { outcome: 'applied', document: parsed.document };\n}\n\nexport function links(document: Document, file: string): readonly Link[] {\n const found: Link[] = [];\n const seen = new Set<string>();\n for (const occurrence of hrefOccurrences(document.content.slice(bodyStartOf(document.content)))) {\n if (seen.has(occurrence.href)) continue;\n const resolved = target(file, occurrence.href);\n if (resolved === null) continue;\n seen.add(occurrence.href);\n found.push({ href: occurrence.href, target: resolved });\n }\n return found;\n}\n\nexport function apply(document: Document, change: Change): ApplyResult {\n if (change.kind === 'link') return applyLink(document, change.href, change.to);\n if (change.kind === 'preamble') return applyPreamble(document, change.value, change.prior);\n try {\n if (change.kind === 'field')\n return applyField(document, change.name, change.value, change.prior);\n return applySection(document, change.name, change.value, change.prior);\n } catch (error) {\n if (error instanceof YamlError) {\n return { outcome: 'refuse', refusal: refuse('', 'frontmatter-fence', change.name) };\n }\n throw error;\n }\n}\n\nexport function serialize(document: Document): string {\n return document.content;\n}\n\nexport function frontmatter(document: Document): YamlMap | null {\n return internals.get(document)?.root ?? null;\n}\n"],"names":["hrefOccurrences","retarget","target","headingSpans","sectionsRecord","refusal","bodyStartAfterYaml","bodyStartOf","equalValue","extractFrontmatter","jsValue","lineEnding","mapEntry","parseYamlMapping","serializeJs","serializeKey","YamlError","internals","WeakMap","refuse","file","rule","location","undefined","freezeDocument","content","type","fields","preamble","sections","internal","document","Object","freeze","set","declaredType","value","parse","fence","kind","spans","ok","slice","headingStart","root","yamlEnd","bodyStart","yamlStart","Array","isArray","record","error","splice","start","end","insert","applyField","name","prior","get","outcome","nextContent","existing","entries","length","nl","lineStart","lastIndexOf","indent","line","before","prefix","endsWith","parsed","applySection","span","find","item","current","bodyEnd","applyPreamble","fitsBare","to","startsWith","depth","character","test","fitsBrackets","destinationText","bracketed","applyLink","href","matches","filter","occurrence","written","rewritten","cursor","match","text","links","found","seen","Set","has","resolved","add","push","apply","change","serialize","frontmatter"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  export { divide } from './divide.js';
2
2
  export { apply, links, parse, serialize } from './document.js';
3
+ export { retarget, target } from './paths.js';
3
4
  export { MARKDOWN_SYNTAX_PROFILE } from './profile.js';
4
5
  export { project } from './project.js';
5
- export type { ApplyResult, Change, Division, DivisionContext, Document, Library, Link, ParseResult, Projection, ProjectionContext, Refusal, Span, Validation, ValidationContext, } from './types.js';
6
- export { validate } from './validate.js';
6
+ export type { Definition, FieldSpec, SectionSpec } from './definition.js';
7
+ export type { ApplyResult, Change, Division, DivisionContext, Document, Library, ModelVerification, Link, ParseResult, Projection, ProjectionContext, Refusal, Span, Validation, ValidationContext, VerifiedModel, } from './types.js';
8
+ export { validate, verify, verifyDocuments } from './validate.js';
7
9
  export { VERSION } from './version.js';
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EACV,WAAW,EACX,MAAM,EACN,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,OAAO,EACP,IAAI,EACJ,UAAU,EACV,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC1E,YAAY,EACV,WAAW,EACX,MAAM,EACN,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,OAAO,EACP,iBAAiB,EACjB,IAAI,EACJ,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,OAAO,EACP,IAAI,EACJ,UAAU,EACV,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  export { divide } from './divide.js';
2
2
  export { apply, links, parse, serialize } from './document.js';
3
+ export { retarget, target } from './paths.js';
3
4
  export { MARKDOWN_SYNTAX_PROFILE } from './profile.js';
4
5
  export { project } from './project.js';
5
- export { validate } from './validate.js';
6
+ export { validate, verify, verifyDocuments } from './validate.js';
6
7
  export { VERSION } from './version.js';
7
8
 
8
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/index.ts"],"sourcesContent":["export { divide } from './divide.js';\nexport { apply, links, parse, serialize } from './document.js';\nexport { MARKDOWN_SYNTAX_PROFILE } from './profile.js';\nexport { project } from './project.js';\nexport type {\n ApplyResult,\n Change,\n Division,\n DivisionContext,\n Document,\n Library,\n Link,\n ParseResult,\n Projection,\n ProjectionContext,\n Refusal,\n Span,\n Validation,\n ValidationContext,\n} from './types.js';\nexport { validate } from './validate.js';\nexport { VERSION } from './version.js';\n"],"names":["divide","apply","links","parse","serialize","MARKDOWN_SYNTAX_PROFILE","project","validate","VERSION"],"mappings":"AAAA,SAASA,MAAM,QAAQ,cAAc;AACrC,SAASC,KAAK,EAAEC,KAAK,EAAEC,KAAK,EAAEC,SAAS,QAAQ,gBAAgB;AAC/D,SAASC,uBAAuB,QAAQ,eAAe;AACvD,SAASC,OAAO,QAAQ,eAAe;AAiBvC,SAASC,QAAQ,QAAQ,gBAAgB;AACzC,SAASC,OAAO,QAAQ,eAAe"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/index.ts"],"sourcesContent":["export { divide } from './divide.js';\nexport { apply, links, parse, serialize } from './document.js';\nexport { retarget, target } from './paths.js';\nexport { MARKDOWN_SYNTAX_PROFILE } from './profile.js';\nexport { project } from './project.js';\nexport type { Definition, FieldSpec, SectionSpec } from './definition.js';\nexport type {\n ApplyResult,\n Change,\n Division,\n DivisionContext,\n Document,\n Library,\n ModelVerification,\n Link,\n ParseResult,\n Projection,\n ProjectionContext,\n Refusal,\n Span,\n Validation,\n ValidationContext,\n VerifiedModel,\n} from './types.js';\nexport { validate, verify, verifyDocuments } from './validate.js';\nexport { VERSION } from './version.js';\n"],"names":["divide","apply","links","parse","serialize","retarget","target","MARKDOWN_SYNTAX_PROFILE","project","validate","verify","verifyDocuments","VERSION"],"mappings":"AAAA,SAASA,MAAM,QAAQ,cAAc;AACrC,SAASC,KAAK,EAAEC,KAAK,EAAEC,KAAK,EAAEC,SAAS,QAAQ,gBAAgB;AAC/D,SAASC,QAAQ,EAAEC,MAAM,QAAQ,aAAa;AAC9C,SAASC,uBAAuB,QAAQ,eAAe;AACvD,SAASC,OAAO,QAAQ,eAAe;AAoBvC,SAASC,QAAQ,EAAEC,MAAM,EAAEC,eAAe,QAAQ,gBAAgB;AAClE,SAASC,OAAO,QAAQ,eAAe"}
package/dist/paths.d.ts CHANGED
@@ -3,7 +3,6 @@ export declare function join(base: string, relative: string): string;
3
3
  export declare function normalize(path: string): string | null;
4
4
  export declare function isTypesPath(path: string): boolean;
5
5
  export declare function typeNameFromPath(path: string): string;
6
- export declare function hrefSuffix(href: string): string;
7
6
  export declare function classifyHref(from: string, href: string): {
8
7
  kind: 'skip';
9
8
  } | {
@@ -12,4 +11,6 @@ export declare function classifyHref(from: string, href: string): {
12
11
  } | {
13
12
  kind: 'invalid';
14
13
  };
14
+ export declare function target(from: string, href: string): string | null;
15
+ export declare function retarget(href: string, to: string): string;
15
16
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYrD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAUzE"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYrD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAUzE;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAIzD"}
package/dist/paths.js CHANGED
@@ -26,11 +26,6 @@ export function typeNameFromPath(path) {
26
26
  const base = path.slice(path.lastIndexOf('/') + 1);
27
27
  return base.endsWith('.md') ? base.slice(0, -3) : base;
28
28
  }
29
- export function hrefSuffix(href) {
30
- const trimmed = href.trim();
31
- const match = /[?#]/.exec(trimmed);
32
- return match === null ? '' : trimmed.slice(match.index);
33
- }
34
29
  export function classifyHref(from, href) {
35
30
  const trimmed = href.trim();
36
31
  if (trimmed === '' || trimmed.startsWith('#')) return {
@@ -55,5 +50,14 @@ export function classifyHref(from, href) {
55
50
  path: resolved
56
51
  };
57
52
  }
53
+ export function target(from, href) {
54
+ const resolved = classifyHref(from, href);
55
+ return resolved.kind === 'path' ? resolved.path : null;
56
+ }
57
+ export function retarget(href, to) {
58
+ const trimmed = href.trim();
59
+ const match = /[?#]/.exec(trimmed);
60
+ return match === null ? to : to + trimmed.slice(match.index);
61
+ }
58
62
 
59
63
  //# sourceMappingURL=paths.js.map
package/dist/paths.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/paths.ts"],"sourcesContent":["export function dirname(path: string): string {\n const index = path.lastIndexOf('/');\n return index === -1 ? '' : path.slice(0, index);\n}\n\nexport function join(base: string, relative: string): string {\n if (base === '') return relative;\n return `${base}/${relative}`;\n}\n\nexport function normalize(path: string): string | null {\n const parts: string[] = [];\n for (const part of path.split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') {\n if (parts.length === 0) return null;\n parts.pop();\n continue;\n }\n parts.push(part);\n }\n return parts.join('/');\n}\n\nexport function isTypesPath(path: string): boolean {\n return path === 'types' || path.startsWith('types/');\n}\n\nexport function typeNameFromPath(path: string): string {\n const base = path.slice(path.lastIndexOf('/') + 1);\n return base.endsWith('.md') ? base.slice(0, -3) : base;\n}\n\nexport function hrefSuffix(href: string): string {\n const trimmed = href.trim();\n const match = /[?#]/.exec(trimmed);\n return match === null ? '' : trimmed.slice(match.index);\n}\n\nexport function classifyHref(\n from: string,\n href: string,\n): { kind: 'skip' } | { kind: 'path'; path: string } | { kind: 'invalid' } {\n const trimmed = href.trim();\n if (trimmed === '' || trimmed.startsWith('#')) return { kind: 'skip' };\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return { kind: 'skip' };\n if (trimmed.startsWith('/')) return { kind: 'invalid' };\n const bare = trimmed.replace(/[?#].*$/, '');\n if (bare === '') return { kind: 'skip' };\n const resolved = normalize(join(dirname(from), bare));\n if (resolved === null || resolved === '') return { kind: 'invalid' };\n return { kind: 'path', path: resolved };\n}\n"],"names":["dirname","path","index","lastIndexOf","slice","join","base","relative","normalize","parts","part","split","length","pop","push","isTypesPath","startsWith","typeNameFromPath","endsWith","hrefSuffix","href","trimmed","trim","match","exec","classifyHref","from","kind","test","bare","replace","resolved"],"mappings":"AAAA,OAAO,SAASA,QAAQC,IAAY;IAClC,MAAMC,QAAQD,KAAKE,WAAW,CAAC;IAC/B,OAAOD,UAAU,CAAC,IAAI,KAAKD,KAAKG,KAAK,CAAC,GAAGF;AAC3C;AAEA,OAAO,SAASG,KAAKC,IAAY,EAAEC,QAAgB;IACjD,IAAID,SAAS,IAAI,OAAOC;IACxB,OAAO,GAAGD,KAAK,CAAC,EAAEC,UAAU;AAC9B;AAEA,OAAO,SAASC,UAAUP,IAAY;IACpC,MAAMQ,QAAkB,EAAE;IAC1B,KAAK,MAAMC,QAAQT,KAAKU,KAAK,CAAC,KAAM;QAClC,IAAID,SAAS,MAAMA,SAAS,KAAK;QACjC,IAAIA,SAAS,MAAM;YACjB,IAAID,MAAMG,MAAM,KAAK,GAAG,OAAO;YAC/BH,MAAMI,GAAG;YACT;QACF;QACAJ,MAAMK,IAAI,CAACJ;IACb;IACA,OAAOD,MAAMJ,IAAI,CAAC;AACpB;AAEA,OAAO,SAASU,YAAYd,IAAY;IACtC,OAAOA,SAAS,WAAWA,KAAKe,UAAU,CAAC;AAC7C;AAEA,OAAO,SAASC,iBAAiBhB,IAAY;IAC3C,MAAMK,OAAOL,KAAKG,KAAK,CAACH,KAAKE,WAAW,CAAC,OAAO;IAChD,OAAOG,KAAKY,QAAQ,CAAC,SAASZ,KAAKF,KAAK,CAAC,GAAG,CAAC,KAAKE;AACpD;AAEA,OAAO,SAASa,WAAWC,IAAY;IACrC,MAAMC,UAAUD,KAAKE,IAAI;IACzB,MAAMC,QAAQ,OAAOC,IAAI,CAACH;IAC1B,OAAOE,UAAU,OAAO,KAAKF,QAAQjB,KAAK,CAACmB,MAAMrB,KAAK;AACxD;AAEA,OAAO,SAASuB,aACdC,IAAY,EACZN,IAAY;IAEZ,MAAMC,UAAUD,KAAKE,IAAI;IACzB,IAAID,YAAY,MAAMA,QAAQL,UAAU,CAAC,MAAM,OAAO;QAAEW,MAAM;IAAO;IACrE,IAAI,4BAA4BC,IAAI,CAACP,UAAU,OAAO;QAAEM,MAAM;IAAO;IACrE,IAAIN,QAAQL,UAAU,CAAC,MAAM,OAAO;QAAEW,MAAM;IAAU;IACtD,MAAME,OAAOR,QAAQS,OAAO,CAAC,WAAW;IACxC,IAAID,SAAS,IAAI,OAAO;QAAEF,MAAM;IAAO;IACvC,MAAMI,WAAWvB,UAAUH,KAAKL,QAAQ0B,OAAOG;IAC/C,IAAIE,aAAa,QAAQA,aAAa,IAAI,OAAO;QAAEJ,MAAM;IAAU;IACnE,OAAO;QAAEA,MAAM;QAAQ1B,MAAM8B;IAAS;AACxC"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/paths.ts"],"sourcesContent":["export function dirname(path: string): string {\n const index = path.lastIndexOf('/');\n return index === -1 ? '' : path.slice(0, index);\n}\n\nexport function join(base: string, relative: string): string {\n if (base === '') return relative;\n return `${base}/${relative}`;\n}\n\nexport function normalize(path: string): string | null {\n const parts: string[] = [];\n for (const part of path.split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') {\n if (parts.length === 0) return null;\n parts.pop();\n continue;\n }\n parts.push(part);\n }\n return parts.join('/');\n}\n\nexport function isTypesPath(path: string): boolean {\n return path === 'types' || path.startsWith('types/');\n}\n\nexport function typeNameFromPath(path: string): string {\n const base = path.slice(path.lastIndexOf('/') + 1);\n return base.endsWith('.md') ? base.slice(0, -3) : base;\n}\n\nexport function classifyHref(\n from: string,\n href: string,\n): { kind: 'skip' } | { kind: 'path'; path: string } | { kind: 'invalid' } {\n const trimmed = href.trim();\n if (trimmed === '' || trimmed.startsWith('#')) return { kind: 'skip' };\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return { kind: 'skip' };\n if (trimmed.startsWith('/')) return { kind: 'invalid' };\n const bare = trimmed.replace(/[?#].*$/, '');\n if (bare === '') return { kind: 'skip' };\n const resolved = normalize(join(dirname(from), bare));\n if (resolved === null || resolved === '') return { kind: 'invalid' };\n return { kind: 'path', path: resolved };\n}\n\nexport function target(from: string, href: string): string | null {\n const resolved = classifyHref(from, href);\n return resolved.kind === 'path' ? resolved.path : null;\n}\n\nexport function retarget(href: string, to: string): string {\n const trimmed = href.trim();\n const match = /[?#]/.exec(trimmed);\n return match === null ? to : to + trimmed.slice(match.index);\n}\n"],"names":["dirname","path","index","lastIndexOf","slice","join","base","relative","normalize","parts","part","split","length","pop","push","isTypesPath","startsWith","typeNameFromPath","endsWith","classifyHref","from","href","trimmed","trim","kind","test","bare","replace","resolved","target","retarget","to","match","exec"],"mappings":"AAAA,OAAO,SAASA,QAAQC,IAAY;IAClC,MAAMC,QAAQD,KAAKE,WAAW,CAAC;IAC/B,OAAOD,UAAU,CAAC,IAAI,KAAKD,KAAKG,KAAK,CAAC,GAAGF;AAC3C;AAEA,OAAO,SAASG,KAAKC,IAAY,EAAEC,QAAgB;IACjD,IAAID,SAAS,IAAI,OAAOC;IACxB,OAAO,GAAGD,KAAK,CAAC,EAAEC,UAAU;AAC9B;AAEA,OAAO,SAASC,UAAUP,IAAY;IACpC,MAAMQ,QAAkB,EAAE;IAC1B,KAAK,MAAMC,QAAQT,KAAKU,KAAK,CAAC,KAAM;QAClC,IAAID,SAAS,MAAMA,SAAS,KAAK;QACjC,IAAIA,SAAS,MAAM;YACjB,IAAID,MAAMG,MAAM,KAAK,GAAG,OAAO;YAC/BH,MAAMI,GAAG;YACT;QACF;QACAJ,MAAMK,IAAI,CAACJ;IACb;IACA,OAAOD,MAAMJ,IAAI,CAAC;AACpB;AAEA,OAAO,SAASU,YAAYd,IAAY;IACtC,OAAOA,SAAS,WAAWA,KAAKe,UAAU,CAAC;AAC7C;AAEA,OAAO,SAASC,iBAAiBhB,IAAY;IAC3C,MAAMK,OAAOL,KAAKG,KAAK,CAACH,KAAKE,WAAW,CAAC,OAAO;IAChD,OAAOG,KAAKY,QAAQ,CAAC,SAASZ,KAAKF,KAAK,CAAC,GAAG,CAAC,KAAKE;AACpD;AAEA,OAAO,SAASa,aACdC,IAAY,EACZC,IAAY;IAEZ,MAAMC,UAAUD,KAAKE,IAAI;IACzB,IAAID,YAAY,MAAMA,QAAQN,UAAU,CAAC,MAAM,OAAO;QAAEQ,MAAM;IAAO;IACrE,IAAI,4BAA4BC,IAAI,CAACH,UAAU,OAAO;QAAEE,MAAM;IAAO;IACrE,IAAIF,QAAQN,UAAU,CAAC,MAAM,OAAO;QAAEQ,MAAM;IAAU;IACtD,MAAME,OAAOJ,QAAQK,OAAO,CAAC,WAAW;IACxC,IAAID,SAAS,IAAI,OAAO;QAAEF,MAAM;IAAO;IACvC,MAAMI,WAAWpB,UAAUH,KAAKL,QAAQoB,OAAOM;IAC/C,IAAIE,aAAa,QAAQA,aAAa,IAAI,OAAO;QAAEJ,MAAM;IAAU;IACnE,OAAO;QAAEA,MAAM;QAAQvB,MAAM2B;IAAS;AACxC;AAEA,OAAO,SAASC,OAAOT,IAAY,EAAEC,IAAY;IAC/C,MAAMO,WAAWT,aAAaC,MAAMC;IACpC,OAAOO,SAASJ,IAAI,KAAK,SAASI,SAAS3B,IAAI,GAAG;AACpD;AAEA,OAAO,SAAS6B,SAAST,IAAY,EAAEU,EAAU;IAC/C,MAAMT,UAAUD,KAAKE,IAAI;IACzB,MAAMS,QAAQ,OAAOC,IAAI,CAACX;IAC1B,OAAOU,UAAU,OAAOD,KAAKA,KAAKT,QAAQlB,KAAK,CAAC4B,MAAM9B,KAAK;AAC7D"}
package/dist/project.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readDefinition } from './definition.js';
2
2
  import { frontmatter, parse } from './document.js';
3
3
  import { linkInventory } from './links.js';
4
- import { classifyHref } from './paths.js';
4
+ import { target } from './paths.js';
5
5
  import { refusal } from './refuse.js';
6
6
  import { headingSpans } from './sections.js';
7
7
  import { bodyStartOf, mapEntry } from './yaml.js';
@@ -10,8 +10,8 @@ function internalEdits(content, bodyStart, file, documentTargets) {
10
10
  const internal = new Set();
11
11
  const edits = [];
12
12
  for (const use of inventory.uses){
13
- const resolved = classifyHref(file, use.destination.href);
14
- if (resolved.kind !== 'path' || !documentTargets.has(resolved.path)) continue;
13
+ const resolved = target(file, use.destination.href);
14
+ if (resolved === null || !documentTargets.has(resolved)) continue;
15
15
  internal.add(use.destination.start);
16
16
  edits.push({
17
17
  start: bodyStart + use.start,
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/project.ts"],"sourcesContent":["import { readDefinition, type Definition, type SectionSpec } from './definition.js';\nimport { frontmatter, parse } from './document.js';\nimport { linkInventory } from './links.js';\nimport { classifyHref } from './paths.js';\nimport { refusal } from './refuse.js';\nimport { headingSpans } from './sections.js';\nimport type { Document, Extent, Projection, ProjectionContext, Refusal } from './types.js';\nimport { bodyStartOf, mapEntry } from './yaml.js';\n\nexport type Piece = Extent & { readonly text: string };\n\nexport type Edit = Piece;\n\nexport type Input = {\n readonly values: readonly Piece[];\n readonly ranges: readonly Extent[];\n readonly edits: readonly Edit[];\n};\n\nexport type InputResult =\n | { readonly ok: true; readonly input: Input }\n | { readonly ok: false; readonly refusal: Refusal };\n\nfunction internalEdits(\n content: string,\n bodyStart: number,\n file: string,\n documentTargets: ReadonlySet<string>,\n): Edit[] {\n const inventory = linkInventory(content.slice(bodyStart));\n const internal = new Set<number>();\n const edits: Edit[] = [];\n for (const use of inventory.uses) {\n const resolved = classifyHref(file, use.destination.href);\n if (resolved.kind !== 'path' || !documentTargets.has(resolved.path)) continue;\n internal.add(use.destination.start);\n edits.push({\n start: bodyStart + use.start,\n end: bodyStart + use.end,\n text: content.slice(bodyStart + use.labelStart, bodyStart + use.labelEnd),\n });\n }\n for (const block of inventory.blocks) {\n if (!internal.has(block.destination.start)) continue;\n edits.push({ start: bodyStart + block.start, end: bodyStart + block.end, text: '' });\n }\n return edits.sort((left, right) => left.start - right.start);\n}\n\nexport function rangeText(content: string, range: Extent, edits: readonly Edit[]): string {\n let text = '';\n let cursor = range.start;\n for (const edit of edits) {\n if (edit.start < cursor || edit.end > range.end) continue;\n text += content.slice(cursor, edit.start) + edit.text;\n cursor = edit.end;\n }\n return text + content.slice(cursor, range.end);\n}\n\nfunction structural(spec: SectionSpec): boolean {\n return spec.kind === 'list' && spec.of.kind !== 'text';\n}\n\nfunction freeTextValues(definition: Definition, document: Document): Piece[] {\n const root = frontmatter(document);\n if (root === null) return [];\n const values: Piece[] = [];\n for (const [name, spec] of Object.entries(definition.fields)) {\n const entry = mapEntry(root, name);\n if (entry === undefined) continue;\n const node = entry.value;\n if (spec.kind === 'text') {\n if (node.kind === 'scalar' && typeof node.value === 'string') {\n values.push({ start: node.start, end: node.end, text: `${node.value}\\n\\n` });\n }\n continue;\n }\n if (spec.kind !== 'list' || spec.of.kind !== 'text' || node.kind !== 'seq') continue;\n for (const item of node.items) {\n if (item.kind === 'scalar' && typeof item.value === 'string') {\n values.push({ start: item.start, end: item.end, text: `${item.value}\\n\\n` });\n }\n }\n }\n return values;\n}\n\nexport function projectionInput(\n document: Document,\n file: string,\n context: ProjectionContext,\n): InputResult {\n const content = document.content;\n const bodyStart = bodyStartOf(content);\n const edits = internalEdits(content, bodyStart, file, new Set(context.documentTargets));\n const declared = document.type;\n if (declared === undefined || declared === 'any') {\n return {\n ok: true,\n input: { values: [], ranges: [{ start: bodyStart, end: content.length }], edits },\n };\n }\n const source = context.definition;\n if (source === undefined) {\n return { ok: false, refusal: refusal(file, 'unknown-type', { location: 'type' }) };\n }\n const definitionFile = `types/${declared}.md`;\n const parsed = parse(source, definitionFile);\n if (!parsed.ok) return { ok: false, refusal: parsed.refusal };\n const definition = readDefinition(definitionFile, parsed.document);\n if ('rule' in definition) return { ok: false, refusal: definition };\n const structure = new Set(\n Object.entries(definition.sections).flatMap(([name, spec]) => (structural(spec) ? [name] : [])),\n );\n const headings = headingSpans(content, bodyStart);\n const ranges: Extent[] = [{ start: bodyStart, end: headings[0]?.headingStart ?? content.length }];\n for (const heading of headings) {\n if (structure.has(heading.name)) continue;\n ranges.push({ start: heading.headingStart, end: heading.bodyEnd });\n }\n return { ok: true, input: { values: freeTextValues(definition, document), ranges, edits } };\n}\n\nexport function project(\n document: Document,\n file: string,\n context: ProjectionContext = { documentTargets: [] },\n): Projection {\n const result = projectionInput(document, file, context);\n if (!result.ok) return { ok: false, refusal: result.refusal };\n const { values, ranges, edits } = result.input;\n const prose = ranges.map((range) => rangeText(document.content, range, edits)).join('');\n return { ok: true, text: values.map((value) => value.text).join('') + prose };\n}\n"],"names":["readDefinition","frontmatter","parse","linkInventory","classifyHref","refusal","headingSpans","bodyStartOf","mapEntry","internalEdits","content","bodyStart","file","documentTargets","inventory","slice","internal","Set","edits","use","uses","resolved","destination","href","kind","has","path","add","start","push","end","text","labelStart","labelEnd","block","blocks","sort","left","right","rangeText","range","cursor","edit","structural","spec","of","freeTextValues","definition","document","root","values","name","Object","entries","fields","entry","undefined","node","value","item","items","projectionInput","context","declared","type","ok","input","ranges","length","source","location","definitionFile","parsed","structure","sections","flatMap","headings","headingStart","heading","bodyEnd","project","result","prose","map","join"],"mappings":"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"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/project.ts"],"sourcesContent":["import { readDefinition, type Definition, type SectionSpec } from './definition.js';\nimport { frontmatter, parse } from './document.js';\nimport { linkInventory } from './links.js';\nimport { target } from './paths.js';\nimport { refusal } from './refuse.js';\nimport { headingSpans } from './sections.js';\nimport type { Document, Extent, Projection, ProjectionContext, Refusal } from './types.js';\nimport { bodyStartOf, mapEntry } from './yaml.js';\n\nexport type Piece = Extent & { readonly text: string };\n\nexport type Edit = Piece;\n\nexport type Input = {\n readonly values: readonly Piece[];\n readonly ranges: readonly Extent[];\n readonly edits: readonly Edit[];\n};\n\nexport type InputResult =\n | { readonly ok: true; readonly input: Input }\n | { readonly ok: false; readonly refusal: Refusal };\n\nfunction internalEdits(\n content: string,\n bodyStart: number,\n file: string,\n documentTargets: ReadonlySet<string>,\n): Edit[] {\n const inventory = linkInventory(content.slice(bodyStart));\n const internal = new Set<number>();\n const edits: Edit[] = [];\n for (const use of inventory.uses) {\n const resolved = target(file, use.destination.href);\n if (resolved === null || !documentTargets.has(resolved)) continue;\n internal.add(use.destination.start);\n edits.push({\n start: bodyStart + use.start,\n end: bodyStart + use.end,\n text: content.slice(bodyStart + use.labelStart, bodyStart + use.labelEnd),\n });\n }\n for (const block of inventory.blocks) {\n if (!internal.has(block.destination.start)) continue;\n edits.push({ start: bodyStart + block.start, end: bodyStart + block.end, text: '' });\n }\n return edits.sort((left, right) => left.start - right.start);\n}\n\nexport function rangeText(content: string, range: Extent, edits: readonly Edit[]): string {\n let text = '';\n let cursor = range.start;\n for (const edit of edits) {\n if (edit.start < cursor || edit.end > range.end) continue;\n text += content.slice(cursor, edit.start) + edit.text;\n cursor = edit.end;\n }\n return text + content.slice(cursor, range.end);\n}\n\nfunction structural(spec: SectionSpec): boolean {\n return spec.kind === 'list' && spec.of.kind !== 'text';\n}\n\nfunction freeTextValues(definition: Definition, document: Document): Piece[] {\n const root = frontmatter(document);\n if (root === null) return [];\n const values: Piece[] = [];\n for (const [name, spec] of Object.entries(definition.fields)) {\n const entry = mapEntry(root, name);\n if (entry === undefined) continue;\n const node = entry.value;\n if (spec.kind === 'text') {\n if (node.kind === 'scalar' && typeof node.value === 'string') {\n values.push({ start: node.start, end: node.end, text: `${node.value}\\n\\n` });\n }\n continue;\n }\n if (spec.kind !== 'list' || spec.of.kind !== 'text' || node.kind !== 'seq') continue;\n for (const item of node.items) {\n if (item.kind === 'scalar' && typeof item.value === 'string') {\n values.push({ start: item.start, end: item.end, text: `${item.value}\\n\\n` });\n }\n }\n }\n return values;\n}\n\nexport function projectionInput(\n document: Document,\n file: string,\n context: ProjectionContext,\n): InputResult {\n const content = document.content;\n const bodyStart = bodyStartOf(content);\n const edits = internalEdits(content, bodyStart, file, new Set(context.documentTargets));\n const declared = document.type;\n if (declared === undefined || declared === 'any') {\n return {\n ok: true,\n input: { values: [], ranges: [{ start: bodyStart, end: content.length }], edits },\n };\n }\n const source = context.definition;\n if (source === undefined) {\n return { ok: false, refusal: refusal(file, 'unknown-type', { location: 'type' }) };\n }\n const definitionFile = `types/${declared}.md`;\n const parsed = parse(source, definitionFile);\n if (!parsed.ok) return { ok: false, refusal: parsed.refusal };\n const definition = readDefinition(definitionFile, parsed.document);\n if ('rule' in definition) return { ok: false, refusal: definition };\n const structure = new Set(\n Object.entries(definition.sections).flatMap(([name, spec]) => (structural(spec) ? [name] : [])),\n );\n const headings = headingSpans(content, bodyStart);\n const ranges: Extent[] = [{ start: bodyStart, end: headings[0]?.headingStart ?? content.length }];\n for (const heading of headings) {\n if (structure.has(heading.name)) continue;\n ranges.push({ start: heading.headingStart, end: heading.bodyEnd });\n }\n return { ok: true, input: { values: freeTextValues(definition, document), ranges, edits } };\n}\n\nexport function project(\n document: Document,\n file: string,\n context: ProjectionContext = { documentTargets: [] },\n): Projection {\n const result = projectionInput(document, file, context);\n if (!result.ok) return { ok: false, refusal: result.refusal };\n const { values, ranges, edits } = result.input;\n const prose = ranges.map((range) => rangeText(document.content, range, edits)).join('');\n return { ok: true, text: values.map((value) => value.text).join('') + prose };\n}\n"],"names":["readDefinition","frontmatter","parse","linkInventory","target","refusal","headingSpans","bodyStartOf","mapEntry","internalEdits","content","bodyStart","file","documentTargets","inventory","slice","internal","Set","edits","use","uses","resolved","destination","href","has","add","start","push","end","text","labelStart","labelEnd","block","blocks","sort","left","right","rangeText","range","cursor","edit","structural","spec","kind","of","freeTextValues","definition","document","root","values","name","Object","entries","fields","entry","undefined","node","value","item","items","projectionInput","context","declared","type","ok","input","ranges","length","source","location","definitionFile","parsed","structure","sections","flatMap","headings","headingStart","heading","bodyEnd","project","result","prose","map","join"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,15 @@
1
+ import type { Definition } from './definition.js';
1
2
  export type Library = Readonly<Record<string, string>>;
3
+ export type VerifiedModel = {
4
+ readonly types: Readonly<Record<string, Definition>>;
5
+ };
6
+ export type ModelVerification = {
7
+ readonly verdict: 'accept';
8
+ readonly model: VerifiedModel;
9
+ } | ({
10
+ readonly verdict: 'refuse';
11
+ readonly source: 'model';
12
+ } & Refusal);
2
13
  export type ValidationContext = {
3
14
  readonly binaryTargets: readonly string[];
4
15
  };
@@ -34,6 +45,7 @@ export type Validation = {
34
45
  readonly verdict: 'accept';
35
46
  } | ({
36
47
  readonly verdict: 'refuse';
48
+ readonly source?: 'content';
37
49
  } & Refusal);
38
50
  export type Projection = {
39
51
  readonly ok: true;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEvD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,iBAAiB,GAAG;IAChD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAC9B,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAAG,OAAO,CAAC,CAAC;AAE/C,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,QAAQ,GAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,MAAM,GACd;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB,CAAC;AAEN,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/types.ts"],"sourcesContent":["export type Library = Readonly<Record<string, string>>;\n\nexport type ValidationContext = {\n readonly binaryTargets: readonly string[];\n};\n\nexport type ProjectionContext = {\n readonly documentTargets: readonly string[];\n readonly definition?: string;\n};\n\nexport type DivisionContext = ProjectionContext & {\n readonly budget: number;\n};\n\nexport type Extent = {\n readonly start: number;\n readonly end: number;\n};\n\nexport type Span = Extent & {\n readonly text: string;\n};\n\nexport type Document = {\n readonly content: string;\n readonly type: string | undefined;\n readonly fields: Readonly<Record<string, unknown>>;\n readonly preamble: string;\n readonly sections: Readonly<Record<string, string>>;\n};\n\nexport type Refusal = {\n readonly file: string;\n readonly rule: string;\n readonly version: string;\n readonly location?: string;\n readonly referrers?: readonly string[];\n};\n\nexport type Validation =\n | { readonly verdict: 'accept' }\n | ({ readonly verdict: 'refuse' } & Refusal);\n\nexport type Projection =\n | { readonly ok: true; readonly text: string }\n | { readonly ok: false; readonly refusal: Refusal };\n\nexport type Division =\n | { readonly ok: true; readonly spans: readonly Span[] }\n | { readonly ok: false; readonly refusal: Refusal };\n\nexport type ParseResult =\n | { readonly ok: true; readonly document: Document }\n | { readonly ok: false; readonly refusal: Refusal };\n\nexport type Link = {\n readonly href: string;\n readonly target: string;\n};\n\nexport type Change =\n | {\n readonly kind: 'field';\n readonly name: string;\n readonly value: unknown;\n readonly prior: unknown;\n }\n | {\n readonly kind: 'section';\n readonly name: string;\n readonly value: string;\n readonly prior: string;\n }\n | {\n readonly kind: 'preamble';\n readonly value: string;\n readonly prior: string;\n }\n | {\n readonly kind: 'link';\n readonly href: string;\n readonly to: string;\n };\n\nexport type ApplyResult =\n | { readonly outcome: 'applied'; readonly document: Document }\n | { readonly outcome: 'stale'; readonly document: Document }\n | { readonly outcome: 'refuse'; readonly refusal: Refusal };\n"],"names":[],"mappings":"AAqFA,WAG8D"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/types.ts"],"sourcesContent":["import type { Definition } from './definition.js';\n\nexport type Library = Readonly<Record<string, string>>;\n\nexport type VerifiedModel = {\n readonly types: Readonly<Record<string, Definition>>;\n};\n\nexport type ModelVerification =\n | { readonly verdict: 'accept'; readonly model: VerifiedModel }\n | ({ readonly verdict: 'refuse'; readonly source: 'model' } & Refusal);\n\nexport type ValidationContext = {\n readonly binaryTargets: readonly string[];\n};\n\nexport type ProjectionContext = {\n readonly documentTargets: readonly string[];\n readonly definition?: string;\n};\n\nexport type DivisionContext = ProjectionContext & {\n readonly budget: number;\n};\n\nexport type Extent = {\n readonly start: number;\n readonly end: number;\n};\n\nexport type Span = Extent & {\n readonly text: string;\n};\n\nexport type Document = {\n readonly content: string;\n readonly type: string | undefined;\n readonly fields: Readonly<Record<string, unknown>>;\n readonly preamble: string;\n readonly sections: Readonly<Record<string, string>>;\n};\n\nexport type Refusal = {\n readonly file: string;\n readonly rule: string;\n readonly version: string;\n readonly location?: string;\n readonly referrers?: readonly string[];\n};\n\nexport type Validation =\n | { readonly verdict: 'accept' }\n | ({ readonly verdict: 'refuse'; readonly source?: 'content' } & Refusal);\n\nexport type Projection =\n | { readonly ok: true; readonly text: string }\n | { readonly ok: false; readonly refusal: Refusal };\n\nexport type Division =\n | { readonly ok: true; readonly spans: readonly Span[] }\n | { readonly ok: false; readonly refusal: Refusal };\n\nexport type ParseResult =\n | { readonly ok: true; readonly document: Document }\n | { readonly ok: false; readonly refusal: Refusal };\n\nexport type Link = {\n readonly href: string;\n readonly target: string;\n};\n\nexport type Change =\n | {\n readonly kind: 'field';\n readonly name: string;\n readonly value: unknown;\n readonly prior: unknown;\n }\n | {\n readonly kind: 'section';\n readonly name: string;\n readonly value: string;\n readonly prior: string;\n }\n | {\n readonly kind: 'preamble';\n readonly value: string;\n readonly prior: string;\n }\n | {\n readonly kind: 'link';\n readonly href: string;\n readonly to: string;\n };\n\nexport type ApplyResult =\n | { readonly outcome: 'applied'; readonly document: Document }\n | { readonly outcome: 'stale'; readonly document: Document }\n | { readonly outcome: 'refuse'; readonly refusal: Refusal };\n"],"names":[],"mappings":"AA+FA,WAG8D"}
@@ -1,3 +1,5 @@
1
- import type { Library, Validation, ValidationContext } from './types.js';
2
- export declare function validate(library: Library, context?: ValidationContext): Validation;
1
+ import type { Document, Library, ModelVerification, Validation, ValidationContext, VerifiedModel } from './types.js';
2
+ export declare function verify(definitions: Library): ModelVerification;
3
+ export declare function verifyDocuments(definitions: Readonly<Record<string, Document>>): ModelVerification;
4
+ export declare function validate(library: Library, context?: ValidationContext, model?: VerifiedModel): Validation;
3
5
  //# sourceMappingURL=validate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAY,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAuCnF,wBAAgB,QAAQ,CACtB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,iBAAyC,GACjD,UAAU,CAuHZ"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,QAAQ,EACR,OAAO,EACP,iBAAiB,EAGjB,UAAU,EACV,iBAAiB,EACjB,aAAa,EACd,MAAM,YAAY,CAAC;AA2CpB,wBAAgB,MAAM,CAAC,WAAW,EAAE,OAAO,GAAG,iBAAiB,CAI9D;AAED,wBAAgB,eAAe,CAC7B,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,GAC9C,iBAAiB,CAKnB;AAwCD,wBAAgB,QAAQ,CACtB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,iBAAyC,EAClD,KAAK,CAAC,EAAE,aAAa,GACpB,UAAU,CAKZ"}
package/dist/validate.js CHANGED
@@ -12,8 +12,8 @@ function refuse(file, rule, extra) {
12
12
  ...refusal(file, rule, extra)
13
13
  };
14
14
  }
15
- function instanceType(document, file) {
16
- if (isTypesPath(file)) return 'definition';
15
+ function instanceType(document, file, model) {
16
+ if (model === undefined && isTypesPath(file)) return 'definition';
17
17
  const raw = document.fields.type;
18
18
  if (raw === undefined || raw === null) return 'any';
19
19
  if (typeof raw !== 'string' || raw === '') return 'invalid';
@@ -38,9 +38,63 @@ function declaredTypeOf(content) {
38
38
  if (!parsed.ok) return undefined;
39
39
  return parsed.document.type ?? 'any';
40
40
  }
41
+ export function verify(definitions) {
42
+ return verifyEntries(Object.keys(definitions).sort(), (address)=>parse(definitions[address], address));
43
+ }
44
+ export function verifyDocuments(definitions) {
45
+ return verifyEntries(Object.keys(definitions).sort(), (address)=>({
46
+ ok: true,
47
+ document: definitions[address]
48
+ }));
49
+ }
50
+ function verifyEntries(addresses, read) {
51
+ const definitionsByName = new Map();
52
+ for (const address of addresses){
53
+ const failure = collectDefinition(definitionsByName, address, read(address));
54
+ if (failure !== undefined) return {
55
+ verdict: 'refuse',
56
+ source: 'model',
57
+ ...failure
58
+ };
59
+ }
60
+ const types = Object.create(null);
61
+ for (const [name, definition] of definitionsByName)types[name] = definition;
62
+ return {
63
+ verdict: 'accept',
64
+ model: Object.freeze({
65
+ types: Object.freeze(types)
66
+ })
67
+ };
68
+ }
69
+ function collectDefinition(definitions, address, parsed) {
70
+ if (!parsed.ok) return parsed.refusal;
71
+ const definition = readDefinition(address, parsed.document);
72
+ if ('rule' in definition) return definition;
73
+ if (definitions.has(definition.name)) return refusal(address, 'definition-duplicate', {
74
+ location: definition.name
75
+ });
76
+ for (const spec of Object.values(definition.fields))freezeSpec(spec);
77
+ for (const spec of Object.values(definition.sections))freezeSpec(spec);
78
+ Object.freeze(definition.fields);
79
+ Object.freeze(definition.sections);
80
+ definitions.set(definition.name, Object.freeze(definition));
81
+ return undefined;
82
+ }
83
+ function freezeSpec(spec) {
84
+ if (spec.kind === 'list') freezeSpec(spec.of);
85
+ if (spec.kind === 'enum') Object.freeze(spec.values);
86
+ Object.freeze(spec);
87
+ }
41
88
  export function validate(library, context = {
42
89
  binaryTargets: []
43
- }) {
90
+ }, model) {
91
+ const verdict = validateLibrary(library, context, model);
92
+ return model !== undefined && verdict.verdict === 'refuse' ? {
93
+ ...verdict,
94
+ source: 'content'
95
+ } : verdict;
96
+ }
97
+ function validateLibrary(library, context, model) {
44
98
  const binaryTargets = new Set(context.binaryTargets);
45
99
  const files = Object.keys(library).sort();
46
100
  const documents = new Map();
@@ -54,28 +108,27 @@ export function validate(library, context = {
54
108
  };
55
109
  }
56
110
  const definitions = new Map();
57
- for (const file of files){
58
- if (!isTypesPath(file)) continue;
59
- const parsed = documents.get(file);
60
- if (parsed === undefined || !parsed.ok) continue;
61
- const definition = readDefinition(file, parsed.document);
62
- if ('rule' in definition) return {
63
- verdict: 'refuse',
64
- ...definition
65
- };
66
- const existing = definitions.get(definition.name);
67
- if (existing !== undefined) return refuse(file, 'definition-duplicate', {
68
- location: definition.name
69
- });
70
- definitions.set(definition.name, definition);
111
+ if (model !== undefined) {
112
+ for (const [name, definition] of Object.entries(model.types))definitions.set(name, definition);
113
+ } else {
114
+ for (const file of files){
115
+ if (!isTypesPath(file)) continue;
116
+ const parsed = documents.get(file);
117
+ if (parsed === undefined) continue;
118
+ const failure = collectDefinition(definitions, file, parsed);
119
+ if (failure !== undefined) return {
120
+ verdict: 'refuse',
121
+ ...failure
122
+ };
123
+ }
71
124
  }
72
125
  for (const file of files){
73
126
  const parsed = documents.get(file);
74
127
  if (parsed === undefined || !parsed.ok) continue;
75
- const kind = instanceType(parsed.document, file);
128
+ const kind = instanceType(parsed.document, file, model);
76
129
  if (kind === 'any') continue;
77
130
  if (kind === 'invalid' || kind === 'definition') {
78
- if (kind === 'definition' && isTypesPath(file)) continue;
131
+ if (kind === 'definition' && model === undefined && isTypesPath(file)) continue;
79
132
  return refuse(file, 'unknown-type', {
80
133
  location: 'type'
81
134
  });
@@ -117,7 +170,7 @@ export function validate(library, context = {
117
170
  for (const file of files){
118
171
  const parsed = documents.get(file);
119
172
  if (parsed === undefined || !parsed.ok) continue;
120
- const kind = instanceType(parsed.document, file);
173
+ const kind = instanceType(parsed.document, file, model);
121
174
  if (kind === 'any' || kind === 'definition' || kind === 'invalid') continue;
122
175
  const definition = definitions.get(kind);
123
176
  if (definition === undefined) continue;
@@ -150,7 +203,7 @@ export function validate(library, context = {
150
203
  for (const file of files){
151
204
  const parsed = documents.get(file);
152
205
  if (parsed === undefined || !parsed.ok) continue;
153
- const kind = instanceType(parsed.document, file);
206
+ const kind = instanceType(parsed.document, file, model);
154
207
  if (kind === 'any' || kind === 'definition' || kind === 'invalid') continue;
155
208
  const definition = definitions.get(kind);
156
209
  if (definition === undefined) continue;
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/validate.ts"],"sourcesContent":["import { readDefinition, type Definition, type FieldSpec } from './definition.js';\nimport { parse } from './document.js';\nimport { hrefOccurrences } from './links.js';\nimport { classifyHref, isTypesPath } from './paths.js';\nimport { refusal } from './refuse.js';\nimport { parseListSection } from './sections.js';\nimport { validateFields } from './schema.js';\nimport type { Document, Library, Validation, ValidationContext } from './types.js';\nimport { bodyAfterFrontmatter } from './yaml.js';\n\nfunction refuse(\n file: string,\n rule: string,\n extra?: { location?: string; referrers?: readonly string[] },\n): Validation {\n return { verdict: 'refuse', ...refusal(file, rule, extra) };\n}\n\nfunction instanceType(document: Document, file: string): 'any' | 'definition' | 'invalid' | string {\n if (isTypesPath(file)) return 'definition';\n const raw = document.fields.type;\n if (raw === undefined || raw === null) return 'any';\n if (typeof raw !== 'string' || raw === '') return 'invalid';\n return raw;\n}\n\nfunction referenceTargets(spec: FieldSpec, value: unknown): string[] {\n if (spec.kind === 'reference' && typeof value === 'string') return [value];\n if (spec.kind === 'list' && spec.of.kind === 'reference' && Array.isArray(value)) {\n return value.filter((item): item is string => typeof item === 'string');\n }\n return [];\n}\n\nfunction expectedReferenceType(spec: FieldSpec): string | null {\n if (spec.kind === 'reference') return spec.to;\n if (spec.kind === 'list' && spec.of.kind === 'reference') return spec.of.to;\n return null;\n}\n\nfunction declaredTypeOf(content: string): string | undefined {\n const parsed = parse(content);\n if (!parsed.ok) return undefined;\n return parsed.document.type ?? 'any';\n}\n\nexport function validate(\n library: Library,\n context: ValidationContext = { binaryTargets: [] },\n): Validation {\n const binaryTargets = new Set(context.binaryTargets);\n const files = Object.keys(library).sort();\n const documents = new Map<string, ReturnType<typeof parse>>();\n for (const file of files) {\n if (binaryTargets.has(file)) return refuse(file, 'binary-target-document');\n const parsed = parse(library[file]!, file);\n documents.set(file, parsed);\n if (!parsed.ok) return { verdict: 'refuse', ...parsed.refusal };\n }\n\n const definitions = new Map<string, Definition>();\n for (const file of files) {\n if (!isTypesPath(file)) continue;\n const parsed = documents.get(file);\n if (parsed === undefined || !parsed.ok) continue;\n const definition = readDefinition(file, parsed.document);\n if ('rule' in definition) return { verdict: 'refuse', ...definition };\n const existing = definitions.get(definition.name);\n if (existing !== undefined)\n return refuse(file, 'definition-duplicate', { location: definition.name });\n definitions.set(definition.name, definition);\n }\n\n for (const file of files) {\n const parsed = documents.get(file);\n if (parsed === undefined || !parsed.ok) continue;\n const kind = instanceType(parsed.document, file);\n if (kind === 'any') continue;\n if (kind === 'invalid' || kind === 'definition') {\n if (kind === 'definition' && isTypesPath(file)) continue;\n return refuse(file, 'unknown-type', { location: 'type' });\n }\n const definition = definitions.get(kind);\n if (definition === undefined) return refuse(file, 'unknown-type', { location: 'type' });\n const fieldFailure = validateFields(definition.fields, parsed.document.fields);\n if (fieldFailure !== undefined) {\n return refuse(file, fieldFailure.rule, { location: fieldFailure.field });\n }\n const declaredFields = new Set(Object.keys(definition.fields));\n const undeclared = Object.keys(parsed.document.fields).find(\n (name) => !['type', 'site', 'received'].includes(name) && !declaredFields.has(name),\n );\n if (undeclared !== undefined) return refuse(file, 'undeclared-field', { location: undeclared });\n for (const [name, spec] of Object.entries(definition.sections)) {\n const body = parsed.document.sections[name];\n if (body === undefined) {\n if (spec.required) return refuse(file, 'required-section', { location: name });\n continue;\n }\n if (spec.kind === 'list' && !parseListSection(body)) {\n return refuse(file, 'structured-section', { location: name });\n }\n }\n }\n\n for (const file of files) {\n const parsed = documents.get(file);\n if (parsed === undefined || !parsed.ok) continue;\n const kind = instanceType(parsed.document, file);\n if (kind === 'any' || kind === 'definition' || kind === 'invalid') continue;\n const definition = definitions.get(kind);\n if (definition === undefined) continue;\n for (const [name, spec] of Object.entries(definition.fields)) {\n const targets = referenceTargets(spec, parsed.document.fields[name]);\n const expected = expectedReferenceType(spec);\n if (expected === null) continue;\n for (const target of targets) {\n const resolved = classifyHref(file, target);\n if (resolved.kind !== 'path' || binaryTargets.has(resolved.path))\n return refuse(file, 'unresolved-reference', { location: name });\n if (!documents.has(resolved.path)) continue;\n const targetType = declaredTypeOf(library[resolved.path]!);\n if (targetType !== expected)\n return refuse(file, 'unresolved-reference', { location: name });\n }\n }\n const body = bodyAfterFrontmatter(library[file]!);\n for (const occurrence of hrefOccurrences(body)) {\n const resolved = classifyHref(file, occurrence.href);\n if (resolved.kind === 'skip') continue;\n if (\n resolved.kind === 'invalid' ||\n (!documents.has(resolved.path) && !binaryTargets.has(resolved.path))\n ) {\n return refuse(file, 'unresolved-link');\n }\n }\n }\n\n const missing = new Map<string, string[]>();\n for (const file of files) {\n const parsed = documents.get(file);\n if (parsed === undefined || !parsed.ok) continue;\n const kind = instanceType(parsed.document, file);\n if (kind === 'any' || kind === 'definition' || kind === 'invalid') continue;\n const definition = definitions.get(kind);\n if (definition === undefined) continue;\n for (const [name, spec] of Object.entries(definition.fields)) {\n const expected = expectedReferenceType(spec);\n if (expected === null) continue;\n for (const target of referenceTargets(spec, parsed.document.fields[name])) {\n const resolved = classifyHref(file, target);\n if (resolved.kind !== 'path') continue;\n if (documents.has(resolved.path)) continue;\n const referrers = missing.get(resolved.path) ?? [];\n referrers.push(file);\n missing.set(resolved.path, referrers);\n }\n }\n }\n const missingPaths = [...missing.keys()].sort();\n if (missingPaths.length > 0) {\n const path = missingPaths[0]!;\n const referrers = [...new Set(missing.get(path) ?? [])].sort();\n return refuse(path, 'referenced-missing-file', { referrers });\n }\n\n return { verdict: 'accept' };\n}\n"],"names":["readDefinition","parse","hrefOccurrences","classifyHref","isTypesPath","refusal","parseListSection","validateFields","bodyAfterFrontmatter","refuse","file","rule","extra","verdict","instanceType","document","raw","fields","type","undefined","referenceTargets","spec","value","kind","of","Array","isArray","filter","item","expectedReferenceType","to","declaredTypeOf","content","parsed","ok","validate","library","context","binaryTargets","Set","files","Object","keys","sort","documents","Map","has","set","definitions","get","definition","existing","name","location","fieldFailure","field","declaredFields","undeclared","find","includes","entries","sections","body","required","targets","expected","target","resolved","path","targetType","occurrence","href","missing","referrers","push","missingPaths","length"],"mappings":"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"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/validate.ts"],"sourcesContent":["import { readDefinition, type Definition, type FieldSpec } from './definition.js';\nimport { parse } from './document.js';\nimport { hrefOccurrences } from './links.js';\nimport { classifyHref, isTypesPath } from './paths.js';\nimport { refusal } from './refuse.js';\nimport { parseListSection } from './sections.js';\nimport { validateFields } from './schema.js';\nimport type {\n Document,\n Library,\n ModelVerification,\n ParseResult,\n Refusal,\n Validation,\n ValidationContext,\n VerifiedModel,\n} from './types.js';\nimport { bodyAfterFrontmatter } from './yaml.js';\n\nfunction refuse(\n file: string,\n rule: string,\n extra?: { location?: string; referrers?: readonly string[] },\n): Validation {\n return { verdict: 'refuse', ...refusal(file, rule, extra) };\n}\n\nfunction instanceType(\n document: Document,\n file: string,\n model?: VerifiedModel,\n): 'any' | 'definition' | 'invalid' | string {\n if (model === undefined && isTypesPath(file)) return 'definition';\n const raw = document.fields.type;\n if (raw === undefined || raw === null) return 'any';\n if (typeof raw !== 'string' || raw === '') return 'invalid';\n return raw;\n}\n\nfunction referenceTargets(spec: FieldSpec, value: unknown): string[] {\n if (spec.kind === 'reference' && typeof value === 'string') return [value];\n if (spec.kind === 'list' && spec.of.kind === 'reference' && Array.isArray(value)) {\n return value.filter((item): item is string => typeof item === 'string');\n }\n return [];\n}\n\nfunction expectedReferenceType(spec: FieldSpec): string | null {\n if (spec.kind === 'reference') return spec.to;\n if (spec.kind === 'list' && spec.of.kind === 'reference') return spec.of.to;\n return null;\n}\n\nfunction declaredTypeOf(content: string): string | undefined {\n const parsed = parse(content);\n if (!parsed.ok) return undefined;\n return parsed.document.type ?? 'any';\n}\n\nexport function verify(definitions: Library): ModelVerification {\n return verifyEntries(Object.keys(definitions).sort(), (address) =>\n parse(definitions[address]!, address),\n );\n}\n\nexport function verifyDocuments(\n definitions: Readonly<Record<string, Document>>,\n): ModelVerification {\n return verifyEntries(Object.keys(definitions).sort(), (address) => ({\n ok: true,\n document: definitions[address]!,\n }));\n}\n\nfunction verifyEntries(\n addresses: readonly string[],\n read: (address: string) => ParseResult,\n): ModelVerification {\n const definitionsByName = new Map<string, Definition>();\n for (const address of addresses) {\n const failure = collectDefinition(definitionsByName, address, read(address));\n if (failure !== undefined) return { verdict: 'refuse', source: 'model', ...failure };\n }\n const types: Record<string, Definition> = Object.create(null);\n for (const [name, definition] of definitionsByName) types[name] = definition;\n return { verdict: 'accept', model: Object.freeze({ types: Object.freeze(types) }) };\n}\n\nfunction collectDefinition(\n definitions: Map<string, Definition>,\n address: string,\n parsed: ParseResult,\n): Refusal | undefined {\n if (!parsed.ok) return parsed.refusal;\n const definition = readDefinition(address, parsed.document);\n if ('rule' in definition) return definition;\n if (definitions.has(definition.name))\n return refusal(address, 'definition-duplicate', { location: definition.name });\n for (const spec of Object.values(definition.fields)) freezeSpec(spec);\n for (const spec of Object.values(definition.sections)) freezeSpec(spec);\n Object.freeze(definition.fields);\n Object.freeze(definition.sections);\n definitions.set(definition.name, Object.freeze(definition));\n return undefined;\n}\n\nfunction freezeSpec(spec: FieldSpec): void {\n if (spec.kind === 'list') freezeSpec(spec.of);\n if (spec.kind === 'enum') Object.freeze(spec.values);\n Object.freeze(spec);\n}\n\nexport function validate(\n library: Library,\n context: ValidationContext = { binaryTargets: [] },\n model?: VerifiedModel,\n): Validation {\n const verdict = validateLibrary(library, context, model);\n return model !== undefined && verdict.verdict === 'refuse'\n ? { ...verdict, source: 'content' }\n : verdict;\n}\n\nfunction validateLibrary(\n library: Library,\n context: ValidationContext,\n model?: VerifiedModel,\n): Validation {\n const binaryTargets = new Set(context.binaryTargets);\n const files = Object.keys(library).sort();\n const documents = new Map<string, ReturnType<typeof parse>>();\n for (const file of files) {\n if (binaryTargets.has(file)) return refuse(file, 'binary-target-document');\n const parsed = parse(library[file]!, file);\n documents.set(file, parsed);\n if (!parsed.ok) return { verdict: 'refuse', ...parsed.refusal };\n }\n\n const definitions = new Map<string, Definition>();\n if (model !== undefined) {\n for (const [name, definition] of Object.entries(model.types)) definitions.set(name, definition);\n } else {\n for (const file of files) {\n if (!isTypesPath(file)) continue;\n const parsed = documents.get(file);\n if (parsed === undefined) continue;\n const failure = collectDefinition(definitions, file, parsed);\n if (failure !== undefined) return { verdict: 'refuse', ...failure };\n }\n }\n\n for (const file of files) {\n const parsed = documents.get(file);\n if (parsed === undefined || !parsed.ok) continue;\n const kind = instanceType(parsed.document, file, model);\n if (kind === 'any') continue;\n if (kind === 'invalid' || kind === 'definition') {\n if (kind === 'definition' && model === undefined && isTypesPath(file)) continue;\n return refuse(file, 'unknown-type', { location: 'type' });\n }\n const definition = definitions.get(kind);\n if (definition === undefined) return refuse(file, 'unknown-type', { location: 'type' });\n const fieldFailure = validateFields(definition.fields, parsed.document.fields);\n if (fieldFailure !== undefined) {\n return refuse(file, fieldFailure.rule, { location: fieldFailure.field });\n }\n const declaredFields = new Set(Object.keys(definition.fields));\n const undeclared = Object.keys(parsed.document.fields).find(\n (name) => !['type', 'site', 'received'].includes(name) && !declaredFields.has(name),\n );\n if (undeclared !== undefined) return refuse(file, 'undeclared-field', { location: undeclared });\n for (const [name, spec] of Object.entries(definition.sections)) {\n const body = parsed.document.sections[name];\n if (body === undefined) {\n if (spec.required) return refuse(file, 'required-section', { location: name });\n continue;\n }\n if (spec.kind === 'list' && !parseListSection(body)) {\n return refuse(file, 'structured-section', { location: name });\n }\n }\n }\n\n for (const file of files) {\n const parsed = documents.get(file);\n if (parsed === undefined || !parsed.ok) continue;\n const kind = instanceType(parsed.document, file, model);\n if (kind === 'any' || kind === 'definition' || kind === 'invalid') continue;\n const definition = definitions.get(kind);\n if (definition === undefined) continue;\n for (const [name, spec] of Object.entries(definition.fields)) {\n const targets = referenceTargets(spec, parsed.document.fields[name]);\n const expected = expectedReferenceType(spec);\n if (expected === null) continue;\n for (const target of targets) {\n const resolved = classifyHref(file, target);\n if (resolved.kind !== 'path' || binaryTargets.has(resolved.path))\n return refuse(file, 'unresolved-reference', { location: name });\n if (!documents.has(resolved.path)) continue;\n const targetType = declaredTypeOf(library[resolved.path]!);\n if (targetType !== expected)\n return refuse(file, 'unresolved-reference', { location: name });\n }\n }\n const body = bodyAfterFrontmatter(library[file]!);\n for (const occurrence of hrefOccurrences(body)) {\n const resolved = classifyHref(file, occurrence.href);\n if (resolved.kind === 'skip') continue;\n if (\n resolved.kind === 'invalid' ||\n (!documents.has(resolved.path) && !binaryTargets.has(resolved.path))\n ) {\n return refuse(file, 'unresolved-link');\n }\n }\n }\n\n const missing = new Map<string, string[]>();\n for (const file of files) {\n const parsed = documents.get(file);\n if (parsed === undefined || !parsed.ok) continue;\n const kind = instanceType(parsed.document, file, model);\n if (kind === 'any' || kind === 'definition' || kind === 'invalid') continue;\n const definition = definitions.get(kind);\n if (definition === undefined) continue;\n for (const [name, spec] of Object.entries(definition.fields)) {\n const expected = expectedReferenceType(spec);\n if (expected === null) continue;\n for (const target of referenceTargets(spec, parsed.document.fields[name])) {\n const resolved = classifyHref(file, target);\n if (resolved.kind !== 'path') continue;\n if (documents.has(resolved.path)) continue;\n const referrers = missing.get(resolved.path) ?? [];\n referrers.push(file);\n missing.set(resolved.path, referrers);\n }\n }\n }\n const missingPaths = [...missing.keys()].sort();\n if (missingPaths.length > 0) {\n const path = missingPaths[0]!;\n const referrers = [...new Set(missing.get(path) ?? [])].sort();\n return refuse(path, 'referenced-missing-file', { referrers });\n }\n\n return { verdict: 'accept' };\n}\n"],"names":["readDefinition","parse","hrefOccurrences","classifyHref","isTypesPath","refusal","parseListSection","validateFields","bodyAfterFrontmatter","refuse","file","rule","extra","verdict","instanceType","document","model","undefined","raw","fields","type","referenceTargets","spec","value","kind","of","Array","isArray","filter","item","expectedReferenceType","to","declaredTypeOf","content","parsed","ok","verify","definitions","verifyEntries","Object","keys","sort","address","verifyDocuments","addresses","read","definitionsByName","Map","failure","collectDefinition","source","types","create","name","definition","freeze","has","location","values","freezeSpec","sections","set","validate","library","context","binaryTargets","validateLibrary","Set","files","documents","entries","get","fieldFailure","field","declaredFields","undeclared","find","includes","body","required","targets","expected","target","resolved","path","targetType","occurrence","href","missing","referrers","push","missingPaths","length"],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.0-alpha.13";
1
+ export declare const VERSION = "0.1.0-alpha.15";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
- export const VERSION = '0.1.0-alpha.13';
1
+ export const VERSION = '0.1.0-alpha.15';
2
2
 
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/version.ts"],"sourcesContent":["export const VERSION = '0.1.0-alpha.13';\n"],"names":["VERSION"],"mappings":"AAAA,OAAO,MAAMA,UAAU,iBAAiB"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/version.ts"],"sourcesContent":["export const VERSION = '0.1.0-alpha.15';\n"],"names":["VERSION"],"mappings":"AAAA,OAAO,MAAMA,UAAU,iBAAiB"}
@@ -2,10 +2,13 @@
2
2
 
3
3
  Each directory under `cases/` is one text Library, one validation context,
4
4
  and one expected verdict. Consumers load the files under `library/` as
5
- path-to-content, load the required `context.json` as `ValidationContext`, and
6
- compare `validate(library, context)` against `expected.json`. Text-only cases
7
- carry `{ "binaryTargets": [] }`. Binary targets are membership declarations;
8
- the corpus supplies no binary bytes or placeholder Documents.
5
+ path-to-content and the required `context.json` as `ValidationContext`. Cases
6
+ with a `definitions/` directory load those files into a separate address-to-text
7
+ map, call `verify(definitions)`, then compare its refusal or
8
+ `validate(library, context, verified.model)` against `expected.json`. Other
9
+ cases compare `validate(library, context)` directly. Text-only cases carry
10
+ `{ "binaryTargets": [] }`. Binary targets are membership declarations; the
11
+ corpus supplies no binary bytes or placeholder Documents.
9
12
 
10
13
  ## Preamble operations
11
14
 
@@ -81,6 +84,9 @@ Refusal:
81
84
 
82
85
  `location` is omitted when the rule is not about a field or section.
83
86
  `referrers` is present only for `referenced-missing-file`.
87
+ Separate-model cases add `source: "model"` to a verification refusal or
88
+ `source: "content"` to a validation refusal. A definition refusal's `file` is
89
+ its supplied canonical address; a content refusal's `file` is its Library Path.
84
90
  The `version` field in these fixtures is the token `<package-version>`;
85
91
  replace it with the package's semantic version before comparing.
86
92
 
@@ -102,7 +108,7 @@ replace it with the package's semantic version before comparing.
102
108
  | `definition-section` | A section spec is not an object of the accepted keys |
103
109
  | `definition-section-kind` | A section kind is not `text` or `list` |
104
110
  | `definition-duplicate` | Two definition files share a type name |
105
- | `unknown-type` | A file declares a type that is not in `types/` |
111
+ | `unknown-type` | A file declares a type absent from the governing definitions |
106
112
  | `required-field` | A required field is missing |
107
113
  | `required-section` | A required section heading is missing |
108
114
  | `field-kind` | A field value fails its kind, including date |
@@ -0,0 +1 @@
1
+ {"binaryTargets":[]}
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: definition
3
+ fields:
4
+ title: { kind: widget }
5
+ ---
@@ -0,0 +1 @@
1
+ {"verdict":"refuse","source":"model","file":"schema/task.md","location":"title","rule":"definition-field-kind","version":"<package-version>"}
@@ -0,0 +1 @@
1
+ {"binaryTargets":[]}
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: definition
3
+ fields:
4
+ title: { kind: string }
5
+ ---
@@ -0,0 +1 @@
1
+ {"verdict":"refuse","source":"content","file":"item.md","location":"type","rule":"unknown-type","version":"<package-version>"}
@@ -0,0 +1,3 @@
1
+ ---
2
+ type: missing
3
+ ---
@@ -0,0 +1 @@
1
+ {"binaryTargets":[]}
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: definition
3
+ fields:
4
+ title: { kind: string, required: true }
5
+ ---
@@ -0,0 +1 @@
1
+ {"verdict":"accept"}
@@ -0,0 +1,4 @@
1
+ ---
2
+ type: task
3
+ title: Shipped
4
+ ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentshouse/mdmodel",
3
- "version": "0.1.0-alpha.13",
3
+ "version": "0.1.0-alpha.15",
4
4
  "description": "MD Type language, parser, validator, structured change application, Markdown syntax profile, and conformance fixtures",
5
5
  "license": "MIT",
6
6
  "type": "module",