@agentshouse/mdmodel 0.1.0-alpha.16 → 0.1.0-alpha.17
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/API.md +44 -33
- package/README.md +2 -4
- package/dist/definition.d.ts +7 -3
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +83 -38
- package/dist/definition.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/paths.d.ts +0 -2
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +0 -7
- package/dist/paths.js.map +1 -1
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +3 -15
- package/dist/project.js.map +1 -1
- package/dist/types.d.ts +6 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/validate.d.ts +2 -3
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +42 -86
- 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/dist/yaml.js +1 -1
- package/dist/yaml.js.map +1 -1
- package/fixtures/README.md +45 -44
- package/fixtures/cases/binary-any-reference/schema.yaml +4 -0
- package/fixtures/cases/binary-document-collision/schema.yaml +2 -0
- package/fixtures/cases/binary-link-outside-collection/schema.yaml +2 -0
- package/fixtures/cases/binary-prototype-reference/schema.yaml +4 -0
- package/fixtures/cases/binary-typed-reference/schema.yaml +5 -0
- package/fixtures/cases/bracketed-link-definition/schema.yaml +6 -0
- package/fixtures/cases/declared-binary-links/schema.yaml +2 -0
- package/fixtures/cases/duplicate-link-definition/schema.yaml +6 -0
- package/fixtures/cases/fenced-link-definition/schema.yaml +6 -0
- package/fixtures/cases/field-enum/schema.yaml +7 -0
- package/fixtures/cases/frontmatter-schema/expected.json +6 -0
- package/fixtures/cases/frontmatter-schema/schema.yaml +6 -0
- package/fixtures/cases/interrupted-link-definition/schema.yaml +2 -0
- package/fixtures/cases/long-fence-link-definition/schema.yaml +2 -0
- package/fixtures/cases/malformed-definition/expected.json +1 -2
- package/fixtures/cases/malformed-definition/schema.yaml +4 -0
- package/fixtures/cases/member-document/context.json +1 -0
- package/fixtures/cases/member-document/library/people/ana.md +5 -0
- package/fixtures/cases/member-document/schema.yaml +5 -0
- package/fixtures/cases/missing-binary-image/schema.yaml +2 -0
- package/fixtures/cases/missing-binary-link/schema.yaml +2 -0
- package/fixtures/cases/missing-required-field/schema.yaml +7 -0
- package/fixtures/cases/missing-section-item-kind/expected.json +1 -2
- package/fixtures/cases/missing-section-item-kind/schema.yaml +6 -0
- package/fixtures/cases/paragraph-link-definition/schema.yaml +2 -0
- package/fixtures/cases/prototype-field/schema.yaml +6 -0
- package/fixtures/cases/quoted-link-definition/schema.yaml +2 -0
- package/fixtures/cases/referenced-missing-file/schema.yaml +10 -0
- package/fixtures/cases/second-member-document/context.json +1 -0
- package/fixtures/cases/second-member-document/expected.json +6 -0
- package/fixtures/cases/second-member-document/schema.yaml +5 -0
- package/fixtures/cases/structured-section/schema.yaml +7 -0
- package/fixtures/cases/submission-keys/schema.yaml +4 -0
- package/fixtures/cases/truncated-link-definition/schema.yaml +2 -0
- package/fixtures/cases/types-folder-content/schema.yaml +4 -0
- package/fixtures/cases/undeclared-field/schema.yaml +6 -0
- package/fixtures/cases/unknown-type/expected.json +7 -0
- package/fixtures/cases/unknown-type/schema.yaml +4 -0
- package/fixtures/cases/unlisted-reference-type/context.json +1 -0
- package/fixtures/cases/unlisted-reference-type/expected.json +6 -0
- package/fixtures/cases/unlisted-reference-type/schema.yaml +4 -0
- package/fixtures/cases/unresolved-link/schema.yaml +6 -0
- package/fixtures/cases/valid-typed-document/schema.yaml +15 -0
- package/fixtures/cases/wide-item-fence-link/schema.yaml +2 -0
- package/fixtures/division.json +1 -21
- package/fixtures/projection.json +1 -24
- package/package.json +1 -1
- package/fixtures/cases/binary-any-reference/library/types/note.md +0 -5
- package/fixtures/cases/binary-document-collision/library/types/note.md +0 -3
- package/fixtures/cases/binary-link-outside-collection/library/types/note.md +0 -3
- package/fixtures/cases/binary-prototype-reference/library/types/note.md +0 -5
- package/fixtures/cases/binary-typed-reference/library/types/note.md +0 -5
- package/fixtures/cases/binary-typed-reference/library/types/person.md +0 -3
- package/fixtures/cases/bracketed-link-definition/library/types/task.md +0 -7
- package/fixtures/cases/declared-binary-links/library/types/note.md +0 -3
- package/fixtures/cases/duplicate-link-definition/library/types/task.md +0 -7
- package/fixtures/cases/external-invalid-model/definitions/schema/task.md +0 -5
- package/fixtures/cases/external-invalid-model/expected.json +0 -1
- package/fixtures/cases/external-invalid-model/library/note.md +0 -1
- package/fixtures/cases/external-unknown-type/definitions/schema/task.md +0 -5
- package/fixtures/cases/external-unknown-type/expected.json +0 -1
- package/fixtures/cases/external-valid/context.json +0 -1
- package/fixtures/cases/external-valid/definitions/types/task.md +0 -5
- package/fixtures/cases/fenced-link-definition/library/types/task.md +0 -7
- package/fixtures/cases/field-enum/library/types/task.md +0 -8
- package/fixtures/cases/interrupted-link-definition/library/types/note.md +0 -3
- package/fixtures/cases/long-fence-link-definition/library/types/note.md +0 -3
- package/fixtures/cases/malformed-definition/library/types/task.md +0 -5
- package/fixtures/cases/missing-binary-image/library/types/note.md +0 -3
- package/fixtures/cases/missing-binary-link/library/types/note.md +0 -3
- package/fixtures/cases/missing-required-field/library/types/task.md +0 -8
- package/fixtures/cases/missing-section-item-kind/library/types/task.md +0 -7
- package/fixtures/cases/paragraph-link-definition/library/types/note.md +0 -3
- package/fixtures/cases/prd-definition/library/types/task.md +0 -16
- package/fixtures/cases/prototype-field/library/types/task.md +0 -7
- package/fixtures/cases/quoted-link-definition/library/types/note.md +0 -3
- package/fixtures/cases/referenced-missing-file/library/types/person.md +0 -5
- package/fixtures/cases/referenced-missing-file/library/types/task.md +0 -8
- package/fixtures/cases/structured-section/library/types/task.md +0 -8
- package/fixtures/cases/submission-keys/library/types/note.md +0 -5
- package/fixtures/cases/truncated-link-definition/library/types/note.md +0 -3
- package/fixtures/cases/undeclared-field/library/types/task.md +0 -7
- package/fixtures/cases/unresolved-link/library/types/task.md +0 -7
- package/fixtures/cases/valid-typed-document/library/types/person.md +0 -5
- package/fixtures/cases/valid-typed-document/library/types/task.md +0 -13
- package/fixtures/cases/wide-item-fence-link/library/types/note.md +0 -3
- /package/fixtures/cases/{prd-definition → frontmatter-schema}/context.json +0 -0
- /package/fixtures/cases/{prd-definition → member-document}/expected.json +0 -0
- /package/fixtures/cases/{external-invalid-model → types-folder-content}/context.json +0 -0
- /package/fixtures/cases/{external-valid → types-folder-content}/expected.json +0 -0
- /package/fixtures/cases/{external-valid → types-folder-content}/library/types/task.md +0 -0
- /package/fixtures/cases/{external-unknown-type → unknown-type}/context.json +0 -0
- /package/fixtures/cases/{external-unknown-type → unknown-type}/library/item.md +0 -0
package/API.md
CHANGED
|
@@ -13,23 +13,17 @@ import {
|
|
|
13
13
|
target,
|
|
14
14
|
validate,
|
|
15
15
|
verify,
|
|
16
|
-
verifyDocuments,
|
|
17
16
|
VERSION,
|
|
18
17
|
} from '@agentshouse/mdmodel';
|
|
19
18
|
|
|
20
19
|
validate({ 'note.md': '# Hello\n' });
|
|
21
|
-
|
|
22
|
-
{
|
|
23
|
-
'types/note.md': '---\ntype: definition\n---\n',
|
|
24
|
-
'note.md': '---\ntype: note\n---\n\n',
|
|
25
|
-
},
|
|
26
|
-
{ binaryTargets: ['assets/figure.png'] },
|
|
27
|
-
);
|
|
28
|
-
const checked = verify({
|
|
29
|
-
'model/task.md': '---\ntype: definition\nfields:\n title: { kind: string }\n---\n',
|
|
30
|
-
});
|
|
20
|
+
const checked = verify('types:\n task:\n fields:\n title: { kind: string }\n');
|
|
31
21
|
if (checked.verdict === 'accept') {
|
|
32
|
-
validate(
|
|
22
|
+
validate(
|
|
23
|
+
{ 'tasks/one.md': '---\ntype: task\ntitle: Ship\n---\n\n' },
|
|
24
|
+
{ binaryTargets: ['assets/figure.png'] },
|
|
25
|
+
checked.model,
|
|
26
|
+
);
|
|
33
27
|
const task = checked.model.types.task;
|
|
34
28
|
const titleKind = task?.fields.title?.kind;
|
|
35
29
|
}
|
|
@@ -54,14 +48,33 @@ if (parsed.ok) {
|
|
|
54
48
|
}
|
|
55
49
|
```
|
|
56
50
|
|
|
57
|
-
`verify(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
51
|
+
`verify(schema)` reads one schema text, the MD Types of one Room or App, and
|
|
52
|
+
returns a verified model whose `types` expose each MD Type's `name`,
|
|
53
|
+
`memberDocument` flag, parsed field specs, and declared sections. The text is a
|
|
54
|
+
YAML mapping in the frontmatter subset whose one key, `types`, maps each MD Type
|
|
55
|
+
name to an entry of optional `fields`, `sections`, and boolean `member_document`:
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
types:
|
|
59
|
+
plan:
|
|
60
|
+
fields:
|
|
61
|
+
title: { kind: string, required: true }
|
|
62
|
+
status: { kind: enum, values: [active, done] }
|
|
63
|
+
owner: { kind: reference, to: contact }
|
|
64
|
+
sections:
|
|
65
|
+
Goals: { kind: text }
|
|
66
|
+
contact:
|
|
67
|
+
member_document: true
|
|
68
|
+
fields:
|
|
69
|
+
name: { kind: string, required: true }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
A field spec names its `kind` and `required` flag; a list carries `of`, an enum
|
|
73
|
+
carries `values`, and a reference carries `to`, which names `any` or a type of
|
|
74
|
+
the same schema. At most one type is marked `member_document: true`. A
|
|
75
|
+
malformed schema is refused whole, naming its `rule`, `VERSION`, and, where the
|
|
76
|
+
rule concerns one part of the text, its `location`: a dotted path such as
|
|
77
|
+
`types.plan.fields.status`, or `line <n>` where the text leaves the YAML subset.
|
|
65
78
|
|
|
66
79
|
`validate(library, context?, model?)` takes the resulting text Library and one
|
|
67
80
|
`ValidationContext` containing `binaryTargets: readonly string[]`. Omitting the
|
|
@@ -72,14 +85,13 @@ in typed Documents may resolve to either membership, including relative
|
|
|
72
85
|
normalization from the source Document. A binary target supplies no Document
|
|
73
86
|
or MD Type and cannot satisfy a typed reference, including one to `any`.
|
|
74
87
|
The existing `any` Document rules are unchanged.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
content refusal then names `source: 'content'` and its Library Path. Without
|
|
78
|
-
`model`, definition Documents under `types/` are read from the Library.
|
|
88
|
+
`model` is the verified schema that types the Library, and every Library member
|
|
89
|
+
is content, whatever its Path. Without `model` the Library declares no type.
|
|
79
90
|
|
|
80
91
|
A typed Document carries the frontmatter fields its MD type declares, plus
|
|
81
|
-
`type`, `site`, and `received`;
|
|
82
|
-
`
|
|
92
|
+
`type`, `site`, and `received`; a Document of the type marked
|
|
93
|
+
`member_document` also carries `member`, a string, unless that type declares
|
|
94
|
+
it. Any other field is refused as `undeclared-field` at that field name. A field
|
|
83
95
|
name YAML carries to a record prototype, `__proto__` among them, is an ordinary
|
|
84
96
|
undeclared field and is refused as one. A declared list section is validated as
|
|
85
97
|
a list; its declared item kind governs projection eligibility rather than the
|
|
@@ -190,18 +202,17 @@ const parsed = parse(content);
|
|
|
190
202
|
if (parsed.ok) {
|
|
191
203
|
const projected = project(parsed.document, 'tasks/two.md', {
|
|
192
204
|
documentTargets: ['plans/q3.md', 'people/ana.md'],
|
|
193
|
-
definition: types
|
|
205
|
+
definition: model.types.task,
|
|
194
206
|
});
|
|
195
207
|
if (projected.ok) embed(projected.text);
|
|
196
208
|
}
|
|
197
209
|
```
|
|
198
210
|
|
|
199
211
|
`ProjectionContext` carries `documentTargets`, the collection-relative Paths the
|
|
200
|
-
caller holds as Markdown documents, and `definition`, the
|
|
201
|
-
|
|
202
|
-
the caller supplies no definition for is refused as
|
|
203
|
-
|
|
204
|
-
`types/<type>.md`. `documentTargets` is what makes a destination internal: a
|
|
212
|
+
caller holds as Markdown documents, and `definition`, the verified MD Type the
|
|
213
|
+
Document's `type` names, taken from the model `verify` returned. A Document that
|
|
214
|
+
declares a type the caller supplies no definition for is refused as
|
|
215
|
+
`unknown-type`. `documentTargets` is what makes a destination internal: a
|
|
205
216
|
destination resolving to a supplied Path is internal, and every other
|
|
206
217
|
destination stays authored text, a retained binary target and a Path nobody
|
|
207
218
|
supplied alike. The caller supplies that membership, as it does for `validate`;
|
|
@@ -234,7 +245,7 @@ const parsed = parse(content);
|
|
|
234
245
|
if (parsed.ok) {
|
|
235
246
|
const divided = divide(parsed.document, 'tasks/two.md', {
|
|
236
247
|
documentTargets: ['plans/q3.md', 'people/ana.md'],
|
|
237
|
-
definition: types
|
|
248
|
+
definition: model.types.task,
|
|
238
249
|
budget: 2000,
|
|
239
250
|
});
|
|
240
251
|
if (divided.ok) for (const span of divided.spans) embed(span.text);
|
package/README.md
CHANGED
|
@@ -19,9 +19,7 @@ npm install @agentshouse/mdmodel
|
|
|
19
19
|
```ts
|
|
20
20
|
import { apply, parse, serialize, validate, verify } from '@agentshouse/mdmodel';
|
|
21
21
|
|
|
22
|
-
const checked = verify({
|
|
23
|
-
'model/task.md': '---\ntype: definition\nfields:\n title: { kind: string }\n---\n',
|
|
24
|
-
});
|
|
22
|
+
const checked = verify('types:\n task:\n fields:\n title: { kind: string }\n');
|
|
25
23
|
if (checked.verdict === 'accept') {
|
|
26
24
|
validate({ 'tasks/one.md': '---\ntype: task\ntitle: Ship\n---\n' }, undefined, checked.model);
|
|
27
25
|
}
|
|
@@ -42,7 +40,7 @@ if (parsed.ok) {
|
|
|
42
40
|
|
|
43
41
|
| Export | Purpose |
|
|
44
42
|
| ------------------------------------ | ---------------------------------------------------------- |
|
|
45
|
-
| `verify
|
|
43
|
+
| `verify` | Verify one schema text into a model of MD Types |
|
|
46
44
|
| `validate` | Validate a text Library; returns acceptance or one refusal |
|
|
47
45
|
| `parse`, `serialize` | Read and write one Document |
|
|
48
46
|
| `apply` | Apply one field, section, preamble, or link change |
|
package/dist/definition.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { VerifiedModel } from './types.js';
|
|
2
2
|
export type TextSpec = {
|
|
3
3
|
readonly kind: 'text';
|
|
4
4
|
readonly required: boolean;
|
|
@@ -30,9 +30,13 @@ 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 memberDocument: boolean;
|
|
34
34
|
readonly fields: Readonly<Record<string, FieldSpec>>;
|
|
35
35
|
readonly sections: Readonly<Record<string, SectionSpec>>;
|
|
36
36
|
};
|
|
37
|
-
export
|
|
37
|
+
export type Failure = {
|
|
38
|
+
readonly rule: string;
|
|
39
|
+
readonly location?: string;
|
|
40
|
+
};
|
|
41
|
+
export declare function readSchema(text: string): VerifiedModel | Failure;
|
|
38
42
|
//# sourceMappingURL=definition.d.ts.map
|
package/dist/definition.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,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,cAAc,EAAE,OAAO,CAAC;IACjC,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;AAEF,MAAM,MAAM,OAAO,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAwJ5E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,OAAO,CAgChE"}
|
package/dist/definition.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { jsValue, parseYamlMapping, YamlError } from './yaml.js';
|
|
2
|
+
function refuse(rule, location) {
|
|
3
|
+
return location === undefined ? {
|
|
4
|
+
rule
|
|
5
|
+
} : {
|
|
6
|
+
rule,
|
|
5
7
|
location
|
|
6
|
-
}
|
|
8
|
+
};
|
|
7
9
|
}
|
|
8
10
|
function isRecord(value) {
|
|
9
11
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -28,7 +30,7 @@ const SCALAR_KINDS = new Set([
|
|
|
28
30
|
'enum',
|
|
29
31
|
'reference'
|
|
30
32
|
]);
|
|
31
|
-
function parseScalar(
|
|
33
|
+
function parseScalar(names, location, spec, required) {
|
|
32
34
|
const kind = spec.kind;
|
|
33
35
|
if (kind === 'text') return {
|
|
34
36
|
kind: 'text',
|
|
@@ -48,7 +50,7 @@ function parseScalar(file, location, spec, required) {
|
|
|
48
50
|
};
|
|
49
51
|
if (kind === 'enum') {
|
|
50
52
|
const values = stringList(spec.values);
|
|
51
|
-
if (values === undefined) return refuse(
|
|
53
|
+
if (values === undefined) return refuse('definition-enum-values', location);
|
|
52
54
|
return {
|
|
53
55
|
kind: 'enum',
|
|
54
56
|
required,
|
|
@@ -56,21 +58,21 @@ function parseScalar(file, location, spec, required) {
|
|
|
56
58
|
};
|
|
57
59
|
}
|
|
58
60
|
if (kind === 'reference') {
|
|
59
|
-
if (typeof spec.to !== 'string' || spec.to
|
|
61
|
+
if (typeof spec.to !== 'string' || spec.to !== 'any' && !names.has(spec.to)) return refuse('definition-reference-to', location);
|
|
60
62
|
return {
|
|
61
63
|
kind: 'reference',
|
|
62
64
|
required,
|
|
63
65
|
to: spec.to
|
|
64
66
|
};
|
|
65
67
|
}
|
|
66
|
-
return refuse(
|
|
68
|
+
return refuse('definition-field-kind', location);
|
|
67
69
|
}
|
|
68
70
|
function extraKeys(spec, allowed) {
|
|
69
71
|
return Object.keys(spec).some((key)=>!allowed.includes(key));
|
|
70
72
|
}
|
|
71
|
-
function parseList(
|
|
73
|
+
function parseList(names, location, spec, required, malformed) {
|
|
72
74
|
if (typeof spec.of !== 'string' || !SCALAR_KINDS.has(spec.of)) {
|
|
73
|
-
return refuse(
|
|
75
|
+
return refuse('definition-list-of', location);
|
|
74
76
|
}
|
|
75
77
|
const allowed = spec.of === 'enum' ? [
|
|
76
78
|
'kind',
|
|
@@ -87,8 +89,8 @@ function parseList(file, location, spec, required, malformed) {
|
|
|
87
89
|
'required',
|
|
88
90
|
'of'
|
|
89
91
|
];
|
|
90
|
-
if (extraKeys(spec, allowed)) return refuse(
|
|
91
|
-
const inner = parseScalar(
|
|
92
|
+
if (extraKeys(spec, allowed)) return refuse(malformed, location);
|
|
93
|
+
const inner = parseScalar(names, location, {
|
|
92
94
|
...spec,
|
|
93
95
|
kind: spec.of
|
|
94
96
|
}, false);
|
|
@@ -99,11 +101,11 @@ function parseList(file, location, spec, required, malformed) {
|
|
|
99
101
|
of: inner
|
|
100
102
|
};
|
|
101
103
|
}
|
|
102
|
-
function parseField(
|
|
103
|
-
if (!isRecord(value) || typeof value.kind !== 'string') return refuse(
|
|
104
|
+
function parseField(names, location, value) {
|
|
105
|
+
if (!isRecord(value) || typeof value.kind !== 'string') return refuse('definition-field', location);
|
|
104
106
|
const required = requiredFlag(value.required);
|
|
105
|
-
if (required === undefined) return refuse(
|
|
106
|
-
if (value.kind === 'list') return parseList(
|
|
107
|
+
if (required === undefined) return refuse('definition-field', location);
|
|
108
|
+
if (value.kind === 'list') return parseList(names, location, value, required, 'definition-field');
|
|
107
109
|
const allowed = value.kind === 'enum' ? [
|
|
108
110
|
'kind',
|
|
109
111
|
'required',
|
|
@@ -116,58 +118,101 @@ function parseField(file, location, value) {
|
|
|
116
118
|
'kind',
|
|
117
119
|
'required'
|
|
118
120
|
];
|
|
119
|
-
if (extraKeys(value, allowed)) return refuse(
|
|
120
|
-
return parseScalar(
|
|
121
|
+
if (extraKeys(value, allowed)) return refuse('definition-field', location);
|
|
122
|
+
return parseScalar(names, location, value, required);
|
|
121
123
|
}
|
|
122
|
-
function parseSection(
|
|
124
|
+
function parseSection(names, location, value) {
|
|
123
125
|
if (!isRecord(value) || value.kind !== 'text' && value.kind !== 'list') {
|
|
124
|
-
return refuse(
|
|
126
|
+
return refuse('definition-section-kind', location);
|
|
125
127
|
}
|
|
126
128
|
const required = requiredFlag(value.required);
|
|
127
|
-
if (required === undefined) return refuse(
|
|
128
|
-
if (value.kind === 'list') return parseList(
|
|
129
|
+
if (required === undefined) return refuse('definition-section', location);
|
|
130
|
+
if (value.kind === 'list') return parseList(names, location, value, required, 'definition-section');
|
|
129
131
|
if (extraKeys(value, [
|
|
130
132
|
'kind',
|
|
131
133
|
'required'
|
|
132
|
-
])) return refuse(
|
|
134
|
+
])) return refuse('definition-section', location);
|
|
133
135
|
return {
|
|
134
136
|
kind: 'text',
|
|
135
137
|
required
|
|
136
138
|
};
|
|
137
139
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return refuse(file, 'definition-shape', key);
|
|
140
|
+
function readType(names, name, value) {
|
|
141
|
+
const location = `types.${name}`;
|
|
142
|
+
if (!isRecord(value)) return refuse('definition-shape', location);
|
|
143
|
+
for (const key of Object.keys(value)){
|
|
144
|
+
if (key !== 'fields' && key !== 'sections' && key !== 'member_document') {
|
|
145
|
+
return refuse('definition-shape', `${location}.${key}`);
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
const mark = value.member_document === undefined ? false : value.member_document;
|
|
149
|
+
if (typeof mark !== 'boolean') return refuse('definition-shape', `${location}.member_document`);
|
|
150
|
+
const fieldsValue = value.fields;
|
|
151
|
+
const sectionsValue = value.sections;
|
|
152
|
+
if (fieldsValue !== undefined && !isRecord(fieldsValue)) return refuse('definition-fields', `${location}.fields`);
|
|
150
153
|
if (sectionsValue !== undefined && !isRecord(sectionsValue)) {
|
|
151
|
-
return refuse(
|
|
154
|
+
return refuse('definition-sections', `${location}.sections`);
|
|
152
155
|
}
|
|
153
156
|
const fields = Object.create(null);
|
|
154
157
|
for (const [fieldName, spec] of Object.entries(fieldsValue ?? {})){
|
|
155
|
-
const parsed = parseField(
|
|
158
|
+
const parsed = parseField(names, `${location}.fields.${fieldName}`, spec);
|
|
156
159
|
if ('rule' in parsed) return parsed;
|
|
157
160
|
fields[fieldName] = parsed;
|
|
158
161
|
}
|
|
159
162
|
const sections = Object.create(null);
|
|
160
163
|
for (const [sectionName, spec] of Object.entries(sectionsValue ?? {})){
|
|
161
|
-
const parsed = parseSection(
|
|
164
|
+
const parsed = parseSection(names, `${location}.sections.${sectionName}`, spec);
|
|
162
165
|
if ('rule' in parsed) return parsed;
|
|
163
166
|
sections[sectionName] = parsed;
|
|
164
167
|
}
|
|
165
168
|
return {
|
|
166
169
|
name,
|
|
167
|
-
|
|
170
|
+
memberDocument: mark,
|
|
168
171
|
fields,
|
|
169
172
|
sections
|
|
170
173
|
};
|
|
171
174
|
}
|
|
175
|
+
function freezeSpec(spec) {
|
|
176
|
+
if (spec.kind === 'list') freezeSpec(spec.of);
|
|
177
|
+
if (spec.kind === 'enum') Object.freeze(spec.values);
|
|
178
|
+
Object.freeze(spec);
|
|
179
|
+
}
|
|
180
|
+
function lineAt(text, offset) {
|
|
181
|
+
return text.slice(0, offset).split(/\r\n|\r|\n/).length;
|
|
182
|
+
}
|
|
183
|
+
export function readSchema(text) {
|
|
184
|
+
let root;
|
|
185
|
+
try {
|
|
186
|
+
root = jsValue(parseYamlMapping(text, 0, text.length));
|
|
187
|
+
} catch (error) {
|
|
188
|
+
if (error instanceof YamlError) return refuse('schema-yaml', `line ${lineAt(text, error.offset)}`);
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
const schema = root;
|
|
192
|
+
for (const key of Object.keys(schema)){
|
|
193
|
+
if (key !== 'types') return refuse('schema-shape', key);
|
|
194
|
+
}
|
|
195
|
+
if (!isRecord(schema.types)) return refuse('schema-shape', 'types');
|
|
196
|
+
const names = new Set(Object.keys(schema.types));
|
|
197
|
+
if (names.has('')) return refuse('schema-shape', 'types');
|
|
198
|
+
const types = Object.create(null);
|
|
199
|
+
let marked = false;
|
|
200
|
+
for (const [name, value] of Object.entries(schema.types)){
|
|
201
|
+
const definition = readType(names, name, value);
|
|
202
|
+
if ('rule' in definition) return definition;
|
|
203
|
+
if (definition.memberDocument) {
|
|
204
|
+
if (marked) return refuse('schema-member-document', `types.${name}.member_document`);
|
|
205
|
+
marked = true;
|
|
206
|
+
}
|
|
207
|
+
for (const spec of Object.values(definition.fields))freezeSpec(spec);
|
|
208
|
+
for (const spec of Object.values(definition.sections))freezeSpec(spec);
|
|
209
|
+
Object.freeze(definition.fields);
|
|
210
|
+
Object.freeze(definition.sections);
|
|
211
|
+
types[name] = Object.freeze(definition);
|
|
212
|
+
}
|
|
213
|
+
return Object.freeze({
|
|
214
|
+
types: Object.freeze(types)
|
|
215
|
+
});
|
|
216
|
+
}
|
|
172
217
|
|
|
173
218
|
//# sourceMappingURL=definition.js.map
|
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 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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"}
|
|
1
|
+
{"version":3,"sources":["/workspace/packages/mdmodel/src/definition.ts"],"sourcesContent":["import type { VerifiedModel } from './types.js';\nimport { jsValue, parseYamlMapping, YamlError } from './yaml.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 memberDocument: boolean;\n readonly fields: Readonly<Record<string, FieldSpec>>;\n readonly sections: Readonly<Record<string, SectionSpec>>;\n};\n\nexport type Failure = { readonly rule: string; readonly location?: string };\n\nfunction refuse(rule: string, location?: string): Failure {\n return location === undefined ? { rule } : { 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 names: ReadonlySet<string>,\n location: string,\n spec: Record<string, unknown>,\n required: boolean,\n): ScalarSpec | Failure {\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('definition-enum-values', location);\n return { kind: 'enum', required, values };\n }\n if (kind === 'reference') {\n if (typeof spec.to !== 'string' || (spec.to !== 'any' && !names.has(spec.to)))\n return refuse('definition-reference-to', location);\n return { kind: 'reference', required, to: spec.to };\n }\n return refuse('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 names: ReadonlySet<string>,\n location: string,\n spec: Record<string, unknown>,\n required: boolean,\n malformed: string,\n): ListSpec | Failure {\n if (typeof spec.of !== 'string' || !SCALAR_KINDS.has(spec.of)) {\n return refuse('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(malformed, location);\n const inner = parseScalar(names, location, { ...spec, kind: spec.of }, false);\n if ('rule' in inner) return inner;\n return { kind: 'list', required, of: inner };\n}\n\nfunction parseField(\n names: ReadonlySet<string>,\n location: string,\n value: unknown,\n): FieldSpec | Failure {\n if (!isRecord(value) || typeof value.kind !== 'string')\n return refuse('definition-field', location);\n const required = requiredFlag(value.required);\n if (required === undefined) return refuse('definition-field', location);\n if (value.kind === 'list') return parseList(names, 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('definition-field', location);\n return parseScalar(names, location, value, required);\n}\n\nfunction parseSection(\n names: ReadonlySet<string>,\n location: string,\n value: unknown,\n): SectionSpec | Failure {\n if (!isRecord(value) || (value.kind !== 'text' && value.kind !== 'list')) {\n return refuse('definition-section-kind', location);\n }\n const required = requiredFlag(value.required);\n if (required === undefined) return refuse('definition-section', location);\n if (value.kind === 'list')\n return parseList(names, location, value, required, 'definition-section');\n if (extraKeys(value, ['kind', 'required'])) return refuse('definition-section', location);\n return { kind: 'text', required };\n}\n\nfunction readType(names: ReadonlySet<string>, name: string, value: unknown): Definition | Failure {\n const location = `types.${name}`;\n if (!isRecord(value)) return refuse('definition-shape', location);\n for (const key of Object.keys(value)) {\n if (key !== 'fields' && key !== 'sections' && key !== 'member_document') {\n return refuse('definition-shape', `${location}.${key}`);\n }\n }\n const mark = value.member_document === undefined ? false : value.member_document;\n if (typeof mark !== 'boolean') return refuse('definition-shape', `${location}.member_document`);\n const fieldsValue = value.fields;\n const sectionsValue = value.sections;\n if (fieldsValue !== undefined && !isRecord(fieldsValue))\n return refuse('definition-fields', `${location}.fields`);\n if (sectionsValue !== undefined && !isRecord(sectionsValue)) {\n return refuse('definition-sections', `${location}.sections`);\n }\n const fields: Record<string, FieldSpec> = Object.create(null);\n for (const [fieldName, spec] of Object.entries(fieldsValue ?? {})) {\n const parsed = parseField(names, `${location}.fields.${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(names, `${location}.sections.${sectionName}`, spec);\n if ('rule' in parsed) return parsed;\n sections[sectionName] = parsed;\n }\n return { name, memberDocument: mark, fields, sections };\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\nfunction lineAt(text: string, offset: number): number {\n return text.slice(0, offset).split(/\\r\\n|\\r|\\n/).length;\n}\n\nexport function readSchema(text: string): VerifiedModel | Failure {\n let root: unknown;\n try {\n root = jsValue(parseYamlMapping(text, 0, text.length));\n } catch (error) {\n if (error instanceof YamlError)\n return refuse('schema-yaml', `line ${lineAt(text, error.offset)}`);\n throw error;\n }\n const schema = root as Record<string, unknown>;\n for (const key of Object.keys(schema)) {\n if (key !== 'types') return refuse('schema-shape', key);\n }\n if (!isRecord(schema.types)) return refuse('schema-shape', 'types');\n const names = new Set(Object.keys(schema.types));\n if (names.has('')) return refuse('schema-shape', 'types');\n const types: Record<string, Definition> = Object.create(null);\n let marked = false;\n for (const [name, value] of Object.entries(schema.types)) {\n const definition = readType(names, name, value);\n if ('rule' in definition) return definition;\n if (definition.memberDocument) {\n if (marked) return refuse('schema-member-document', `types.${name}.member_document`);\n marked = true;\n }\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 types[name] = Object.freeze(definition);\n }\n return Object.freeze({ types: Object.freeze(types) });\n}\n"],"names":["jsValue","parseYamlMapping","YamlError","refuse","rule","location","undefined","isRecord","value","Array","isArray","requiredFlag","stringList","length","every","item","SCALAR_KINDS","Set","parseScalar","names","spec","required","kind","values","to","has","extraKeys","allowed","Object","keys","some","key","includes","parseList","malformed","of","inner","parseField","parseSection","readType","name","mark","member_document","fieldsValue","fields","sectionsValue","sections","create","fieldName","entries","parsed","sectionName","memberDocument","freezeSpec","freeze","lineAt","text","offset","slice","split","readSchema","root","error","schema","types","marked","definition"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,6 @@ export { MARKDOWN_SYNTAX_PROFILE } from './profile.js';
|
|
|
5
5
|
export { project } from './project.js';
|
|
6
6
|
export type { Definition, FieldSpec, SectionSpec } from './definition.js';
|
|
7
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
|
|
8
|
+
export { validate, verify } from './validate.js';
|
|
9
9
|
export { VERSION } from './version.js';
|
|
10
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,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,
|
|
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,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export { apply, links, parse, serialize } from './document.js';
|
|
|
3
3
|
export { retarget, target } from './paths.js';
|
|
4
4
|
export { MARKDOWN_SYNTAX_PROFILE } from './profile.js';
|
|
5
5
|
export { project } from './project.js';
|
|
6
|
-
export { validate, verify
|
|
6
|
+
export { validate, verify } from './validate.js';
|
|
7
7
|
export { VERSION } from './version.js';
|
|
8
8
|
|
|
9
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 { 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
|
|
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 } from './validate.js';\nexport { VERSION } from './version.js';\n"],"names":["divide","apply","links","parse","serialize","retarget","target","MARKDOWN_SYNTAX_PROFILE","project","validate","verify","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,QAAQ,gBAAgB;AACjD,SAASC,OAAO,QAAQ,eAAe"}
|
package/dist/paths.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
export declare function dirname(path: string): string;
|
|
2
2
|
export declare function join(base: string, relative: string): string;
|
|
3
3
|
export declare function normalize(path: string): string | null;
|
|
4
|
-
export declare function isTypesPath(path: string): boolean;
|
|
5
|
-
export declare function typeNameFromPath(path: string): string;
|
|
6
4
|
export declare function classifyHref(from: string, href: string): {
|
|
7
5
|
kind: 'skip';
|
|
8
6
|
} | {
|
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,
|
|
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,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
|
@@ -19,13 +19,6 @@ export function normalize(path) {
|
|
|
19
19
|
}
|
|
20
20
|
return parts.join('/');
|
|
21
21
|
}
|
|
22
|
-
export function isTypesPath(path) {
|
|
23
|
-
return path === 'types' || path.startsWith('types/');
|
|
24
|
-
}
|
|
25
|
-
export function typeNameFromPath(path) {
|
|
26
|
-
const base = path.slice(path.lastIndexOf('/') + 1);
|
|
27
|
-
return base.endsWith('.md') ? base.slice(0, -3) : base;
|
|
28
|
-
}
|
|
29
22
|
export function classifyHref(from, href) {
|
|
30
23
|
const trimmed = href.trim();
|
|
31
24
|
if (trimmed === '' || trimmed.startsWith('#')) return {
|
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
|
|
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 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","classifyHref","from","href","trimmed","trim","startsWith","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,aACdC,IAAY,EACZC,IAAY;IAEZ,MAAMC,UAAUD,KAAKE,IAAI;IACzB,IAAID,YAAY,MAAMA,QAAQE,UAAU,CAAC,MAAM,OAAO;QAAEC,MAAM;IAAO;IACrE,IAAI,4BAA4BC,IAAI,CAACJ,UAAU,OAAO;QAAEG,MAAM;IAAO;IACrE,IAAIH,QAAQE,UAAU,CAAC,MAAM,OAAO;QAAEC,MAAM;IAAU;IACtD,MAAME,OAAOL,QAAQM,OAAO,CAAC,WAAW;IACxC,IAAID,SAAS,IAAI,OAAO;QAAEF,MAAM;IAAO;IACvC,MAAMI,WAAWjB,UAAUH,KAAKL,QAAQgB,OAAOO;IAC/C,IAAIE,aAAa,QAAQA,aAAa,IAAI,OAAO;QAAEJ,MAAM;IAAU;IACnE,OAAO;QAAEA,MAAM;QAAQpB,MAAMwB;IAAS;AACxC;AAEA,OAAO,SAASC,OAAOV,IAAY,EAAEC,IAAY;IAC/C,MAAMQ,WAAWV,aAAaC,MAAMC;IACpC,OAAOQ,SAASJ,IAAI,KAAK,SAASI,SAASxB,IAAI,GAAG;AACpD;AAEA,OAAO,SAAS0B,SAASV,IAAY,EAAEW,EAAU;IAC/C,MAAMV,UAAUD,KAAKE,IAAI;IACzB,MAAMU,QAAQ,OAAOC,IAAI,CAACZ;IAC1B,OAAOW,UAAU,OAAOD,KAAKA,KAAKV,QAAQd,KAAK,CAACyB,MAAM3B,KAAK;AAC7D"}
|
package/dist/project.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG3F,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC;AAEzB,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAC5C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AA4BtD,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,MAAM,CASxF;AA8BD,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,iBAAiB,GACzB,WAAW,
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG3F,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC;AAEzB,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAC5C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AA4BtD,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,MAAM,CASxF;AA8BD,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,iBAAiB,GACzB,WAAW,CAyBb;AAED,wBAAgB,OAAO,CACrB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,iBAA2C,GACnD,UAAU,CAMZ"}
|
package/dist/project.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { frontmatter, parse } from './document.js';
|
|
1
|
+
import { frontmatter } from './document.js';
|
|
3
2
|
import { linkInventory } from './links.js';
|
|
4
3
|
import { target } from './paths.js';
|
|
5
4
|
import { refusal } from './refuse.js';
|
|
@@ -93,8 +92,8 @@ export function projectionInput(document, file, context) {
|
|
|
93
92
|
}
|
|
94
93
|
};
|
|
95
94
|
}
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
95
|
+
const definition = context.definition;
|
|
96
|
+
if (definition === undefined) {
|
|
98
97
|
return {
|
|
99
98
|
ok: false,
|
|
100
99
|
refusal: refusal(file, 'unknown-type', {
|
|
@@ -102,17 +101,6 @@ export function projectionInput(document, file, context) {
|
|
|
102
101
|
})
|
|
103
102
|
};
|
|
104
103
|
}
|
|
105
|
-
const definitionFile = `types/${declared}.md`;
|
|
106
|
-
const parsed = parse(source, definitionFile);
|
|
107
|
-
if (!parsed.ok) return {
|
|
108
|
-
ok: false,
|
|
109
|
-
refusal: parsed.refusal
|
|
110
|
-
};
|
|
111
|
-
const definition = readDefinition(definitionFile, parsed.document);
|
|
112
|
-
if ('rule' in definition) return {
|
|
113
|
-
ok: false,
|
|
114
|
-
refusal: definition
|
|
115
|
-
};
|
|
116
104
|
const structure = new Set(Object.entries(definition.sections).flatMap(([name, spec])=>structural(spec) ? [
|
|
117
105
|
name
|
|
118
106
|
] : []));
|