@effected/schemastore-cli 0.9.1 → 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.
- package/ConfigLoader.js +35 -23
- package/README.md +23 -29
- package/Report.js +54 -29
- package/Runner.js +102 -63
- package/cli/execute.js +56 -20
- package/cli/flags.js +2 -2
- package/cli/program.js +2 -1
- package/main.js +1 -1
- package/package.json +3 -3
package/ConfigLoader.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, FileSystem, Path, Schema } from "effect";
|
|
1
|
+
import { Effect, FileSystem, Path, Predicate, Schema } from "effect";
|
|
2
2
|
import { isSchemastoreConfig } from "@effected/schemastore";
|
|
3
3
|
import { createJiti } from "jiti";
|
|
4
4
|
|
|
@@ -19,8 +19,9 @@ searched: Schema.Array(Schema.String) }) {
|
|
|
19
19
|
/**
|
|
20
20
|
* The config file exists but could not be turned into a `SchemastoreConfig`:
|
|
21
21
|
* the module threw on import, its default export is not a `defineConfig(...)`
|
|
22
|
-
* value,
|
|
23
|
-
*
|
|
22
|
+
* value, `outputDir`/`catalogPath` is not a string, a `schemas` element is
|
|
23
|
+
* not resolved-schema-shaped (or its `target`, `catalog`, or a `frozen`
|
|
24
|
+
* entry is not shaped), or two outputs resolve to one absolute path.
|
|
24
25
|
*
|
|
25
26
|
* @public
|
|
26
27
|
*/
|
|
@@ -34,16 +35,22 @@ var ConfigLoadError = class extends Schema.TaggedError()("ConfigLoadError", {
|
|
|
34
35
|
};
|
|
35
36
|
const jitiImport = (path) => createJiti(path, { interopDefault: true }).import(path);
|
|
36
37
|
const describeCause = (cause) => cause instanceof Error ? cause.stack ?? cause.message : String(cause);
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
const isTargetShaped = (target) => Predicate.isObject(target) && Schema.isSchema(target.schema) && typeof target.$id === "string" && typeof target.path === "string" && typeof target.published === "boolean";
|
|
39
|
+
const isCatalogEntryShaped = (catalog) => Predicate.isObject(catalog) && typeof catalog.name === "string" && typeof catalog.description === "string" && Array.isArray(catalog.fileMatch) && typeof catalog.url === "string";
|
|
40
|
+
const describeMalformed = (config) => {
|
|
41
|
+
if (typeof config.outputDir !== "string") return "outputDir is not a string";
|
|
42
|
+
if (typeof config.catalogPath !== "string") return "catalogPath is not a string";
|
|
43
|
+
if (!Array.isArray(config.schemas)) return "schemas is not an array";
|
|
44
|
+
for (const [index, schema] of config.schemas.entries()) {
|
|
45
|
+
if (!Predicate.isObject(schema) || typeof schema.name !== "string" || !Array.isArray(schema.frozen) || typeof schema.drift !== "string") return `schemas[${index}] is not a resolved schema (missing name/target/frozen/drift)`;
|
|
46
|
+
if (!isTargetShaped(schema.target)) return `schemas[${index}].target is not a SchemaTarget (missing schema/$id/path/published)`;
|
|
47
|
+
if (schema.catalog !== void 0 && !isCatalogEntryShaped(schema.catalog)) return `schemas[${index}].catalog is not a catalog entry (missing name/description/fileMatch/url)`;
|
|
48
|
+
for (const [j, frozen] of schema.frozen.entries()) if (!Predicate.isObject(frozen) || typeof frozen.version !== "string" || typeof frozen.path !== "string" || typeof frozen.url !== "string") return `schemas[${index}].frozen[${j}] is not a frozen version (missing version/path/url)`;
|
|
42
49
|
}
|
|
43
50
|
};
|
|
44
51
|
const describeDuplicatePath = (config) => {
|
|
45
52
|
const seen = /* @__PURE__ */ new Set();
|
|
46
|
-
const paths = [...config.schemas.
|
|
53
|
+
const paths = [...config.schemas.flatMap((schema) => [schema.target.path, ...schema.frozen.map((f) => f.path)]), config.catalogPath];
|
|
47
54
|
for (const p of paths) {
|
|
48
55
|
if (seen.has(p)) return `output path "${p}" is declared twice after resolution`;
|
|
49
56
|
seen.add(p);
|
|
@@ -92,25 +99,30 @@ var ConfigLoader = class ConfigLoader {
|
|
|
92
99
|
}
|
|
93
100
|
});
|
|
94
101
|
/**
|
|
95
|
-
* Resolve every relative `path` in the config (
|
|
96
|
-
*
|
|
97
|
-
*
|
|
102
|
+
* Resolve every relative `path` in the config (`outputDir`, `catalogPath`,
|
|
103
|
+
* each schema's current target, and every frozen predecessor) against
|
|
104
|
+
* `directory`; absolute paths are left alone. `defineConfig` already
|
|
105
|
+
* prefixes `outputDir` onto every target/frozen `path`, so resolving them
|
|
106
|
+
* against the config directory equals resolving against the resolved
|
|
107
|
+
* `outputDir`. The result keeps the `defineConfig` brand.
|
|
98
108
|
*/
|
|
99
109
|
static resolvePaths = Effect.fn("ConfigLoader.resolvePaths")(function* (config, directory) {
|
|
100
110
|
const path = yield* Path.Path;
|
|
101
111
|
const absolute = (p) => path.isAbsolute(p) ? p : path.resolve(directory, p);
|
|
102
112
|
return {
|
|
103
113
|
...config,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
outputDir: absolute(config.outputDir),
|
|
115
|
+
catalogPath: absolute(config.catalogPath),
|
|
116
|
+
schemas: config.schemas.map((schema) => ({
|
|
117
|
+
...schema,
|
|
118
|
+
target: {
|
|
119
|
+
...schema.target,
|
|
120
|
+
path: absolute(schema.target.path)
|
|
121
|
+
},
|
|
122
|
+
frozen: schema.frozen.map((f) => ({
|
|
123
|
+
...f,
|
|
124
|
+
path: absolute(f.path)
|
|
125
|
+
}))
|
|
114
126
|
}))
|
|
115
127
|
};
|
|
116
128
|
});
|
|
@@ -136,7 +148,7 @@ var ConfigLoader = class ConfigLoader {
|
|
|
136
148
|
path: configPath,
|
|
137
149
|
reason: "default export is not a defineConfig(...) value from @effected/schemastore"
|
|
138
150
|
}));
|
|
139
|
-
const malformed =
|
|
151
|
+
const malformed = describeMalformed(exported);
|
|
140
152
|
if (malformed !== void 0) return yield* Effect.fail(new ConfigLoadError({
|
|
141
153
|
path: configPath,
|
|
142
154
|
reason: malformed
|
package/README.md
CHANGED
|
@@ -38,37 +38,30 @@ pnpm add -D @effected/schemastore-cli @effected/schemastore effect
|
|
|
38
38
|
Create `schemastore.config.ts` (also `.mts`, `.js`, `.mjs`). The CLI finds it by walking upward from the working directory, or takes its path as a positional argument. Relative `path` values resolve against the config file's directory.
|
|
39
39
|
|
|
40
40
|
```ts
|
|
41
|
-
import { defineConfig
|
|
42
|
-
import {
|
|
41
|
+
import { defineConfig } from "@effected/schemastore";
|
|
42
|
+
import { OkfitConfig } from "./src/config-schema.js";
|
|
43
43
|
|
|
44
44
|
export default defineConfig({
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
path: "schemas/silk-release-action-5.0.0.json",
|
|
45
|
+
outputDir: "schemas",
|
|
46
|
+
baseUrl: "schemastore",
|
|
47
|
+
schemas: {
|
|
48
|
+
okfit: {
|
|
49
|
+
schema: OkfitConfig,
|
|
50
|
+
versions: ["1.0"],
|
|
52
51
|
published: true,
|
|
53
|
-
|
|
54
|
-
}),
|
|
55
|
-
],
|
|
56
|
-
catalog: [
|
|
57
|
-
{
|
|
58
|
-
name: "silk-release-action",
|
|
59
|
-
description: "Structured output of the silk-release GitHub Action",
|
|
60
|
-
fileMatch: ["silk-release-output.json"],
|
|
61
|
-
baseUrl: "https://raw.githubusercontent.com/savvy-web/silk-release-action/main/schemas",
|
|
62
|
-
path: "schemas/catalog-entry.json",
|
|
52
|
+
catalog: { description: "okfit configuration", fileMatch: ["okfit.toml", ".okfit.toml"] },
|
|
63
53
|
},
|
|
64
|
-
|
|
65
|
-
drift: { policy: "semantic", onDrift: "error" },
|
|
54
|
+
},
|
|
66
55
|
});
|
|
67
56
|
```
|
|
68
57
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
-
|
|
58
|
+
A second label is appended to `versions` only once the first is published
|
|
59
|
+
and its file already exists on disk — see "The lifecycle" in the
|
|
60
|
+
`building-schemastore-schemas` skill's `drift-and-versioning.md` reference.
|
|
61
|
+
A first-run config should declare a single label; naming an extra one before
|
|
62
|
+
its file exists fails the build with `FrozenVersionMissingError`.
|
|
63
|
+
|
|
64
|
+
`schemas` is keyed by file base name — the key IS the schema's `name`, and `$id`, the write `path` and every catalog URL derive from it, `outputDir` and `baseUrl`; there is no `$id` override. `versions` lists every label the catalog advertises; `current` (default: the newest) is the one generated at `path`/`$id`, and every other label becomes a **frozen** file the CLI verifies still exists on disk but never regenerates — advertising a frozen label with nothing on disk fails the build before anything is written. `published` (default `false`) marks a version other people already depend on. `baseUrl: "schemastore"` expands `$id` to `https://json.schemastore.org/…` and the catalog URL to `https://www.schemastore.org/…`; any other value is one `https://` base for both. `outputDir` and `onDrift` are top-level only; `baseUrl` and `drift` are top-level defaults an entry may override. `catalog` is required under `baseUrl: "schemastore"` and optional under a custom host. Every schema's declared `catalog` entry lands in ONE file at `catalogPath` (default `<outputDir>/catalog.json`) — never one file per schema.
|
|
72
65
|
|
|
73
66
|
Then add two scripts:
|
|
74
67
|
|
|
@@ -88,10 +81,11 @@ schemastore build [config] [--drift=strict|semantic|allow] [--on-drift=error|war
|
|
|
88
81
|
schemastore check [config] [--drift=strict|semantic|allow] [--on-drift=error|warn] [--force] [--format=human|json]
|
|
89
82
|
```
|
|
90
83
|
|
|
91
|
-
-
|
|
92
|
-
- `
|
|
93
|
-
-
|
|
94
|
-
- `--
|
|
84
|
+
- Before anything is generated, every advertised frozen version is checked for existence — a schema that advertises a label with nothing on disk fails with `FrozenVersionMissingError` (exit `1`) and nothing is written.
|
|
85
|
+
- `build` generates every schema, runs the gates (structural lints and ajv strict mode), applies the drift policy, and writes what passes — content-compared, so unchanged files are untouched — along with the single `catalog.json` every declared catalog entry lands in.
|
|
86
|
+
- `check` is the identical walk with no writes: it reports what `build` would do under the same flags and exits under the same conditions. It is the CI gate, so it also fails (exit `1`) whenever a build would write anything — a committed schema or catalog file that differs from what the config generates, or is missing, is stale; run `schemastore build` and commit the result.
|
|
87
|
+
- `--drift` and `--on-drift` override the config's `drift` block for one run; `--force` is sugar for `--drift=allow` and nothing else — combined with an explicit non-`allow` `--drift` it is a usage error (exit 64), not a precedence question; `--force --drift=allow` is accepted.
|
|
88
|
+
- `--format=json` emits one JSON document on stdout (config path, per-schema outcome and effective drift tolerance, the single catalog entry's outcome, and `drift: { onDrift, policy? }` — `policy` present only when a flag forced one tolerance over every schema's own); human text moves to stderr.
|
|
95
89
|
- When `GITHUB_STEP_SUMMARY` is set, both commands append a markdown summary table.
|
|
96
90
|
|
|
97
91
|
An unpublished schema is never drift: a contract change at a pinned but unpublished version rewrites the file in place.
|
|
@@ -101,7 +95,7 @@ An unpublished schema is never drift: a contract change at a pinned but unpublis
|
|
|
101
95
|
| code | meaning |
|
|
102
96
|
| ---- | -------------------------------------------------------------------------- |
|
|
103
97
|
| 0 | success, including drift under `onDrift: warn` |
|
|
104
|
-
| 1 | drift under `onDrift: error`, a gate failure, or — for `check` — any document `build` would write |
|
|
98
|
+
| 1 | drift under `onDrift: error` (the error lists one line per drifting schema: `$id`, change, current and next version), a gate failure, a missing frozen version (`FrozenVersionMissingError`), or — for `check` — any document `build` would write |
|
|
105
99
|
| 2 | config not found, failed to load, or failed `SchemastoreConfig` validation |
|
|
106
100
|
| 3 | infrastructure failure |
|
|
107
101
|
| 64 | usage error |
|
package/Report.js
CHANGED
|
@@ -3,32 +3,36 @@ const findingLine = (finding) => ` ${finding.label} at "${finding.path}": ${fin
|
|
|
3
3
|
const blockingCount = (findings) => findings.filter((finding) => finding.severity === "warning").length;
|
|
4
4
|
const suggestionClause = (schema) => schema.nextVersion !== void 0 && schema.nextVersion !== schema.version ? ` → suggest ${schema.nextVersion}` : "";
|
|
5
5
|
const publishedClause = (schema) => schema.version !== void 0 ? ` at published ${schema.version}` : "";
|
|
6
|
+
const policyClause = (schema, report) => report.policy === void 0 ? ` [policy ${schema.policy}]` : "";
|
|
7
|
+
const frozenClause = (schema) => schema.frozen.length > 0 ? ` (frozen: ${schema.frozen.join(", ")})` : "";
|
|
6
8
|
const schemaLines = (schema, report) => {
|
|
9
|
+
const suffix = `${policyClause(schema, report)}${frozenClause(schema)}`;
|
|
7
10
|
switch (schema.outcome) {
|
|
8
|
-
case "written": return [`written (${schema.change}) ${schema.path}`];
|
|
9
|
-
case "unchanged": return [`unchanged ${schema.path}`];
|
|
10
|
-
case "would-write": return [`would write (${schema.change}) ${schema.path}`];
|
|
11
|
-
case "drift": return [`DRIFT ${schema.change}${publishedClause(schema)}${suggestionClause(schema)} — ${schema.path}`];
|
|
12
|
-
case "held": return [`held (${report.gateFailed ? "gate failed elsewhere" : "drift elsewhere"}) ${schema.path}`];
|
|
13
|
-
case "gate-failed": return [`GATE FAILED ${schema.path} (${blockingCount(schema.findings)} blocking finding(s))`, ...schema.findings.map(findingLine)];
|
|
11
|
+
case "written": return [`written (${schema.change}) ${schema.path}${suffix}`];
|
|
12
|
+
case "unchanged": return [`unchanged ${schema.path}${suffix}`];
|
|
13
|
+
case "would-write": return [`would write (${schema.change}) ${schema.path}${suffix}`];
|
|
14
|
+
case "drift": return [`DRIFT ${schema.change}${publishedClause(schema)}${suggestionClause(schema)} — ${schema.path}${suffix}`];
|
|
15
|
+
case "held": return [`held (${report.gateFailed ? "gate failed elsewhere" : "drift elsewhere"}) ${schema.path}${suffix}`];
|
|
16
|
+
case "gate-failed": return [`GATE FAILED ${schema.path}${suffix} (${blockingCount(schema.findings)} blocking finding(s))`, ...schema.findings.map(findingLine)];
|
|
14
17
|
default: return schema.outcome;
|
|
15
18
|
}
|
|
16
19
|
};
|
|
17
20
|
const catalogLine = (entry) => {
|
|
18
21
|
switch (entry.outcome) {
|
|
19
|
-
case "written": return `written catalog ${entry.path}`;
|
|
20
|
-
case "unchanged": return `unchanged catalog ${entry.path}`;
|
|
21
|
-
case "would-write": return `would write catalog ${entry.path}`;
|
|
22
|
-
case "held": return `held catalog ${entry.path}`;
|
|
22
|
+
case "written": return `written catalog ${entry.path} (${entry.entries} entries)`;
|
|
23
|
+
case "unchanged": return `unchanged catalog ${entry.path} (${entry.entries} entries)`;
|
|
24
|
+
case "would-write": return `would write catalog ${entry.path} (${entry.entries} entries)`;
|
|
25
|
+
case "held": return `held catalog ${entry.path} (${entry.entries} entries)`;
|
|
23
26
|
default: return entry.outcome;
|
|
24
27
|
}
|
|
25
28
|
};
|
|
29
|
+
const driftClause = (report) => `drift ${report.policy !== void 0 ? `${report.policy} (flag)` : "per schema (config)"}, on-drift ${report.onDrift}`;
|
|
26
30
|
const summaryLine = (report) => {
|
|
27
31
|
const written = report.schemas.filter((schema) => schema.outcome === "written").length;
|
|
28
32
|
const unchanged = report.schemas.filter((schema) => schema.outcome === "unchanged").length;
|
|
29
33
|
const drift = report.schemas.filter((schema) => schema.verdict === "drift").length;
|
|
30
34
|
const gateFailed = report.schemas.filter((schema) => schema.outcome === "gate-failed").length;
|
|
31
|
-
return `${report.schemas.length} schema(s): ${written} written, ${unchanged} unchanged, ${drift} drift, ${gateFailed} gate failed —
|
|
35
|
+
return `${report.schemas.length} schema(s): ${written} written, ${unchanged} unchanged, ${drift} drift, ${gateFailed} gate failed — ${driftClause(report)}`;
|
|
32
36
|
};
|
|
33
37
|
const warningLine = (schema, report) => `warning: DRIFT ${schema.change}${publishedClause(schema)} ${report.mode === "build" ? "written" : "would write"} under --on-drift=warn — ${schema.path}`;
|
|
34
38
|
const tableRow = (columns) => `| ${columns.join(" | ")} |`;
|
|
@@ -40,11 +44,19 @@ const tableRow = (columns) => `| ${columns.join(" | ")} |`;
|
|
|
40
44
|
*/
|
|
41
45
|
var Report = class {
|
|
42
46
|
constructor() {}
|
|
43
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* stdout lines.
|
|
49
|
+
*
|
|
50
|
+
* @remarks
|
|
51
|
+
* The summary's `drift` count is the number of schemas whose VERDICT is
|
|
52
|
+
* `"drift"`, independent of `written`/`unchanged`: under
|
|
53
|
+
* `onDrift: "warn"` a drifting schema is written AND counted as drift,
|
|
54
|
+
* so the four counts need not sum to the schema total.
|
|
55
|
+
*/
|
|
44
56
|
static human(report) {
|
|
45
57
|
const lines = [];
|
|
46
58
|
for (const schema of report.schemas) lines.push(...schemaLines(schema, report));
|
|
47
|
-
|
|
59
|
+
if (report.catalog !== void 0) lines.push(catalogLine(report.catalog));
|
|
48
60
|
lines.push(summaryLine(report));
|
|
49
61
|
return lines;
|
|
50
62
|
}
|
|
@@ -54,7 +66,7 @@ var Report = class {
|
|
|
54
66
|
* would be) written, so there is no drift to warn about.
|
|
55
67
|
*/
|
|
56
68
|
static warnings(report) {
|
|
57
|
-
if (report.
|
|
69
|
+
if (report.onDrift !== "warn" || report.gateFailed) return [];
|
|
58
70
|
return report.schemas.filter((schema) => schema.verdict === "drift").map((schema) => warningLine(schema, report));
|
|
59
71
|
}
|
|
60
72
|
/** One JSON document, stable key order. */
|
|
@@ -63,20 +75,21 @@ var Report = class {
|
|
|
63
75
|
mode: report.mode,
|
|
64
76
|
configPath: report.configPath,
|
|
65
77
|
drift: {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
source: report.drift.source
|
|
78
|
+
onDrift: report.onDrift,
|
|
79
|
+
...report.policy !== void 0 ? { policy: report.policy } : {}
|
|
69
80
|
},
|
|
70
81
|
schemas: report.schemas.map((schema) => ({
|
|
71
82
|
$id: schema.$id,
|
|
72
83
|
path: schema.path,
|
|
73
|
-
|
|
84
|
+
name: schema.name,
|
|
74
85
|
...schema.version !== void 0 ? { version: schema.version } : {},
|
|
75
86
|
published: schema.published,
|
|
76
87
|
change: schema.change,
|
|
77
88
|
verdict: schema.verdict,
|
|
89
|
+
policy: schema.policy,
|
|
78
90
|
outcome: schema.outcome,
|
|
79
91
|
...schema.nextVersion !== void 0 ? { nextVersion: schema.nextVersion } : {},
|
|
92
|
+
...schema.frozen.length > 0 ? { frozen: schema.frozen } : {},
|
|
80
93
|
findings: schema.findings.map((finding) => ({
|
|
81
94
|
source: finding.source,
|
|
82
95
|
severity: finding.severity,
|
|
@@ -85,11 +98,11 @@ var Report = class {
|
|
|
85
98
|
message: finding.message
|
|
86
99
|
}))
|
|
87
100
|
})),
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
outcome:
|
|
92
|
-
}
|
|
101
|
+
...report.catalog !== void 0 ? { catalog: {
|
|
102
|
+
path: report.catalog.path,
|
|
103
|
+
entries: report.catalog.entries,
|
|
104
|
+
outcome: report.catalog.outcome
|
|
105
|
+
} } : {},
|
|
93
106
|
drifted: report.drifted,
|
|
94
107
|
gateFailed: report.gateFailed,
|
|
95
108
|
wrote: report.wrote
|
|
@@ -102,6 +115,7 @@ var Report = class {
|
|
|
102
115
|
lines.push(tableRow([
|
|
103
116
|
"schema",
|
|
104
117
|
"version",
|
|
118
|
+
"frozen",
|
|
105
119
|
"published",
|
|
106
120
|
"change",
|
|
107
121
|
"outcome"
|
|
@@ -110,26 +124,37 @@ var Report = class {
|
|
|
110
124
|
"---",
|
|
111
125
|
"---",
|
|
112
126
|
"---",
|
|
127
|
+
"---",
|
|
113
128
|
"---"
|
|
114
129
|
]));
|
|
115
130
|
for (const schema of report.schemas) lines.push(tableRow([
|
|
116
|
-
schema.name
|
|
131
|
+
schema.name,
|
|
117
132
|
schema.version ?? "",
|
|
133
|
+
schema.frozen.join(", "),
|
|
118
134
|
schema.published ? "yes" : "no",
|
|
119
135
|
schema.change,
|
|
120
136
|
schema.outcome
|
|
121
137
|
]));
|
|
122
|
-
if (report.catalog
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
138
|
+
if (report.catalog !== void 0) lines.push("", tableRow([
|
|
139
|
+
"catalog",
|
|
140
|
+
"entries",
|
|
141
|
+
"outcome"
|
|
142
|
+
]), tableRow([
|
|
143
|
+
"---",
|
|
144
|
+
"---",
|
|
145
|
+
"---"
|
|
146
|
+
]), tableRow([
|
|
147
|
+
report.catalog.path,
|
|
148
|
+
String(report.catalog.entries),
|
|
149
|
+
report.catalog.outcome
|
|
150
|
+
]));
|
|
126
151
|
lines.push("");
|
|
127
152
|
if (report.gateFailed) {
|
|
128
153
|
const failed = report.schemas.filter((schema) => schema.outcome === "gate-failed").length;
|
|
129
154
|
lines.push(`**Gate:** ${failed} schema(s) failed`);
|
|
130
155
|
} else if (report.drifted) {
|
|
131
156
|
const drifted = report.schemas.filter((schema) => schema.verdict === "drift").length;
|
|
132
|
-
lines.push(`**Drift:** ${drifted} schema(s) drifted
|
|
157
|
+
lines.push(`**Drift:** ${drifted} schema(s) drifted — ${driftClause(report)}`);
|
|
133
158
|
} else lines.push("**Drift:** none");
|
|
134
159
|
lines.push("");
|
|
135
160
|
return lines.join("\n");
|
package/Runner.js
CHANGED
|
@@ -1,45 +1,73 @@
|
|
|
1
|
-
import { Effect, FileSystem, Path, Schema } from "effect";
|
|
1
|
+
import { Effect, FileSystem, Option, Path, Schema } from "effect";
|
|
2
2
|
import { CanonicalJson, CatalogEntry, DriftPolicy, SchemaPipeline, SchemaVersioning } from "@effected/schemastore";
|
|
3
3
|
|
|
4
4
|
//#region src/Runner.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Indicates that one or more schemas advertise a version label (via
|
|
7
|
+
* {@link ResolvedSchema.frozen}) whose file is missing on disk. Raised by
|
|
8
|
+
* {@link Runner.run} before anything is generated — a build must never
|
|
9
|
+
* publish a catalog pointing a frozen label at a 404. Every miss is
|
|
10
|
+
* collected and reported at once, not just the first.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
var FrozenVersionMissingError = class extends Schema.TaggedError()("FrozenVersionMissingError", {
|
|
15
|
+
/** One entry per schema/version whose frozen file is missing or not a file. */
|
|
16
|
+
missing: Schema.Array(Schema.Struct({
|
|
17
|
+
/** The schema's key in the config. */
|
|
18
|
+
name: Schema.String,
|
|
19
|
+
/** The missing frozen version label. */
|
|
20
|
+
version: Schema.String,
|
|
21
|
+
/** The path that does not exist. */
|
|
22
|
+
path: Schema.String
|
|
23
|
+
})) }) {
|
|
24
|
+
get message() {
|
|
25
|
+
const lines = this.missing.map((entry) => ` schema "${entry.name}" version ${entry.version}: ${entry.path}`);
|
|
26
|
+
return `${this.missing.length} frozen version(s) advertised but not on disk; nothing was written.\n${lines.join("\n")}`;
|
|
27
|
+
}
|
|
15
28
|
};
|
|
16
|
-
const
|
|
29
|
+
const pipelineOptions = { contractChanges: "allow" };
|
|
30
|
+
const orNone = (read) => read.pipe(Effect.map(Option.some), Effect.catchIf((error) => error.reason._tag === "NotFound", () => Effect.succeed(Option.none())));
|
|
31
|
+
const pendingOutcome = (wouldWrite, refused) => !wouldWrite ? "unchanged" : refused ? "held" : "would-write";
|
|
32
|
+
const parsesEqual = (existing, text) => {
|
|
17
33
|
try {
|
|
18
|
-
return
|
|
34
|
+
return CanonicalJson.equals(JSON.parse(existing), JSON.parse(text));
|
|
19
35
|
} catch {
|
|
20
36
|
return false;
|
|
21
37
|
}
|
|
22
38
|
};
|
|
23
39
|
/**
|
|
24
|
-
* The shared `build` / `check` walk:
|
|
25
|
-
* {@link DriftPolicy} over
|
|
26
|
-
* `SchemaPipeline.run` only when
|
|
40
|
+
* The shared `build` / `check` walk: verify every advertised frozen version
|
|
41
|
+
* exists, classify every current target through {@link DriftPolicy} over
|
|
42
|
+
* `SchemaPipeline.check`, then write through `SchemaPipeline.run` only when
|
|
43
|
+
* nothing is refused.
|
|
27
44
|
*
|
|
28
45
|
* @remarks
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* predicate (`mode === "build" && !refused`) gates every write, schemas
|
|
36
|
-
* and catalog entries alike. Under `onDrift: "warn"` drifting schemas are
|
|
37
|
-
* written and keep their `"drift"` verdict for the renderer to shout
|
|
38
|
-
* about.
|
|
46
|
+
* **The frozen check runs first, before anything is generated.** Every
|
|
47
|
+
* schema's {@link ResolvedSchema.frozen} versions are walked, and every miss
|
|
48
|
+
* is reported at once: a build fails typed with
|
|
49
|
+
* {@link FrozenVersionMissingError} listing every label with no file on disk
|
|
50
|
+
* — nothing is written — a catalog that points a label at a 404 is a worse
|
|
51
|
+
* failure than an early refusal.
|
|
39
52
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
53
|
+
* **Drift is classified per schema, under that schema's own
|
|
54
|
+
* {@link ResolvedSchema.drift} tolerance — unless `options.policy` is set,
|
|
55
|
+
* in which case it overrides every schema's own for this run** (the `--drift`
|
|
56
|
+
* / `--force` flags). A build writes NOTHING when any schema fails its gate,
|
|
57
|
+
* or when any schema drifts under `onDrift: "error"` — a partial write would
|
|
58
|
+
* leave a repository half-bumped. Every otherwise-writable schema then
|
|
59
|
+
* reports `held`, so a reader sees why a clean schema was not written — in
|
|
60
|
+
* both modes, since `check` reports what `build` would do under the same
|
|
61
|
+
* flags. Both modes share one `SchemaFile`; the single `writing` predicate
|
|
62
|
+
* (`mode === "build" && !refused`) gates every write, schemas and the
|
|
63
|
+
* catalog file alike. Under `onDrift: "warn"` drifting schemas are written
|
|
64
|
+
* and keep their `"drift"` verdict for the renderer to shout about.
|
|
65
|
+
*
|
|
66
|
+
* **Every catalog entry the config declares lands in ONE file** at
|
|
67
|
+
* `config.catalogPath` — never one file per schema — serialized canonically
|
|
68
|
+
* and compared by parsed content against the file on disk, written only
|
|
69
|
+
* when different and only when the run is writing. The report omits
|
|
70
|
+
* `catalog` entirely when no schema declared one.
|
|
43
71
|
*
|
|
44
72
|
* @public
|
|
45
73
|
*/
|
|
@@ -48,78 +76,89 @@ var Runner = class {
|
|
|
48
76
|
static run = Effect.fn("Runner.run")(function* (config, options) {
|
|
49
77
|
const fs = yield* FileSystem.FileSystem;
|
|
50
78
|
const path = yield* Path.Path;
|
|
51
|
-
const
|
|
79
|
+
const missing = [];
|
|
80
|
+
for (const schema of config.schemas) for (const frozen of schema.frozen) {
|
|
81
|
+
const info = yield* orNone(fs.stat(frozen.path));
|
|
82
|
+
if (Option.isNone(info) || info.value.type !== "File") missing.push({
|
|
83
|
+
name: schema.name,
|
|
84
|
+
version: frozen.version,
|
|
85
|
+
path: frozen.path
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (missing.length > 0) return yield* Effect.fail(new FrozenVersionMissingError({ missing }));
|
|
89
|
+
const targets = config.schemas.map((schema) => schema.target);
|
|
90
|
+
const checks = yield* SchemaPipeline.check(targets, pipelineOptions);
|
|
52
91
|
const gateFailed = checks.some((check) => check.blocked);
|
|
53
92
|
const classified = checks.map((check, i) => {
|
|
54
|
-
const
|
|
93
|
+
const schema = config.schemas[i];
|
|
94
|
+
const target = schema.target;
|
|
95
|
+
const policy = options.policy ?? schema.drift;
|
|
55
96
|
return {
|
|
97
|
+
schema,
|
|
56
98
|
target,
|
|
57
99
|
check,
|
|
58
100
|
verdict: DriftPolicy.classify({
|
|
59
101
|
published: target.published,
|
|
60
102
|
change: check.change
|
|
61
|
-
},
|
|
103
|
+
}, policy),
|
|
104
|
+
policy,
|
|
62
105
|
nextVersion: target.version !== void 0 && check.change === "contract" && SchemaVersioning.isPinned(target.version) ? SchemaVersioning.next(target.version, "contract") : void 0
|
|
63
106
|
};
|
|
64
107
|
});
|
|
65
108
|
const drifted = classified.some((entry) => entry.verdict === "drift");
|
|
66
|
-
const refused = gateFailed || drifted && options.
|
|
109
|
+
const refused = gateFailed || drifted && options.onDrift === "error";
|
|
67
110
|
const writing = options.mode === "build" && !refused;
|
|
68
|
-
const written = writing ? yield* SchemaPipeline.run(
|
|
111
|
+
const written = writing ? yield* SchemaPipeline.run(targets, pipelineOptions).pipe(Effect.catchTags({
|
|
69
112
|
SchemaGateError: (error) => Effect.die(error),
|
|
70
113
|
SchemaContractChangeError: (error) => Effect.die(error)
|
|
71
114
|
})) : void 0;
|
|
72
|
-
const schemas = classified.map(({ target, check, verdict, nextVersion }, i) => {
|
|
73
|
-
const outcome = check.blocked ? "gate-failed" : written !== void 0 ? written[i].outcome : verdict === "drift" ? "drift" :
|
|
115
|
+
const schemas = classified.map(({ schema, target, check, verdict, policy, nextVersion }, i) => {
|
|
116
|
+
const outcome = check.blocked ? "gate-failed" : written !== void 0 ? written[i].outcome : verdict === "drift" ? "drift" : pendingOutcome(check.wouldWrite, refused);
|
|
74
117
|
return {
|
|
75
118
|
$id: target.$id,
|
|
76
119
|
path: target.path,
|
|
120
|
+
name: schema.name,
|
|
77
121
|
published: target.published,
|
|
78
122
|
change: check.change,
|
|
79
123
|
verdict,
|
|
124
|
+
policy,
|
|
80
125
|
outcome,
|
|
81
126
|
findings: check.findings,
|
|
82
|
-
|
|
127
|
+
frozen: schema.frozen.map((frozen) => frozen.version),
|
|
83
128
|
...target.version !== void 0 ? { version: target.version } : {},
|
|
84
129
|
...nextVersion !== void 0 ? { nextVersion } : {}
|
|
85
130
|
};
|
|
86
131
|
});
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const text = yield*
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
name,
|
|
98
|
-
path: file,
|
|
99
|
-
outcome: refused ? "held" : "would-write"
|
|
100
|
-
});
|
|
101
|
-
else {
|
|
102
|
-
yield* fs.makeDirectory(path.dirname(file), { recursive: true });
|
|
103
|
-
yield* fs.writeFileString(file, text);
|
|
104
|
-
catalog.push({
|
|
105
|
-
name,
|
|
106
|
-
path: file,
|
|
107
|
-
outcome: "written"
|
|
108
|
-
});
|
|
132
|
+
const entries = config.schemas.flatMap((schema) => schema.catalog !== void 0 ? [schema.catalog] : []);
|
|
133
|
+
let catalog;
|
|
134
|
+
if (entries.length > 0) {
|
|
135
|
+
const text = yield* CanonicalJson.serialize(entries.map((entry) => Schema.encodeSync(CatalogEntry)(entry)));
|
|
136
|
+
const existing = yield* orNone(fs.readFileString(config.catalogPath));
|
|
137
|
+
const same = Option.isSome(existing) && parsesEqual(existing.value, text);
|
|
138
|
+
const outcome = writing && !same ? "written" : pendingOutcome(!same, refused);
|
|
139
|
+
if (outcome === "written") {
|
|
140
|
+
yield* fs.makeDirectory(path.dirname(config.catalogPath), { recursive: true });
|
|
141
|
+
yield* fs.writeFileString(config.catalogPath, text);
|
|
109
142
|
}
|
|
143
|
+
catalog = {
|
|
144
|
+
path: config.catalogPath,
|
|
145
|
+
entries: entries.length,
|
|
146
|
+
outcome
|
|
147
|
+
};
|
|
110
148
|
}
|
|
111
149
|
return {
|
|
112
150
|
mode: options.mode,
|
|
113
151
|
configPath: options.configPath,
|
|
114
|
-
|
|
152
|
+
onDrift: options.onDrift,
|
|
153
|
+
...options.policy !== void 0 ? { policy: options.policy } : {},
|
|
115
154
|
schemas,
|
|
116
|
-
catalog,
|
|
155
|
+
...catalog !== void 0 ? { catalog } : {},
|
|
117
156
|
drifted,
|
|
118
157
|
gateFailed,
|
|
119
|
-
wrote: schemas.some((s) => s.outcome === "written") || catalog
|
|
158
|
+
wrote: schemas.some((s) => s.outcome === "written") || catalog?.outcome === "written"
|
|
120
159
|
};
|
|
121
160
|
});
|
|
122
161
|
};
|
|
123
162
|
|
|
124
163
|
//#endregion
|
|
125
|
-
export { Runner };
|
|
164
|
+
export { FrozenVersionMissingError, Runner };
|
package/cli/execute.js
CHANGED
|
@@ -7,15 +7,30 @@ import { Console, Effect, Option, Schema } from "effect";
|
|
|
7
7
|
import { SchemaFile, SchemaValidator } from "@effected/schemastore";
|
|
8
8
|
|
|
9
9
|
//#region src/cli/execute.ts
|
|
10
|
+
const DriftedSchema = Schema.Struct({
|
|
11
|
+
$id: Schema.String,
|
|
12
|
+
change: Schema.Literals([
|
|
13
|
+
"none",
|
|
14
|
+
"created",
|
|
15
|
+
"annotations",
|
|
16
|
+
"contract"
|
|
17
|
+
]),
|
|
18
|
+
version: Schema.optionalKey(Schema.String),
|
|
19
|
+
nextVersion: Schema.optionalKey(Schema.String)
|
|
20
|
+
});
|
|
10
21
|
/**
|
|
11
22
|
* A published schema drifted under `onDrift: "error"`, so nothing was
|
|
12
23
|
* written. Exit `1`.
|
|
13
24
|
*
|
|
14
25
|
* @public
|
|
15
26
|
*/
|
|
16
|
-
var DriftError = class extends Schema.TaggedError()("DriftError", {
|
|
27
|
+
var DriftError = class extends Schema.TaggedError()("DriftError", { drifted: Schema.Array(DriftedSchema) }) {
|
|
28
|
+
get count() {
|
|
29
|
+
return this.drifted.length;
|
|
30
|
+
}
|
|
17
31
|
get message() {
|
|
18
|
-
|
|
32
|
+
const lines = this.drifted.map((s) => ` ${s.$id}: ${s.change}${s.version !== void 0 ? ` at published ${s.version}` : ""}${s.nextVersion !== void 0 ? ` → suggest ${s.nextVersion}` : ""}`);
|
|
33
|
+
return `${this.count} published schema(s) drifted; nothing was written.\n${lines.join("\n")}\nBump the drifting versions in the config, or re-run with --force to write anyway.`;
|
|
19
34
|
}
|
|
20
35
|
};
|
|
21
36
|
/**
|
|
@@ -40,11 +55,23 @@ var StaleError = class extends Schema.TaggedError()("StaleError", { count: Schem
|
|
|
40
55
|
return `${this.count} document(s) are stale; run \`schemastore build\` and commit the result.`;
|
|
41
56
|
}
|
|
42
57
|
};
|
|
43
|
-
|
|
58
|
+
/**
|
|
59
|
+
* `--force` (shorthand for `--drift=allow`) was combined with an explicit
|
|
60
|
+
* `--drift` that is not `allow`. Contradictory, so refused as a usage
|
|
61
|
+
* error rather than silently resolving to `allow`. Exit `64`.
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
var ConflictingFlagsError = class extends Schema.TaggedError()("ConflictingFlagsError", { policy: Schema.String }) {
|
|
66
|
+
get message() {
|
|
67
|
+
return `--force conflicts with --drift=${this.policy}: --force means --drift=allow`;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const effectiveDrift = (config, input) => {
|
|
71
|
+
const forced = input.force ? "allow" : Option.getOrUndefined(input.drift);
|
|
44
72
|
return {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
source: input.force || Option.isSome(input.drift) || Option.isSome(input.onDrift) ? "flag" : "config"
|
|
73
|
+
onDrift: Option.getOrElse(input.onDrift, () => config.onDrift),
|
|
74
|
+
...forced !== void 0 ? { policy: forced } : {}
|
|
48
75
|
};
|
|
49
76
|
};
|
|
50
77
|
const emit = Effect.fn("schemastore.emit")(function* (report, format) {
|
|
@@ -58,29 +85,33 @@ const emit = Effect.fn("schemastore.emit")(function* (report, format) {
|
|
|
58
85
|
* Run one `build` or `check`.
|
|
59
86
|
*
|
|
60
87
|
* @remarks
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* `
|
|
88
|
+
* Before anything is loaded, `--force` combined with an explicit `--drift`
|
|
89
|
+
* other than `allow` short-circuits with `ConflictingFlagsError` at exit
|
|
90
|
+
* `64` — a usage error, not a run outcome. Otherwise loads the config,
|
|
91
|
+
* applies the flag overrides, runs the shared walk, emits the report in the
|
|
92
|
+
* requested format, appends the step summary, and fails typed —
|
|
93
|
+
* `GateError`, then `DriftError`, then (for `check` only) `StaleError`,
|
|
94
|
+
* each carrying exit `1` — when the report says the run refused to write
|
|
95
|
+
* or, under `check`, that a build would write. `SchemaFile` is built here
|
|
96
|
+
* over the environment's `FileSystem`; the validator is `deps.validator` or
|
|
97
|
+
* the real engine.
|
|
68
98
|
*
|
|
69
99
|
* @public
|
|
70
100
|
*/
|
|
71
101
|
const execute = Effect.fn("schemastore.execute")(function* (mode, input, deps) {
|
|
102
|
+
if (input.force && Option.isSome(input.drift) && input.drift.value !== "allow") return yield* Effect.fail(CliRuntime.reported(new ConflictingFlagsError({ policy: input.drift.value }), 64));
|
|
72
103
|
const loaded = yield* ConfigLoader.load({
|
|
73
104
|
cwd: deps.cwd,
|
|
74
105
|
...Option.isSome(input.config) ? { explicit: input.config.value } : {},
|
|
75
106
|
...deps.importModule !== void 0 ? { importModule: deps.importModule } : {}
|
|
76
107
|
});
|
|
77
|
-
const drift = effectiveDrift(loaded.config
|
|
108
|
+
const drift = effectiveDrift(loaded.config, input);
|
|
78
109
|
if (input.force) yield* Effect.logWarning(`--force: drift policy is allow for this run; a published document ${mode === "check" ? "would be" : "may be"} rewritten in place, which breaks every consumer pinned to its URL.`);
|
|
79
110
|
const report = yield* Runner.run(loaded.config, {
|
|
80
111
|
mode,
|
|
81
112
|
configPath: loaded.path,
|
|
82
|
-
drift
|
|
83
|
-
}).pipe(Effect.provide(SchemaFile.layer), Effect.provide(deps.validator ?? SchemaValidator.layer));
|
|
113
|
+
...drift
|
|
114
|
+
}).pipe(Effect.provide(SchemaFile.layer), Effect.provide(deps.validator ?? SchemaValidator.layer), Effect.catchTag("FrozenVersionMissingError", (error) => Effect.fail(CliRuntime.reported(error, 1))));
|
|
84
115
|
yield* emit(report, input.format);
|
|
85
116
|
yield* StepSummary.append(Report.markdown(report));
|
|
86
117
|
if (report.gateFailed) {
|
|
@@ -88,14 +119,19 @@ const execute = Effect.fn("schemastore.execute")(function* (mode, input, deps) {
|
|
|
88
119
|
return yield* Effect.fail(CliRuntime.reported(new GateError({ count }), 1));
|
|
89
120
|
}
|
|
90
121
|
if (report.drifted && drift.onDrift === "error") {
|
|
91
|
-
const
|
|
92
|
-
|
|
122
|
+
const drifted = report.schemas.filter((schema) => schema.verdict === "drift").map((schema) => ({
|
|
123
|
+
$id: schema.$id,
|
|
124
|
+
change: schema.change,
|
|
125
|
+
...schema.version !== void 0 ? { version: schema.version } : {},
|
|
126
|
+
...schema.nextVersion !== void 0 ? { nextVersion: schema.nextVersion } : {}
|
|
127
|
+
}));
|
|
128
|
+
return yield* Effect.fail(CliRuntime.reported(new DriftError({ drifted }), 1));
|
|
93
129
|
}
|
|
94
130
|
if (mode === "check") {
|
|
95
|
-
const count = report.schemas.filter((schema) => schema.outcome === "would-write").length + report.catalog
|
|
131
|
+
const count = report.schemas.filter((schema) => schema.outcome === "would-write").length + (report.catalog?.outcome === "would-write" ? 1 : 0);
|
|
96
132
|
if (count > 0) return yield* Effect.fail(CliRuntime.reported(new StaleError({ count }), 1));
|
|
97
133
|
}
|
|
98
134
|
});
|
|
99
135
|
|
|
100
136
|
//#endregion
|
|
101
|
-
export { DriftError, GateError, StaleError, execute };
|
|
137
|
+
export { ConflictingFlagsError, DriftError, GateError, StaleError, execute };
|
package/cli/flags.js
CHANGED
|
@@ -17,13 +17,13 @@ const driftFlag = Flag.Literals("drift", [
|
|
|
17
17
|
"strict",
|
|
18
18
|
"semantic",
|
|
19
19
|
"allow"
|
|
20
|
-
]).pipe(Flag.withDescription("Drift tolerance for published schemas; overrides
|
|
20
|
+
]).pipe(Flag.withDescription("Drift tolerance for published schemas; overrides every schema's drift"), Flag.optional);
|
|
21
21
|
/**
|
|
22
22
|
* `--on-drift`: what drift does, overriding the config.
|
|
23
23
|
*
|
|
24
24
|
* @public
|
|
25
25
|
*/
|
|
26
|
-
const onDriftFlag = Flag.Literals("on-drift", ["error", "warn"]).pipe(Flag.withDescription("What drift does: refuse every write (error) or write and warn; overrides
|
|
26
|
+
const onDriftFlag = Flag.Literals("on-drift", ["error", "warn"]).pipe(Flag.withDescription("What drift does: refuse every write (error) or write and warn; overrides the config's onDrift"), Flag.optional);
|
|
27
27
|
/**
|
|
28
28
|
* `--force`: shorthand for `--drift=allow`.
|
|
29
29
|
*
|
package/cli/program.js
CHANGED
|
@@ -28,7 +28,8 @@ const trimLoadError = Effect.fn("schemastore.trimLoadError")(function* (error) {
|
|
|
28
28
|
* Fails with the marked error the runtime maps to the exit code:
|
|
29
29
|
* `ShowHelp` is `64` with parse errors and `0` without (help itself was
|
|
30
30
|
* already rendered); `ConfigNotFoundError` / `ConfigLoadError` are `2`;
|
|
31
|
-
* `
|
|
31
|
+
* `ConflictingFlagsError` arrives already marked `64`; `DriftError` /
|
|
32
|
+
* `GateError` / `StaleError` arrive already marked `1`.
|
|
32
33
|
*
|
|
33
34
|
* @public
|
|
34
35
|
*/
|
package/main.js
CHANGED
|
@@ -15,7 +15,7 @@ const render = (error) => CliError.isCliError(error) && error._tag === "ShowHelp
|
|
|
15
15
|
const main = () => {
|
|
16
16
|
const run = program(process.argv.slice(2), {
|
|
17
17
|
cwd: process.cwd(),
|
|
18
|
-
version: "0.
|
|
18
|
+
version: "0.11.0"
|
|
19
19
|
}).pipe(Effect.provide(NodeServices.layer), CliRuntime.reportFailures({
|
|
20
20
|
exitCode: 3,
|
|
21
21
|
render
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/schemastore-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The schemastore command: build and check SchemaStore-shaped JSON Schema documents from a schemastore.config.ts, with a per-schema published flag and a drift policy.",
|
|
6
6
|
"keywords": [
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@effect/platform-node": "4.0.0-rc.115",
|
|
39
|
-
"@effected/cli": "^0.5.
|
|
39
|
+
"@effected/cli": "^0.5.1",
|
|
40
40
|
"jiti": "^2.6.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@effected/schemastore": "0.
|
|
43
|
+
"@effected/schemastore": "0.11.0",
|
|
44
44
|
"effect": "4.0.0-rc.115"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|