@pagefront/lint-commerce 0.9.0 → 0.11.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.
Files changed (44) hide show
  1. package/README.md +57 -13
  2. package/dist/catalogue.js +5 -3
  3. package/dist/generated/release-manifest.d.ts +22 -0
  4. package/dist/generated/release-manifest.js +27 -0
  5. package/dist/generated/schema-ids.d.ts +1 -0
  6. package/dist/generated/schema-ids.js +7 -0
  7. package/dist/generated/schema-properties.d.ts +1 -0
  8. package/dist/{schema-properties.js → generated/schema-properties.js} +2 -10
  9. package/dist/generated/schemas.d.ts +1 -0
  10. package/dist/generated/schemas.js +4883 -0
  11. package/dist/index.d.ts +10 -4
  12. package/dist/index.js +9 -3
  13. package/dist/organization-catalogue.js +6 -3
  14. package/dist/releases.d.ts +22 -0
  15. package/dist/releases.js +27 -0
  16. package/dist/rules/org-e-002.d.ts +7 -0
  17. package/dist/rules/org-e-002.js +13 -0
  18. package/dist/rules/org-e-003.d.ts +7 -0
  19. package/dist/rules/org-e-003.js +13 -0
  20. package/dist/rules/pdp-e-002.d.ts +3 -9
  21. package/dist/rules/pdp-e-002.js +6 -26
  22. package/dist/rules/pdp-e-016.d.ts +7 -0
  23. package/dist/rules/pdp-e-016.js +13 -0
  24. package/dist/rules/pdp-i-001.js +3 -2
  25. package/dist/rules/release-schema.d.ts +16 -0
  26. package/dist/rules/release-schema.js +77 -0
  27. package/dist/schema-registry.d.ts +29 -0
  28. package/dist/schema-registry.js +35 -0
  29. package/dist/schema-validators.d.ts +7 -6
  30. package/dist/schema-validators.js +15 -3
  31. package/dist/sheet-type.d.ts +17 -0
  32. package/dist/sheet-type.js +25 -0
  33. package/dist/validate-and-lint.d.ts +24 -17
  34. package/dist/validate-and-lint.js +47 -28
  35. package/dist/validate-organization.d.ts +5 -5
  36. package/dist/validate-organization.js +8 -15
  37. package/dist/version.d.ts +1 -1
  38. package/dist/version.js +1 -1
  39. package/package.json +3 -3
  40. package/dist/organization-schema.d.ts +0 -9
  41. package/dist/organization-schema.js +0 -441
  42. package/dist/product-schema.d.ts +0 -9
  43. package/dist/product-schema.js +0 -2014
  44. package/dist/schema-properties.d.ts +0 -10
@@ -15,4 +15,21 @@ import type { Sheet } from "@pagefront/lint-core";
15
15
  * page type the catalogue predates dispatch with.
16
16
  */
17
17
  export type SheetType = "product" | "organization";
18
+ /**
19
+ * The two lines a sheet can belong to. A sheet on the *release* line
20
+ * carries `release` and validates against the current sheet-spec
21
+ * schemas; a sheet on the *legacy* draft line carries `format_version`
22
+ * (≤ 0.9) and validates against the frozen legacy schemas.
23
+ */
24
+ export type SheetLine = "release" | "legacy";
25
+ /**
26
+ * Line detection reads the envelope field first: `release` puts a sheet
27
+ * on the release line (also when `format_version` is present beside it,
28
+ * which the release-line schemas and PDP-E-016 / ORG-E-002 reject), and
29
+ * `format_version` alone puts it on the legacy line. A sheet carrying
30
+ * neither is placed by its `$schema`: a two-part version segment, or
31
+ * the pre-2026-09-08 `/schemas/` path, is legacy; anything else is the
32
+ * release line, whose schema then reports the missing `release`.
33
+ */
34
+ export declare function detectSheetLine(sheet: Sheet): SheetLine;
18
35
  export declare function detectSheetType(sheet: Sheet): SheetType;
