yarramate 1.15.2 → 1.16.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.
@@ -1,18 +1,8 @@
1
- import Ajv2020Module from 'ajv/dist/2020.js';
2
1
  import { diagnosticOrder, loadSourceDocument, locateSourcePath, } from './source-document.js';
3
- import { lazyValidator } from './schema-validation.js';
4
- import adapterMappingSchema from '../schema/yarramate-adapter-mapping.schema.json' with { type: 'json'
5
- };
6
- // `.default ?? module`, not a bare `.default`: NodeNext sees the raw CJS
7
- // `module.exports` and a bundler the unwrapped class. One shape for all of
8
- // them, so which modules a browser happens to reach is not a thing anyone has
9
- // to keep track of (#252).
10
- const ajv2020Module = Ajv2020Module;
11
- const Ajv2020 = ajv2020Module.default ?? ajv2020Module;
12
- const validateSchema = lazyValidator(() => new Ajv2020({ allErrors: true }).compile(adapterMappingSchema));
2
+ import { validateAdapterMapping as validateSchema } from './schema-validation.js';
13
3
  const mappingLocations = new WeakMap();
14
4
  export function loadAdapterMapping(source) {
15
- const loaded = loadSourceDocument(source, validateSchema(), 'Adapter mapping');
5
+ const loaded = loadSourceDocument(source, validateSchema, 'Adapter mapping');
16
6
  if (!loaded.ok)
17
7
  return loaded;
18
8
  const { value, yaml, lineCounter } = loaded.document;
@@ -1,5 +1,4 @@
1
1
  import { isMap, isScalar, isSeq, parseDocument, } from 'yaml';
2
- import Ajv2020Module from 'ajv/dist/2020.js';
3
2
  import { loadAdapterMapping } from './adapter-mapping.js';
4
3
  import { compileWorkspace, withDiagnosticSubjects, } from './compiler.js';
5
4
  import { evaluateEvidence, loadEvidence } from './evidence.js';
@@ -20,22 +19,9 @@ export const posixDirectoryOf = (path) => {
20
19
  const cut = normalised.lastIndexOf('/');
21
20
  return cut === -1 ? '' : normalised.slice(0, cut);
22
21
  };
23
- import operationsSchema from '../schema/yarramate-operations.schema.json' with { type: 'json'
24
- };
25
- import { lazyValidator } from './schema-validation.js';
26
- // `.default ?? module`, not a bare `.default`: NodeNext sees the raw CJS
27
- // `module.exports` and a bundler sees the unwrapped class, and this file is
28
- // reachable from a browser through `./apply-operations.js` (#252).
29
- const ajv2020Module = Ajv2020Module;
30
- const Ajv2020 = ajv2020Module.default ?? ajv2020Module;
22
+ import { validateOperations } from './schema-validation.js';
31
23
  // `discriminator` routes a batch entry to the single branch its `op` names, so
32
24
  // one malformed operation reports one fault instead of ten near-misses.
33
- // Keeps its own Ajv instance: `discriminator` changes how a schema compiles,
34
- // so it cannot share one with the nine that do not set it.
35
- const validateOperations = lazyValidator(() => new Ajv2020({
36
- allErrors: true,
37
- discriminator: true,
38
- }).compile(operationsSchema));
39
25
  // Scalar fields replace; list fields append; `remove` retracts (ADR 0062).
40
26
  // An answer enriches what is there and may explicitly take back what it
41
27
  // asserted — it never silently shrinks anything.
@@ -313,7 +299,7 @@ export const applyOperations = (input) => {
313
299
  ok: false,
314
300
  diagnostics,
315
301
  });
316
- const loadedOperations = loadSourceDocument(operations, validateOperations(), 'Operations');
302
+ const loadedOperations = loadSourceDocument(operations, validateOperations, 'Operations');
317
303
  if (!loadedOperations.ok)
318
304
  return failed(loadedOperations.diagnostics);
319
305
  const operationList = loadedOperations.document.value.operations;
