@agentshouse/mdmodel 0.1.0-cc9fa0498a7f7 → 0.1.0-cd90851746292

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/API.md +231 -225
  2. package/README.md +16 -19
  3. package/dist/blocks.d.ts.map +1 -1
  4. package/dist/blocks.js +35 -20
  5. package/dist/condition.d.ts +41 -11
  6. package/dist/condition.d.ts.map +1 -1
  7. package/dist/condition.js +223 -87
  8. package/dist/definition.d.ts +17 -1
  9. package/dist/definition.d.ts.map +1 -1
  10. package/dist/definition.js +319 -43
  11. package/dist/divide.d.ts.map +1 -1
  12. package/dist/divide.js +27 -17
  13. package/dist/document.d.ts +6 -3
  14. package/dist/document.d.ts.map +1 -1
  15. package/dist/document.js +326 -176
  16. package/dist/index.d.ts +13 -9
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +7 -6
  19. package/dist/links.d.ts +3 -0
  20. package/dist/links.d.ts.map +1 -1
  21. package/dist/links.js +108 -51
  22. package/dist/paths.d.ts +10 -1
  23. package/dist/paths.d.ts.map +1 -1
  24. package/dist/paths.js +118 -12
  25. package/dist/pattern.d.ts +10 -0
  26. package/dist/pattern.d.ts.map +1 -0
  27. package/dist/pattern.js +355 -0
  28. package/dist/project.d.ts +1 -0
  29. package/dist/project.d.ts.map +1 -1
  30. package/dist/project.js +38 -15
  31. package/dist/references.d.ts +2 -2
  32. package/dist/references.d.ts.map +1 -1
  33. package/dist/references.js +6 -1
  34. package/dist/schema.d.ts +1 -0
  35. package/dist/schema.d.ts.map +1 -1
  36. package/dist/schema.js +55 -4
  37. package/dist/types.d.ts +50 -2
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/validate.d.ts +30 -2
  40. package/dist/validate.d.ts.map +1 -1
  41. package/dist/validate.js +317 -114
  42. package/dist/yaml.d.ts.map +1 -1
  43. package/dist/yaml.js +66 -21
  44. package/fixtures/README.md +10 -5
  45. package/fixtures/cases/conditional-section/context.json +1 -0
  46. package/fixtures/cases/conditional-section/expected.json +6 -0
  47. package/fixtures/cases/conditional-section/library/questions/hosting.md +9 -0
  48. package/fixtures/cases/conditional-section/library/questions/payments.md +12 -0
  49. package/fixtures/cases/conditional-section/schema.yaml +14 -0
  50. package/fixtures/cases/cross-room-link/context.json +1 -0
  51. package/fixtures/cases/cross-room-link/expected.json +1 -0
  52. package/fixtures/cases/cross-room-link/library/clients/acme.md +6 -0
  53. package/fixtures/cases/cross-room-link/schema.yaml +3 -0
  54. package/fixtures/cases/cross-room-reference/context.json +1 -0
  55. package/fixtures/cases/cross-room-reference/expected.json +1 -0
  56. package/fixtures/cases/cross-room-reference/library/clients/acme.md +9 -0
  57. package/fixtures/cases/cross-room-reference/schema.yaml +9 -0
  58. package/fixtures/division.json +26 -26
  59. package/package.json +10 -3
package/dist/types.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { Definition } from './definition.js';
2
2
  export type Library = Readonly<Record<string, string>>;
3
3
  export type VerifiedModel = {
4
4
  readonly types: Readonly<Record<string, Definition>>;
5
+ readonly nameable?: readonly string[];
5
6
  };
