@cimplify/sdk 0.100.3 → 0.100.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/advanced.d.mts +1 -1
- package/dist/advanced.d.ts +1 -1
- package/dist/advanced.js +20 -20
- package/dist/advanced.mjs +1 -1
- package/dist/{chunk-FWKSBF3F.js → chunk-3HU5I5VG.js} +20 -4
- package/dist/{chunk-NOGCGI4J.mjs → chunk-HSDQWJLA.mjs} +2 -2
- package/dist/{chunk-CNY2XFN4.js → chunk-JEVCHTKZ.js} +48 -47
- package/dist/{chunk-KNCW5DI7.js → chunk-LMD7B33E.js} +4 -4
- package/dist/{chunk-XCS56XSS.js → chunk-PNTINRAU.js} +31 -1
- package/dist/{chunk-HFTRLRLM.mjs → chunk-RQPXLXB2.mjs} +31 -1
- package/dist/{chunk-XG4DZT4I.mjs → chunk-RWR7JF7F.mjs} +2 -1
- package/dist/{chunk-FFRQNNUQ.mjs → chunk-Z7M6GAHS.mjs} +20 -4
- package/dist/{client-Bx4NRdl8.d.mts → client-BwRAAk4y.d.mts} +15 -0
- package/dist/{client-Cvp8W1r9.d.ts → client-CPcZIrjC.d.ts} +2 -2
- package/dist/{client-BWdeCgmo.d.ts → client-CrPglBBz.d.ts} +15 -0
- package/dist/{client-BGeSemVv.d.mts → client-DGrvLiJv.d.mts} +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +69 -69
- package/dist/index.mjs +3 -3
- package/dist/lint-rules.json +1 -0
- package/dist/lint.d.mts +540 -0
- package/dist/lint.d.ts +540 -0
- package/dist/lint.js +540 -0
- package/dist/lint.mjs +524 -0
- package/dist/mock/cli.mjs +31 -1
- package/dist/mock/library.js +31 -1
- package/dist/mock/library.mjs +31 -1
- package/dist/mock/msw.js +31 -1
- package/dist/mock/msw.mjs +31 -1
- package/dist/react.d.mts +10 -5
- package/dist/react.d.ts +10 -5
- package/dist/react.js +40 -35
- package/dist/react.mjs +14 -9
- package/dist/{server-BRJ61o2J.d.mts → server-DRAW2OOX.d.mts} +4 -1
- package/dist/{server-CXrVYtNo.d.ts → server-zyrpzJVn.d.ts} +4 -1
- package/dist/server.d.mts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +7 -7
- package/dist/server.mjs +2 -2
- package/dist/styles.css +1 -1
- package/dist/testing/msw.d.mts +1 -1
- package/dist/testing/msw.d.ts +1 -1
- package/dist/testing/msw.js +2 -2
- package/dist/testing/msw.mjs +1 -1
- package/dist/testing/suite.d.mts +4 -4
- package/dist/testing/suite.d.ts +4 -4
- package/dist/testing/suite.js +23 -23
- package/dist/testing/suite.mjs +4 -4
- package/dist/testing.d.mts +18 -18
- package/dist/testing.d.ts +18 -18
- package/dist/testing.js +79 -79
- package/dist/testing.mjs +5 -5
- package/package.json +10 -2
package/dist/lint.mjs
ADDED
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
import './chunk-3G6RQLXK.mjs';
|
|
2
|
+
import { RE2JS } from 're2js';
|
|
3
|
+
|
|
4
|
+
// src/lint/types.ts
|
|
5
|
+
var LINT_RULE_SET_SCHEMA_VERSION = 1;
|
|
6
|
+
var MAX_LINT_RULE_MANIFEST_BYTES = 256 * 1024;
|
|
7
|
+
var MAX_RULES = 64;
|
|
8
|
+
var MAX_ARRAY_ITEMS = 64;
|
|
9
|
+
var MAX_TOTAL_REGEX_PATTERNS = 64;
|
|
10
|
+
var MAX_TOTAL_RULE_TERMS = 512;
|
|
11
|
+
var MAX_PATH_SEGMENTS = 8;
|
|
12
|
+
var MAX_NAME_LENGTH = 160;
|
|
13
|
+
var MAX_MESSAGE_LENGTH = 512;
|
|
14
|
+
var MAX_HELP_LENGTH = 1024;
|
|
15
|
+
var MAX_PATTERN_LENGTH = 512;
|
|
16
|
+
var MAX_MODULE_LENGTH = 256;
|
|
17
|
+
var MAX_IDENTIFIER_LENGTH = 128;
|
|
18
|
+
var RULE_ID_PATTERN = /^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/;
|
|
19
|
+
var JAVASCRIPT_IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
20
|
+
var JSX_COMPONENT_IDENTIFIER_PATTERN = /^[A-Z][A-Za-z0-9_$]*$/;
|
|
21
|
+
var NUMERIC_OPERATORS = /* @__PURE__ */ new Set(["+", "-", "*", "/", "%", "**", "<", "<=", ">", ">="]);
|
|
22
|
+
var PRIMITIVE_KINDS = /* @__PURE__ */ new Set([
|
|
23
|
+
"required-result-check",
|
|
24
|
+
"required-wrapper-call",
|
|
25
|
+
"banned-import",
|
|
26
|
+
"banned-call-argument",
|
|
27
|
+
"banned-jsx-element",
|
|
28
|
+
"banned-classname-pattern"
|
|
29
|
+
]);
|
|
30
|
+
function isRecord(value) {
|
|
31
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
32
|
+
}
|
|
33
|
+
function expectRecord(value, label) {
|
|
34
|
+
if (!isRecord(value)) throw new TypeError(`${label} must be an object`);
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
function expectOnlyKeys(value, label, allowed, required) {
|
|
38
|
+
const allowedSet = new Set(allowed);
|
|
39
|
+
for (const key of Object.keys(value)) {
|
|
40
|
+
if (!allowedSet.has(key)) throw new TypeError(`${label} has unknown property ${key}`);
|
|
41
|
+
}
|
|
42
|
+
for (const key of required) {
|
|
43
|
+
if (!(key in value)) throw new TypeError(`${label} is missing ${key}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function expectString(value, label, maxLength) {
|
|
47
|
+
if (typeof value !== "string" || value.length === 0 || value.length > maxLength) {
|
|
48
|
+
throw new TypeError(`${label} must be a non-empty string of at most ${maxLength} characters`);
|
|
49
|
+
}
|
|
50
|
+
if (value.includes("\0")) throw new TypeError(`${label} cannot contain NUL`);
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
function expectBoolean(value, label) {
|
|
54
|
+
if (typeof value !== "boolean") throw new TypeError(`${label} must be boolean`);
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
function expectArray(value, label, options = {}) {
|
|
58
|
+
if (!Array.isArray(value) || value.length > MAX_ARRAY_ITEMS) {
|
|
59
|
+
throw new TypeError(`${label} must be an array of at most ${MAX_ARRAY_ITEMS} items`);
|
|
60
|
+
}
|
|
61
|
+
if (options.nonEmpty && value.length === 0) throw new TypeError(`${label} cannot be empty`);
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
function expectStringArray(value, label, maxLength = MAX_IDENTIFIER_LENGTH, options = {}) {
|
|
65
|
+
return expectArray(value, label, options).map(
|
|
66
|
+
(item, index) => expectString(item, `${label}[${index}]`, maxLength)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
function expectIntegerArray(value, label) {
|
|
70
|
+
return expectArray(value, label, { nonEmpty: true }).map((item, index) => {
|
|
71
|
+
if (typeof item !== "number" || !Number.isSafeInteger(item) || item < 0 || item > 32) {
|
|
72
|
+
throw new TypeError(`${label}[${index}] must be an integer between 0 and 32`);
|
|
73
|
+
}
|
|
74
|
+
return item;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function validateSafePattern(value, label) {
|
|
78
|
+
const pattern = expectString(value, label, MAX_PATTERN_LENGTH);
|
|
79
|
+
try {
|
|
80
|
+
RE2JS.compile(pattern);
|
|
81
|
+
} catch {
|
|
82
|
+
throw new TypeError(`${label} is not a valid linear-time regular expression`);
|
|
83
|
+
}
|
|
84
|
+
return pattern;
|
|
85
|
+
}
|
|
86
|
+
function expectIdentifier(value, label, pattern = JAVASCRIPT_IDENTIFIER_PATTERN) {
|
|
87
|
+
const identifier = expectString(value, label, MAX_IDENTIFIER_LENGTH);
|
|
88
|
+
if (!pattern.test(identifier)) throw new TypeError(`${label} must be a safe identifier`);
|
|
89
|
+
return identifier;
|
|
90
|
+
}
|
|
91
|
+
function validateImportBindings(value, label) {
|
|
92
|
+
for (const [index, item] of expectArray(value, label, { nonEmpty: true }).entries()) {
|
|
93
|
+
const binding = expectRecord(item, `${label}[${index}]`);
|
|
94
|
+
expectOnlyKeys(binding, `${label}[${index}]`, ["source", "imported"], ["source", "imported"]);
|
|
95
|
+
expectString(binding.source, `${label}[${index}].source`, MAX_MODULE_LENGTH);
|
|
96
|
+
expectStringArray(binding.imported, `${label}[${index}].imported`, MAX_IDENTIFIER_LENGTH, {
|
|
97
|
+
nonEmpty: true
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function validateImportSources(value, label) {
|
|
102
|
+
for (const [index, item] of expectArray(value, label, { nonEmpty: true }).entries()) {
|
|
103
|
+
const source = expectRecord(item, `${label}[${index}]`);
|
|
104
|
+
expectOnlyKeys(source, `${label}[${index}]`, ["value", "match"], ["value", "match"]);
|
|
105
|
+
expectString(source.value, `${label}[${index}].value`, MAX_MODULE_LENGTH);
|
|
106
|
+
if (source.match !== "exact" && source.match !== "prefix") {
|
|
107
|
+
throw new TypeError(`${label}[${index}].match must be exact or prefix`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function validatePrimitive(value, label) {
|
|
112
|
+
const primitive = expectRecord(value, label);
|
|
113
|
+
if (!PRIMITIVE_KINDS.has(primitive.kind)) {
|
|
114
|
+
throw new TypeError(`${label}.kind is unsupported`);
|
|
115
|
+
}
|
|
116
|
+
switch (primitive.kind) {
|
|
117
|
+
case "required-result-check":
|
|
118
|
+
expectOnlyKeys(
|
|
119
|
+
primitive,
|
|
120
|
+
label,
|
|
121
|
+
["kind", "factories", "guardProperty", "valueProperty"],
|
|
122
|
+
["kind", "factories", "guardProperty", "valueProperty"]
|
|
123
|
+
);
|
|
124
|
+
validateImportBindings(primitive.factories, `${label}.factories`);
|
|
125
|
+
expectString(primitive.guardProperty, `${label}.guardProperty`, MAX_IDENTIFIER_LENGTH);
|
|
126
|
+
expectString(primitive.valueProperty, `${label}.valueProperty`, MAX_IDENTIFIER_LENGTH);
|
|
127
|
+
break;
|
|
128
|
+
case "required-wrapper-call": {
|
|
129
|
+
expectOnlyKeys(
|
|
130
|
+
primitive,
|
|
131
|
+
label,
|
|
132
|
+
["kind", "context", "activationImports", "subjectNamePattern", "wrapper", "operators"],
|
|
133
|
+
["kind", "context", "activationImports", "subjectNamePattern", "wrapper"]
|
|
134
|
+
);
|
|
135
|
+
if (primitive.context !== "jsx-child" && primitive.context !== "numeric-operation") {
|
|
136
|
+
throw new TypeError(`${label}.context is unsupported`);
|
|
137
|
+
}
|
|
138
|
+
validateImportSources(primitive.activationImports, `${label}.activationImports`);
|
|
139
|
+
validateSafePattern(primitive.subjectNamePattern, `${label}.subjectNamePattern`);
|
|
140
|
+
const wrapper = expectRecord(primitive.wrapper, `${label}.wrapper`);
|
|
141
|
+
if (wrapper.syntax === "jsx") {
|
|
142
|
+
expectOnlyKeys(
|
|
143
|
+
wrapper,
|
|
144
|
+
`${label}.wrapper`,
|
|
145
|
+
["syntax", "source", "imported", "prop"],
|
|
146
|
+
["syntax", "source", "imported", "prop"]
|
|
147
|
+
);
|
|
148
|
+
if (primitive.context !== "jsx-child") {
|
|
149
|
+
throw new TypeError(`${label} uses a JSX wrapper outside JSX context`);
|
|
150
|
+
}
|
|
151
|
+
expectString(wrapper.source, `${label}.wrapper.source`, MAX_MODULE_LENGTH);
|
|
152
|
+
expectIdentifier(
|
|
153
|
+
wrapper.imported,
|
|
154
|
+
`${label}.wrapper.imported`,
|
|
155
|
+
JSX_COMPONENT_IDENTIFIER_PATTERN
|
|
156
|
+
);
|
|
157
|
+
expectIdentifier(wrapper.prop, `${label}.wrapper.prop`);
|
|
158
|
+
} else if (wrapper.syntax === "call") {
|
|
159
|
+
expectOnlyKeys(wrapper, `${label}.wrapper`, ["syntax", "imports"], ["syntax", "imports"]);
|
|
160
|
+
if (primitive.context !== "numeric-operation") {
|
|
161
|
+
throw new TypeError(`${label} uses a call wrapper outside numeric context`);
|
|
162
|
+
}
|
|
163
|
+
validateImportBindings(wrapper.imports, `${label}.wrapper.imports`);
|
|
164
|
+
} else {
|
|
165
|
+
throw new TypeError(`${label}.wrapper.syntax is unsupported`);
|
|
166
|
+
}
|
|
167
|
+
if (primitive.operators !== void 0) {
|
|
168
|
+
const operators = expectStringArray(primitive.operators, `${label}.operators`, 4, {
|
|
169
|
+
nonEmpty: true
|
|
170
|
+
});
|
|
171
|
+
if (operators.some((operator) => !NUMERIC_OPERATORS.has(operator))) {
|
|
172
|
+
throw new TypeError(`${label}.operators contains an unsupported operator`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case "banned-import":
|
|
178
|
+
expectOnlyKeys(primitive, label, ["kind", "sources"], ["kind", "sources"]);
|
|
179
|
+
validateImportSources(primitive.sources, `${label}.sources`);
|
|
180
|
+
break;
|
|
181
|
+
case "banned-call-argument":
|
|
182
|
+
expectOnlyKeys(
|
|
183
|
+
primitive,
|
|
184
|
+
label,
|
|
185
|
+
[
|
|
186
|
+
"kind",
|
|
187
|
+
"callees",
|
|
188
|
+
"globalCalleesOnly",
|
|
189
|
+
"argumentIndexes",
|
|
190
|
+
"objectPaths",
|
|
191
|
+
"caseInsensitive"
|
|
192
|
+
],
|
|
193
|
+
["kind", "callees", "argumentIndexes", "objectPaths"]
|
|
194
|
+
);
|
|
195
|
+
expectStringArray(primitive.callees, `${label}.callees`, MAX_IDENTIFIER_LENGTH, {
|
|
196
|
+
nonEmpty: true
|
|
197
|
+
});
|
|
198
|
+
if (primitive.globalCalleesOnly !== void 0) {
|
|
199
|
+
expectBoolean(primitive.globalCalleesOnly, `${label}.globalCalleesOnly`);
|
|
200
|
+
}
|
|
201
|
+
expectIntegerArray(primitive.argumentIndexes, `${label}.argumentIndexes`);
|
|
202
|
+
for (const [index, item] of expectArray(primitive.objectPaths, `${label}.objectPaths`, {
|
|
203
|
+
nonEmpty: true
|
|
204
|
+
}).entries()) {
|
|
205
|
+
const segments = expectStringArray(
|
|
206
|
+
item,
|
|
207
|
+
`${label}.objectPaths[${index}]`,
|
|
208
|
+
MAX_IDENTIFIER_LENGTH,
|
|
209
|
+
{ nonEmpty: true }
|
|
210
|
+
);
|
|
211
|
+
if (segments.length > MAX_PATH_SEGMENTS) {
|
|
212
|
+
throw new TypeError(
|
|
213
|
+
`${label}.objectPaths[${index}] exceeds ${MAX_PATH_SEGMENTS} segments`
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (primitive.caseInsensitive !== void 0) {
|
|
218
|
+
expectBoolean(primitive.caseInsensitive, `${label}.caseInsensitive`);
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
221
|
+
case "banned-jsx-element":
|
|
222
|
+
expectOnlyKeys(primitive, label, ["kind", "elements"], ["kind", "elements"]);
|
|
223
|
+
expectStringArray(primitive.elements, `${label}.elements`, MAX_IDENTIFIER_LENGTH, {
|
|
224
|
+
nonEmpty: true
|
|
225
|
+
});
|
|
226
|
+
break;
|
|
227
|
+
case "banned-classname-pattern":
|
|
228
|
+
expectOnlyKeys(primitive, label, ["kind", "patterns", "replacements"], ["kind", "patterns"]);
|
|
229
|
+
for (const [index, pattern] of expectArray(primitive.patterns, `${label}.patterns`, {
|
|
230
|
+
nonEmpty: true
|
|
231
|
+
}).entries()) {
|
|
232
|
+
validateSafePattern(pattern, `${label}.patterns[${index}]`);
|
|
233
|
+
}
|
|
234
|
+
if (primitive.replacements !== void 0) {
|
|
235
|
+
for (const [index, item] of expectArray(
|
|
236
|
+
primitive.replacements,
|
|
237
|
+
`${label}.replacements`
|
|
238
|
+
).entries()) {
|
|
239
|
+
const replacement = expectRecord(item, `${label}.replacements[${index}]`);
|
|
240
|
+
expectOnlyKeys(
|
|
241
|
+
replacement,
|
|
242
|
+
`${label}.replacements[${index}]`,
|
|
243
|
+
["from", "to"],
|
|
244
|
+
["from", "to"]
|
|
245
|
+
);
|
|
246
|
+
expectString(replacement.from, `${label}.replacements[${index}].from`, 256);
|
|
247
|
+
expectString(replacement.to, `${label}.replacements[${index}].to`, 256);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
break;
|
|
251
|
+
default:
|
|
252
|
+
throw new TypeError(`${label}.kind is unsupported`);
|
|
253
|
+
}
|
|
254
|
+
return primitive;
|
|
255
|
+
}
|
|
256
|
+
function validateFix(value, label, primitive) {
|
|
257
|
+
const fix = expectRecord(value, label);
|
|
258
|
+
expectOnlyKeys(fix, label, ["kind"], ["kind"]);
|
|
259
|
+
if (fix.kind === "wrap-jsx-expression") {
|
|
260
|
+
if (primitive.kind !== "required-wrapper-call" || primitive.context !== "jsx-child" || primitive.wrapper.syntax !== "jsx") {
|
|
261
|
+
throw new TypeError(`${label} is incompatible with its primitive`);
|
|
262
|
+
}
|
|
263
|
+
} else if (fix.kind === "replace-classname") {
|
|
264
|
+
if (primitive.kind !== "banned-classname-pattern") {
|
|
265
|
+
throw new TypeError(`${label} is incompatible with its primitive`);
|
|
266
|
+
}
|
|
267
|
+
} else if (fix.kind === "remove-object-property") {
|
|
268
|
+
if (primitive.kind !== "banned-call-argument") {
|
|
269
|
+
throw new TypeError(`${label} is incompatible with its primitive`);
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
throw new TypeError(`${label}.kind is unsupported`);
|
|
273
|
+
}
|
|
274
|
+
return fix;
|
|
275
|
+
}
|
|
276
|
+
function validatedRule(value, label) {
|
|
277
|
+
const rule = expectRecord(value, label);
|
|
278
|
+
expectOnlyKeys(
|
|
279
|
+
rule,
|
|
280
|
+
label,
|
|
281
|
+
["id", "severity", "message", "help", "primitive", "fix"],
|
|
282
|
+
["id", "severity", "message", "help", "primitive"]
|
|
283
|
+
);
|
|
284
|
+
const id = expectString(rule.id, `${label}.id`, MAX_IDENTIFIER_LENGTH);
|
|
285
|
+
if (!RULE_ID_PATTERN.test(id)) throw new TypeError(`${label}.id is invalid`);
|
|
286
|
+
if (rule.severity !== "error" && rule.severity !== "warning") {
|
|
287
|
+
throw new TypeError(`${label}.severity must be error or warning`);
|
|
288
|
+
}
|
|
289
|
+
expectString(rule.message, `${label}.message`, MAX_MESSAGE_LENGTH);
|
|
290
|
+
expectString(rule.help, `${label}.help`, MAX_HELP_LENGTH);
|
|
291
|
+
const primitive = validatePrimitive(rule.primitive, `${label}.primitive`);
|
|
292
|
+
if (rule.fix !== void 0) validateFix(rule.fix, `${label}.fix`, primitive);
|
|
293
|
+
return rule;
|
|
294
|
+
}
|
|
295
|
+
function deepFreeze(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
296
|
+
if (value === null || typeof value !== "object" || seen.has(value)) return value;
|
|
297
|
+
seen.add(value);
|
|
298
|
+
for (const nested of Object.values(value)) deepFreeze(nested, seen);
|
|
299
|
+
return Object.freeze(value);
|
|
300
|
+
}
|
|
301
|
+
function validateLintRule(value) {
|
|
302
|
+
return deepFreeze(validatedRule(value, "lint rule"));
|
|
303
|
+
}
|
|
304
|
+
function validateLintRuleSet(value) {
|
|
305
|
+
const candidate = expectRecord(value, "lint rule set");
|
|
306
|
+
expectOnlyKeys(
|
|
307
|
+
candidate,
|
|
308
|
+
"lint rule set",
|
|
309
|
+
["schemaVersion", "name", "rules"],
|
|
310
|
+
["schemaVersion", "name", "rules"]
|
|
311
|
+
);
|
|
312
|
+
if (candidate.schemaVersion !== LINT_RULE_SET_SCHEMA_VERSION) {
|
|
313
|
+
throw new TypeError(
|
|
314
|
+
`unsupported lint rule schema ${String(candidate.schemaVersion)}; expected ${LINT_RULE_SET_SCHEMA_VERSION}`
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
const name = expectString(candidate.name, "lint rule set.name", MAX_NAME_LENGTH);
|
|
318
|
+
if (!name.trim()) throw new TypeError("lint rule set.name cannot be blank");
|
|
319
|
+
if (!Array.isArray(candidate.rules) || candidate.rules.length > MAX_RULES) {
|
|
320
|
+
throw new TypeError(`lint rule set.rules must contain at most ${MAX_RULES} rules`);
|
|
321
|
+
}
|
|
322
|
+
const ids = /* @__PURE__ */ new Set();
|
|
323
|
+
let regexPatterns = 0;
|
|
324
|
+
let ruleTerms = 0;
|
|
325
|
+
for (const [index, value2] of candidate.rules.entries()) {
|
|
326
|
+
const rule = validatedRule(value2, `rules[${index}]`);
|
|
327
|
+
if (ids.has(rule.id)) throw new TypeError(`lint rule set contains duplicate id ${rule.id}`);
|
|
328
|
+
ids.add(rule.id);
|
|
329
|
+
const primitive = rule.primitive;
|
|
330
|
+
switch (primitive.kind) {
|
|
331
|
+
case "required-result-check":
|
|
332
|
+
ruleTerms += primitive.factories.length;
|
|
333
|
+
ruleTerms += primitive.factories.reduce((sum, factory) => sum + factory.imported.length, 0);
|
|
334
|
+
break;
|
|
335
|
+
case "required-wrapper-call":
|
|
336
|
+
regexPatterns += 1;
|
|
337
|
+
ruleTerms += primitive.activationImports.length;
|
|
338
|
+
if (primitive.wrapper.syntax === "call") {
|
|
339
|
+
ruleTerms += primitive.wrapper.imports.length;
|
|
340
|
+
ruleTerms += primitive.wrapper.imports.reduce(
|
|
341
|
+
(sum, pattern) => sum + pattern.imported.length,
|
|
342
|
+
0
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
ruleTerms += primitive.operators?.length ?? 0;
|
|
346
|
+
break;
|
|
347
|
+
case "banned-import":
|
|
348
|
+
ruleTerms += primitive.sources.length;
|
|
349
|
+
break;
|
|
350
|
+
case "banned-call-argument":
|
|
351
|
+
ruleTerms += primitive.callees.length + primitive.argumentIndexes.length;
|
|
352
|
+
ruleTerms += primitive.objectPaths.reduce((sum, objectPath) => sum + objectPath.length, 0);
|
|
353
|
+
break;
|
|
354
|
+
case "banned-jsx-element":
|
|
355
|
+
ruleTerms += primitive.elements.length;
|
|
356
|
+
break;
|
|
357
|
+
case "banned-classname-pattern":
|
|
358
|
+
regexPatterns += primitive.patterns.length;
|
|
359
|
+
ruleTerms += (primitive.replacements?.length ?? 0) * 2;
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (regexPatterns > MAX_TOTAL_REGEX_PATTERNS) {
|
|
364
|
+
throw new TypeError(
|
|
365
|
+
`lint rule set exceeds ${MAX_TOTAL_REGEX_PATTERNS} total regular expressions`
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
if (ruleTerms > MAX_TOTAL_RULE_TERMS) {
|
|
369
|
+
throw new TypeError(`lint rule set exceeds ${MAX_TOTAL_RULE_TERMS} total match terms`);
|
|
370
|
+
}
|
|
371
|
+
let serialized;
|
|
372
|
+
try {
|
|
373
|
+
serialized = JSON.stringify(candidate);
|
|
374
|
+
} catch {
|
|
375
|
+
throw new TypeError("lint rule set must be JSON-serializable data");
|
|
376
|
+
}
|
|
377
|
+
if (new TextEncoder().encode(serialized).byteLength > MAX_LINT_RULE_MANIFEST_BYTES) {
|
|
378
|
+
throw new TypeError(`lint rule set exceeds ${MAX_LINT_RULE_MANIFEST_BYTES} UTF-8 bytes`);
|
|
379
|
+
}
|
|
380
|
+
return deepFreeze(candidate);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// src/lint/define.ts
|
|
384
|
+
function defineLintRule(rule) {
|
|
385
|
+
return validateLintRule(rule);
|
|
386
|
+
}
|
|
387
|
+
function defineLintRuleSet(options) {
|
|
388
|
+
return validateLintRuleSet({
|
|
389
|
+
schemaVersion: LINT_RULE_SET_SCHEMA_VERSION,
|
|
390
|
+
name: options.name,
|
|
391
|
+
rules: [...options.rules]
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// src/lint/rules.ts
|
|
396
|
+
var MONEY_NAME_PATTERN = "(?:^|_)(?:price|amount|subtotal|total|tax|fee|discount|cost)$";
|
|
397
|
+
var SDK_CLIENT_FACTORIES = [
|
|
398
|
+
{ source: "@cimplify/sdk", imported: ["createCimplifyClient"] },
|
|
399
|
+
{ source: "@cimplify/sdk/server", imported: ["getServerClient"] }
|
|
400
|
+
];
|
|
401
|
+
var SDK_MODULES = [{ value: "@cimplify/sdk", match: "prefix" }];
|
|
402
|
+
var PARSE_PRICE_IMPORTS = [
|
|
403
|
+
{ source: "@cimplify/sdk", imported: ["parsePrice"] },
|
|
404
|
+
{ source: "@cimplify/sdk/utils", imported: ["parsePrice"] }
|
|
405
|
+
];
|
|
406
|
+
var TAILWIND_COLOR_SCALE = "(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950)";
|
|
407
|
+
var COLOR_UTILITY = "(?:accent|bg|border|caret|decoration|divide|fill|from|outline|placeholder|ring|shadow|stroke|text|to|via)";
|
|
408
|
+
var checkResultOkRule = defineLintRule({
|
|
409
|
+
id: "sdk/check-result-ok",
|
|
410
|
+
severity: "error",
|
|
411
|
+
message: "Check `result.ok` before reading `result.value`.",
|
|
412
|
+
help: "Cimplify SDK calls return Result values. Handle the error branch before using the value.",
|
|
413
|
+
primitive: {
|
|
414
|
+
kind: "required-result-check",
|
|
415
|
+
factories: SDK_CLIENT_FACTORIES,
|
|
416
|
+
guardProperty: "ok",
|
|
417
|
+
valueProperty: "value"
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
var renderPriceComponentRule = defineLintRule({
|
|
421
|
+
id: "sdk/render-price-component",
|
|
422
|
+
severity: "error",
|
|
423
|
+
message: "Render money with the SDK `Price` component.",
|
|
424
|
+
help: "`Price` applies the active business currency and locale consistently.",
|
|
425
|
+
primitive: {
|
|
426
|
+
kind: "required-wrapper-call",
|
|
427
|
+
context: "jsx-child",
|
|
428
|
+
activationImports: SDK_MODULES,
|
|
429
|
+
subjectNamePattern: MONEY_NAME_PATTERN,
|
|
430
|
+
wrapper: {
|
|
431
|
+
syntax: "jsx",
|
|
432
|
+
source: "@cimplify/sdk/react",
|
|
433
|
+
imported: "Price",
|
|
434
|
+
prop: "amount"
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
fix: { kind: "wrap-jsx-expression" }
|
|
438
|
+
});
|
|
439
|
+
var parsePriceBeforeMathRule = defineLintRule({
|
|
440
|
+
id: "sdk/parse-price-before-math",
|
|
441
|
+
severity: "error",
|
|
442
|
+
message: "Call `parsePrice` before using a money value in numeric operations.",
|
|
443
|
+
help: "Money arrives over the wire as a decimal string; implicit coercion can produce incorrect comparisons and totals.",
|
|
444
|
+
primitive: {
|
|
445
|
+
kind: "required-wrapper-call",
|
|
446
|
+
context: "numeric-operation",
|
|
447
|
+
activationImports: SDK_MODULES,
|
|
448
|
+
subjectNamePattern: MONEY_NAME_PATTERN,
|
|
449
|
+
wrapper: { syntax: "call", imports: PARSE_PRICE_IMPORTS },
|
|
450
|
+
operators: ["+", "-", "*", "/", "%", "**", "<", "<=", ">", ">="]
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
var noReactQueryRule = defineLintRule({
|
|
454
|
+
id: "sdk/no-react-query",
|
|
455
|
+
severity: "error",
|
|
456
|
+
message: "Use Cimplify SDK hooks instead of React Query.",
|
|
457
|
+
help: "Use the SDK hooks and their provider-owned cache so cart, catalogue, and account state stay coherent.",
|
|
458
|
+
primitive: {
|
|
459
|
+
kind: "banned-import",
|
|
460
|
+
sources: [
|
|
461
|
+
{ value: "react-query", match: "exact" },
|
|
462
|
+
{ value: "@tanstack/react-query", match: "prefix" }
|
|
463
|
+
]
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
var noCookieInCacheKeyRule = defineLintRule({
|
|
467
|
+
id: "sdk/no-cookie-in-cache-key",
|
|
468
|
+
severity: "error",
|
|
469
|
+
message: "Remove the Cookie header from this cacheable request.",
|
|
470
|
+
help: "Cookie-bearing requests bypass the shared cache by design. Keep personalized cart/account reads in a client island.",
|
|
471
|
+
primitive: {
|
|
472
|
+
kind: "banned-call-argument",
|
|
473
|
+
callees: ["fetch", "Request"],
|
|
474
|
+
globalCalleesOnly: true,
|
|
475
|
+
argumentIndexes: [1],
|
|
476
|
+
objectPaths: [["headers", "cookie"]],
|
|
477
|
+
caseInsensitive: true
|
|
478
|
+
},
|
|
479
|
+
fix: { kind: "remove-object-property" }
|
|
480
|
+
});
|
|
481
|
+
var noRawImgRule = defineLintRule({
|
|
482
|
+
id: "ui/no-raw-img",
|
|
483
|
+
severity: "warning",
|
|
484
|
+
message: "Use `next/image` instead of a raw `<img>` element.",
|
|
485
|
+
help: "The storefront image loader supplies responsive sizes, modern formats, and intrinsic dimensions.",
|
|
486
|
+
primitive: { kind: "banned-jsx-element", elements: ["img"] }
|
|
487
|
+
});
|
|
488
|
+
var themeTokensOnlyRule = defineLintRule({
|
|
489
|
+
id: "ui/theme-tokens-only",
|
|
490
|
+
severity: "warning",
|
|
491
|
+
message: "Use storefront theme tokens instead of hard-coded color utilities.",
|
|
492
|
+
help: "Define palette changes in `app/globals.css` and consume semantic utilities such as `bg-background` and `text-foreground`.",
|
|
493
|
+
primitive: {
|
|
494
|
+
kind: "banned-classname-pattern",
|
|
495
|
+
patterns: [
|
|
496
|
+
`^${COLOR_UTILITY}-${TAILWIND_COLOR_SCALE}$`,
|
|
497
|
+
`^${COLOR_UTILITY}-(?:black|white)$`,
|
|
498
|
+
`^${COLOR_UTILITY}-\\[(?:#|rgba?\\(|hsla?\\(|oklch\\(|oklab\\(|lab\\(|lch\\(|color:)`
|
|
499
|
+
],
|
|
500
|
+
replacements: [
|
|
501
|
+
{ from: "bg-white", to: "bg-background" },
|
|
502
|
+
{ from: "bg-black", to: "bg-foreground" },
|
|
503
|
+
{ from: "text-black", to: "text-foreground" },
|
|
504
|
+
{ from: "border-black", to: "border-foreground" },
|
|
505
|
+
{ from: "border-white", to: "border-background" }
|
|
506
|
+
]
|
|
507
|
+
},
|
|
508
|
+
fix: { kind: "replace-classname" }
|
|
509
|
+
});
|
|
510
|
+
var starterLintRuleSet = defineLintRuleSet({
|
|
511
|
+
name: "@cimplify/sdk/starter",
|
|
512
|
+
rules: [
|
|
513
|
+
checkResultOkRule,
|
|
514
|
+
renderPriceComponentRule,
|
|
515
|
+
parsePriceBeforeMathRule,
|
|
516
|
+
noReactQueryRule,
|
|
517
|
+
noCookieInCacheKeyRule,
|
|
518
|
+
noRawImgRule,
|
|
519
|
+
themeTokensOnlyRule
|
|
520
|
+
]
|
|
521
|
+
});
|
|
522
|
+
var starterLintRules = starterLintRuleSet.rules;
|
|
523
|
+
|
|
524
|
+
export { LINT_RULE_SET_SCHEMA_VERSION, MAX_LINT_RULE_MANIFEST_BYTES, checkResultOkRule, defineLintRule, defineLintRuleSet, noCookieInCacheKeyRule, noRawImgRule, noReactQueryRule, parsePriceBeforeMathRule, renderPriceComponentRule, starterLintRuleSet, starterLintRules, themeTokensOnlyRule, validateLintRule, validateLintRuleSet };
|
package/dist/mock/cli.mjs
CHANGED
|
@@ -6654,6 +6654,13 @@ function createLiteService(opts) {
|
|
|
6654
6654
|
}
|
|
6655
6655
|
|
|
6656
6656
|
// src/mock/domain/link.ts
|
|
6657
|
+
var LOCATION_FIELDS = [
|
|
6658
|
+
"street_address",
|
|
6659
|
+
"city",
|
|
6660
|
+
"region",
|
|
6661
|
+
"postal_code",
|
|
6662
|
+
"country"
|
|
6663
|
+
];
|
|
6657
6664
|
var NOT_ENROLLED_ERROR = () => {
|
|
6658
6665
|
throw {
|
|
6659
6666
|
code: "NOT_ENROLLED",
|
|
@@ -6830,7 +6837,30 @@ function createLinkService({ clock, ids }) {
|
|
|
6830
6837
|
},
|
|
6831
6838
|
updateAddress(customerId, id, patch) {
|
|
6832
6839
|
const a = this.getAddressById(customerId, id);
|
|
6833
|
-
|
|
6840
|
+
const {
|
|
6841
|
+
clear_coordinates: clearCoordinates = false,
|
|
6842
|
+
latitude,
|
|
6843
|
+
longitude,
|
|
6844
|
+
...changes
|
|
6845
|
+
} = patch;
|
|
6846
|
+
const hasLatitude = latitude !== void 0;
|
|
6847
|
+
const hasLongitude = longitude !== void 0;
|
|
6848
|
+
if (hasLatitude !== hasLongitude) {
|
|
6849
|
+
throw new Error("latitude and longitude must be supplied together");
|
|
6850
|
+
}
|
|
6851
|
+
if (clearCoordinates && hasLatitude) {
|
|
6852
|
+
throw new Error("clear_coordinates cannot be combined with coordinates");
|
|
6853
|
+
}
|
|
6854
|
+
const locationChanged = LOCATION_FIELDS.some((field) => field in changes);
|
|
6855
|
+
Object.assign(a, changes);
|
|
6856
|
+
if (hasLatitude && hasLongitude) {
|
|
6857
|
+
a.latitude = latitude ?? null;
|
|
6858
|
+
a.longitude = longitude ?? null;
|
|
6859
|
+
} else if (clearCoordinates || locationChanged) {
|
|
6860
|
+
a.latitude = null;
|
|
6861
|
+
a.longitude = null;
|
|
6862
|
+
}
|
|
6863
|
+
a.updated_at = clock.iso();
|
|
6834
6864
|
return a;
|
|
6835
6865
|
},
|
|
6836
6866
|
deleteAddress(customerId, id) {
|
package/dist/mock/library.js
CHANGED
|
@@ -5716,6 +5716,13 @@ function createLiteService(opts) {
|
|
|
5716
5716
|
}
|
|
5717
5717
|
|
|
5718
5718
|
// src/mock/domain/link.ts
|
|
5719
|
+
var LOCATION_FIELDS = [
|
|
5720
|
+
"street_address",
|
|
5721
|
+
"city",
|
|
5722
|
+
"region",
|
|
5723
|
+
"postal_code",
|
|
5724
|
+
"country"
|
|
5725
|
+
];
|
|
5719
5726
|
var NOT_ENROLLED_ERROR = () => {
|
|
5720
5727
|
throw {
|
|
5721
5728
|
code: "NOT_ENROLLED",
|
|
@@ -5892,7 +5899,30 @@ function createLinkService({ clock, ids }) {
|
|
|
5892
5899
|
},
|
|
5893
5900
|
updateAddress(customerId, id, patch) {
|
|
5894
5901
|
const a = this.getAddressById(customerId, id);
|
|
5895
|
-
|
|
5902
|
+
const {
|
|
5903
|
+
clear_coordinates: clearCoordinates = false,
|
|
5904
|
+
latitude,
|
|
5905
|
+
longitude,
|
|
5906
|
+
...changes
|
|
5907
|
+
} = patch;
|
|
5908
|
+
const hasLatitude = latitude !== void 0;
|
|
5909
|
+
const hasLongitude = longitude !== void 0;
|
|
5910
|
+
if (hasLatitude !== hasLongitude) {
|
|
5911
|
+
throw new Error("latitude and longitude must be supplied together");
|
|
5912
|
+
}
|
|
5913
|
+
if (clearCoordinates && hasLatitude) {
|
|
5914
|
+
throw new Error("clear_coordinates cannot be combined with coordinates");
|
|
5915
|
+
}
|
|
5916
|
+
const locationChanged = LOCATION_FIELDS.some((field) => field in changes);
|
|
5917
|
+
Object.assign(a, changes);
|
|
5918
|
+
if (hasLatitude && hasLongitude) {
|
|
5919
|
+
a.latitude = latitude ?? null;
|
|
5920
|
+
a.longitude = longitude ?? null;
|
|
5921
|
+
} else if (clearCoordinates || locationChanged) {
|
|
5922
|
+
a.latitude = null;
|
|
5923
|
+
a.longitude = null;
|
|
5924
|
+
}
|
|
5925
|
+
a.updated_at = clock.iso();
|
|
5896
5926
|
return a;
|
|
5897
5927
|
},
|
|
5898
5928
|
deleteAddress(customerId, id) {
|
package/dist/mock/library.mjs
CHANGED
|
@@ -5714,6 +5714,13 @@ function createLiteService(opts) {
|
|
|
5714
5714
|
}
|
|
5715
5715
|
|
|
5716
5716
|
// src/mock/domain/link.ts
|
|
5717
|
+
var LOCATION_FIELDS = [
|
|
5718
|
+
"street_address",
|
|
5719
|
+
"city",
|
|
5720
|
+
"region",
|
|
5721
|
+
"postal_code",
|
|
5722
|
+
"country"
|
|
5723
|
+
];
|
|
5717
5724
|
var NOT_ENROLLED_ERROR = () => {
|
|
5718
5725
|
throw {
|
|
5719
5726
|
code: "NOT_ENROLLED",
|
|
@@ -5890,7 +5897,30 @@ function createLinkService({ clock, ids }) {
|
|
|
5890
5897
|
},
|
|
5891
5898
|
updateAddress(customerId, id, patch) {
|
|
5892
5899
|
const a = this.getAddressById(customerId, id);
|
|
5893
|
-
|
|
5900
|
+
const {
|
|
5901
|
+
clear_coordinates: clearCoordinates = false,
|
|
5902
|
+
latitude,
|
|
5903
|
+
longitude,
|
|
5904
|
+
...changes
|
|
5905
|
+
} = patch;
|
|
5906
|
+
const hasLatitude = latitude !== void 0;
|
|
5907
|
+
const hasLongitude = longitude !== void 0;
|
|
5908
|
+
if (hasLatitude !== hasLongitude) {
|
|
5909
|
+
throw new Error("latitude and longitude must be supplied together");
|
|
5910
|
+
}
|
|
5911
|
+
if (clearCoordinates && hasLatitude) {
|
|
5912
|
+
throw new Error("clear_coordinates cannot be combined with coordinates");
|
|
5913
|
+
}
|
|
5914
|
+
const locationChanged = LOCATION_FIELDS.some((field) => field in changes);
|
|
5915
|
+
Object.assign(a, changes);
|
|
5916
|
+
if (hasLatitude && hasLongitude) {
|
|
5917
|
+
a.latitude = latitude ?? null;
|
|
5918
|
+
a.longitude = longitude ?? null;
|
|
5919
|
+
} else if (clearCoordinates || locationChanged) {
|
|
5920
|
+
a.latitude = null;
|
|
5921
|
+
a.longitude = null;
|
|
5922
|
+
}
|
|
5923
|
+
a.updated_at = clock.iso();
|
|
5894
5924
|
return a;
|
|
5895
5925
|
},
|
|
5896
5926
|
deleteAddress(customerId, id) {
|