package/dist/compiler.js CHANGED
@@ -1,23 +1,11 @@
1
- import Ajv2020Import from 'ajv/dist/2020.js';
2
1
  import { LineCounter, parse, parseDocument } from 'yaml';
3
2
  import { conceptKinds, relationshipPolicies, } from './profile.js';
4
3
  import { isCoreConceptKindId, matrixEndpointAspects, permittedRelationshipKinds as tablePermittedKinds, } from './relationship-matrix.js';
5
4
  import { closestCandidate, describeSchemaViolation, } from './source-document.js';
6
- import documentSchema from '../schema/yarramate-document.schema.json' with { type: 'json'
7
- };
8
- import profileSchema from '../schema/yarramate-profile.schema.json' with { type: 'json'
9
- };
10
- import patternSchema from '../schema/yarramate-pattern.schema.json' with { type: 'json'
11
- };
12
5
  import { ATTESTATION_PREDICATE_PREFIX, attestationClaimValue } from './graph-claims.js';
13
6
  import { shippedPolicyIdentity, shippedPolicySource, } from './shipped-profile.js';
14
- import { lazyValidator } from './schema-validation.js';
7
+ import { validateDocument, validateProfile, validatePattern } from './schema-validation.js';
15
8
  const coreProfile = 'yarramate/core@0.1';
