@okfit/cli 0.9.0 → 0.10.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/errors.js +24 -13
- package/index.d.ts +13 -11
- package/internal/initWizard.js +6 -4
- package/internal/versionFormatter.js +11 -22
- package/main.js +8 -3
- package/package.json +13 -13
- package/version.js +1 -1
package/errors.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { InitBundleDirError } from "./internal/initWizard.js";
|
|
2
2
|
import { DocumentStdinIsTerminalError } from "./internal/stdin.js";
|
|
3
|
-
import {
|
|
3
|
+
import { ConfigIssueRenderer } from "@effected/cli";
|
|
4
4
|
import { ConfigMalformedError, ConfigPathNotFoundError, DocumentPathError, InitOverwriteError, NotAPublicationError, PublicationNotFoundError, QueryConceptNotFoundError, QuerySelectionError, QueryUnknownVocabularyError, SyncPublicationConflictError, SyncStagedLogError, VerifyConceptNotFoundError, VerifySelectionError, VerifyUnsupportedFrontmatterError } from "@okfit/engine";
|
|
5
5
|
|
|
6
6
|
//#region src/errors.ts
|
|
7
7
|
const hasTag = (error, tag) => typeof error === "object" && error !== null && "_tag" in error && error._tag === tag;
|
|
8
|
+
/** Where a defect's report sends the reader. */
|
|
9
|
+
const ISSUE_URL = "https://github.com/spencerbeggs/okfit/issues";
|
|
8
10
|
/** `path` relative to `cwd` when it is under it, else the absolute path unchanged (K-51). */
|
|
9
11
|
const relativeToCwd = (path, cwd) => {
|
|
10
12
|
if (path === cwd) return ".";
|
|
@@ -18,14 +20,10 @@ const relativeToCwd = (path, cwd) => {
|
|
|
18
20
|
*
|
|
19
21
|
* Rules, in order:
|
|
20
22
|
*
|
|
21
|
-
* 1. A
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* defensive only: `@effected/cli`'s `CliRuntime.main`/`reportFailures`
|
|
26
|
-
* already handles a `ShowHelp` before `render` is ever called
|
|
27
|
-
* (`main.ts`'s own doc comment), so `renderFailure` never actually sees
|
|
28
|
-
* one on the path this package uses.
|
|
23
|
+
* 1. A cancelled or non-interactive run (`details.isCancelled`,
|
|
24
|
+
* `details.isNotInteractive`: a cancelled fallback prompt is a defect in the
|
|
25
|
+
* cause, but not a bug) renders as the kit's own `defaultLines`, unprefixed.
|
|
26
|
+
* `ShowHelp` never reaches `render`: `CliRuntime.main` handles it first.
|
|
29
27
|
* 2. `ConfigPathNotFoundError` renders as its own `error: <message>` line;
|
|
30
28
|
* `InitOverwriteError` renders as the K-51 header, one two-space-indented
|
|
31
29
|
* relativised path per conflict, and the literal `Nothing was written.`.
|
|
@@ -56,18 +54,23 @@ const relativeToCwd = (path, cwd) => {
|
|
|
56
54
|
* 5d. `QueryUnknownVocabularyError`, `QueryConceptNotFoundError` and
|
|
57
55
|
* `QuerySelectionError` (`okfit query`) each render as one
|
|
58
56
|
* `error: <message>` line.
|
|
59
|
-
* 6.
|
|
57
|
+
* 6. A defect (`details.isDefect`: a `die`, a thrown exception, a bug) that no
|
|
58
|
+
* rule above claimed renders as `error: ` plus the kit's report for the
|
|
59
|
+
* run without its status marker, then `Please report at <issues URL>`.
|
|
60
|
+
* 7. Every other typed failure — core's `BundleRootNotFoundError`/`BundleReadError`/
|
|
60
61
|
* `BundleDepthExceededError`, config-file's other errors, `XdgEnvError`
|
|
61
62
|
* (the K-13 `HOME`-unset case) — renders as the single line
|
|
62
63
|
* `error: ${String(error)}`. Each of those
|
|
63
64
|
* classes' own `message` already names the offending path, which is all
|
|
64
65
|
* K-46 asserts.
|
|
65
66
|
*
|
|
67
|
+
* `details` is the kit's `FailureDetails`: `isDefect` tells a typed failure
|
|
68
|
+
* from a defect exactly, so no rule here guesses from an error's shape.
|
|
69
|
+
*
|
|
66
70
|
* @public
|
|
67
71
|
*/
|
|
68
|
-
const renderFailure = (error) => {
|
|
69
|
-
if (
|
|
70
|
-
if (error instanceof Cancelled || error instanceof NotInteractive) return [error.message];
|
|
72
|
+
const renderFailure = (error, details) => {
|
|
73
|
+
if (details.isCancelled || details.isNotInteractive) return details.defaultLines;
|
|
71
74
|
if (error instanceof ConfigPathNotFoundError) return [`error: ${error.message}`];
|
|
72
75
|
if (error instanceof ConfigMalformedError) return [`error: ${error.message}`];
|
|
73
76
|
if (error instanceof InitOverwriteError) return [
|
|
@@ -92,6 +95,14 @@ const renderFailure = (error) => {
|
|
|
92
95
|
const validationError = error;
|
|
93
96
|
return [`error: ${String(validationError)}`, ...ConfigIssueRenderer.render(validationError).map((line) => ` ${line}`)];
|
|
94
97
|
}
|
|
98
|
+
if (details.isDefect) {
|
|
99
|
+
const [first = String(error), ...rest] = details.lines({ status: false });
|
|
100
|
+
return [
|
|
101
|
+
`error: ${first}`,
|
|
102
|
+
...rest,
|
|
103
|
+
`Please report at ${ISSUE_URL}`
|
|
104
|
+
];
|
|
105
|
+
}
|
|
95
106
|
return [`error: ${String(error)}`];
|
|
96
107
|
};
|
|
97
108
|
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from "effect/cli";
|
|
2
|
-
import "@effected/cli";
|
|
2
|
+
import { FailureDetails } from "@effected/cli";
|
|
3
3
|
import { Runtime, Schema } from "effect";
|
|
4
4
|
import { ContextEnvelope, RenderedDiagnostic } from "@okfit/engine";
|
|
5
5
|
//#region src/commands/root.d.ts
|
|
@@ -47,14 +47,10 @@ export declare const rootCommand: Command.Command<"okfit", {
|
|
|
47
47
|
*
|
|
48
48
|
* Rules, in order:
|
|
49
49
|
*
|
|
50
|
-
* 1. A
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* defensive only: `@effected/cli`'s `CliRuntime.main`/`reportFailures`
|
|
55
|
-
* already handles a `ShowHelp` before `render` is ever called
|
|
56
|
-
* (`main.ts`'s own doc comment), so `renderFailure` never actually sees
|
|
57
|
-
* one on the path this package uses.
|
|
50
|
+
* 1. A cancelled or non-interactive run (`details.isCancelled`,
|
|
51
|
+
* `details.isNotInteractive`: a cancelled fallback prompt is a defect in the
|
|
52
|
+
* cause, but not a bug) renders as the kit's own `defaultLines`, unprefixed.
|
|
53
|
+
* `ShowHelp` never reaches `render`: `CliRuntime.main` handles it first.
|
|
58
54
|
* 2. `ConfigPathNotFoundError` renders as its own `error: <message>` line;
|
|
59
55
|
* `InitOverwriteError` renders as the K-51 header, one two-space-indented
|
|
60
56
|
* relativised path per conflict, and the literal `Nothing was written.`.
|
|
@@ -85,16 +81,22 @@ export declare const rootCommand: Command.Command<"okfit", {
|
|
|
85
81
|
* 5d. `QueryUnknownVocabularyError`, `QueryConceptNotFoundError` and
|
|
86
82
|
* `QuerySelectionError` (`okfit query`) each render as one
|
|
87
83
|
* `error: <message>` line.
|
|
88
|
-
* 6.
|
|
84
|
+
* 6. A defect (`details.isDefect`: a `die`, a thrown exception, a bug) that no
|
|
85
|
+
* rule above claimed renders as `error: ` plus the kit's report for the
|
|
86
|
+
* run without its status marker, then `Please report at <issues URL>`.
|
|
87
|
+
* 7. Every other typed failure — core's `BundleRootNotFoundError`/`BundleReadError`/
|
|
89
88
|
* `BundleDepthExceededError`, config-file's other errors, `XdgEnvError`
|
|
90
89
|
* (the K-13 `HOME`-unset case) — renders as the single line
|
|
91
90
|
* `error: ${String(error)}`. Each of those
|
|
92
91
|
* classes' own `message` already names the offending path, which is all
|
|
93
92
|
* K-46 asserts.
|
|
94
93
|
*
|
|
94
|
+
* `details` is the kit's `FailureDetails`: `isDefect` tells a typed failure
|
|
95
|
+
* from a defect exactly, so no rule here guesses from an error's shape.
|
|
96
|
+
*
|
|
95
97
|
* @public
|
|
96
98
|
*/
|
|
97
|
-
export declare const renderFailure: (error: unknown) => ReadonlyArray<string>;
|
|
99
|
+
export declare const renderFailure: (error: unknown, details: FailureDetails) => ReadonlyArray<string>;
|
|
98
100
|
//#endregion
|
|
99
101
|
//#region src/internal/initWizard.d.ts
|
|
100
102
|
declare const InitBundleDirError_base: Schema.Class<InitBundleDirError, Schema.TaggedStruct<"InitBundleDirError", {
|
package/internal/initWizard.js
CHANGED
|
@@ -63,7 +63,8 @@ const checkBundleDir = (value) => {
|
|
|
63
63
|
/**
|
|
64
64
|
* The `okfit init` wizard: profile, bundle directory, config location, in
|
|
65
65
|
* that order. A setting is prompted for only when its flag was not given and
|
|
66
|
-
* the run is interactive
|
|
66
|
+
* the run is interactive (the profile also needs more than one registered: a
|
|
67
|
+
* lone profile is used without a screen); otherwise its flag value or default is used
|
|
67
68
|
* (`CliUi.prompt`'s `otherwise`, so a non-interactive run never loads Ink).
|
|
68
69
|
*
|
|
69
70
|
* A bad `--bundle` flag fails with {@link InitBundleDirError} before any
|
|
@@ -86,14 +87,15 @@ const initWizard = (given, defaults) => Effect.gen(function* () {
|
|
|
86
87
|
});
|
|
87
88
|
flagBundle = checked.dir;
|
|
88
89
|
}
|
|
90
|
+
const profileNames = PROFILE_NAMES;
|
|
89
91
|
return {
|
|
90
|
-
profile: Option.isSome(given.profile) ? given.profile.value : yield* CliUi.prompt(Select.screen({
|
|
92
|
+
profile: Option.isSome(given.profile) ? given.profile.value : profileNames.length === 1 ? defaults.profile : yield* CliUi.prompt(Select.screen({
|
|
91
93
|
message: "Profile to scaffold with",
|
|
92
|
-
choices:
|
|
94
|
+
choices: profileNames.map((name) => ({
|
|
93
95
|
label: name,
|
|
94
96
|
value: name
|
|
95
97
|
})),
|
|
96
|
-
initial: Math.max(0,
|
|
98
|
+
initial: Math.max(0, profileNames.indexOf(defaults.profile))
|
|
97
99
|
}), { otherwise: defaults.profile }),
|
|
98
100
|
bundle: flagBundle ?? (yield* CliUi.prompt(TextInput.screen({
|
|
99
101
|
message: "Bundle directory (relative to the project root)",
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CurrentDistribution, distributionSuffix } from "@effected/engine";
|
|
1
|
+
import { distributionSuffix } from "@effected/engine";
|
|
3
2
|
import { ENGINE_VERSION } from "@okfit/engine";
|
|
4
|
-
import { Effect, Layer } from "effect";
|
|
5
3
|
import { CONFIG_SCHEMA_VERSION, OKF_SPEC_VERSION } from "@okfit/core";
|
|
6
4
|
|
|
7
5
|
//#region src/internal/versionFormatter.ts
|
|
@@ -9,28 +7,19 @@ import { CONFIG_SCHEMA_VERSION, OKF_SPEC_VERSION } from "@okfit/core";
|
|
|
9
7
|
* `okfit --version`'s full text (okfit #137):
|
|
10
8
|
* `<name> <version>[ via <distName> <distVersion>] (engine <ENGINE_VERSION>, okf <OKF_SPEC_VERSION>, config-schema <CONFIG_SCHEMA_VERSION>)`.
|
|
11
9
|
* `GlobalFlag.Version`'s built-in `run` calls `formatter.formatVersion(command.name,
|
|
12
|
-
* version)` (`command.name` is always `"okfit"`, `version` is `CLI_VERSION`
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* distribution parts.
|
|
10
|
+
* version)` (`command.name` is always `"okfit"`, `version` is `CLI_VERSION`), so
|
|
11
|
+
* those two arguments alone are exactly `okfit <CLI_VERSION>`; this appends the
|
|
12
|
+
* distribution, engine and okf parts.
|
|
16
13
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* overridden; every other `Formatter` method (help, error rendering) is
|
|
23
|
-
* `CliColor.formatterLayer`'s own default, so help/error output stays
|
|
24
|
-
* consistent with the rest of the program's colour decision.
|
|
25
|
-
*
|
|
26
|
-
* `Layer.unwrap` around `Effect.map(CurrentDistribution, ...)` reads the
|
|
27
|
-
* distribution once, from the ambient `CurrentDistribution` reference
|
|
28
|
-
* `main.ts` provides, rather than threading it in as a constructor argument
|
|
29
|
-
* the way the hand-rolled formatter used to.
|
|
14
|
+
* Passed to `CliRuntime.main` as `env.formatter`: `helpOnUsageError: "stderr"`
|
|
15
|
+
* only reroutes help written through a formatter `main` installed, so a layer
|
|
16
|
+
* inside the program would not do. Every method left out keeps the kit's
|
|
17
|
+
* coloured default. `distribution` is the value `main` was given, known before
|
|
18
|
+
* the program runs, so it is read directly rather than from the context.
|
|
30
19
|
*
|
|
31
20
|
* @internal
|
|
32
21
|
*/
|
|
33
|
-
const
|
|
22
|
+
const versionFormatter = (distribution) => ({ formatVersion: (name, version) => `${name} ${version}${distributionSuffix(distribution)} (engine ${ENGINE_VERSION}, okf ${OKF_SPEC_VERSION}, config-schema ${CONFIG_SCHEMA_VERSION})` });
|
|
34
23
|
|
|
35
24
|
//#endregion
|
|
36
|
-
export {
|
|
25
|
+
export { versionFormatter };
|
package/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CLI_VERSION } from "./version.js";
|
|
2
2
|
import { rootCommand } from "./commands/root.js";
|
|
3
3
|
import { renderFailure } from "./errors.js";
|
|
4
|
-
import {
|
|
4
|
+
import { versionFormatter } from "./internal/versionFormatter.js";
|
|
5
5
|
import { CliAudience, CliRuntime } from "@effected/cli";
|
|
6
6
|
import { CurrentDistribution } from "@effected/engine";
|
|
7
7
|
import { Now, OkfitPlatform } from "@okfit/engine";
|
|
@@ -46,12 +46,17 @@ const main = (options = {}) => {
|
|
|
46
46
|
const program = Effect.gen(function* () {
|
|
47
47
|
const now = yield* nowEffect;
|
|
48
48
|
return yield* CliAudience.run(rootCommand, { version: CLI_VERSION }).pipe(Effect.provideService(Now, now));
|
|
49
|
-
}).pipe(Effect.
|
|
49
|
+
}).pipe(Effect.provideService(CurrentDistribution, distribution));
|
|
50
50
|
NodeRuntime.runMain(CliRuntime.main(program, {
|
|
51
51
|
platform: OkfitPlatform,
|
|
52
52
|
exitCode: 3,
|
|
53
53
|
render: renderFailure,
|
|
54
|
-
|
|
54
|
+
helpOnUsageError: "stderr",
|
|
55
|
+
env: {
|
|
56
|
+
audienceEnvVar: "OKFIT_AUDIENCE",
|
|
57
|
+
stderrIsTerminal: Effect.sync(() => process.stderr.isTTY === true),
|
|
58
|
+
formatter: versionFormatter(distribution)
|
|
59
|
+
}
|
|
55
60
|
}));
|
|
56
61
|
};
|
|
57
62
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@okfit/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The okfit command line: validate, lint, index, and inspect Open Knowledge Format (OKF) bundles.",
|
|
6
6
|
"keywords": [
|
|
@@ -42,23 +42,23 @@
|
|
|
42
42
|
"okfit": "bin/okfit.js"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@effect/platform-node": "^4.0.
|
|
46
|
-
"@effected/cli": "^0.
|
|
47
|
-
"@effected/config-file": "^0.14.
|
|
48
|
-
"@effected/engine": "^0.
|
|
45
|
+
"@effect/platform-node": "^4.0.1",
|
|
46
|
+
"@effected/cli": "^0.13.0",
|
|
47
|
+
"@effected/config-file": "^0.14.2",
|
|
48
|
+
"@effected/engine": "^0.4.0",
|
|
49
49
|
"@effected/env": "^0.1.0",
|
|
50
50
|
"@effected/git": "^0.20.0",
|
|
51
51
|
"@effected/glob": "^0.10.0",
|
|
52
|
-
"@effected/jsonc": "^0.15.
|
|
53
|
-
"@effected/markdown": "^0.15.
|
|
54
|
-
"@effected/schemastore": "^0.
|
|
55
|
-
"@effected/toml": "^0.11.
|
|
52
|
+
"@effected/jsonc": "^0.15.1",
|
|
53
|
+
"@effected/markdown": "^0.15.1",
|
|
54
|
+
"@effected/schemastore": "^0.21.1",
|
|
55
|
+
"@effected/toml": "^0.11.1",
|
|
56
56
|
"@effected/walker": "^0.15.0",
|
|
57
|
-
"@effected/yaml": "^0.19.
|
|
58
|
-
"@okfit/core": "0.9.
|
|
59
|
-
"@okfit/engine": "0.
|
|
57
|
+
"@effected/yaml": "^0.19.1",
|
|
58
|
+
"@okfit/core": "0.9.1",
|
|
59
|
+
"@okfit/engine": "0.13.0",
|
|
60
60
|
"@okfit/profiles": "0.9.0",
|
|
61
|
-
"effect": "^4.0.
|
|
61
|
+
"effect": "^4.0.1",
|
|
62
62
|
"ink": "^7.1.1",
|
|
63
63
|
"react": "^19.2.0"
|
|
64
64
|
},
|