6
7
  export type ModelVerification = {
7
8
  readonly verdict: 'accept';
@@ -13,13 +14,14 @@ export type ModelVerification = {
13
14
  };
14
15
  export type ValidationContext = {
15
16
  readonly binaryTargets: readonly string[];
17
+ readonly anyRoom?: true;
16
18
  };
17
19
  export type ProjectionContext = {
18
20
  readonly documentTargets: readonly string[];
19
21
  readonly definition?: Definition;
20
22
  };
21
23
  export type DivisionContext = ProjectionContext & {
22
- readonly budget: number;
24
+ readonly bound: number;
23
25
  };
24
26
  export type Extent = {
25
27
  readonly start: number;
@@ -28,10 +30,12 @@ export type Extent = {
28
30
  export type Span = Extent & {
29
31
  readonly text: string;
30
32
  };
31
- export type Document = {
33
+ export type Frontmatter = {
32
34
  readonly content: string;
33
35
  readonly type: string | undefined;
34
36
  readonly fields: Readonly<Record<string, unknown>>;
37
+ };
38
+ export type Document = Frontmatter & {
35
39
  readonly preamble: string;
36
40
  readonly sections: Readonly<Record<string, string>>;
37
41
  };
@@ -41,11 +45,27 @@ export type Refusal = {
41
45
  readonly location?: string;
42
46
  readonly referrers?: readonly string[];
43
47
  };
48
+ export type Reached = {
49
+ readonly target: string | null;
50
+ readonly to: readonly string[];
51
+ };
52
+ export type DocumentCheck = {
53
+ readonly ok: false;
54
+ } | {
55
+ readonly ok: true;
56
+ readonly type: string;
57
+ readonly typed: boolean;
58
+ readonly references: readonly Reached[];
59
+ };
44
60
  export type Validation = {
45
61
  readonly verdict: 'accept';
46
62
  } | ({
47
63
  readonly verdict: 'refuse';
48
64
  } & Refusal);
65
+ export type ValidationStep = {
66
+ readonly path: string;
67
+ readonly resolved: number;
68
+ };
49
69
  export type Projection = {
50
70
  readonly ok: true;
51
71
  readonly text: string;
@@ -60,6 +80,13 @@ export type Division = {
60
80
  readonly ok: false;
61
81
  readonly refusal: Refusal;
62
82
  };
83
+ export type FrontmatterResult = {
84
+ readonly ok: true;
85
+ readonly frontmatter: Frontmatter;
86
+ } | {
87
+ readonly ok: false;
88
+ readonly refusal: Refusal;
89
+ };
63
90
  export type ParseResult = {
64
91
  readonly ok: true;
65
92
  readonly document: Document;
@@ -75,7 +102,27 @@ export type Reference = {
75
102
  readonly pointer: string;
76
103
  readonly value: string;
77
104
  readonly to: readonly string[];
105
+ readonly crossRoom?: true;
78
106
  };
107
+ export type RoomReference = {
108
+ readonly handle: string;
109
+ readonly path: string;
110
+ } & ({
111
+ readonly kind: 'link';
112
+ readonly href: string;
113
+ } | {
114
+ readonly kind: 'field';
115
+ readonly pointer: string;
116
+ readonly value: string;
117
+ readonly to: readonly string[];
118
+ readonly crossRoom?: true;
119
+ } | {
120
+ readonly kind: 'item';
121
+ readonly section: string;
122
+ readonly href: string;
123
+ readonly to: readonly string[];
124
+ readonly crossRoom?: true;
125
+ });
79
126
  export type Change = {
80
127
  readonly kind: 'field';
81
128
  readonly name: string;
@@ -106,6 +153,7 @@ export type ApplyResult = {
106
153
  } | {
107
154
  readonly outcome: 'stale';
108
155
  readonly document: Document;
156
+ readonly stale: readonly number[];
109
157
  } | {
110
158
  readonly outcome: 'refuse';
111
159
  readonly refusal: Refusal;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEvD,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAC7D;IACE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEN,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,iBAAiB,GAAG;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,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,WAAW,GAAG;IACxB,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;CACpD,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG;IACnC,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,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAA;CAAE,GACtB;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,SAAS,OAAO,EAAE,CAAC;CACzC,CAAC;AAEN,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAC9B,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAAG,OAAO,CAAC,CAAC;AAE/C,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAElF,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,QAAQ,GAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,CAC7E;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC;CAC3B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC;CAC3B,CACJ,CAAC;AAEF,MAAM,MAAM,MAAM,GACd;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEN,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC5D;IACE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,GACD;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9D,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC"}
@@ -1,4 +1,32 @@
1
- import type { Library, ModelVerification, Validation, ValidationContext, VerifiedModel } from './types.js';
2
- export declare function verify(schema: string): ModelVerification;
1
+ import { type Definition } from './definition.js';
2
+ import type { DocumentCheck, Library, ModelVerification, Reached, RoomReference, Validation, ValidationContext, ValidationStep, VerifiedModel } from './types.js';
3
+ export declare function resolves(reference: Reached, typeOf: (path: string) => string | undefined, binary: (path: string) => boolean): boolean;
4
+ export declare function verify(schema: string, provided?: VerifiedModel): ModelVerification;
5
+ export declare function checkDocument(file: string, content: string, model: VerifiedModel, context?: Pick<ValidationContext, 'anyRoom'>): DocumentCheck;
6
+ export declare function sectionReferences(file: string, content: string, definition: Definition): readonly Reached[];
7
+ export declare function bodyRoomLinks(body: string): RoomReference[];
8
+ export declare function roomReferences(file: string, content: string, definition?: Definition): readonly RoomReference[];
9
+ type Placed = {
10
+ readonly reference: Reached;
11
+ readonly location: string;
12
+ };
13
+ export type Assessment = {
14
+ readonly file: string;
15
+ readonly type: string | undefined;
16
+ readonly targets: readonly string[];
17
+ readonly read: Validation | null;
18
+ readonly structured: Validation | null;
19
+ readonly fields: readonly Placed[];
20
+ readonly linked: boolean;
21
+ readonly sections: readonly Placed[];
22
+ };
23
+ export declare function assess(file: string, content: string, binary: boolean, model?: VerifiedModel, context?: Pick<ValidationContext, 'anyRoom'>): Assessment;
24
+ export type Verdicts = {
25
+ add(assessment: Assessment, typeOf: (path: string) => string | undefined, binary: (path: string) => boolean): number;
26
+ verdict(): Validation;
27
+ };
28
+ export declare function verdicts(): Verdicts;
29
+ export declare function validating(library: ReadonlyMap<string, string>, context?: ValidationContext, model?: VerifiedModel): Generator<ValidationStep, Validation, void>;
3
30
  export declare function validate(library: Library, context?: ValidationContext, model?: VerifiedModel): Validation;
31
+ export {};
4
32
  //# sourceMappingURL=validate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAGV,OAAO,EACP,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,aAAa,EACd,MAAM,YAAY,CAAC;AAwDpB,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAQxD;AAED,wBAAgB,QAAQ,CACtB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,iBAAyC,EAClD,KAAK,GAAE,aAA6B,GACnC,UAAU,CAqGZ"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AASzF,OAAO,KAAK,EAEV,aAAa,EAEb,OAAO,EACP,iBAAiB,EACjB,OAAO,EACP,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AA8CpB,wBAAgB,QAAQ,CACtB,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,EAC5C,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAChC,OAAO,CAET;AA8BD,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,iBAAiB,CAQlF;AA0ED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,aAAa,EACpB,OAAO,GAAE,IAAI,CAAC,iBAAiB,EAAE,SAAS,CAAM,GAC/C,aAAa,CA0Bf;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,UAAU,GACrB,SAAS,OAAO,EAAE,CAiBpB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAO3D;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,UAAU,GACtB,SAAS,aAAa,EAAE,CAsC1B;AAQD,KAAK,MAAM,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,CAAC;AAEF,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,EACf,KAAK,GAAE,aAA6B,EACpC,OAAO,GAAE,IAAI,CAAC,iBAAiB,EAAE,SAAS,CAAM,GAC/C,UAAU,CA0BZ;AAyCD,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,CACD,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,EAC5C,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAChC,MAAM,CAAC;IACV,OAAO,IAAI,UAAU,CAAC;CACvB,CAAC;AAEF,wBAAgB,QAAQ,IAAI,QAAQ,CA+DnC;AAED,wBAAiB,UAAU,CACzB,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,OAAO,GAAE,iBAAyC,EAClD,KAAK,GAAE,aAA6B,GACnC,SAAS,CAAC,cAAc,EAAE,UAAU,EAAE,IAAI,CAAC,CAsB7C;AAED,wBAAgB,QAAQ,CACtB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,iBAAyC,EAClD,KAAK,GAAE,aAA6B,GACnC,UAAU,CAKZ"}
package/dist/validate.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { ATTACHMENT, BUILT_IN_TYPE, readSchema } from './definition.js';
2
2
  import { parse } from './document.js';
3
3
  import { hrefOccurrences, linkInventory } from './links.js';
4
- import { classifyHref } from './paths.js';
4
+ import { classifyHref, roomTarget } from './paths.js';
5
5
  import { references } from './references.js';
6
6
  import { refusal } from './refuse.js';
7
- import { fitsItem, frontmatterRefusal } from './schema.js';
7
+ import { conditionedSections, fitsItem, frontmatterRefusal } from './schema.js';
8
+ import { openPatternBudget, PatternTooCostly } from './pattern.js';
8
9
  import { headingSpans, listItems } from './sections.js';
9
10
  import { bodyAfterFrontmatter, bodyStartOf } from './yaml.js';
10
11
  function refuse(file, rule, extra) {
@@ -18,33 +19,50 @@ function instanceType(document) {
18
19
  return null;
19
20
  return raw;
20
21
  }
21
- function reaches(file, href, to, types, binaryTargets) {
22
- const resolved = classifyHref(file, href);
23
- if (resolved.kind !== 'path')
22
+ function reaches(reference, typeOf, binary) {
23
+ if (reference.target === null)
24
24
  return false;
25
- if (to.includes(ATTACHMENT))
25
+ if (reference.to.includes(ATTACHMENT))
26
26
  return true;
27
- if (binaryTargets.has(resolved.path))
27
+ if (binary(reference.target))
28
+ return false;
29
+ const held = typeOf(reference.target);
30
+ return held === undefined || reference.to.includes(held);
31
+ }
32
+ function missing(reference, typeOf, binary) {
33
+ if (reference.to.includes(ATTACHMENT) || reference.target === null)
28
34
  return false;
29
- const held = types.get(resolved.path);
30
- return held === undefined || to.includes(held);
35
+ return typeOf(reference.target) === undefined && !binary(reference.target);
36
+ }
37
+ export function resolves(reference, typeOf, binary) {
38
+ return reaches(reference, typeOf, binary) && !missing(reference, typeOf, binary);
31
39
  }
32
- function itemHrefs(content, items) {
33
- const bodyStart = bodyStartOf(content);
34
- const { uses } = linkInventory(content.slice(bodyStart));
40
+ function usesIn(content) {
41
+ let held;
42
+ return () => {
43
+ if (held !== undefined)
44
+ return held;
45
+ const bodyStart = bodyStartOf(content);
46
+ held = linkInventory(content.slice(bodyStart)).uses.map((use) => ({
47
+ ...use,
48
+ start: bodyStart + use.start,
49
+ end: bodyStart + use.end,
50
+ }));
51
+ return held;
52
+ };
53
+ }
54
+ function itemHrefs(content, items, uses) {
35
55
  const hrefs = [];
36
56
  for (const item of items) {
37
- const link = uses.find((use) => bodyStart + use.start === item.start &&
38
- bodyStart + use.end === item.end &&
39
- content[item.start] === '[');
57
+ const link = uses().find((use) => use.start === item.start && use.end === item.end && content[item.start] === '[');
40
58
  if (link === undefined)
41
59
  return null;
42
60
  hrefs.push(link.destination.href);
43
61
  }
44
62
  return hrefs;
45
63
  }
46
- export function verify(schema) {
47
- const read = readSchema(schema);
64
+ export function verify(schema, provided) {
65
+ const read = readSchema(schema, provided);
48
66
  if ('types' in read)
49
67
  return { verdict: 'accept', model: read };
50
68
  return {
@@ -53,114 +71,299 @@ export function verify(schema) {
53
71
  ...(read.location === undefined ? {} : { location: read.location }),
54
72
  };
55
73
  }
56
- export function validate(library, context = { binaryTargets: [] }, model = { types: {} }) {
57
- const binaryTargets = new Set(context.binaryTargets);
58
- const files = Object.keys(library).sort();
59
- const types = new Map();
60
- const documents = new Map();
61
- for (const file of files) {
62
- if (binaryTargets.has(file))
63
- return refuse(file, 'binary-target-document');
64
- const parsed = parse(library[file], file);
65
- if (!parsed.ok)
66
- return { verdict: 'refuse', ...parsed.refusal };
67
- types.set(file, parsed.document.type ?? BUILT_IN_TYPE);
68
- if (instanceType(parsed.document) !== BUILT_IN_TYPE)
69
- documents.set(file, parsed.document);
74
+ function structure(file, content, document, definition) {
75
+ if (definition === undefined)
76
+ return { refusal: refuse(file, 'unknown-type', { location: '/type' }) };
77
+ const fieldFailure = frontmatterRefusal(definition, document.fields);
78
+ if (fieldFailure !== undefined) {
79
+ return { refusal: refuse(file, fieldFailure.rule, { location: fieldFailure.location }) };
70
80
  }
71
- const definitions = new Map(Object.entries(model.types));
72
- const sectionReferences = new Map();
73
- for (const [file, document] of documents) {
74
- const kind = instanceType(document);
75
- if (kind === BUILT_IN_TYPE)
81
+ const spans = headingSpans(content, bodyStartOf(content));
82
+ const uses = usesIn(content);
83
+ const sections = [];
84
+ const conditioned = conditionedSections(definition, document.fields);
85
+ for (const [name, spec] of Object.entries(definition.sections)) {
86
+ const occurrences = spans.filter((one) => one.name === name);
87
+ if (occurrences.length === 0 && spec.required)
88
+ return { refusal: refuse(file, 'required-section', { location: name }) };
89
+ if (conditioned.includes(name) &&
90
+ occurrences.every((span) => content.slice(span.bodyStart, span.bodyEnd).trim() === ''))
91
+ return { refusal: refuse(file, 'conditional-section', { location: name }) };
92
+ if (spec.kind !== 'list')
76
93
  continue;
77
- const definition = kind === null ? undefined : definitions.get(kind);
78
- if (definition === undefined)
79
- return refuse(file, 'unknown-type', { location: '/type' });
80
- const fieldFailure = frontmatterRefusal(definition, document.fields);
81
- if (fieldFailure !== undefined) {
82
- return refuse(file, fieldFailure.rule, { location: fieldFailure.location });
83
- }
84
- const content = library[file];
85
- const spans = headingSpans(content, bodyStartOf(content));
86
- const references = [];
87
- for (const [name, spec] of Object.entries(definition.sections)) {
88
- const occurrences = spans.filter((one) => one.name === name);
89
- if (occurrences.length === 0 && spec.required)
90
- return refuse(file, 'required-section', { location: name });
91
- if (spec.kind !== 'list')
94
+ for (const span of occurrences) {
95
+ const items = listItems(content, span.bodyStart, span.bodyEnd);
96
+ if (items === null ||
97
+ items.some((item) => !fitsItem(definition, name, content.slice(item.start, item.end))))
98
+ return { refusal: refuse(file, 'structured-section', { location: name }) };
99
+ if (spec.items.reference === undefined)
92
100
  continue;
93
- for (const span of occurrences) {
94
- const items = listItems(content, span.bodyStart, span.bodyEnd);
95
- if (items === null ||
96
- items.some((item) => !fitsItem(definition, name, content.slice(item.start, item.end))))
97
- return refuse(file, 'structured-section', { location: name });
98
- if (spec.items.reference === undefined)
99
- continue;
100
- const hrefs = itemHrefs(content, items);
101
- if (hrefs === null)
102
- return refuse(file, 'structured-section', { location: name });
103
- references.push({ section: name, to: spec.items.reference, hrefs });
104
- }
101
+ const hrefs = itemHrefs(content, items, uses);
102
+ if (hrefs === null)
103
+ return { refusal: refuse(file, 'structured-section', { location: name }) };
104
+ sections.push({
105
+ section: name,
106
+ to: spec.items.reference,
107
+ crossRoom: spec.items.crossRoom === true,
108
+ hrefs,
109
+ });
105
110
  }
106
- sectionReferences.set(file, references);
107
111
  }
108
- for (const [file, document] of documents) {
109
- const kind = instanceType(document);
110
- if (kind === null || kind === BUILT_IN_TYPE)
112
+ return { sections };
113
+ }
114
+ function linked(file, content) {
115
+ return hrefOccurrences(bodyAfterFrontmatter(content)).every((occurrence) => classifyHref(file, occurrence.href).kind !== 'invalid');
116
+ }
117
+ function reached(file, href, to) {
118
+ const resolved = classifyHref(file, href);
119
+ return { target: resolved.kind === 'path' ? resolved.path : null, to };
120
+ }
121
+ function crossing(file, href, crossRoom) {
122
+ return crossRoom === true && classifyHref(file, href).kind === 'room';
123
+ }
124
+ function definitionOf(document, model) {
125
+ const kind = instanceType(document);
126
+ return kind === null || !Object.hasOwn(model.types, kind) ? undefined : model.types[kind];
127
+ }
128
+ export function checkDocument(file, content, model, context = {}) {
129
+ const anyRoom = context.anyRoom === true;
130
+ const parsed = parse(content, file);
131
+ if (!parsed.ok)
132
+ return { ok: false };
133
+ const document = parsed.document;
134
+ const type = document.type ?? BUILT_IN_TYPE;
135
+ if (instanceType(document) === BUILT_IN_TYPE)
136
+ return { ok: true, type, typed: false, references: [] };
137
+ const definition = definitionOf(document, model);
138
+ const read = structure(file, content, document, definition);
139
+ if ('refusal' in read || definition === undefined || !linked(file, content))
140
+ return { ok: false };
141
+ return {
142
+ ok: true,
143
+ type,
144
+ typed: true,
145
+ references: [
146
+ ...references(document, definition).flatMap(({ value, to, crossRoom }) => crossing(file, value, anyRoom || crossRoom) ? [] : [reached(file, value, to)]),
147
+ ...read.sections.flatMap(({ to, crossRoom, hrefs }) => hrefs.flatMap((href) => crossing(file, href, anyRoom || crossRoom) ? [] : [reached(file, href, to)])),
148
+ ],
149
+ };
150
+ }
151
+ export function sectionReferences(file, content, definition) {
152
+ const referring = (name) => {
153
+ const spec = Object.hasOwn(definition.sections, name) ? definition.sections[name] : undefined;
154
+ return spec?.kind === 'list' && spec.items.reference !== undefined ? spec.items : undefined;
155
+ };
156
+ if (!Object.keys(definition.sections).some((name) => referring(name) !== undefined))
157
+ return [];
158
+ const uses = usesIn(content);
159
+ const found = [];
160
+ for (const span of headingSpans(content, bodyStartOf(content))) {
161
+ const items = referring(span.name);
162
+ if (items === undefined)
111
163
  continue;
112
- const definition = definitions.get(kind);
113
- if (definition === undefined)
164
+ const listed = listItems(content, span.bodyStart, span.bodyEnd);
165
+ const hrefs = listed === null ? null : itemHrefs(content, listed, uses);
166
+ for (const href of hrefs ?? [])
167
+ if (!crossing(file, href, items.crossRoom))
168
+ found.push(reached(file, href, items.reference));
169
+ }
170
+ return found;
171
+ }
172
+ export function bodyRoomLinks(body) {
173
+ const found = [];
174
+ for (const href of new Set(hrefOccurrences(body).map((occurrence) => occurrence.href))) {
175
+ const room = roomTarget(href);
176
+ if (room !== null)
177
+ found.push({ kind: 'link', href, ...room });
178
+ }
179
+ return found;
180
+ }
181
+ export function roomReferences(file, content, definition) {
182
+ const found = bodyRoomLinks(bodyAfterFrontmatter(content));
183
+ if (definition === undefined)
184
+ return found;
185
+ const parsed = parse(content, file);
186
+ if (!parsed.ok)
187
+ return found;
188
+ for (const { pointer, value, to, crossRoom } of references(parsed.document, definition)) {
189
+ const room = roomTarget(value);
190
+ if (room !== null)
191
+ found.push({
192
+ kind: 'field',
193
+ pointer,
194
+ value,
195
+ to,
196
+ ...room,
197
+ ...(crossRoom ? { crossRoom } : {}),
198
+ });
199
+ }
200
+ const uses = usesIn(content);
201
+ for (const span of headingSpans(content, bodyStartOf(content))) {
202
+ const spec = Object.hasOwn(definition.sections, span.name)
203
+ ? definition.sections[span.name]
204
+ : undefined;
205
+ if (spec?.kind !== 'list' || spec.items.reference === undefined)
114
206
  continue;
115
- for (const { pointer, to, value } of references(document, definition)) {
116
- if (!reaches(file, value, to, types, binaryTargets))
117
- return refuse(file, 'unresolved-reference', { location: pointer });
118
- }
119
- const body = bodyAfterFrontmatter(library[file]);
120
- for (const occurrence of hrefOccurrences(body)) {
121
- const resolved = classifyHref(file, occurrence.href);
122
- if (resolved.kind === 'invalid')
123
- return refuse(file, 'unresolved-link');
207
+ const listed = listItems(content, span.bodyStart, span.bodyEnd);
208
+ for (const href of (listed === null ? null : itemHrefs(content, listed, uses)) ?? []) {
209
+ const room = roomTarget(href);
210
+ if (room !== null)
211
+ found.push({
212
+ kind: 'item',
213
+ section: span.name,
214
+ href,
215
+ to: spec.items.reference,
216
+ ...room,
217
+ ...(spec.items.crossRoom === true ? { crossRoom: true } : {}),
218
+ });
124
219
  }
125
- for (const { section, to, hrefs } of sectionReferences.get(file)) {
126
- for (const href of hrefs) {
127
- if (!reaches(file, href, to, types, binaryTargets))
128
- return refuse(file, 'unresolved-reference', { location: section });
220
+ }
221
+ return found;
222
+ }
223
+ function least(refused, file, verdict) {
224
+ return refused === undefined || file < refused.file ? { file, verdict } : refused;
225
+ }
226
+ export function assess(file, content, binary, model = { types: {} }, context = {}) {
227
+ const unread = { file, type: undefined, targets: [], structured: null, fields: [], sections: [] };
228
+ if (binary)
229
+ return { ...unread, read: refuse(file, 'binary-target-document'), linked: true };
230
+ const parsed = parse(content, file);
231
+ if (!parsed.ok)
232
+ return { ...unread, read: { verdict: 'refuse', ...parsed.refusal }, linked: true };
233
+ const document = parsed.document;
234
+ const type = document.type ?? BUILT_IN_TYPE;
235
+ const typed = { file, type, read: null, structured: null };
236
+ if (instanceType(document) === BUILT_IN_TYPE) {
237
+ return { ...typed, targets: [], fields: [], linked: true, sections: [] };
238
+ }
239
+ const definition = definitionOf(document, model);
240
+ try {
241
+ return structured(file, content, typed, document, definition, context);
242
+ }
243
+ catch (error) {
244
+ if (!(error instanceof PatternTooCostly))
245
+ throw error;
246
+ return {
247
+ ...typed,
248
+ targets: [],
249
+ structured: refuse(file, 'pattern', { location: '' }),
250
+ fields: [],
251
+ linked: true,
252
+ sections: [],
253
+ };
254
+ }
255
+ }
256
+ function structured(file, content, typed, document, definition, context) {
257
+ const read = structure(file, content, document, definition);
258
+ if ('refusal' in read || definition === undefined) {
259
+ return {
260
+ ...typed,
261
+ targets: [],
262
+ structured: 'refusal' in read ? read.refusal : null,
263
+ fields: [],
264
+ linked: true,
265
+ sections: [],
266
+ };
267
+ }
268
+ const anyRoom = context.anyRoom === true;
269
+ const fields = references(document, definition).flatMap(({ pointer, value, to, crossRoom }) => crossing(file, value, anyRoom || crossRoom)
270
+ ? []
271
+ : [{ reference: reached(file, value, to), location: pointer }]);
272
+ const sections = read.sections.flatMap(({ section, to, crossRoom, hrefs }) => hrefs.flatMap((href) => crossing(file, href, anyRoom || crossRoom)
273
+ ? []
274
+ : [{ reference: reached(file, href, to), location: section }]));
275
+ const targets = new Set();
276
+ for (const { reference } of [...fields, ...sections]) {
277
+ if (reference.target !== null)
278
+ targets.add(reference.target);
279
+ }
280
+ return { ...typed, targets: [...targets], fields, linked: linked(file, content), sections };
281
+ }
282
+ export function verdicts() {
283
+ let read;
284
+ let structured;
285
+ let referred;
286
+ let missed;
287
+ const unreached = (placed, typeOf, binary) => placed.find(({ reference }) => !reaches(reference, typeOf, binary));
288
+ return {
289
+ add(assessment, typeOf, binary) {
290
+ const { file } = assessment;
291
+ if (assessment.read !== null) {
292
+ read = least(read, file, assessment.read);
293
+ return 0;
294
+ }
295
+ if (assessment.structured !== null) {
296
+ structured = least(structured, file, assessment.structured);
297
+ return 0;
298
+ }
299
+ const field = unreached(assessment.fields, typeOf, binary);
300
+ if (field !== undefined) {
301
+ referred = least(referred, file, refuse(file, 'unresolved-reference', { location: field.location }));
302
+ return 0;
129
303
  }
304
+ if (!assessment.linked) {
305
+ referred = least(referred, file, refuse(file, 'unresolved-link'));
306
+ return 0;
307
+ }
308
+ const section = unreached(assessment.sections, typeOf, binary);
309
+ if (section !== undefined) {
310
+ referred = least(referred, file, refuse(file, 'unresolved-reference', { location: section.location }));
311
+ return 0;
312
+ }
313
+ const all = [...assessment.fields, ...assessment.sections];
314
+ for (const { reference } of all) {
315
+ if (!missing(reference, typeOf, binary))
316
+ continue;
317
+ const path = reference.target;
318
+ if (missed === undefined || path < missed.path)
319
+ missed = { path, referrers: [] };
320
+ if (path === missed.path && missed.referrers.at(-1) !== file)
321
+ missed.referrers.push(file);
322
+ }
323
+ return all.length;
324
+ },
325
+ verdict() {
326
+ const refused = read ?? structured ?? referred;
327
+ if (refused !== undefined)
328
+ return refused.verdict;
329
+ if (missed !== undefined) {
330
+ return refuse(missed.path, 'referenced-missing-file', {
331
+ referrers: [...missed.referrers].sort(),
332
+ });
333
+ }
334
+ return { verdict: 'accept' };
335
+ },
336
+ };
337
+ }
338
+ export function* validating(library, context = { binaryTargets: [] }, model = { types: {} }) {
339
+ const binaryTargets = new Set(context.binaryTargets);
340
+ const binary = (path) => binaryTargets.has(path);
341
+ const types = new Map();
342
+ const assessments = [];
343
+ const closeBudget = openPatternBudget();
344
+ try {
345
+ for (const [file, content] of library) {
346
+ const assessment = assess(file, content, binary(file), model, context);
347
+ if (assessment.type !== undefined)
348
+ types.set(file, assessment.type);
349
+ assessments.push(assessment);
350
+ yield { path: file, resolved: 0 };
130
351
  }
131
- }
132
- const missing = new Map();
133
- for (const [file, document] of documents) {
134
- const kind = instanceType(document);
135
- if (kind === null || kind === BUILT_IN_TYPE)
136
- continue;
137
- const definition = definitions.get(kind);
138
- if (definition === undefined)
139
- continue;
140
- const named = [
141
- ...references(document, definition),
142
- ...sectionReferences
143
- .get(file)
144
- .flatMap(({ to, hrefs }) => hrefs.map((value) => ({ value, to }))),
145
- ];
146
- for (const { value, to } of named) {
147
- if (to.includes(ATTACHMENT))
148
- continue;
149
- const resolved = classifyHref(file, value);
150
- if (resolved.kind !== 'path')
151
- continue;
152
- if (types.has(resolved.path) || binaryTargets.has(resolved.path))
153
- continue;
154
- const referrers = missing.get(resolved.path) ?? [];
155
- referrers.push(file);
156
- missing.set(resolved.path, referrers);
352
+ const judged = verdicts();
353
+ for (const assessment of assessments) {
354
+ const resolved = judged.add(assessment, (path) => types.get(path), binary);
355
+ yield { path: assessment.file, resolved };
157
356
  }
357
+ return judged.verdict();
158
358
  }
159
- const missingPaths = [...missing.keys()].sort();
160
- if (missingPaths.length > 0) {
161
- const path = missingPaths[0];
162
- const referrers = [...new Set(missing.get(path) ?? [])].sort();
163
- return refuse(path, 'referenced-missing-file', { referrers });
359
+ finally {
360
+ closeBudget();
164
361
  }
165
- return { verdict: 'accept' };
362
+ }
363
+ export function validate(library, context = { binaryTargets: [] }, model = { types: {} }) {
364
+ const steps = validating(new Map(Object.entries(library)), context, model);
365
+ let step = steps.next();
366
+ while (step.done !== true)
367
+ step = steps.next();
368
+ return step.value;
166
369
  }