@@ -1,3 +1,28 @@
1
+ /** The legacy line's `$schema` version segment: two parts, `v0.9.json`. */
2
+ const LEGACY_SCHEMA_SEGMENT = /\/v\d+\.\d+\.json$/;
3
+ /**
4
+ * Line detection reads the envelope field first: `release` puts a sheet
5
+ * on the release line (also when `format_version` is present beside it,
6
+ * which the release-line schemas and PDP-E-016 / ORG-E-002 reject), and
7
+ * `format_version` alone puts it on the legacy line. A sheet carrying
8
+ * neither is placed by its `$schema`: a two-part version segment, or
9
+ * the pre-2026-09-08 `/schemas/` path, is legacy; anything else is the
10
+ * release line, whose schema then reports the missing `release`.
11
+ */
12
+ export function detectSheetLine(sheet) {
13
+ if (sheet.release !== undefined)
14
+ return "release";
15
+ if (sheet.format_version !== undefined)
16
+ return "legacy";
17
+ const schema = sheet.$schema;
18
+ if (typeof schema === "string") {
19
+ if (LEGACY_SCHEMA_SEGMENT.test(schema))
20
+ return "legacy";
21
+ if (schema.includes("/schemas/organization/") || schema.includes("/schemas/product/"))
22
+ return "legacy";
23
+ }
24
+ return "release";
25
+ }
1
26
  const ORG_DATA_TYPES = new Set(["Organization", "OnlineStore", "OnlineBusiness"]);
