@jskit-ai/kernel 0.1.154 → 0.1.156

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.
@@ -1,256 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { createSchema } from "json-rest-schema";
4
- import {
5
- DEFAULT_CRUD_LOOKUP_CONTAINER_KEY,
6
- normalizeCrudLookupApiPath,
7
- normalizeCrudLookupNamespace,
8
- resolveCrudLookupApiPathFromNamespace,
9
- resolveCrudResourceScopeName,
10
- normalizeCrudLookupContainerKey,
11
- resolveCrudLookupContainerKey,
12
- resolveCrudParentFilterKeys,
13
- resolveCrudLookupFieldKeys,
14
- resolveCrudLookupFieldKeyFromRouteParam,
15
- resolveCrudParentFilterFieldKeyFromRouteParam
16
- } from "./crudLookup.js";
17
-
18
- function createCrudResource({
19
- viewFields = {},
20
- createFields = {},
21
- patchFields = {},
22
- contract = {}
23
- } = {}) {
24
- return {
25
- ...(Object.keys(contract).length > 0 ? { contract } : {}),
26
- operations: {
27
- view: {
28
- output: {
29
- schema: createSchema(viewFields)
30
- }
31
- },
32
- create: {
33
- body: {
34
- schema: createSchema(createFields)
35
- }
36
- },
37
- patch: {
38
- body: {
39
- schema: createSchema(patchFields)
40
- }
41
- }
42
- }
43
- };
44
- }
45
-
46
- test("normalizeCrudLookupApiPath normalizes and rejects root", () => {
47
- assert.equal(normalizeCrudLookupApiPath("vets"), "/vets");
48
- assert.equal(normalizeCrudLookupApiPath("/vets//"), "/vets");
49
- assert.equal(normalizeCrudLookupApiPath("/"), "");
50
- });
51
-
52
- test("normalizeCrudLookupNamespace normalizes namespace-like values", () => {
53
- assert.equal(normalizeCrudLookupNamespace("vets"), "vets");
54
- assert.equal(normalizeCrudLookupNamespace("/customer-categories//"), "customer-categories");
55
- assert.equal(normalizeCrudLookupNamespace("/"), "");
56
- });
57
-
58
- test("resolveCrudLookupApiPathFromNamespace maps namespace to api path", () => {
59
- assert.equal(resolveCrudLookupApiPathFromNamespace("vets"), "/vets");
60
- assert.equal(resolveCrudLookupApiPathFromNamespace("/customer-categories"), "/customer-categories");
61
- assert.equal(resolveCrudLookupApiPathFromNamespace(""), "");
62
- });
63
-
64
- test("resolveCrudResourceScopeName maps namespace and api path values to json-rest-api scope names", () => {
65
- assert.equal(resolveCrudResourceScopeName("pets"), "pets");
66
- assert.equal(resolveCrudResourceScopeName("/customer-categories"), "customerCategories");
67
- assert.equal(resolveCrudResourceScopeName("/workspace/pets"), "workspacePets");
68
- assert.equal(resolveCrudResourceScopeName(""), "");
69
- });
70
-
71
- test("normalizeCrudLookupContainerKey defaults to canonical value", () => {
72
- assert.equal(normalizeCrudLookupContainerKey(undefined), DEFAULT_CRUD_LOOKUP_CONTAINER_KEY);
73
- assert.equal(normalizeCrudLookupContainerKey(""), DEFAULT_CRUD_LOOKUP_CONTAINER_KEY);
74
- });
75
-
76
- test("resolveCrudLookupContainerKey reads resource contract override", () => {
77
- assert.equal(
78
- resolveCrudLookupContainerKey({
79
- contract: {
80
- lookup: {
81
- containerKey: "lookupData"
82
- }
83
- }
84
- }),
85
- "lookupData"
86
- );
87
- });
88
-
89
- test("resolveCrudLookupContainerKey throws for invalid contract shape", () => {
90
- assert.throws(
91
- () => resolveCrudLookupContainerKey({ contract: { lookup: [] } }),
92
- /contract\.lookup must be an object/
93
- );
94
- });
95
-
96
- test("resolveCrudLookupFieldKeys returns lookup field keys with optional allow-list", () => {
97
- const resource = createCrudResource({
98
- viewFields: {
99
- contactId: {
100
- type: "integer",
101
- relation: {
102
- kind: "lookup",
103
- apiPath: "/contacts",
104
- valueKey: "id"
105
- }
106
- },
107
- status: {
108
- type: "string"
109
- },
110
- vetId: {
111
- type: "integer",
112
- parentRouteParamKey: "primaryVetId",
113
- relation: {
114
- kind: "lookup",
115
- apiPath: "/vets",
116
- valueKey: "id"
117
- }
118
- }
119
- }
120
- });
121
-
122
- assert.deepEqual(resolveCrudLookupFieldKeys(resource), ["contactId", "vetId"]);
123
- assert.deepEqual(resolveCrudLookupFieldKeys(resource, { allowKeys: ["vetId", "missing"] }), ["vetId"]);
124
- });
125
-
126
- test("resolveCrudLookupFieldKeyFromRouteParam matches parent route param aliases to canonical lookup field keys", () => {
127
- const resource = createCrudResource({
128
- viewFields: {
129
- staffContactId: {
130
- type: "integer",
131
- parentRouteParamKey: "contactId",
132
- relation: {
133
- kind: "lookup",
134
- apiPath: "/contacts",
135
- valueKey: "id"
136
- }
137
- },
138
- serviceId: {
139
- type: "integer",
140
- relation: {
141
- kind: "lookup",
142
- apiPath: "/services",
143
- valueKey: "id"
144
- }
145
- }
146
- }
147
- });
148
-
149
- assert.equal(resolveCrudLookupFieldKeyFromRouteParam(resource, "contactId"), "staffContactId");
150
- assert.equal(resolveCrudLookupFieldKeyFromRouteParam(resource, "staffContactId"), "staffContactId");
151
- assert.equal(resolveCrudLookupFieldKeyFromRouteParam(resource, "serviceId"), "serviceId");
152
- assert.equal(resolveCrudLookupFieldKeyFromRouteParam(resource, "unknown"), "");
153
- assert.equal(
154
- resolveCrudLookupFieldKeyFromRouteParam(resource, "contactId", { allowKeys: ["serviceId"] }),
155
- ""
156
- );
157
- });
158
-
159
- test("resolveCrudLookupFieldKeyFromRouteParam prefers exact field keys before alias matches", () => {
160
- const resource = createCrudResource({
161
- viewFields: {
162
- staffContactId: {
163
- type: "integer",
164
- parentRouteParamKey: "contactId",
165
- relation: {
166
- kind: "lookup",
167
- apiPath: "/contacts",
168
- valueKey: "id"
169
- }
170
- },
171
- contactId: {
172
- type: "integer",
173
- relation: {
174
- kind: "lookup",
175
- apiPath: "/contacts",
176
- valueKey: "id"
177
- }
178
- }
179
- }
180
- });
181
-
182
- assert.equal(resolveCrudLookupFieldKeyFromRouteParam(resource, "contactId"), "contactId");
183
- });
184
-
185
- test("resolveCrudParentFilterKeys keeps only lookup keys that are writable through create", () => {
186
- const resource = createCrudResource({
187
- viewFields: {
188
- staffContactId: {
189
- type: "integer",
190
- parentRouteParamKey: "contactId",
191
- relation: {
192
- kind: "lookup",
193
- apiPath: "/contacts",
194
- valueKey: "id"
195
- }
196
- },
197
- serviceId: {
198
- type: "integer",
199
- relation: {
200
- kind: "lookup",
201
- apiPath: "/services",
202
- valueKey: "id"
203
- }
204
- }
205
- },
206
- createFields: {
207
- serviceId: {
208
- type: "integer",
209
- relation: {
210
- kind: "lookup",
211
- apiPath: "/services",
212
- valueKey: "id"
213
- }
214
- }
215
- }
216
- });
217
-
218
- assert.deepEqual(resolveCrudParentFilterKeys(resource), ["serviceId"]);
219
- });
220
-
221
- test("resolveCrudParentFilterFieldKeyFromRouteParam uses the same allowed keys as server parent filters", () => {
222
- const resource = createCrudResource({
223
- viewFields: {
224
- staffContactId: {
225
- type: "integer",
226
- parentRouteParamKey: "contactId",
227
- relation: {
228
- kind: "lookup",
229
- apiPath: "/contacts",
230
- valueKey: "id"
231
- }
232
- },
233
- serviceId: {
234
- type: "integer",
235
- relation: {
236
- kind: "lookup",
237
- apiPath: "/services",
238
- valueKey: "id"
239
- }
240
- }
241
- },
242
- createFields: {
243
- serviceId: {
244
- type: "integer",
245
- relation: {
246
- kind: "lookup",
247
- apiPath: "/services",
248
- valueKey: "id"
249
- }
250
- }
251
- }
252
- });
253
-
254
- assert.equal(resolveCrudParentFilterFieldKeyFromRouteParam(resource, "contactId"), "");
255
- assert.equal(resolveCrudParentFilterFieldKeyFromRouteParam(resource, "serviceId"), "serviceId");
256
- });