@agentshouse/mdmodel 0.1.0-alpha.14 → 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.
package/README.md CHANGED
@@ -28,7 +28,9 @@ import {
28
28
  MARKDOWN_SYNTAX_PROFILE,
29
29
  parse,
30
30
  project,
31
+ retarget,
31
32
  serialize,
33
+ target,
32
34
  validate,
33
35
  verify,
34
36
  verifyDocuments,
@@ -160,6 +162,21 @@ link, one that is empty, a bare fragment, or carries a URL scheme, and one that
160
162
  leaves the collection are not in the inventory. Frontmatter field values,
161
163
  including typed references, are not link destinations and are never enumerated.
162
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
+
163
180
  `apply(document, { kind: 'link', href, to })` rewrites every body occurrence of
164
181
  that written destination and changes nothing else, so a caller that moves a Path
165
182
  rewrites its referring Documents without a second Markdown parser. `to` is the
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,5 +1,6 @@
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
6
  export type { Definition, FieldSpec, SectionSpec } from './definition.js';
@@ -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,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"}
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,5 +1,6 @@
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
6
  export { validate, verify, verifyDocuments } from './validate.js';
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 { 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","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,uBAAuB,QAAQ,eAAe;AACvD,SAASC,OAAO,QAAQ,eAAe;AAoBvC,SAASC,QAAQ,EAAEC,MAAM,EAAEC,eAAe,QAAQ,gBAAgB;AAClE,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/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.0-alpha.14";
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.14';
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.14';\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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentshouse/mdmodel",
3
- "version": "0.1.0-alpha.14",
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",