2
27
  export function detectSheetType(sheet) {
3
28
  const schema = sheet.$schema;
@@ -5,6 +5,7 @@
5
5
  * boundary: callers see `SchemaError`, never Ajv's own error type.
6
6
  */
7
7
  import type { LintOptions, Report } from "@pagefront/lint-core";
8
+ import type { SheetType } from "./sheet-type.js";
8
9
  /**
9
10
  * One Layer 1 (JSON Schema) validation failure, in a shape this
10
11
  * package owns. `instancePath` is a JSON Pointer to the offending
@@ -24,24 +25,30 @@ export type ValidateAndLintResult = {
24
25
  report: Report;
25
26
  };
26
27
  /**
27
- * Validate a parsed-but-unvalidated document against the bundled
28
- * product JSON Schema (Layer 1), and — only if it passes — lint it
29
- * against the commerce rule catalogue (Layer 2). The engine assumes a
30
- * schema-valid Sheet, so a failing document never reaches the
31
- * catalogue; Layer 1 success is also what makes the internal cast to
32
- * `Sheet` sound (the schema requires the envelope fields).
28
+ * Layer 1 for one document: validate it against the frozen schema its
29
+ * `$schema` names, or, when it declares none, the schema its own
30
+ * statements lead to (see schema-registry.ts). Returns the errors, empty
31
+ * when the document is valid. A `$schema` naming no bundled schema is a
32
+ * Layer 1 failure of its own, reported at `/$schema` with the keyword
33
+ * `$schema`: the document is not validated against some other version.
34
+ */
35
+ export declare function schemaErrorsFor(input: unknown, sheetType?: SheetType): SchemaError[];
36
+ /**
37
+ * Validate a parsed-but-unvalidated document against a bundled JSON
38
+ * Schema (Layer 1), and — only if it passes — lint it against the
39
+ * commerce rule catalogue (Layer 2). The engine assumes a schema-valid
40
+ * Sheet, so a failing document never reaches the catalogue; Layer 1
41
+ * success is also what makes the internal cast to `Sheet` sound (the
42
+ * schema requires the envelope fields).
33
43
  *
34
- * The bundled schemas are the current catalogue's format version. A
35
- * document declaring some other `format_version` failing Layer 1 is
36
- * the intended behavior, not a gap: this package lints exactly one
37
- * format version, and there is no separate "unsupported version"
38
- * outcome.
44
+ * The package bundles every schema ever published, on both lines: the
45
+ * sheet-spec versions of each release, and the legacy draft line's
46
+ * format 0.9 schemas. A document is validated against the one its
47
+ * `$schema` names. A `$schema` naming a version this package does not
48
+ * bundle fails Layer 1 with a single error saying so.
39
49
  *
40
- * Dispatches by page type (see sheet-type.ts): product sheets validate
41
- * against the product schema and lint with the product catalogue;
42
- * Commerce Organization Sheets validate against the organization
43
- * schema and lint with the organization catalogue. Detection reads the
44
- * envelope `$schema` first, falling back to data-block shape, so a
45
- * document of either type routes to its own schema's errors.
50
+ * Layer 2 dispatches by page type (see sheet-type.ts): product sheets
51
+ * lint with the product catalogue, Commerce Organization Sheets with
52
+ * the organization catalogue.
46
53
  */
47
54
  export declare function validateAndLint(input: unknown, options?: LintOptions): ValidateAndLintResult;
@@ -1,41 +1,60 @@
1
1
  import { lintSheet } from "./lint-sheet.js";
2
- import { detectSheetType } from "./sheet-type.js";
3
- import { validateProduct, validateOrganization } from "./schema-validators.js";
2
+ import { resolveSchema } from "./schema-registry.js";
3
+ import { VALIDATORS } from "./schema-validators.js";
4
4
  // The validators are compiled ahead of time (see schema-validators.d.ts):
5
5
  // nothing here generates code at load time, so the pipeline runs where
6
6
  // eval is unavailable, and consumers calling it in a loop pay no
7
7
  // compilation cost.
8
8
  /**
9
- * Validate a parsed-but-unvalidated document against the bundled
10
- * product JSON Schema (Layer 1), and — only if it passes — lint it
11
- * against the commerce rule catalogue (Layer 2). The engine assumes a
12
- * schema-valid Sheet, so a failing document never reaches the
13
- * catalogue; Layer 1 success is also what makes the internal cast to
14
- * `Sheet` sound (the schema requires the envelope fields).
9
+ * Layer 1 for one document: validate it against the frozen schema its
10
+ * `$schema` names, or, when it declares none, the schema its own
11
+ * statements lead to (see schema-registry.ts). Returns the errors, empty
12
+ * when the document is valid. A `$schema` naming no bundled schema is a
13
+ * Layer 1 failure of its own, reported at `/$schema` with the keyword
14
+ * `$schema`: the document is not validated against some other version.
15
+ */
16
+ export function schemaErrorsFor(input, sheetType) {
17
+ const envelope = (typeof input === "object" && input !== null ? input : {});
18
+ const resolution = resolveSchema(envelope, sheetType);
19
+ if (resolution.kind === "unknown") {
20
+ return [
21
+ {
22
+ instancePath: "/$schema",
23
+ message: `names no schema this linter bundles: ${resolution.declared}`,
24
+ keyword: "$schema",
25
+ },
26
+ ];
27
+ }
28
+ const validate = VALIDATORS[resolution.id];
29
+ if (validate(input))
30
+ return [];
31
+ return (validate.errors ?? []).map((error) => ({
32
+ instancePath: error.instancePath,
33
+ message: error.message ?? "invalid",
34
+ keyword: error.keyword,
35
+ }));
36
+ }
37
+ /**
38
+ * Validate a parsed-but-unvalidated document against a bundled JSON
39
+ * Schema (Layer 1), and — only if it passes — lint it against the
40
+ * commerce rule catalogue (Layer 2). The engine assumes a schema-valid
41
+ * Sheet, so a failing document never reaches the catalogue; Layer 1
42
+ * success is also what makes the internal cast to `Sheet` sound (the
43
+ * schema requires the envelope fields).
15
44
  *
16
- * The bundled schemas are the current catalogue's format version. A
17
- * document declaring some other `format_version` failing Layer 1 is
18
- * the intended behavior, not a gap: this package lints exactly one
19
- * format version, and there is no separate "unsupported version"
20
- * outcome.
45
+ * The package bundles every schema ever published, on both lines: the
46
+ * sheet-spec versions of each release, and the legacy draft line's
47
+ * format 0.9 schemas. A document is validated against the one its
48
+ * `$schema` names. A `$schema` naming a version this package does not
49
+ * bundle fails Layer 1 with a single error saying so.
21
50
  *
22
- * Dispatches by page type (see sheet-type.ts): product sheets validate
23
- * against the product schema and lint with the product catalogue;
24
- * Commerce Organization Sheets validate against the organization
25
- * schema and lint with the organization catalogue. Detection reads the
26
- * envelope `$schema` first, falling back to data-block shape, so a
27
- * document of either type routes to its own schema's errors.
51
+ * Layer 2 dispatches by page type (see sheet-type.ts): product sheets
52
+ * lint with the product catalogue, Commerce Organization Sheets with
53
+ * the organization catalogue.
28
54
  */
29
55
  export function validateAndLint(input, options) {
30
- const sheetType = detectSheetType((typeof input === "object" && input !== null ? input : {}));
31
- const validate = sheetType === "organization" ? validateOrganization : validateProduct;
32
- if (!validate(input)) {
33
- const schemaErrors = (validate.errors ?? []).map((error) => ({
34
- instancePath: error.instancePath,
35
- message: error.message ?? "invalid",
36
- keyword: error.keyword,
37
- }));
56
+ const schemaErrors = schemaErrorsFor(input);
57
+ if (schemaErrors.length > 0)
38
58
  return { layer: 1, schemaErrors };
39
- }
40
59
  return { layer: 2, report: lintSheet(input, options) };
41
60
  }
@@ -18,10 +18,10 @@ export type ValidateOrganizationResult = {
18
18
  schemaErrors: SchemaError[];
19
19
  };
20
20
  /**
21
- * Validate a parsed-but-unvalidated document against the bundled
22
- * Commerce Organization Sheet JSON Schema. The bundled schema is the
23
- * current format version; a document declaring some other
24
- * `format_version` failing Layer 1 is the intended behavior, exactly
25
- * as in the product pipeline.
21
+ * Validate a parsed-but-unvalidated document against a bundled
22
+ * Commerce Organization Sheet JSON Schema: the one its `$schema` names,
23
+ * or, when it declares none, the organization schema for its line (the
24
+ * sheet-spec version its `release` bundles, or the legacy format 0.9
25
+ * schema for a sheet carrying `format_version`).
26
26
  */
27
27
  export declare function validateOrganizationSheet(input: unknown): ValidateOrganizationResult;
@@ -1,19 +1,12 @@
1
- import { validateOrganization as validate } from "./schema-validators.js";
1
+ import { schemaErrorsFor } from "./validate-and-lint.js";
2
2
  /**
3
- * Validate a parsed-but-unvalidated document against the bundled
4
- * Commerce Organization Sheet JSON Schema. The bundled schema is the
5
- * current format version; a document declaring some other
6
- * `format_version` failing Layer 1 is the intended behavior, exactly
7
- * as in the product pipeline.
3
+ * Validate a parsed-but-unvalidated document against a bundled
4
+ * Commerce Organization Sheet JSON Schema: the one its `$schema` names,
5
+ * or, when it declares none, the organization schema for its line (the
6
+ * sheet-spec version its `release` bundles, or the legacy format 0.9
7
+ * schema for a sheet carrying `format_version`).
8
8
  */
9
9
  export function validateOrganizationSheet(input) {
10
- if (!validate(input)) {
11
- const schemaErrors = (validate.errors ?? []).map((error) => ({
12
- instancePath: error.instancePath,
13
- message: error.message ?? "invalid",
14
- keyword: error.keyword,
15
- }));
16
- return { valid: false, schemaErrors };
17
- }
18
- return { valid: true };
10
+ const schemaErrors = schemaErrorsFor(input, "organization");
11
+ return schemaErrors.length > 0 ? { valid: false, schemaErrors } : { valid: true };
19
12
  }
package/dist/version.d.ts CHANGED
@@ -5,4 +5,4 @@
5
5
  * (test/linter-version.test.mjs) fails when they diverge. Regenerate
6
6
  * on version bump.
7
7
  */
8
- export declare const PACKAGE_VERSION = "0.9.0";
8
+ export declare const PACKAGE_VERSION = "0.11.0";
package/dist/version.js CHANGED
@@ -5,4 +5,4 @@
5
5
  * (test/linter-version.test.mjs) fails when they diverge. Regenerate
6
6
  * on version bump.
7
7
  */
8
- export const PACKAGE_VERSION = "0.9.0";
8
+ export const PACKAGE_VERSION = "0.11.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagefront/lint-commerce",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Pagefront commerce linter: the commerce rule catalogue and CLI, on the @pagefront/lint-core engine.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -34,12 +34,12 @@
34
34
  "access": "public"
35
35
  },
36
36
  "scripts": {
37
- "build": "tsc && node scripts/compile-validators.mjs",
37
+ "build": "node scripts/bundle-schemas.mjs && tsc && node scripts/compile-validators.mjs",
38
38
  "test": "npm run build && node --test test/*.test.mjs",
39
39
  "prepublishOnly": "npm test"
40
40
  },
41
41
  "dependencies": {
42
- "@pagefront/lint-core": "^0.1.0",
42
+ "@pagefront/lint-core": "^0.2.0",
43
43
  "ajv": "^8.20.0",
44
44
  "ajv-formats": "^3.0.1"
45
45
  },
@@ -1,9 +0,0 @@
1
- /**
2
- * The Pagefront Commerce Organization Sheet JSON Schema
3
- * (commerce/spec/organization.json, format 0.9), bundled verbatim so
4
- * the published package can run Layer 1 validation without the
5
- * monorepo checkout. Generated from the spec file; the schema drift
6
- * test (test/schema.test.mjs) fails when the two diverge. Regenerate
7
- * on any schema change, in the same change that motivates it.
8
- */
9
- export declare const ORGANIZATION_SCHEMA: Record<string, unknown>;