@patterkit/core 0.1.5 → 0.2.1
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/dist/index.cjs +53 -4
- package/dist/index.js +49 -0
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -31,11 +31,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
canonicalStringify: () => canonicalStringify,
|
|
34
|
-
effectiveGameId: () =>
|
|
35
|
-
gameIdify: () =>
|
|
34
|
+
effectiveGameId: () => import_model4.effectiveGameId,
|
|
35
|
+
gameIdify: () => import_model4.gameIdify,
|
|
36
36
|
hash32: () => hash32,
|
|
37
37
|
hash4: () => hash4,
|
|
38
|
-
isValidGameId: () =>
|
|
38
|
+
isValidGameId: () => import_model4.isValidGameId,
|
|
39
39
|
newId: () => newId,
|
|
40
40
|
parseSource: () => parseSource,
|
|
41
41
|
slug: () => slug,
|
|
@@ -81,7 +81,7 @@ function hash32(input) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// src/index.ts
|
|
84
|
-
var
|
|
84
|
+
var import_model4 = require("@patterkit/model");
|
|
85
85
|
|
|
86
86
|
// src/serialize.ts
|
|
87
87
|
var import_json5 = __toESM(require("json5"), 1);
|
|
@@ -120,6 +120,7 @@ ${indent}}`;
|
|
|
120
120
|
// src/validate.ts
|
|
121
121
|
var import_model = require("@patterkit/model");
|
|
122
122
|
var import_model2 = require("@patterkit/model");
|
|
123
|
+
var import_model3 = require("@patterkit/model");
|
|
123
124
|
function choiceLoopsBack(choice, ...targets) {
|
|
124
125
|
const back = new Set(targets.filter((s) => typeof s === "string" && s.length > 0));
|
|
125
126
|
const hits = (n) => n.type === "snippet" ? !!n.jump && back.has(n.jump.to) : (n.children ?? []).some(hits);
|
|
@@ -307,6 +308,18 @@ function validateProject(input) {
|
|
|
307
308
|
}
|
|
308
309
|
function validateProjectFile(project, issues) {
|
|
309
310
|
checkDecls(project.properties, "project properties", issues);
|
|
311
|
+
for (const scope of project.scopeRegistry?.scopes ?? []) {
|
|
312
|
+
const where = `host scope '@${scope.token}'`;
|
|
313
|
+
for (const decl of scope.declarations ?? []) {
|
|
314
|
+
const name = decl.name?.toLowerCase();
|
|
315
|
+
if (!name) {
|
|
316
|
+
issues.push({ code: "invalid-declaration", message: `${where}: a property declaration has no name` });
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
const problem = propertyNameProblem(decl.name);
|
|
320
|
+
if (problem) issues.push({ code: "invalid-declaration", message: `${where}: ${problem}` });
|
|
321
|
+
}
|
|
322
|
+
}
|
|
310
323
|
for (const decl of project.properties ?? []) {
|
|
311
324
|
if (decl.temporary) {
|
|
312
325
|
issues.push({
|
|
@@ -410,6 +423,23 @@ function checkLadderNames(names, where, issues) {
|
|
|
410
423
|
seen.add(name);
|
|
411
424
|
}
|
|
412
425
|
}
|
|
426
|
+
function propertyNameProblem(raw) {
|
|
427
|
+
if ((0, import_model3.isValidPropertyName)(raw)) return void 0;
|
|
428
|
+
const suggestion = (0, import_model3.propertyNameify)(raw);
|
|
429
|
+
const tail = suggestion ? ` Try '${suggestion}'.` : "";
|
|
430
|
+
const q = `property name '${raw}'`;
|
|
431
|
+
if (import_model3.RESERVED_PROPERTY_NAMES.includes(raw.toLowerCase())) {
|
|
432
|
+
return `${q} is a keyword in expressions ('${raw.toLowerCase()}'), so a reference to it will not parse.${tail}`;
|
|
433
|
+
}
|
|
434
|
+
if (raw.includes("-")) {
|
|
435
|
+
return `${q} contains a hyphen, which an expression reads as subtraction: a reference would compile to a subtraction, not to this property.${tail}`;
|
|
436
|
+
}
|
|
437
|
+
if (/^[0-9]/.test(raw)) return `${q} starts with a digit, which an expression cannot parse as a name.${tail}`;
|
|
438
|
+
if (raw !== raw.toLowerCase() && (0, import_model3.isValidPropertyName)(raw.toLowerCase())) {
|
|
439
|
+
return `${q} must be lower case: expressions fold names, so a reference looks for '${raw.toLowerCase()}' and finds nothing.${tail}`;
|
|
440
|
+
}
|
|
441
|
+
return `${q} can only hold lower case letters, digits and underscores.${tail}`;
|
|
442
|
+
}
|
|
413
443
|
function checkDecls(decls, where, issues) {
|
|
414
444
|
const seen = /* @__PURE__ */ new Set();
|
|
415
445
|
for (const decl of decls ?? []) {
|
|
@@ -422,12 +452,29 @@ function checkDecls(decls, where, issues) {
|
|
|
422
452
|
issues.push({ code: "invalid-declaration", message: `${where}: duplicate property '${decl.name}'` });
|
|
423
453
|
}
|
|
424
454
|
seen.add(name);
|
|
455
|
+
const problem = propertyNameProblem(decl.name);
|
|
456
|
+
if (problem) issues.push({ code: "invalid-declaration", message: `${where}: ${problem}` });
|
|
425
457
|
if ((decl.type === "enum" || decl.type === "flags") && !decl.values?.length) {
|
|
426
458
|
issues.push({
|
|
427
459
|
code: "invalid-declaration",
|
|
428
460
|
message: `${where}: '${decl.name}' is ${decl.type} but declares no values`
|
|
429
461
|
});
|
|
430
462
|
}
|
|
463
|
+
if (decl.type === "quality") {
|
|
464
|
+
const stages = decl.stages ?? [];
|
|
465
|
+
if (stages.length < 2) {
|
|
466
|
+
issues.push({
|
|
467
|
+
code: "invalid-declaration",
|
|
468
|
+
message: `${where}: '${decl.name}' is a quality but declares ${stages.length === 0 ? "no stages" : "only one stage"} (a ladder needs at least two)`
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
const seenStages = /* @__PURE__ */ new Set();
|
|
472
|
+
for (const s of stages) {
|
|
473
|
+
if (!s.trim()) issues.push({ code: "invalid-declaration", message: `${where}: '${decl.name}' has an empty stage name` });
|
|
474
|
+
else if (seenStages.has(s)) issues.push({ code: "invalid-declaration", message: `${where}: '${decl.name}' declares stage '${s}' more than once` });
|
|
475
|
+
else seenStages.add(s);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
431
478
|
if (decl.default !== void 0 && !defaultMatchesType(decl.default, decl)) {
|
|
432
479
|
issues.push({
|
|
433
480
|
code: "invalid-declaration",
|
|
@@ -448,6 +495,8 @@ function defaultMatchesType(value, decl) {
|
|
|
448
495
|
return typeof value === "string" && (decl.values?.includes(value) ?? true);
|
|
449
496
|
case "flags":
|
|
450
497
|
return Array.isArray(value) && value.every((v) => typeof v === "string" && (decl.values?.includes(v) ?? true));
|
|
498
|
+
case "quality":
|
|
499
|
+
return typeof value === "string" && (decl.stages?.includes(value) ?? true);
|
|
451
500
|
}
|
|
452
501
|
}
|
|
453
502
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.js
CHANGED
|
@@ -75,6 +75,7 @@ ${indent}}`;
|
|
|
75
75
|
// src/validate.ts
|
|
76
76
|
import { walkNodes, DEFAULT_WRITING_STATUSES, DEFAULT_RECORDING_STATUSES, DEFAULT_DOCUMENTATION_CLASSES } from "@patterkit/model";
|
|
77
77
|
import { isValidGameId, effectiveGameId } from "@patterkit/model";
|
|
78
|
+
import { isValidPropertyName, propertyNameify, RESERVED_PROPERTY_NAMES } from "@patterkit/model";
|
|
78
79
|
function choiceLoopsBack(choice, ...targets) {
|
|
79
80
|
const back = new Set(targets.filter((s) => typeof s === "string" && s.length > 0));
|
|
80
81
|
const hits = (n) => n.type === "snippet" ? !!n.jump && back.has(n.jump.to) : (n.children ?? []).some(hits);
|
|
@@ -262,6 +263,18 @@ function validateProject(input) {
|
|
|
262
263
|
}
|
|
263
264
|
function validateProjectFile(project, issues) {
|
|
264
265
|
checkDecls(project.properties, "project properties", issues);
|
|
266
|
+
for (const scope of project.scopeRegistry?.scopes ?? []) {
|
|
267
|
+
const where = `host scope '@${scope.token}'`;
|
|
268
|
+
for (const decl of scope.declarations ?? []) {
|
|
269
|
+
const name = decl.name?.toLowerCase();
|
|
270
|
+
if (!name) {
|
|
271
|
+
issues.push({ code: "invalid-declaration", message: `${where}: a property declaration has no name` });
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
const problem = propertyNameProblem(decl.name);
|
|
275
|
+
if (problem) issues.push({ code: "invalid-declaration", message: `${where}: ${problem}` });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
265
278
|
for (const decl of project.properties ?? []) {
|
|
266
279
|
if (decl.temporary) {
|
|
267
280
|
issues.push({
|
|
@@ -365,6 +378,23 @@ function checkLadderNames(names, where, issues) {
|
|
|
365
378
|
seen.add(name);
|
|
366
379
|
}
|
|
367
380
|
}
|
|
381
|
+
function propertyNameProblem(raw) {
|
|
382
|
+
if (isValidPropertyName(raw)) return void 0;
|
|
383
|
+
const suggestion = propertyNameify(raw);
|
|
384
|
+
const tail = suggestion ? ` Try '${suggestion}'.` : "";
|
|
385
|
+
const q = `property name '${raw}'`;
|
|
386
|
+
if (RESERVED_PROPERTY_NAMES.includes(raw.toLowerCase())) {
|
|
387
|
+
return `${q} is a keyword in expressions ('${raw.toLowerCase()}'), so a reference to it will not parse.${tail}`;
|
|
388
|
+
}
|
|
389
|
+
if (raw.includes("-")) {
|
|
390
|
+
return `${q} contains a hyphen, which an expression reads as subtraction: a reference would compile to a subtraction, not to this property.${tail}`;
|
|
391
|
+
}
|
|
392
|
+
if (/^[0-9]/.test(raw)) return `${q} starts with a digit, which an expression cannot parse as a name.${tail}`;
|
|
393
|
+
if (raw !== raw.toLowerCase() && isValidPropertyName(raw.toLowerCase())) {
|
|
394
|
+
return `${q} must be lower case: expressions fold names, so a reference looks for '${raw.toLowerCase()}' and finds nothing.${tail}`;
|
|
395
|
+
}
|
|
396
|
+
return `${q} can only hold lower case letters, digits and underscores.${tail}`;
|
|
397
|
+
}
|
|
368
398
|
function checkDecls(decls, where, issues) {
|
|
369
399
|
const seen = /* @__PURE__ */ new Set();
|
|
370
400
|
for (const decl of decls ?? []) {
|
|
@@ -377,12 +407,29 @@ function checkDecls(decls, where, issues) {
|
|
|
377
407
|
issues.push({ code: "invalid-declaration", message: `${where}: duplicate property '${decl.name}'` });
|
|
378
408
|
}
|
|
379
409
|
seen.add(name);
|
|
410
|
+
const problem = propertyNameProblem(decl.name);
|
|
411
|
+
if (problem) issues.push({ code: "invalid-declaration", message: `${where}: ${problem}` });
|
|
380
412
|
if ((decl.type === "enum" || decl.type === "flags") && !decl.values?.length) {
|
|
381
413
|
issues.push({
|
|
382
414
|
code: "invalid-declaration",
|
|
383
415
|
message: `${where}: '${decl.name}' is ${decl.type} but declares no values`
|
|
384
416
|
});
|
|
385
417
|
}
|
|
418
|
+
if (decl.type === "quality") {
|
|
419
|
+
const stages = decl.stages ?? [];
|
|
420
|
+
if (stages.length < 2) {
|
|
421
|
+
issues.push({
|
|
422
|
+
code: "invalid-declaration",
|
|
423
|
+
message: `${where}: '${decl.name}' is a quality but declares ${stages.length === 0 ? "no stages" : "only one stage"} (a ladder needs at least two)`
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
const seenStages = /* @__PURE__ */ new Set();
|
|
427
|
+
for (const s of stages) {
|
|
428
|
+
if (!s.trim()) issues.push({ code: "invalid-declaration", message: `${where}: '${decl.name}' has an empty stage name` });
|
|
429
|
+
else if (seenStages.has(s)) issues.push({ code: "invalid-declaration", message: `${where}: '${decl.name}' declares stage '${s}' more than once` });
|
|
430
|
+
else seenStages.add(s);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
386
433
|
if (decl.default !== void 0 && !defaultMatchesType(decl.default, decl)) {
|
|
387
434
|
issues.push({
|
|
388
435
|
code: "invalid-declaration",
|
|
@@ -403,6 +450,8 @@ function defaultMatchesType(value, decl) {
|
|
|
403
450
|
return typeof value === "string" && (decl.values?.includes(value) ?? true);
|
|
404
451
|
case "flags":
|
|
405
452
|
return Array.isArray(value) && value.every((v) => typeof v === "string" && (decl.values?.includes(v) ?? true));
|
|
453
|
+
case "quality":
|
|
454
|
+
return typeof value === "string" && (decl.stages?.includes(value) ?? true);
|
|
406
455
|
}
|
|
407
456
|
}
|
|
408
457
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patterkit/core",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Patter core: stable id generation, readable-handle computation, canonical (de)serialisation, and the structural validator.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"build": "tsup src/index.ts --format esm,cjs --dts --clean"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@patterkit/model": "0.
|
|
37
|
+
"@patterkit/model": "0.4.0",
|
|
38
38
|
"json5": "^2.2.3"
|
|
39
39
|
}
|
|
40
40
|
}
|