contentbase 0.0.4 → 0.0.6
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/package.json +3 -2
- package/.mcp.json +0 -9
- package/MCP-DESCRIPTIONS-REVIEW.md +0 -122
- package/bun.lock +0 -512
- package/dist/cnotes +0 -0
- package/examples/sdlc-queries.ts +0 -161
- package/public/web-demo/index.html +0 -813
- package/scripts/examples/01-collection-setup.ts +0 -46
- package/scripts/examples/02-querying.ts +0 -67
- package/scripts/examples/03-sections.ts +0 -36
- package/scripts/examples/04-relationships.ts +0 -54
- package/scripts/examples/05-document-api.ts +0 -54
- package/scripts/examples/06-extract-sections.ts +0 -55
- package/scripts/examples/07-validation.ts +0 -46
- package/scripts/examples/08-serialization.ts +0 -51
- package/scripts/examples/lib/format.ts +0 -87
- package/scripts/examples/lib/setup.ts +0 -21
- package/scripts/examples/run-all.ts +0 -43
- package/showcases/national-parks/models.ts +0 -74
- package/showcases/national-parks/parks/acadia.mdx +0 -40
- package/showcases/national-parks/parks/yosemite.mdx +0 -44
- package/showcases/national-parks/parks/zion.mdx +0 -44
- package/showcases/national-parks/queries.ts +0 -103
- package/showcases/national-parks/trails/angels-landing.mdx +0 -19
- package/showcases/national-parks/trails/cathedral-lakes.mdx +0 -19
- package/showcases/national-parks/trails/half-dome.mdx +0 -19
- package/showcases/national-parks/trails/jordan-pond-path.mdx +0 -19
- package/showcases/national-parks/trails/mist-trail.mdx +0 -19
- package/showcases/national-parks/trails/observation-point.mdx +0 -19
- package/showcases/national-parks/trails/precipice-trail.mdx +0 -19
- package/showcases/national-parks/trails/the-narrows.mdx +0 -19
- package/showcases/node_modules/.cache/.repl_history +0 -3
- package/showcases/recipes/cuisines/chinese.mdx +0 -28
- package/showcases/recipes/cuisines/italian.mdx +0 -32
- package/showcases/recipes/cuisines/mexican.mdx +0 -28
- package/showcases/recipes/models.ts +0 -77
- package/showcases/recipes/queries.ts +0 -89
- package/showcases/recipes/recipes/chinese/egg-fried-rice.mdx +0 -43
- package/showcases/recipes/recipes/chinese/mapo-tofu.mdx +0 -47
- package/showcases/recipes/recipes/italian/bruschetta.mdx +0 -38
- package/showcases/recipes/recipes/italian/cacio-e-pepe.mdx +0 -39
- package/showcases/recipes/recipes/italian/tiramisu.mdx +0 -43
- package/showcases/recipes/recipes/mexican/chicken-tinga.mdx +0 -44
- package/showcases/recipes/recipes/mexican/guacamole.mdx +0 -39
- package/showcases/vinyl-collection/albums/bitches-brew.mdx +0 -36
- package/showcases/vinyl-collection/albums/i-put-a-spell-on-you.mdx +0 -35
- package/showcases/vinyl-collection/albums/in-rainbows.mdx +0 -35
- package/showcases/vinyl-collection/albums/kind-of-blue.mdx +0 -32
- package/showcases/vinyl-collection/albums/ok-computer.mdx +0 -37
- package/showcases/vinyl-collection/albums/wild-is-the-wind.mdx +0 -35
- package/showcases/vinyl-collection/artists/miles-davis.mdx +0 -27
- package/showcases/vinyl-collection/artists/nina-simone.mdx +0 -26
- package/showcases/vinyl-collection/artists/radiohead.mdx +0 -27
- package/showcases/vinyl-collection/models.ts +0 -73
- package/showcases/vinyl-collection/queries.ts +0 -87
- package/src/__tests__/semantic-search.integration.test.ts +0 -284
- package/test/ast-query.test.ts +0 -128
- package/test/collection.test.ts +0 -215
- package/test/define-model.test.ts +0 -78
- package/test/document.test.ts +0 -225
- package/test/extract-sections.test.ts +0 -356
- package/test/fixtures/sdlc/MODELS.md +0 -106
- package/test/fixtures/sdlc/SKILL.md +0 -404
- package/test/fixtures/sdlc/epics/authentication.mdx +0 -42
- package/test/fixtures/sdlc/epics/searching-and-browsing.mdx +0 -21
- package/test/fixtures/sdlc/index.ts +0 -9
- package/test/fixtures/sdlc/models.ts +0 -91
- package/test/fixtures/sdlc/stories/authentication/a-user-should-be-able-to-login.mdx +0 -20
- package/test/fixtures/sdlc/stories/authentication/a-user-should-be-able-to-register.mdx +0 -20
- package/test/fixtures/sdlc/templates/epic.md +0 -23
- package/test/fixtures/sdlc/templates/story.md +0 -19
- package/test/helpers.ts +0 -21
- package/test/model-instance.test.ts +0 -197
- package/test/pattern.test.ts +0 -191
- package/test/query-dsl.test.ts +0 -431
- package/test/query.test.ts +0 -196
- package/test/relationships.test.ts +0 -214
- package/test/section.test.ts +0 -160
- package/test/table-of-contents.test.ts +0 -135
- package/test/validator.test.ts +0 -62
- package/tsconfig.json +0 -18
- package/vitest.config.ts +0 -11
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
-
import { Collection } from "../src/collection";
|
|
3
|
-
import { createModelInstance } from "../src/model-instance";
|
|
4
|
-
import { createTestCollection } from "./helpers";
|
|
5
|
-
import { Epic, Story } from "./fixtures/sdlc/models";
|
|
6
|
-
|
|
7
|
-
describe("createModelInstance", () => {
|
|
8
|
-
let collection: Collection;
|
|
9
|
-
|
|
10
|
-
beforeEach(async () => {
|
|
11
|
-
collection = await createTestCollection();
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
describe("core properties", () => {
|
|
15
|
-
it("has correct id", () => {
|
|
16
|
-
const doc = collection.document("epics/authentication");
|
|
17
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
18
|
-
expect(instance.id).toBe("epics/authentication");
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("has correct title", () => {
|
|
22
|
-
const doc = collection.document("epics/authentication");
|
|
23
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
24
|
-
expect(instance.title).toBe("Authentication");
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("has correct slug", () => {
|
|
28
|
-
const doc = collection.document("epics/authentication");
|
|
29
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
30
|
-
expect(instance.slug).toBe("authentication");
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it("references the original document", () => {
|
|
34
|
-
const doc = collection.document("epics/authentication");
|
|
35
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
36
|
-
expect(instance.document).toBe(doc);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("references the collection", () => {
|
|
40
|
-
const doc = collection.document("epics/authentication");
|
|
41
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
42
|
-
expect(instance.collection).toBe(collection);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe("meta", () => {
|
|
47
|
-
it("returns Zod-parsed frontmatter", () => {
|
|
48
|
-
const doc = collection.document("epics/authentication");
|
|
49
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
50
|
-
expect(instance.meta.priority).toBe("high");
|
|
51
|
-
expect(instance.meta.status).toBe("created");
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("applies defaults where fields are missing", () => {
|
|
55
|
-
const doc = collection.document("epics/searching-and-browsing");
|
|
56
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
57
|
-
expect(instance.meta.status).toBe("created");
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe("sections", () => {
|
|
62
|
-
it("lazily extracts section data", () => {
|
|
63
|
-
const doc = collection.document(
|
|
64
|
-
"stories/authentication/a-user-should-be-able-to-register"
|
|
65
|
-
);
|
|
66
|
-
const instance = createModelInstance(doc, Story, collection);
|
|
67
|
-
const criteria = instance.sections.acceptanceCriteria;
|
|
68
|
-
expect(Array.isArray(criteria)).toBe(true);
|
|
69
|
-
expect(criteria.length).toBe(4);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it("extracts mockups as record", () => {
|
|
73
|
-
const doc = collection.document(
|
|
74
|
-
"stories/authentication/a-user-should-be-able-to-register"
|
|
75
|
-
);
|
|
76
|
-
const instance = createModelInstance(doc, Story, collection);
|
|
77
|
-
const mockups = instance.sections.mockups;
|
|
78
|
-
expect(typeof mockups).toBe("object");
|
|
79
|
-
expect(Object.keys(mockups).length).toBeGreaterThan(0);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe("computed", () => {
|
|
84
|
-
it("evaluates computed properties", () => {
|
|
85
|
-
const doc = collection.document("epics/authentication");
|
|
86
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
87
|
-
expect(instance.computed.isComplete).toBe(false);
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
describe("relationships", () => {
|
|
92
|
-
it("hasMany fetchAll returns related instances", () => {
|
|
93
|
-
const doc = collection.document("epics/authentication");
|
|
94
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
95
|
-
const stories = instance.relationships.stories.fetchAll();
|
|
96
|
-
expect(stories.length).toBe(2);
|
|
97
|
-
expect(stories[0].title).toBeDefined();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it("hasMany first returns first child", () => {
|
|
101
|
-
const doc = collection.document("epics/authentication");
|
|
102
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
103
|
-
const first = instance.relationships.stories.first();
|
|
104
|
-
expect(first).toBeDefined();
|
|
105
|
-
expect(first!.title).toContain("register");
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("hasMany last returns last child", () => {
|
|
109
|
-
const doc = collection.document("epics/authentication");
|
|
110
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
111
|
-
const last = instance.relationships.stories.last();
|
|
112
|
-
expect(last).toBeDefined();
|
|
113
|
-
expect(last!.title).toContain("login");
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it("belongsTo fetch returns parent", () => {
|
|
117
|
-
const doc = collection.document(
|
|
118
|
-
"stories/authentication/a-user-should-be-able-to-register"
|
|
119
|
-
);
|
|
120
|
-
const instance = createModelInstance(doc, Story, collection);
|
|
121
|
-
const epic = instance.relationships.epic.fetch();
|
|
122
|
-
expect(epic.title).toBe("Authentication");
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
describe("validation", () => {
|
|
127
|
-
it("returns valid for good data", async () => {
|
|
128
|
-
const doc = collection.document("epics/authentication");
|
|
129
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
130
|
-
const result = await instance.validate();
|
|
131
|
-
expect(result.valid).toBe(true);
|
|
132
|
-
expect(result.errors.length).toBe(0);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("returns errors for bad meta", async () => {
|
|
136
|
-
const doc = collection.createDocument({
|
|
137
|
-
id: "test/bad",
|
|
138
|
-
content: "# Bad Doc\n",
|
|
139
|
-
meta: { status: "INVALID_STATUS" },
|
|
140
|
-
});
|
|
141
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
142
|
-
const result = await instance.validate();
|
|
143
|
-
expect(result.valid).toBe(false);
|
|
144
|
-
expect(result.errors.length).toBeGreaterThan(0);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it("populates errors map", async () => {
|
|
148
|
-
const doc = collection.createDocument({
|
|
149
|
-
id: "test/bad",
|
|
150
|
-
content: "# Bad Doc\n",
|
|
151
|
-
meta: { status: "INVALID_STATUS" },
|
|
152
|
-
});
|
|
153
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
154
|
-
await instance.validate();
|
|
155
|
-
expect(instance.hasErrors).toBe(true);
|
|
156
|
-
expect(instance.errors.size).toBeGreaterThan(0);
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
describe("toJSON", () => {
|
|
161
|
-
it("returns id, title, meta by default", () => {
|
|
162
|
-
const doc = collection.document("epics/authentication");
|
|
163
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
164
|
-
const json = instance.toJSON();
|
|
165
|
-
expect(json.id).toBe("epics/authentication");
|
|
166
|
-
expect(json.title).toBe("Authentication");
|
|
167
|
-
expect(json.meta).toBeDefined();
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it("includes requested sections", () => {
|
|
171
|
-
const doc = collection.document(
|
|
172
|
-
"stories/authentication/a-user-should-be-able-to-register"
|
|
173
|
-
);
|
|
174
|
-
const instance = createModelInstance(doc, Story, collection);
|
|
175
|
-
const json = instance.toJSON({
|
|
176
|
-
sections: ["acceptanceCriteria"],
|
|
177
|
-
});
|
|
178
|
-
expect(json.acceptanceCriteria).toBeDefined();
|
|
179
|
-
expect(Array.isArray(json.acceptanceCriteria)).toBe(true);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it("includes requested computed values", () => {
|
|
183
|
-
const doc = collection.document("epics/authentication");
|
|
184
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
185
|
-
const json = instance.toJSON({ computed: ["isComplete"] });
|
|
186
|
-
expect(json.isComplete).toBe(false);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it("includes requested relationships", () => {
|
|
190
|
-
const doc = collection.document("epics/authentication");
|
|
191
|
-
const instance = createModelInstance(doc, Epic, collection);
|
|
192
|
-
const json = instance.toJSON({ related: ["stories"] });
|
|
193
|
-
expect(json.stories).toBeDefined();
|
|
194
|
-
expect(Array.isArray(json.stories)).toBe(true);
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
});
|
package/test/pattern.test.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
-
import { matchPattern, matchPatterns } from "../src/utils/match-pattern";
|
|
3
|
-
import { defineModel, z } from "../src/index";
|
|
4
|
-
import { createModelInstance } from "../src/model-instance";
|
|
5
|
-
import { validateDocument } from "../src/validator";
|
|
6
|
-
import { Collection } from "../src/collection";
|
|
7
|
-
import { createTestCollection } from "./helpers";
|
|
8
|
-
|
|
9
|
-
describe("matchPattern", () => {
|
|
10
|
-
it("extracts named params from matching path", () => {
|
|
11
|
-
const result = matchPattern("plans/:project/:slug", "plans/acme/launch");
|
|
12
|
-
expect(result).toEqual({ project: "acme", slug: "launch" });
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it("returns null on literal segment mismatch", () => {
|
|
16
|
-
const result = matchPattern("plans/:project/:slug", "stories/acme/launch");
|
|
17
|
-
expect(result).toBeNull();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it("returns null on segment count mismatch (too few)", () => {
|
|
21
|
-
const result = matchPattern("plans/:project/:slug", "plans/acme");
|
|
22
|
-
expect(result).toBeNull();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("returns null on segment count mismatch (too many)", () => {
|
|
26
|
-
const result = matchPattern("plans/:project/:slug", "plans/acme/launch/extra");
|
|
27
|
-
expect(result).toBeNull();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("matches literal-only pattern", () => {
|
|
31
|
-
const result = matchPattern("plans/acme/launch", "plans/acme/launch");
|
|
32
|
-
expect(result).toEqual({});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("returns null for literal-only mismatch", () => {
|
|
36
|
-
const result = matchPattern("plans/acme/launch", "plans/acme/other");
|
|
37
|
-
expect(result).toBeNull();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it("handles single-segment patterns", () => {
|
|
41
|
-
const result = matchPattern(":slug", "my-doc");
|
|
42
|
-
expect(result).toEqual({ slug: "my-doc" });
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("handles leading/trailing slashes gracefully", () => {
|
|
46
|
-
const result = matchPattern("/plans/:slug/", "/plans/launch/");
|
|
47
|
-
expect(result).toEqual({ slug: "launch" });
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
describe("matchPatterns", () => {
|
|
52
|
-
it("accepts a single pattern string", () => {
|
|
53
|
-
const result = matchPatterns("plans/:project/:slug", "plans/acme/launch");
|
|
54
|
-
expect(result).toEqual({ project: "acme", slug: "launch" });
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it("returns first matching pattern from array", () => {
|
|
58
|
-
const result = matchPatterns(
|
|
59
|
-
["docs/:category/:slug", "plans/:project/:slug"],
|
|
60
|
-
"plans/acme/launch"
|
|
61
|
-
);
|
|
62
|
-
expect(result).toEqual({ project: "acme", slug: "launch" });
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("skips non-matching patterns", () => {
|
|
66
|
-
const result = matchPatterns(
|
|
67
|
-
["docs/:category/:slug", "plans/:project/:slug"],
|
|
68
|
-
"plans/acme/launch"
|
|
69
|
-
);
|
|
70
|
-
// First pattern doesn't match (docs != plans), second does
|
|
71
|
-
expect(result).toEqual({ project: "acme", slug: "launch" });
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("returns null when no patterns match", () => {
|
|
75
|
-
const result = matchPatterns(
|
|
76
|
-
["docs/:slug", "plans/:slug"],
|
|
77
|
-
"stories/my-story"
|
|
78
|
-
);
|
|
79
|
-
expect(result).toBeNull();
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it("returns first match when multiple patterns could match", () => {
|
|
83
|
-
const result = matchPatterns(
|
|
84
|
-
["things/:a/:b", "things/:x/:y"],
|
|
85
|
-
"things/foo/bar"
|
|
86
|
-
);
|
|
87
|
-
expect(result).toEqual({ a: "foo", b: "bar" });
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
describe("pattern integration", () => {
|
|
92
|
-
let collection: Collection;
|
|
93
|
-
|
|
94
|
-
beforeEach(async () => {
|
|
95
|
-
collection = await createTestCollection();
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
const Plan = defineModel("Plan", {
|
|
99
|
-
prefix: "plans",
|
|
100
|
-
pattern: "plans/:project/:slug",
|
|
101
|
-
meta: z.object({
|
|
102
|
-
project: z.string(),
|
|
103
|
-
status: z.enum(["draft", "active"]).default("draft"),
|
|
104
|
-
}),
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it("infers meta from path pattern via createModelInstance", () => {
|
|
108
|
-
const doc = collection.createDocument({
|
|
109
|
-
id: "plans/acme/launch",
|
|
110
|
-
content: "# Launch Plan\n",
|
|
111
|
-
meta: {},
|
|
112
|
-
});
|
|
113
|
-
const instance = createModelInstance(doc, Plan, collection);
|
|
114
|
-
expect(instance.meta.project).toBe("acme");
|
|
115
|
-
expect(instance.meta.status).toBe("draft");
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it("frontmatter overrides pattern-inferred values", () => {
|
|
119
|
-
const doc = collection.createDocument({
|
|
120
|
-
id: "plans/acme/launch",
|
|
121
|
-
content: "# Launch Plan\n",
|
|
122
|
-
meta: { project: "override-corp" },
|
|
123
|
-
});
|
|
124
|
-
const instance = createModelInstance(doc, Plan, collection);
|
|
125
|
-
expect(instance.meta.project).toBe("override-corp");
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it("defaults < pattern < frontmatter priority chain", () => {
|
|
129
|
-
const ModelWithDefaults = defineModel("ModelWithDefaults", {
|
|
130
|
-
prefix: "items",
|
|
131
|
-
pattern: "items/:category/:slug",
|
|
132
|
-
meta: z.object({
|
|
133
|
-
category: z.string().default("uncategorized"),
|
|
134
|
-
slug: z.string().optional(),
|
|
135
|
-
tag: z.string().default("none"),
|
|
136
|
-
}),
|
|
137
|
-
defaults: { category: "default-cat", tag: "default-tag" },
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
const doc = collection.createDocument({
|
|
141
|
-
id: "items/electronics/phone",
|
|
142
|
-
content: "# Phone\n",
|
|
143
|
-
meta: { tag: "frontmatter-tag" },
|
|
144
|
-
});
|
|
145
|
-
const instance = createModelInstance(doc, ModelWithDefaults, collection);
|
|
146
|
-
|
|
147
|
-
// category: defaults="default-cat", pattern="electronics", frontmatter=absent → "electronics"
|
|
148
|
-
expect(instance.meta.category).toBe("electronics");
|
|
149
|
-
// tag: defaults="default-tag", pattern=absent, frontmatter="frontmatter-tag" → "frontmatter-tag"
|
|
150
|
-
expect(instance.meta.tag).toBe("frontmatter-tag");
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it("no pattern means no change in behavior", () => {
|
|
154
|
-
const NoPattern = defineModel("NoPattern", {
|
|
155
|
-
prefix: "things",
|
|
156
|
-
meta: z.object({
|
|
157
|
-
status: z.string().default("new"),
|
|
158
|
-
}),
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
const doc = collection.createDocument({
|
|
162
|
-
id: "things/foo",
|
|
163
|
-
content: "# Foo\n",
|
|
164
|
-
meta: {},
|
|
165
|
-
});
|
|
166
|
-
const instance = createModelInstance(doc, NoPattern, collection);
|
|
167
|
-
expect(instance.meta.status).toBe("new");
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it("validateDocument uses pattern-inferred values", () => {
|
|
171
|
-
const doc = collection.createDocument({
|
|
172
|
-
id: "plans/acme/launch",
|
|
173
|
-
content: "# Launch Plan\n",
|
|
174
|
-
meta: {},
|
|
175
|
-
});
|
|
176
|
-
const result = validateDocument(doc, Plan);
|
|
177
|
-
// project is inferred from pattern, status gets default → should be valid
|
|
178
|
-
expect(result.valid).toBe(true);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it("validateDocument fails when pattern doesn't match and required field missing", () => {
|
|
182
|
-
const doc = collection.createDocument({
|
|
183
|
-
id: "other/something",
|
|
184
|
-
content: "# Something\n",
|
|
185
|
-
meta: {},
|
|
186
|
-
});
|
|
187
|
-
const result = validateDocument(doc, Plan);
|
|
188
|
-
// pattern won't match, project is required with no default → should fail
|
|
189
|
-
expect(result.valid).toBe(false);
|
|
190
|
-
});
|
|
191
|
-
});
|