16
- const ajv2020Module = Ajv2020Import;
17
- const Ajv2020 = ajv2020Module.default ?? ajv2020Module;
18
- const validateDocument = lazyValidator(() => new Ajv2020({ allErrors: true }).compile(documentSchema));
19
- const validateProfile = lazyValidator(() => new Ajv2020({ allErrors: true }).compile(profileSchema));
20
- const validatePattern = lazyValidator(() => new Ajv2020({ allErrors: true }).compile(patternSchema));
21
9
  const immutableMap = (entries) => {
22
10
  const backing = new Map(entries);
23
11
  const facade = {
@@ -161,12 +149,12 @@ const parseWorkspaceSource = (input) => {
161
149
  fresh,
162
150
  };
163
151
  }
164
- const valid = parseDiagnostics.length === 0 && validateDocument()(value);
152
+ const valid = parseDiagnostics.length === 0 && validateDocument(value);
165
153
  const schemaDiagnostics = parseDiagnostics.length > 0
166
154
  ? parseDiagnostics
167
155
  : valid
168
156
  ? []
169
- : (validateDocument().errors ?? []).map((error) => {
157
+ : (validateDocument.errors ?? []).map((error) => {
170
158
  const property = error.keyword === 'additionalProperties'
171
159
  ? String(error.params.additionalProperty)
172
160
  : undefined;
@@ -331,8 +319,8 @@ function compileWorkspaceResolved(parsed) {
331
319
  profileDiagnostics.push(...entry.schemaDiagnostics);
332
320
  continue;
333
321
  }
334
- if (!validateProfile()(value)) {
335
- for (const error of validateProfile().errors ?? []) {
322
+ if (!validateProfile(value)) {
323
+ for (const error of validateProfile.errors ?? []) {
336
324
  const property = error.keyword === 'additionalProperties'
337
325
  ? String(error.params.additionalProperty)
338
326
  : undefined;
@@ -391,8 +379,8 @@ function compileWorkspaceResolved(parsed) {
391
379
  if (entry.schemaDiagnostics.length > 0) {
392
380
  profileDiagnostics.push(...entry.schemaDiagnostics);
393
381
  }
394
- else if (!validateProfile()(value)) {
395
- for (const error of validateProfile().errors ?? []) {
382
+ else if (!validateProfile(value)) {
383
+ for (const error of validateProfile.errors ?? []) {
396
384
  profileDiagnostics.push({
397
385
  severity: 'error',
398
386
  code: 'YM201',
@@ -641,8 +629,8 @@ function compileWorkspaceResolved(parsed) {
641
629
  patternDiagnostics.push(...entry.schemaDiagnostics);
642
630
  continue;
643
631
  }
644
- if (!validatePattern()(value)) {
645
- for (const error of validatePattern().errors ?? []) {
632
+ if (!validatePattern(value)) {
633
+ for (const error of validatePattern.errors ?? []) {
646
634
  const property = error.keyword === 'additionalProperties'
647
635
  ? String(error.params.additionalProperty)
648
636
  : undefined;
@@ -1,18 +1,8 @@
1
- import Ajv2020Module from 'ajv/dist/2020.js';
2
1
  import { LineCounter, parseDocument } from 'yaml';
3
2
  import { diagnosticOrder, loadSourceDocument, locateSourcePath, } from './source-document.js';
4
- import { lazyValidator } from './schema-validation.js';
5
- import coreContractSchema from '../schema/yarramate-core-contract.schema.json' with { type: 'json'
6
- };
7
- // `.default ?? module`, not a bare `.default`: NodeNext sees the raw CJS
8
- // `module.exports` and a bundler the unwrapped class. One shape for all of
9
- // them, so which modules a browser happens to reach is not a thing anyone has
10
- // to keep track of (#252).
11
- const ajv2020Module = Ajv2020Module;
12
- const Ajv2020 = ajv2020Module.default ?? ajv2020Module;
13
- const validateCoreContract = lazyValidator(() => new Ajv2020({ allErrors: true }).compile(coreContractSchema));
3
+ import { validateCoreContract } from './schema-validation.js';
14
4
  export function loadCoreContract(source) {
15
- const loaded = loadSourceDocument(source, validateCoreContract(), 'Core contract');
5
+ const loaded = loadSourceDocument(source, validateCoreContract, 'Core contract');
16
6
  if (!loaded.ok)
17
7
  return loaded;
18
8
  const { value, yaml, lineCounter } = loaded.document;
package/dist/evidence.js CHANGED
@@ -1,19 +1,9 @@
1
- import Ajv2020Module from 'ajv/dist/2020.js';
2
1
  import { diagnosticOrder, loadSourceDocument, locateSourcePath, } from './source-document.js';
3
- import evidenceSchema from '../schema/yarramate-evidence.schema.json' with { type: 'json'
4
- };
5
- // `.default ?? module`, not a bare `.default`: NodeNext sees the raw CJS
6
- // `module.exports` and a bundler the unwrapped class. One shape for all of
7
- // them, so which modules a browser happens to reach is not a thing anyone has
8
- // to keep track of (#252).
9
- const ajv2020Module = Ajv2020Module;
10
- const Ajv2020 = ajv2020Module.default ?? ajv2020Module;
11
- import { lazyValidator } from './schema-validation.js';
12
- const validateEvidenceSchema = lazyValidator(() => new Ajv2020({ allErrors: true }).compile(evidenceSchema));
2
+ import { validateEvidence as validateEvidenceSchema } from './schema-validation.js';
13
3
  const evidenceLocations = new WeakMap();
14
4
  const observationTarget = (observation) => 'subject' in observation ? observation.subject : observation.claim;
15
5
  export function loadEvidence(source) {
16
- const loaded = loadSourceDocument(source, validateEvidenceSchema(), 'Evidence');
6
+ const loaded = loadSourceDocument(source, validateEvidenceSchema, 'Evidence');
17
7
  if (!loaded.ok)
18
8
  return loaded;
19
9
  const { value, yaml, lineCounter } = loaded.document;
@@ -1,17 +1,7 @@
1
- import Ajv2020Module from 'ajv/dist/2020.js';
2
1
  import { loadSourceDocument, locateSourcePath, } from './source-document.js';
3
2
  import { nearDuplicateIndex } from './subject-identity.js';
4
3
  import { sourceKindsPermitting, tableKnowsConceptKind, tableKnowsRelationshipKind, targetKindsPermitting, } from './relationship-matrix.js';
5
- import catalogueSchema from '../schema/yarramate-question-catalogue.schema.json' with { type: 'json'
6
- };
7
- // `.default ?? module`, not a bare `.default`: NodeNext sees the raw CJS
8
- // `module.exports` and a bundler the unwrapped class. One shape for all of
9
- // them, so which modules a browser happens to reach is not a thing anyone has
10
- // to keep track of (#252).
11
- const ajv2020Module = Ajv2020Module;
12
- const Ajv2020 = ajv2020Module.default ?? ajv2020Module;
13
- import { lazyValidator } from './schema-validation.js';
14
- const validateCatalogue = lazyValidator(() => new Ajv2020({ allErrors: true }).compile(catalogueSchema));
4
+ import { validateCatalogue } from './schema-validation.js';
15
5
  /**
16
6
  * The version of condition evaluation itself, not of the package.
17
7
  *
@@ -917,7 +907,7 @@ const unauthorableOffers = (catalogue, profileContext) => {
917
907
  return found;
918
908
  };
919
909
  const loadCatalogueDocument = (catalogueSource) => {
920
- const loaded = loadSourceDocument(catalogueSource, validateCatalogue(), 'Question catalogue');
910
+ const loaded = loadSourceDocument(catalogueSource, validateCatalogue, 'Question catalogue');
921
911
  if (!loaded.ok)
922
912
  return { ok: false, diagnostics: loaded.diagnostics };
923
913
  return {
@@ -1,12 +1,6 @@
1
- import Ajv2020Import from 'ajv/dist/2020.js';
2
1
  import { isDeclaredNonGoal } from './brief.js';
3
2
  import { loadSourceDocument } from './source-document.js';
4
3
  import { similarity } from './subject-identity.js';
5
- import projectionSchema from '../schema/yarramate-projection.schema.json' with { type: 'json'
6
- };
7
- const ajv2020Module = Ajv2020Import;
8
- const Ajv2020 = ajv2020Module.default ?? ajv2020Module;
9
- const validateProjection = lazyValidator(() => new Ajv2020({ allErrors: true }).compile(projectionSchema));
10
4
  /**
11
5
  * A relationship kind a view may draw as nesting, and the default. Defined in
12
6
  * `./nesting.js`, which imports nothing, and re-exported here so a consumer
@@ -20,9 +14,9 @@ export { DEFAULT_NESTING } from './nesting.js';
20
14
  * nesting vocabulary above, and re-exported here on the same terms (ADR 0121).
21
15
  */
22
16
  export { DEFAULT_DIRECTION } from './layout-direction.js';
23
- import { lazyValidator } from './schema-validation.js';
17
+ import { validateProjection } from './schema-validation.js';
24
18
  export function loadProjection(source) {
25
- const loaded = loadSourceDocument(source, validateProjection(), 'Projection');
19
+ const loaded = loadSourceDocument(source, validateProjection, 'Projection');
26
20
  return loaded.ok
27
21
  ? { ok: true, projection: loaded.document.value }
28
22
  : loaded;
@@ -1,30 +1,42 @@
1
1
  import type { ValidateFunction } from 'ajv';
2
2
  /**
3
- * Defers compiling a JSON Schema until something actually validates against
4
- * it, then reuses the compiled validator forever.
3
+ * The package's JSON Schema validators, precompiled at BUILD time.
5
4
  *
6
- * Ten validators used to be constructed and compiled at MODULE SCOPE, so
7
- * importing the package paid for every one of them whether or not a caller
8
- * ever validated anything. Measured on the published 1.15.1 dist: ten
9
- * `Ajv.compile` calls costing **123.7ms, 80% of the barrel's entire import
10
- * time**, and one more on the `yarramate/interrogation` subpath, which is the
11
- * entry we tell Workers consumers to prefer. That is not an abstract cost:
12
- * Cloudflare Workers budget STARTUP CPU separately from request CPU and refuse
13
- * a Worker that exceeds it, so an adopter's deploy was rejected outright
14
- * (error 10021) by work no request had asked for.
5
+ * Ajv normally compiles a schema by generating source and calling
6
+ * `new Function`, and where that happens decided two releases:
15
7
  *
16
- * Deferring moves that cost to first use, where the budget is seconds rather
17
- * than milliseconds, and a caller pays only for the schemas it actually
18
- * touches - a consumer that compiles a workspace no longer pays for the
19
- * evidence, adapter-mapping and core-contract validators it never calls.
8
+ * - Cloudflare's `workerd` **permits** code generation during module
9
+ * evaluation and **forbids** it at request time. 1.15.2 deferred compilation
10
+ * to first use to save startup CPU, which put it inside a request, and every
11
+ * request that validated anything threw `EvalError`.
12
+ * - 1.15.3 moved compilation back to import, where it is allowed, but that
13
+ * only avoids the forbidden context. The codegen still ran, and Workers
14
+ * budget startup CPU separately (400ms) and refuse a Worker that exceeds it.
15
+ * An adopter's deploy came back at 439ms against that line.
20
16
  *
21
- * The accessor is a function rather than a getter so the deferral is visible
22
- * at every call site: `validateDocument()(value)` reads as "get the validator,
23
- * then use it", and `validateDocument().errors` cannot accidentally be read
24
- * off a validator that was never run. Ajv attaches `errors` to the validator
25
- * itself, so the two must come from the same object.
17
+ * Precompiling removes the question instead of answering it: there is no
18
+ * compile step left to put in the wrong place, and no amount of future
19
+ * refactoring can move one back. `schema-validators.generated.js` is committed
20
+ * and regenerated by `pnpm generate:validators`;
21
+ * `test/generated-validators.test.ts` regenerates and compares byte for byte,
22
+ * so a schema edited without regenerating fails there rather than shipping a
23
+ * validator that checks the old shape.
26
24
  *
27
- * `test/schema-validation-laziness.test.ts` asserts that importing the package
28
- * compiles NOTHING, and fails on the next module-scope validator anyone adds.
25
+ * Behaviour is unchanged: same `allErrors` collection, same messages, same
26
+ * `errors` property on each validator. `validateOperations` is emitted from an
27
+ * instance with `discriminator` enabled, which is compiled into it.
28
+ *
29
+ * Ajv's COMPILER is a build dependency now rather than a runtime one. Two pure
30
+ * helpers - a deep-equal and a UCS-2 string length - are still imported from
31
+ * `ajv/dist/runtime` by the generated module, which is the accurate claim.
29
32
  */
30
- export declare const lazyValidator: <T = unknown>(compile: () => ValidateFunction<T>) => (() => ValidateFunction<T>);
33
+ export declare const validateDocument: ValidateFunction;
34
+ export declare const validateProfile: ValidateFunction;
35
+ export declare const validatePattern: ValidateFunction;
36
+ export declare const validateWorkspace: ValidateFunction;
37
+ export declare const validateProjection: ValidateFunction;
38
+ export declare const validateEvidence: ValidateFunction;
39
+ export declare const validateCoreContract: ValidateFunction;
40
+ export declare const validateAdapterMapping: ValidateFunction;
41
+ export declare const validateCatalogue: ValidateFunction;
42
+ export declare const validateOperations: ValidateFunction;
@@ -1,32 +1,43 @@
1
+ import * as generatedOperations from './schema-validators-operations.generated.js';
2
+ import * as generated from './schema-validators.generated.js';
1
3
  /**
2
- * Defers compiling a JSON Schema until something actually validates against
3
- * it, then reuses the compiled validator forever.
4
+ * The package's JSON Schema validators, precompiled at BUILD time.
4
5
  *
5
- * Ten validators used to be constructed and compiled at MODULE SCOPE, so
6
- * importing the package paid for every one of them whether or not a caller
7
- * ever validated anything. Measured on the published 1.15.1 dist: ten
8
- * `Ajv.compile` calls costing **123.7ms, 80% of the barrel's entire import
9
- * time**, and one more on the `yarramate/interrogation` subpath, which is the
10
- * entry we tell Workers consumers to prefer. That is not an abstract cost:
11
- * Cloudflare Workers budget STARTUP CPU separately from request CPU and refuse
12
- * a Worker that exceeds it, so an adopter's deploy was rejected outright
13
- * (error 10021) by work no request had asked for.
6
+ * Ajv normally compiles a schema by generating source and calling
7
+ * `new Function`, and where that happens decided two releases:
14
8
  *
15
- * Deferring moves that cost to first use, where the budget is seconds rather
16
- * than milliseconds, and a caller pays only for the schemas it actually
17
- * touches - a consumer that compiles a workspace no longer pays for the
18
- * evidence, adapter-mapping and core-contract validators it never calls.
9
+ * - Cloudflare's `workerd` **permits** code generation during module
10
+ * evaluation and **forbids** it at request time. 1.15.2 deferred compilation
11
+ * to first use to save startup CPU, which put it inside a request, and every
12
+ * request that validated anything threw `EvalError`.
13
+ * - 1.15.3 moved compilation back to import, where it is allowed, but that
14
+ * only avoids the forbidden context. The codegen still ran, and Workers
15
+ * budget startup CPU separately (400ms) and refuse a Worker that exceeds it.
16
+ * An adopter's deploy came back at 439ms against that line.
19
17
  *
20
- * The accessor is a function rather than a getter so the deferral is visible
21
- * at every call site: `validateDocument()(value)` reads as "get the validator,
22
- * then use it", and `validateDocument().errors` cannot accidentally be read
23
- * off a validator that was never run. Ajv attaches `errors` to the validator
24
- * itself, so the two must come from the same object.
18
+ * Precompiling removes the question instead of answering it: there is no
19
+ * compile step left to put in the wrong place, and no amount of future
20
+ * refactoring can move one back. `schema-validators.generated.js` is committed
21
+ * and regenerated by `pnpm generate:validators`;
22
+ * `test/generated-validators.test.ts` regenerates and compares byte for byte,
23
+ * so a schema edited without regenerating fails there rather than shipping a
24
+ * validator that checks the old shape.
25
25
  *
26
- * `test/schema-validation-laziness.test.ts` asserts that importing the package
27
- * compiles NOTHING, and fails on the next module-scope validator anyone adds.
26
+ * Behaviour is unchanged: same `allErrors` collection, same messages, same
27
+ * `errors` property on each validator. `validateOperations` is emitted from an
28
+ * instance with `discriminator` enabled, which is compiled into it.
29
+ *
30
+ * Ajv's COMPILER is a build dependency now rather than a runtime one. Two pure
31
+ * helpers - a deep-equal and a UCS-2 string length - are still imported from
32
+ * `ajv/dist/runtime` by the generated module, which is the accurate claim.
28
33
  */
29
- export const lazyValidator = (compile) => {
30
- let compiled;
31
- return () => (compiled ??= compile());
32
- };
34
+ export const validateDocument = generated.validateDocument;
35
+ export const validateProfile = generated.validateProfile;
36
+ export const validatePattern = generated.validatePattern;
37
+ export const validateWorkspace = generated.validateWorkspace;
38
+ export const validateProjection = generated.validateProjection;
39
+ export const validateEvidence = generated.validateEvidence;
40
+ export const validateCoreContract = generated.validateCoreContract;
41
+ export const validateAdapterMapping = generated.validateAdapterMapping;
42
+ export const validateCatalogue = generated.validateCatalogue;
43
+ export const validateOperations = generatedOperations.validateOperations;
@@ -0,0 +1,7 @@
1
+ export declare const validateOperations: typeof validate20;
2
+ declare function validate20(data: any, { instancePath, parentData, parentDataProperty, rootData, dynamicAnchors }?: {
3
+ dynamicAnchors?: {} | undefined;
4
+ instancePath?: string | undefined;
5
+ rootData?: any;
6
+ }): boolean;
7
+ export {};