@patterkit/core 0.1.4 → 0.2.0

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 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: () => import_model3.effectiveGameId,
35
- gameIdify: () => import_model3.gameIdify,
34
+ effectiveGameId: () => import_model4.effectiveGameId,
35
+ gameIdify: () => import_model4.gameIdify,
36
36
  hash32: () => hash32,
37
37
  hash4: () => hash4,
38
- isValidGameId: () => import_model3.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 import_model3 = require("@patterkit/model");
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,6 +452,8 @@ 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",
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,6 +407,8 @@ 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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patterkit/core",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
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.2.0",
37
+ "@patterkit/model": "0.3.0",
38
38
  "json5": "^2.2.3"
39
39
  }
40
40
  }