@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.
- package/README.md +42 -2
- package/dist/definition.d.ts +1 -1
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +4 -2
- package/dist/definition.js.map +1 -1
- package/dist/document.js +5 -5
- package/dist/document.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/paths.d.ts +2 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +9 -5
- package/dist/paths.js.map +1 -1
- package/dist/project.js +3 -3
- package/dist/project.js.map +1 -1
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/validate.d.ts +4 -2
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +74 -21
- package/dist/validate.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/fixtures/README.md +11 -5
- package/fixtures/cases/external-invalid-model/context.json +1 -0
- package/fixtures/cases/external-invalid-model/definitions/schema/task.md +5 -0
- package/fixtures/cases/external-invalid-model/expected.json +1 -0
- package/fixtures/cases/external-invalid-model/library/note.md +1 -0
- package/fixtures/cases/external-unknown-type/context.json +1 -0
- package/fixtures/cases/external-unknown-type/definitions/schema/task.md +5 -0
- package/fixtures/cases/external-unknown-type/expected.json +1 -0
- package/fixtures/cases/external-unknown-type/library/item.md +3 -0
- package/fixtures/cases/external-valid/context.json +1 -0
- package/fixtures/cases/external-valid/definitions/types/task.md +5 -0
- package/fixtures/cases/external-valid/expected.json +1 -0
- package/fixtures/cases/external-valid/library/types/task.md +4 -0
- 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
|
|
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
|
-
`
|
|
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
|
package/dist/definition.d.ts
CHANGED
|
@@ -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
|
|
33
|
+
readonly address: string;
|
|
34
34
|
readonly fields: Readonly<Record<string, FieldSpec>>;
|
|
35
35
|
readonly sections: Readonly<Record<string, SectionSpec>>;
|
|
36
36
|
};
|
package/dist/definition.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/definition.js
CHANGED
|
@@ -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
|
|
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
|
};
|
package/dist/definition.js.map
CHANGED
|
@@ -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 {
|
|
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 =
|
|
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 =
|
|
217
|
-
if (resolved
|
|
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
|
|
221
|
+
target: resolved
|
|
222
222
|
});
|
|
223
223
|
}
|
|
224
224
|
return found;
|
package/dist/document.js.map
CHANGED
|
@@ -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 {
|
|
6
|
-
export {
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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;
|
|
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
|
package/dist/paths.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
|
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 {
|
|
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 =
|
|
14
|
-
if (resolved
|
|
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,
|
package/dist/project.js.map
CHANGED
|
@@ -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;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -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;
|
|
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":["
|
|
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"}
|
package/dist/validate.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import type { Library, Validation, ValidationContext } from './types.js';
|
|
2
|
-
export declare function
|
|
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
|
package/dist/validate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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;
|
package/dist/validate.js.map
CHANGED
|
@@ -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.
|
|
1
|
+
export declare const VERSION = "0.1.0-alpha.15";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/workspace/packages/mdmodel/src/version.ts"],"sourcesContent":["export const VERSION = '0.1.0-alpha.
|
|
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/fixtures/README.md
CHANGED
|
@@ -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
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
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 @@
|
|
|
1
|
+
{"verdict":"refuse","source":"model","file":"schema/task.md","location":"title","rule":"definition-field-kind","version":"<package-version>"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Loose
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"binaryTargets":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"verdict":"refuse","source":"content","file":"item.md","location":"type","rule":"unknown-type","version":"<package-version>"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"binaryTargets":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"verdict":"accept"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentshouse/mdmodel",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
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",
|