@effected/schemastore 0.16.1 → 0.18.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/CatalogEntry.js +1 -1
- package/DriftPolicy.js +12 -0
- package/README.md +6 -5
- package/SchemaPipeline.js +1 -1
- package/SchemastoreConfig.js +48 -11
- package/StoreDocument.js +3 -5
- package/index.d.ts +78 -26
- package/package.json +3 -3
package/CatalogEntry.js
CHANGED
|
@@ -133,7 +133,7 @@ var CatalogEntry = class CatalogEntry extends Schema.Class("CatalogEntry")({
|
|
|
133
133
|
return CatalogEntry.lintFileMatch(this.fileMatch);
|
|
134
134
|
}
|
|
135
135
|
/**
|
|
136
|
-
* {@link CatalogEntry.
|
|
136
|
+
* {@link CatalogEntry.lintFileMatch} over a bare pattern list, for callers
|
|
137
137
|
* checking patterns before an entry exists.
|
|
138
138
|
*/
|
|
139
139
|
static lintFileMatch(patterns) {
|
package/DriftPolicy.js
CHANGED
|
@@ -18,6 +18,18 @@ var DriftPolicy = class {
|
|
|
18
18
|
policy: "semantic",
|
|
19
19
|
onDrift: "error"
|
|
20
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* Answer `"write"` or `"drift"` for one target, given whether it is
|
|
23
|
+
* published and how its content changed.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { DriftPolicy } from "@effected/schemastore";
|
|
28
|
+
*
|
|
29
|
+
* DriftPolicy.classify({ published: true, change: "contract" }, "semantic");
|
|
30
|
+
* // => "drift"
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
21
33
|
static classify(input, policy) {
|
|
22
34
|
if (!input.published || policy === "allow") return "write";
|
|
23
35
|
if (input.change === "contract") return "drift";
|
package/README.md
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
Publish Effect Schemas as SchemaStore-shaped Draft-07 JSON Schema documents. Core `effect` already generates JSON Schema (`Schema.toJsonSchemaDocument`) and lowers it to Draft-07 (`JsonSchema.toDocumentDraft07`); this package owns what [SchemaStore](https://www.schemastore.org) and the editors expect around that output — the publication shape, the hosted identity a document is published under, the keyword-family gate, catalog entries, lints, versioning, canonical JSON and content-comparing file IO — and the [`schemastore`](https://www.npmjs.com/package/@effected/schemastore-cli) command runs all of it from one config file.
|
|
9
9
|
|
|
10
|
-
> **Pre
|
|
11
|
-
>
|
|
12
|
-
> `1.0.0`
|
|
13
|
-
>
|
|
10
|
+
> **Pre-`1.0.0`.** This package is part of the `@effected/*` kit, built on stable
|
|
11
|
+
> Effect v4 (`effect` `^4.0.0`) and still in `0.x` development. Stable Effect
|
|
12
|
+
> makes a kit `1.0.0` possible, not automatic. To keep your `effect` and
|
|
13
|
+
> `@effect/*` versions on the line the kit is built and tested against, install
|
|
14
14
|
> [`@effected/pnpm-plugin-effect`](https://www.npmjs.com/package/@effected/pnpm-plugin-effect).
|
|
15
15
|
>
|
|
16
16
|
> **Stability: unstable.** This package's API surface is not yet considered
|
|
@@ -61,6 +61,7 @@ import { defineConfig } from "@effected/schemastore";
|
|
|
61
61
|
import { OutputSchemaIdentity, ReleaseOutput } from "./src/schema/output.js";
|
|
62
62
|
|
|
63
63
|
export default defineConfig({
|
|
64
|
+
name: "silk-release-action",
|
|
64
65
|
outputDir: "schemas",
|
|
65
66
|
schemas: {
|
|
66
67
|
[OutputSchemaIdentity.name]: { schema: ReleaseOutput, hosted: OutputSchemaIdentity },
|
|
@@ -130,7 +131,7 @@ const program = SchemaPipeline.run(targets).pipe(
|
|
|
130
131
|
## What the library owns
|
|
131
132
|
|
|
132
133
|
- `HostedSchema` — a schema's hosted identity (`github`, `schemastore`, `custom`), deriving `$id`, the catalog URL and the file name for the current or any advertised version.
|
|
133
|
-
- `defineConfig` — the `schemastore.config.ts` contract: validated with one `Schema.Struct` per level (a typo'd key is named, every issue on an entry reported at once), every path and URL derived from the entry key and its identity, frozen labels resolved, a branded result the CLI recognises.
|
|
134
|
+
- `defineConfig` — the `schemastore.config.ts` contract: validated with one `Schema.Struct` per level (a typo'd key is named, every issue on an entry reported at once), a required config `name` (the base name of its catalog slice), every path and URL derived from the entry key and its identity, frozen labels resolved, a branded result the CLI recognises.
|
|
134
135
|
- `StoreDocument` — assembly: `fromSchema` / `fromSchemaResult`, the `draft07` constructor for hand-built documents, the flat `toJson()` publication shape, `serializeResult()`, `DRAFT_07_META_SCHEMA`.
|
|
135
136
|
- `KeywordFamilies` — the one registry of declared non-standard keyword families (the vscode five, `x-taplo`, `x-tombi-`, `x-intellij-`, and the house `x-ai-` machine-annotation namespace). Anything outside it fails `fromSchema` with `UndeclaredAnnotationKeyError`; nothing is silently dropped.
|
|
136
137
|
- `SchemaVersioning` / `SchemaVersion` — one-to-three-component version labels, `Order`, `latest`, `isPinned`, `next`, and the `fileName` / `schemaUrl` / `catalogUrls` derivations.
|
package/SchemaPipeline.js
CHANGED
|
@@ -116,7 +116,7 @@ const gate = (target, findings, options) => {
|
|
|
116
116
|
};
|
|
117
117
|
/**
|
|
118
118
|
* The emit pipeline over a target manifest: generate, lint, validate, gate,
|
|
119
|
-
* write
|
|
119
|
+
* and write each schema document.
|
|
120
120
|
*
|
|
121
121
|
* Requires `SchemaFile` and `SchemaValidator` in `R`; provide
|
|
122
122
|
* `SchemaFile.layer` and an engine — `AjvValidator.layer` from
|
package/SchemastoreConfig.js
CHANGED
|
@@ -50,11 +50,12 @@ const EntryInput = Schema.Struct({
|
|
|
50
50
|
rootAnnotations: Schema.optionalKey(OptionsInput)
|
|
51
51
|
});
|
|
52
52
|
const ConfigInput = Schema.Struct({
|
|
53
|
+
name: Schema.String,
|
|
53
54
|
outputDir: Schema.NonEmptyString,
|
|
54
55
|
baseUrl: Schema.optionalKey(Schema.String),
|
|
55
56
|
drift: Schema.optionalKey(DriftToleranceInput),
|
|
56
57
|
onDrift: Schema.optionalKey(OnDriftInput),
|
|
57
|
-
|
|
58
|
+
catalogDir: Schema.optionalKey(Schema.NonEmptyString),
|
|
58
59
|
schemas: Schema.Record(Schema.String, Schema.Unknown)
|
|
59
60
|
});
|
|
60
61
|
const DECODE_OPTIONS = {
|
|
@@ -156,6 +157,12 @@ const normalizePath = (raw) => {
|
|
|
156
157
|
}
|
|
157
158
|
return `${absolute ? "/" : ""}${out.join("/")}`;
|
|
158
159
|
};
|
|
160
|
+
const assertCatalogDirHoldsOnlySlices = (catalogDir, outputDir, documents) => {
|
|
161
|
+
const dir = normalizePath(catalogDir);
|
|
162
|
+
if (dir === normalizePath(`${catalogDir}/../catalog.json`)) fail(`catalogDir "${catalogDir}" must not be the merged catalog's path (catalog.json in its parent)`);
|
|
163
|
+
if (dir === normalizePath(outputDir)) fail(`catalogDir "${catalogDir}" must not be outputDir: every *.json file in it is read as a catalog slice`);
|
|
164
|
+
for (const document of documents) if (normalizePath(`${document}/..`) === dir) fail(`output path "${document}" sits in catalogDir "${catalogDir}", which holds only catalog slices`);
|
|
165
|
+
};
|
|
159
166
|
const assertUniquePaths = (paths) => {
|
|
160
167
|
const seen = /* @__PURE__ */ new Set();
|
|
161
168
|
for (const p of paths) {
|
|
@@ -189,18 +196,41 @@ const assertUniquePaths = (paths) => {
|
|
|
189
196
|
* {@link HostedSchema}, or one built from `baseUrl`/`versions`/`current`/
|
|
190
197
|
* `layout` and the config default — is validated by `HostedSchema` itself
|
|
191
198
|
* (a `hosted` entry must be keyed by `hosted.name` and must not spell those
|
|
192
|
-
* four fields beside it);
|
|
193
|
-
* `
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
199
|
+
* four fields beside it); the config `name` is required (a missing one
|
|
200
|
+
* fails `defineConfig: name is required — …`, naming what it is for), and
|
|
201
|
+
* it and every schema key must be simple file base names; a `catalog` is required under
|
|
202
|
+
* `baseUrl: "schemastore"`; an empty `schemas` record is rejected; a
|
|
203
|
+
* `catalogDir` that is `outputDir`, that is the merged catalog's own path,
|
|
204
|
+
* or that a derived document sits directly in, is rejected (every `*.json`
|
|
205
|
+
* file there is read as a catalog slice); and an output path (a target, a frozen file, this config's
|
|
206
|
+
* catalog slice `<catalogDir>/<name>.json`, or the merged catalog
|
|
207
|
+
* `catalog.json` in `catalogDir`'s parent) declared twice is rejected after
|
|
208
|
+
* a lexical normalisation (`./`, `..`, trailing `/`) — the CLI's loader
|
|
209
|
+
* re-checks on the resolved absolute paths. Branding the result lets a loader recognise a config
|
|
198
210
|
* module's default export via {@link isSchemastoreConfig}.
|
|
199
211
|
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* import { defineConfig } from "@effected/schemastore";
|
|
215
|
+
* import { Schema } from "effect";
|
|
216
|
+
*
|
|
217
|
+
* const Config = Schema.Struct({ name: Schema.String });
|
|
218
|
+
*
|
|
219
|
+
* export default defineConfig({
|
|
220
|
+
* name: "my-tool",
|
|
221
|
+
* outputDir: "schemas",
|
|
222
|
+
* baseUrl: "https://example.com/schemas",
|
|
223
|
+
* schemas: { config: { schema: Config } },
|
|
224
|
+
* });
|
|
225
|
+
* ```
|
|
226
|
+
*
|
|
200
227
|
* @public
|
|
201
228
|
*/
|
|
202
229
|
const defineConfig = (input) => {
|
|
203
|
-
const
|
|
230
|
+
const raw = withoutUndefined(input);
|
|
231
|
+
if (Predicate.isObject(raw) && !Array.isArray(raw) && !Object.hasOwn(raw, "name")) return fail("name is required — the base name of this config's catalog slice (<catalogDir>/<name>.json)");
|
|
232
|
+
const config = decodeOrThrow(ConfigInput, raw, "");
|
|
233
|
+
if (!SchemaVersioning.isSimpleName(config.name)) return fail(`name "${config.name}" must be a simple file base name (no separators, no whitespace)`);
|
|
204
234
|
const outputDir = trimSlashes(config.outputDir);
|
|
205
235
|
if (Object.keys(config.schemas).length === 0) return fail("at least one schema is required");
|
|
206
236
|
const defaults = {
|
|
@@ -208,13 +238,20 @@ const defineConfig = (input) => {
|
|
|
208
238
|
drift: config.drift ?? DriftPolicy.defaults.policy
|
|
209
239
|
};
|
|
210
240
|
const schemas = Object.entries(config.schemas).map(([name, entry]) => resolveEntry(name, entry, defaults, outputDir));
|
|
211
|
-
const
|
|
212
|
-
|
|
241
|
+
const catalogDir = config.catalogDir !== void 0 ? trimSlashes(config.catalogDir) : `${outputDir}/catalogs`;
|
|
242
|
+
const documents = schemas.flatMap((s) => [s.target.path, ...s.frozen.map((f) => f.path)]);
|
|
243
|
+
assertCatalogDirHoldsOnlySlices(catalogDir, outputDir, documents);
|
|
244
|
+
assertUniquePaths([
|
|
245
|
+
...documents,
|
|
246
|
+
`${catalogDir}/${config.name}.json`,
|
|
247
|
+
`${catalogDir}/../catalog.json`
|
|
248
|
+
]);
|
|
213
249
|
return {
|
|
214
250
|
[ConfigBrand]: true,
|
|
251
|
+
name: config.name,
|
|
215
252
|
outputDir,
|
|
216
253
|
onDrift: config.onDrift ?? DriftPolicy.defaults.onDrift,
|
|
217
|
-
|
|
254
|
+
catalogDir,
|
|
218
255
|
schemas
|
|
219
256
|
};
|
|
220
257
|
};
|
package/StoreDocument.js
CHANGED
|
@@ -7,8 +7,7 @@ import { Effect, JsonPointer, JsonSchema, Result, Schema } from "effect";
|
|
|
7
7
|
* The Draft-07 meta-schema URL SchemaStore documents declare as `$schema`.
|
|
8
8
|
*
|
|
9
9
|
* Deliberately carries the trailing `#` fragment: the SchemaStore corpus
|
|
10
|
-
*
|
|
11
|
-
* where core's `JsonSchema.META_SCHEMA_URI_DRAFT_07` omits it.
|
|
10
|
+
* uses the fragment form, where core's `JsonSchema.META_SCHEMA_URI_DRAFT_07` omits it.
|
|
12
11
|
*
|
|
13
12
|
* @public
|
|
14
13
|
*/
|
|
@@ -185,7 +184,7 @@ const collapseUniformTuples = (node, depth) => {
|
|
|
185
184
|
* `#/$defs` `$ref` rewrite the lowering makes necessary — so every `$ref`
|
|
186
185
|
* in a built document already resolves against the `$defs` pool — the
|
|
187
186
|
* uniform-tuple collapse that keeps open-ended `NonEmptyArray`-shaped
|
|
188
|
-
* arrays publishable through the strict ajv gate
|
|
187
|
+
* arrays publishable through the strict ajv gate, and the gate that
|
|
189
188
|
* holds the document's non-standard surface to the declared keyword
|
|
190
189
|
* families ({@link KeywordFamilies}). The package owns assembly and
|
|
191
190
|
* publication shape, not a JSON Schema engine.
|
|
@@ -299,8 +298,7 @@ var StoreDocument = class StoreDocument extends Schema.Class("StoreDocument")({
|
|
|
299
298
|
/**
|
|
300
299
|
* The flat SchemaStore publication shape: `$schema`, `$id`, the root
|
|
301
300
|
* schema's keywords spread at the top level, then the `$defs` pool.
|
|
302
|
-
* `$defs` is omitted when the pool is empty
|
|
303
|
-
* from the extraction source, which always emitted the key).
|
|
301
|
+
* `$defs` is omitted when the pool is empty.
|
|
304
302
|
*/
|
|
305
303
|
toJson() {
|
|
306
304
|
return {
|
package/index.d.ts
CHANGED
|
@@ -52,8 +52,8 @@ type CanonicalJsonError = NonJsonValueError | JsonDepthExceededError;
|
|
|
52
52
|
*/
|
|
53
53
|
interface CanonicalJsonOptions {
|
|
54
54
|
/**
|
|
55
|
-
* Indentation unit: `"tab"` (the default, matching the
|
|
56
|
-
* convention
|
|
55
|
+
* Indentation unit: `"tab"` (the default, matching the formatter
|
|
56
|
+
* convention of most JSON schema repos) or a
|
|
57
57
|
* space count — a non-negative integer (`0` emits multi-line output
|
|
58
58
|
* with no leading indentation). Counts above 10 are honored as given,
|
|
59
59
|
* deliberately diverging from `JSON.stringify`'s silent clamp to 10.
|
|
@@ -195,8 +195,7 @@ export declare class DocumentDiff {
|
|
|
195
195
|
* The Draft-07 meta-schema URL SchemaStore documents declare as `$schema`.
|
|
196
196
|
*
|
|
197
197
|
* Deliberately carries the trailing `#` fragment: the SchemaStore corpus
|
|
198
|
-
*
|
|
199
|
-
* where core's `JsonSchema.META_SCHEMA_URI_DRAFT_07` omits it.
|
|
198
|
+
* uses the fragment form, where core's `JsonSchema.META_SCHEMA_URI_DRAFT_07` omits it.
|
|
200
199
|
*
|
|
201
200
|
* @public
|
|
202
201
|
*/
|
|
@@ -341,7 +340,7 @@ declare const StoreDocument_base: Schema.Class<StoreDocument, Schema.Struct<{
|
|
|
341
340
|
* `#/$defs` `$ref` rewrite the lowering makes necessary — so every `$ref`
|
|
342
341
|
* in a built document already resolves against the `$defs` pool — the
|
|
343
342
|
* uniform-tuple collapse that keeps open-ended `NonEmptyArray`-shaped
|
|
344
|
-
* arrays publishable through the strict ajv gate
|
|
343
|
+
* arrays publishable through the strict ajv gate, and the gate that
|
|
345
344
|
* holds the document's non-standard surface to the declared keyword
|
|
346
345
|
* families ({@link KeywordFamilies}). The package owns assembly and
|
|
347
346
|
* publication shape, not a JSON Schema engine.
|
|
@@ -404,8 +403,7 @@ export declare class StoreDocument extends StoreDocument_base {
|
|
|
404
403
|
/**
|
|
405
404
|
* The flat SchemaStore publication shape: `$schema`, `$id`, the root
|
|
406
405
|
* schema's keywords spread at the top level, then the `$defs` pool.
|
|
407
|
-
* `$defs` is omitted when the pool is empty
|
|
408
|
-
* from the extraction source, which always emitted the key).
|
|
406
|
+
* `$defs` is omitted when the pool is empty.
|
|
409
407
|
*/
|
|
410
408
|
toJson(): Record<string, unknown>;
|
|
411
409
|
/**
|
|
@@ -913,7 +911,7 @@ export declare class CatalogEntry extends CatalogEntry_base {
|
|
|
913
911
|
*/
|
|
914
912
|
lint(): ReadonlyArray<CatalogLintFinding>;
|
|
915
913
|
/**
|
|
916
|
-
* {@link CatalogEntry.
|
|
914
|
+
* {@link CatalogEntry.lintFileMatch} over a bare pattern list, for callers
|
|
917
915
|
* checking patterns before an entry exists.
|
|
918
916
|
*/
|
|
919
917
|
static lintFileMatch(patterns: ReadonlyArray<string>): ReadonlyArray<CatalogLintFinding>;
|
|
@@ -1001,7 +999,9 @@ type OnDrift = "error" | "warn";
|
|
|
1001
999
|
* @public
|
|
1002
1000
|
*/
|
|
1003
1001
|
interface DriftOptions {
|
|
1002
|
+
/** How much change a published document may absorb. */
|
|
1004
1003
|
readonly policy: DriftTolerance;
|
|
1004
|
+
/** What a build does when it finds drift. */
|
|
1005
1005
|
readonly onDrift: OnDrift;
|
|
1006
1006
|
}
|
|
1007
1007
|
/**
|
|
@@ -1026,6 +1026,18 @@ export declare class DriftPolicy {
|
|
|
1026
1026
|
private constructor();
|
|
1027
1027
|
/** `{ policy: "semantic", onDrift: "error" }` — what a config gets when it says nothing. */
|
|
1028
1028
|
static readonly defaults: DriftOptions;
|
|
1029
|
+
/**
|
|
1030
|
+
* Answer `"write"` or `"drift"` for one target, given whether it is
|
|
1031
|
+
* published and how its content changed.
|
|
1032
|
+
*
|
|
1033
|
+
* @example
|
|
1034
|
+
* ```ts
|
|
1035
|
+
* import { DriftPolicy } from "@effected/schemastore";
|
|
1036
|
+
*
|
|
1037
|
+
* DriftPolicy.classify({ published: true, change: "contract" }, "semantic");
|
|
1038
|
+
* // => "drift"
|
|
1039
|
+
* ```
|
|
1040
|
+
*/
|
|
1029
1041
|
static classify(input: {
|
|
1030
1042
|
readonly published: boolean;
|
|
1031
1043
|
readonly change: WriteChange;
|
|
@@ -1246,8 +1258,7 @@ export declare class KeywordFamilies {
|
|
|
1246
1258
|
/**
|
|
1247
1259
|
* A single schema publication target: an Effect Schema source paired with
|
|
1248
1260
|
* the identity and destination it is serialized under. A repo generating
|
|
1249
|
-
* SchemaStore artifacts declares one target per emitted document
|
|
1250
|
-
* extraction source's `{schema, $id, path}` triples, generalized).
|
|
1261
|
+
* SchemaStore artifacts declares one target per emitted document.
|
|
1251
1262
|
*
|
|
1252
1263
|
* Not a `Schema.Class`: a target carries a live Effect Schema value, which
|
|
1253
1264
|
* is program wiring rather than serializable data.
|
|
@@ -1263,9 +1274,7 @@ export interface SchemaTarget {
|
|
|
1263
1274
|
* The catalog/file base name (`name.json` / `name-<version>.json`).
|
|
1264
1275
|
*
|
|
1265
1276
|
* Only the catalog path consumes it — a target that merely emits a file
|
|
1266
|
-
* to `path` needs no name
|
|
1267
|
-
* satisfy the constructor duplicates the basename with no invariant
|
|
1268
|
-
* tying the two together. Required whenever `version` is present, since
|
|
1277
|
+
* to `path` needs no name. Required whenever `version` is present, since
|
|
1269
1278
|
* versioned catalog naming is defined in terms of it.
|
|
1270
1279
|
*/
|
|
1271
1280
|
readonly name?: string;
|
|
@@ -1538,8 +1547,7 @@ export declare class SchemaGateError extends SchemaGateError_base {
|
|
|
1538
1547
|
* any write. A target with no `version`, or with a prerelease label, is a
|
|
1539
1548
|
* document that replaces its predecessor in place and is rewritten as
|
|
1540
1549
|
* before.
|
|
1541
|
-
* - `"allow"` — classify and report only, never refuse
|
|
1542
|
-
* behaviour. Also the sanctioned REPAIR path for a published file whose
|
|
1550
|
+
* - `"allow"` — classify and report only, never refuse. Also the sanctioned REPAIR path for a published file whose
|
|
1543
1551
|
* text no longer parses — `SchemaFile` classifies unparseable text as
|
|
1544
1552
|
* `"contract"` so it stays regenerable, and under the default that
|
|
1545
1553
|
* classification is refused.
|
|
@@ -1686,7 +1694,7 @@ interface SchemaPipelineOptions {
|
|
|
1686
1694
|
}
|
|
1687
1695
|
/**
|
|
1688
1696
|
* The emit pipeline over a target manifest: generate, lint, validate, gate,
|
|
1689
|
-
* write
|
|
1697
|
+
* and write each schema document.
|
|
1690
1698
|
*
|
|
1691
1699
|
* Requires `SchemaFile` and `SchemaValidator` in `R`; provide
|
|
1692
1700
|
* `SchemaFile.layer` and an engine — `AjvValidator.layer` from
|
|
@@ -1890,6 +1898,15 @@ interface SchemaEntryInput {
|
|
|
1890
1898
|
* @public
|
|
1891
1899
|
*/
|
|
1892
1900
|
interface SchemastoreConfigInput {
|
|
1901
|
+
/**
|
|
1902
|
+
* This config's identity: the base name of the catalog slice it owns
|
|
1903
|
+
* (`<catalogDir>/<name>.json`). Configs sharing a `catalogDir` must each
|
|
1904
|
+
* carry a distinct one — distinct case-insensitively, since on a
|
|
1905
|
+
* case-insensitive volume `docs` and `Docs` name one file and overwrite
|
|
1906
|
+
* each other; it must be a simple file base name (no separators, no
|
|
1907
|
+
* whitespace).
|
|
1908
|
+
*/
|
|
1909
|
+
readonly name: string;
|
|
1893
1910
|
/** The directory every derived `path` is written under; a trailing slash is trimmed. */
|
|
1894
1911
|
readonly outputDir: string;
|
|
1895
1912
|
/** The default {@link SchemaEntryInput.baseUrl} for an entry that declares none. */
|
|
@@ -1898,8 +1915,21 @@ interface SchemastoreConfigInput {
|
|
|
1898
1915
|
readonly drift?: DriftTolerance;
|
|
1899
1916
|
/** What a build does when it finds drift. Defaults to `"error"`. */
|
|
1900
1917
|
readonly onDrift?: OnDrift;
|
|
1901
|
-
/**
|
|
1902
|
-
|
|
1918
|
+
/**
|
|
1919
|
+
* The directory of catalog slices, one per config: this config writes its
|
|
1920
|
+
* own entries to `<catalogDir>/<name>.json`, and the CLI maintains the
|
|
1921
|
+
* merged `catalog.json` — every slice in the directory, united — in the
|
|
1922
|
+
* directory's parent. Defaults to `<outputDir>/catalogs`, so
|
|
1923
|
+
* the merged catalog lands at `<outputDir>/catalog.json`. Every `*.json`
|
|
1924
|
+
* file in it is read as a slice, so it holds nothing else, must not be
|
|
1925
|
+
* `outputDir` itself, and must not be the merged catalog's own path.
|
|
1926
|
+
* Every config that shares a merged catalog must share the same
|
|
1927
|
+
* `catalogDir`, under a `name` unique case-insensitively among them: two
|
|
1928
|
+
* sibling directories (`schemas/catalogs`, `schemas/more`) both merge into
|
|
1929
|
+
* `schemas/catalog.json` from different slice sets and overwrite each
|
|
1930
|
+
* other — no single config can detect it.
|
|
1931
|
+
*/
|
|
1932
|
+
readonly catalogDir?: string;
|
|
1903
1933
|
/**
|
|
1904
1934
|
* The schemas to derive, keyed by file base name — the key IS the
|
|
1905
1935
|
* `name` every derived path and URL is built from, so it must be a
|
|
@@ -1952,12 +1982,14 @@ interface ResolvedSchema {
|
|
|
1952
1982
|
*/
|
|
1953
1983
|
interface SchemastoreConfig {
|
|
1954
1984
|
readonly [ConfigBrand]: true;
|
|
1985
|
+
/** This config's identity: the base name of its catalog slice. */
|
|
1986
|
+
readonly name: string;
|
|
1955
1987
|
/** The directory every derived `path` is written under, trailing slash trimmed. */
|
|
1956
1988
|
readonly outputDir: string;
|
|
1957
1989
|
/** What a build does when it finds drift. */
|
|
1958
1990
|
readonly onDrift: OnDrift;
|
|
1959
|
-
/**
|
|
1960
|
-
readonly
|
|
1991
|
+
/** The directory of catalog slices; this config's own is `<catalogDir>/<name>.json`. */
|
|
1992
|
+
readonly catalogDir: string;
|
|
1961
1993
|
/** Every schema, resolved. */
|
|
1962
1994
|
readonly schemas: ReadonlyArray<ResolvedSchema>;
|
|
1963
1995
|
}
|
|
@@ -1986,14 +2018,34 @@ interface SchemastoreConfig {
|
|
|
1986
2018
|
* {@link HostedSchema}, or one built from `baseUrl`/`versions`/`current`/
|
|
1987
2019
|
* `layout` and the config default — is validated by `HostedSchema` itself
|
|
1988
2020
|
* (a `hosted` entry must be keyed by `hosted.name` and must not spell those
|
|
1989
|
-
* four fields beside it);
|
|
1990
|
-
* `
|
|
1991
|
-
*
|
|
1992
|
-
*
|
|
1993
|
-
*
|
|
1994
|
-
*
|
|
2021
|
+
* four fields beside it); the config `name` is required (a missing one
|
|
2022
|
+
* fails `defineConfig: name is required — …`, naming what it is for), and
|
|
2023
|
+
* it and every schema key must be simple file base names; a `catalog` is required under
|
|
2024
|
+
* `baseUrl: "schemastore"`; an empty `schemas` record is rejected; a
|
|
2025
|
+
* `catalogDir` that is `outputDir`, that is the merged catalog's own path,
|
|
2026
|
+
* or that a derived document sits directly in, is rejected (every `*.json`
|
|
2027
|
+
* file there is read as a catalog slice); and an output path (a target, a frozen file, this config's
|
|
2028
|
+
* catalog slice `<catalogDir>/<name>.json`, or the merged catalog
|
|
2029
|
+
* `catalog.json` in `catalogDir`'s parent) declared twice is rejected after
|
|
2030
|
+
* a lexical normalisation (`./`, `..`, trailing `/`) — the CLI's loader
|
|
2031
|
+
* re-checks on the resolved absolute paths. Branding the result lets a loader recognise a config
|
|
1995
2032
|
* module's default export via {@link isSchemastoreConfig}.
|
|
1996
2033
|
*
|
|
2034
|
+
* @example
|
|
2035
|
+
* ```ts
|
|
2036
|
+
* import { defineConfig } from "@effected/schemastore";
|
|
2037
|
+
* import { Schema } from "effect";
|
|
2038
|
+
*
|
|
2039
|
+
* const Config = Schema.Struct({ name: Schema.String });
|
|
2040
|
+
*
|
|
2041
|
+
* export default defineConfig({
|
|
2042
|
+
* name: "my-tool",
|
|
2043
|
+
* outputDir: "schemas",
|
|
2044
|
+
* baseUrl: "https://example.com/schemas",
|
|
2045
|
+
* schemas: { config: { schema: Config } },
|
|
2046
|
+
* });
|
|
2047
|
+
* ```
|
|
2048
|
+
*
|
|
1997
2049
|
* @public
|
|
1998
2050
|
*/
|
|
1999
2051
|
export declare const defineConfig: (input: SchemastoreConfigInput) => SchemastoreConfig;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/schemastore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Build, validate, version and publish SchemaStore-shaped Draft-07 JSON Schema documents from Effect Schema sources: document assembly, ajv strict-mode validation, structural lints, catalog entries, canonical JSON and a content-comparing emit pipeline.",
|
|
6
6
|
"keywords": [
|
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
"./package.json": "./package.json"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@effected/semver": "^0.
|
|
41
|
+
"@effected/semver": "^0.11.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
|
-
"effect": "4.0.0
|
|
44
|
+
"effect": "^4.0.0"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=24.11.0"
|