@effected/schemastore 0.16.1 → 0.17.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/README.md +2 -1
- package/SchemastoreConfig.js +33 -11
- package/index.d.ts +38 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -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/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,26 @@ 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
|
*
|
|
200
212
|
* @public
|
|
201
213
|
*/
|
|
202
214
|
const defineConfig = (input) => {
|
|
203
|
-
const
|
|
215
|
+
const raw = withoutUndefined(input);
|
|
216
|
+
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)");
|
|
217
|
+
const config = decodeOrThrow(ConfigInput, raw, "");
|
|
218
|
+
if (!SchemaVersioning.isSimpleName(config.name)) return fail(`name "${config.name}" must be a simple file base name (no separators, no whitespace)`);
|
|
204
219
|
const outputDir = trimSlashes(config.outputDir);
|
|
205
220
|
if (Object.keys(config.schemas).length === 0) return fail("at least one schema is required");
|
|
206
221
|
const defaults = {
|
|
@@ -208,13 +223,20 @@ const defineConfig = (input) => {
|
|
|
208
223
|
drift: config.drift ?? DriftPolicy.defaults.policy
|
|
209
224
|
};
|
|
210
225
|
const schemas = Object.entries(config.schemas).map(([name, entry]) => resolveEntry(name, entry, defaults, outputDir));
|
|
211
|
-
const
|
|
212
|
-
|
|
226
|
+
const catalogDir = config.catalogDir !== void 0 ? trimSlashes(config.catalogDir) : `${outputDir}/catalogs`;
|
|
227
|
+
const documents = schemas.flatMap((s) => [s.target.path, ...s.frozen.map((f) => f.path)]);
|
|
228
|
+
assertCatalogDirHoldsOnlySlices(catalogDir, outputDir, documents);
|
|
229
|
+
assertUniquePaths([
|
|
230
|
+
...documents,
|
|
231
|
+
`${catalogDir}/${config.name}.json`,
|
|
232
|
+
`${catalogDir}/../catalog.json`
|
|
233
|
+
]);
|
|
213
234
|
return {
|
|
214
235
|
[ConfigBrand]: true,
|
|
236
|
+
name: config.name,
|
|
215
237
|
outputDir,
|
|
216
238
|
onDrift: config.onDrift ?? DriftPolicy.defaults.onDrift,
|
|
217
|
-
|
|
239
|
+
catalogDir,
|
|
218
240
|
schemas
|
|
219
241
|
};
|
|
220
242
|
};
|
package/index.d.ts
CHANGED
|
@@ -1890,6 +1890,15 @@ interface SchemaEntryInput {
|
|
|
1890
1890
|
* @public
|
|
1891
1891
|
*/
|
|
1892
1892
|
interface SchemastoreConfigInput {
|
|
1893
|
+
/**
|
|
1894
|
+
* This config's identity: the base name of the catalog slice it owns
|
|
1895
|
+
* (`<catalogDir>/<name>.json`). Configs sharing a `catalogDir` must each
|
|
1896
|
+
* carry a distinct one — distinct case-insensitively, since on a
|
|
1897
|
+
* case-insensitive volume `docs` and `Docs` name one file and overwrite
|
|
1898
|
+
* each other; it must be a simple file base name (no separators, no
|
|
1899
|
+
* whitespace).
|
|
1900
|
+
*/
|
|
1901
|
+
readonly name: string;
|
|
1893
1902
|
/** The directory every derived `path` is written under; a trailing slash is trimmed. */
|
|
1894
1903
|
readonly outputDir: string;
|
|
1895
1904
|
/** The default {@link SchemaEntryInput.baseUrl} for an entry that declares none. */
|
|
@@ -1898,8 +1907,20 @@ interface SchemastoreConfigInput {
|
|
|
1898
1907
|
readonly drift?: DriftTolerance;
|
|
1899
1908
|
/** What a build does when it finds drift. Defaults to `"error"`. */
|
|
1900
1909
|
readonly onDrift?: OnDrift;
|
|
1901
|
-
/**
|
|
1902
|
-
|
|
1910
|
+
/**
|
|
1911
|
+
* The directory of catalog slices, one per config: this config writes its
|
|
1912
|
+
* own entries to `<catalogDir>/<name>.json`, and the CLI maintains the
|
|
1913
|
+
* merged `catalog.json` — every slice in the directory, united — in the
|
|
1914
|
+
* directory's parent. Defaults to `<outputDir>/catalogs`, so
|
|
1915
|
+
* the merged catalog lands at `<outputDir>/catalog.json`. Every `*.json`
|
|
1916
|
+
* file in it is read as a slice, so it holds nothing else, must not be
|
|
1917
|
+
* `outputDir` itself, and must not be the merged catalog's own path.
|
|
1918
|
+
* Every config that shares a merged catalog must share the same
|
|
1919
|
+
* `catalogDir`, under a `name` unique case-insensitively among them: two sibling directories (`schemas/catalogs`,
|
|
1920
|
+
* `schemas/more`) both merge into `schemas/catalog.json` from different
|
|
1921
|
+
* slice sets and overwrite each other — no single config can detect it.
|
|
1922
|
+
*/
|
|
1923
|
+
readonly catalogDir?: string;
|
|
1903
1924
|
/**
|
|
1904
1925
|
* The schemas to derive, keyed by file base name — the key IS the
|
|
1905
1926
|
* `name` every derived path and URL is built from, so it must be a
|
|
@@ -1952,12 +1973,14 @@ interface ResolvedSchema {
|
|
|
1952
1973
|
*/
|
|
1953
1974
|
interface SchemastoreConfig {
|
|
1954
1975
|
readonly [ConfigBrand]: true;
|
|
1976
|
+
/** This config's identity: the base name of its catalog slice. */
|
|
1977
|
+
readonly name: string;
|
|
1955
1978
|
/** The directory every derived `path` is written under, trailing slash trimmed. */
|
|
1956
1979
|
readonly outputDir: string;
|
|
1957
1980
|
/** What a build does when it finds drift. */
|
|
1958
1981
|
readonly onDrift: OnDrift;
|
|
1959
|
-
/**
|
|
1960
|
-
readonly
|
|
1982
|
+
/** The directory of catalog slices; this config's own is `<catalogDir>/<name>.json`. */
|
|
1983
|
+
readonly catalogDir: string;
|
|
1961
1984
|
/** Every schema, resolved. */
|
|
1962
1985
|
readonly schemas: ReadonlyArray<ResolvedSchema>;
|
|
1963
1986
|
}
|
|
@@ -1986,12 +2009,17 @@ interface SchemastoreConfig {
|
|
|
1986
2009
|
* {@link HostedSchema}, or one built from `baseUrl`/`versions`/`current`/
|
|
1987
2010
|
* `layout` and the config default — is validated by `HostedSchema` itself
|
|
1988
2011
|
* (a `hosted` entry must be keyed by `hosted.name` and must not spell those
|
|
1989
|
-
* four fields beside it);
|
|
1990
|
-
* `
|
|
1991
|
-
*
|
|
1992
|
-
*
|
|
1993
|
-
*
|
|
1994
|
-
*
|
|
2012
|
+
* four fields beside it); the config `name` is required (a missing one
|
|
2013
|
+
* fails `defineConfig: name is required — …`, naming what it is for), and
|
|
2014
|
+
* it and every schema key must be simple file base names; a `catalog` is required under
|
|
2015
|
+
* `baseUrl: "schemastore"`; an empty `schemas` record is rejected; a
|
|
2016
|
+
* `catalogDir` that is `outputDir`, that is the merged catalog's own path,
|
|
2017
|
+
* or that a derived document sits directly in, is rejected (every `*.json`
|
|
2018
|
+
* file there is read as a catalog slice); and an output path (a target, a frozen file, this config's
|
|
2019
|
+
* catalog slice `<catalogDir>/<name>.json`, or the merged catalog
|
|
2020
|
+
* `catalog.json` in `catalogDir`'s parent) declared twice is rejected after
|
|
2021
|
+
* a lexical normalisation (`./`, `..`, trailing `/`) — the CLI's loader
|
|
2022
|
+
* re-checks on the resolved absolute paths. Branding the result lets a loader recognise a config
|
|
1995
2023
|
* module's default export via {@link isSchemastoreConfig}.
|
|
1996
2024
|
*
|
|
1997
2025
|
* @public
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/schemastore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.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": [
|