@forumulate/cli 0.5.0 → 0.9.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 +124 -5
- package/dist/api/args.d.ts +21 -0
- package/dist/api/args.d.ts.map +1 -0
- package/dist/api/args.js +81 -0
- package/dist/api/args.js.map +1 -0
- package/dist/api/command.d.ts +17 -0
- package/dist/api/command.d.ts.map +1 -0
- package/dist/api/command.js +182 -0
- package/dist/api/command.js.map +1 -0
- package/dist/api/describe.d.ts +5 -0
- package/dist/api/describe.d.ts.map +1 -0
- package/dist/api/describe.js +121 -0
- package/dist/api/describe.js.map +1 -0
- package/dist/api/http.d.ts +81 -0
- package/dist/api/http.d.ts.map +1 -0
- package/dist/api/http.js +183 -0
- package/dist/api/http.js.map +1 -0
- package/dist/api/operations.json +1 -0
- package/dist/api/output.d.ts +35 -0
- package/dist/api/output.d.ts.map +1 -0
- package/dist/api/output.js +176 -0
- package/dist/api/output.js.map +1 -0
- package/dist/api/request.d.ts +37 -0
- package/dist/api/request.d.ts.map +1 -0
- package/dist/api/request.js +230 -0
- package/dist/api/request.js.map +1 -0
- package/dist/api/send.d.ts +35 -0
- package/dist/api/send.d.ts.map +1 -0
- package/dist/api/send.js +85 -0
- package/dist/api/send.js.map +1 -0
- package/dist/api/spec.d.ts +96 -0
- package/dist/api/spec.d.ts.map +1 -0
- package/dist/api/spec.js +126 -0
- package/dist/api/spec.js.map +1 -0
- package/dist/commands/completion.d.ts +12 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +169 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/config.d.ts +33 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +144 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/context.d.ts +35 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +59 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/groups-api.d.ts +11 -0
- package/dist/commands/groups-api.d.ts.map +1 -0
- package/dist/commands/groups-api.js +140 -0
- package/dist/commands/groups-api.js.map +1 -0
- package/dist/commands/groups-community.d.ts +15 -0
- package/dist/commands/groups-community.d.ts.map +1 -0
- package/dist/commands/groups-community.js +344 -0
- package/dist/commands/groups-community.js.map +1 -0
- package/dist/commands/groups-content.d.ts +10 -0
- package/dist/commands/groups-content.d.ts.map +1 -0
- package/dist/commands/groups-content.js +331 -0
- package/dist/commands/groups-content.js.map +1 -0
- package/dist/commands/groups-docs.d.ts +12 -0
- package/dist/commands/groups-docs.d.ts.map +1 -0
- package/dist/commands/groups-docs.js +414 -0
- package/dist/commands/groups-docs.js.map +1 -0
- package/dist/commands/groups-org.d.ts +10 -0
- package/dist/commands/groups-org.d.ts.map +1 -0
- package/dist/commands/groups-org.js +405 -0
- package/dist/commands/groups-org.js.map +1 -0
- package/dist/commands/groups-site.d.ts +3 -0
- package/dist/commands/groups-site.d.ts.map +1 -0
- package/dist/commands/groups-site.js +237 -0
- package/dist/commands/groups-site.js.map +1 -0
- package/dist/commands/groups-spaces.d.ts +3 -0
- package/dist/commands/groups-spaces.d.ts.map +1 -0
- package/dist/commands/groups-spaces.js +273 -0
- package/dist/commands/groups-spaces.js.map +1 -0
- package/dist/commands/groups-types.d.ts +3 -0
- package/dist/commands/groups-types.d.ts.map +1 -0
- package/dist/commands/groups-types.js +251 -0
- package/dist/commands/groups-types.js.map +1 -0
- package/dist/commands/groups.d.ts +4 -0
- package/dist/commands/groups.d.ts.map +1 -0
- package/dist/commands/groups.js +71 -0
- package/dist/commands/groups.js.map +1 -0
- package/dist/commands/index.d.ts +25 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +118 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/resource.d.ts +86 -0
- package/dist/commands/resource.d.ts.map +1 -0
- package/dist/commands/resource.js +314 -0
- package/dist/commands/resource.js.map +1 -0
- package/dist/content/library.d.ts +1 -0
- package/dist/content/library.d.ts.map +1 -1
- package/dist/content/library.js +1 -0
- package/dist/content/library.js.map +1 -1
- package/dist/dev/command.d.ts +41 -0
- package/dist/dev/command.d.ts.map +1 -0
- package/dist/dev/command.js +158 -0
- package/dist/dev/command.js.map +1 -0
- package/dist/help.d.ts +3 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +159 -0
- package/dist/help.js.map +1 -0
- package/dist/publish/api.d.ts +30 -12
- package/dist/publish/api.d.ts.map +1 -1
- package/dist/publish/api.js +62 -10
- package/dist/publish/api.js.map +1 -1
- package/dist/publish/client.d.ts +19 -0
- package/dist/publish/client.d.ts.map +1 -0
- package/dist/publish/client.js +3 -0
- package/dist/publish/client.js.map +1 -0
- package/dist/publish/command.d.ts +31 -2
- package/dist/publish/command.d.ts.map +1 -1
- package/dist/publish/command.js +62 -15
- package/dist/publish/command.js.map +1 -1
- package/dist/publish/context.d.ts +4 -1
- package/dist/publish/context.d.ts.map +1 -1
- package/dist/publish/context.js.map +1 -1
- package/dist/publish/diff.d.ts +21 -0
- package/dist/publish/diff.d.ts.map +1 -0
- package/dist/publish/diff.js +96 -0
- package/dist/publish/diff.js.map +1 -0
- package/dist/publish/docs-apply.d.ts +8 -1
- package/dist/publish/docs-apply.d.ts.map +1 -1
- package/dist/publish/docs-apply.js +37 -10
- package/dist/publish/docs-apply.js.map +1 -1
- package/dist/publish/docs-plan.d.ts +16 -3
- package/dist/publish/docs-plan.d.ts.map +1 -1
- package/dist/publish/docs-plan.js +57 -6
- package/dist/publish/docs-plan.js.map +1 -1
- package/dist/publish/frontmatter.d.ts +1 -1
- package/dist/publish/frontmatter.d.ts.map +1 -1
- package/dist/publish/frontmatter.js +1 -0
- package/dist/publish/frontmatter.js.map +1 -1
- package/dist/publish/index.d.ts +12 -0
- package/dist/publish/index.d.ts.map +1 -0
- package/dist/publish/index.js +17 -0
- package/dist/publish/index.js.map +1 -0
- package/dist/publish/manifest.d.ts.map +1 -1
- package/dist/publish/manifest.js +23 -3
- package/dist/publish/manifest.js.map +1 -1
- package/dist/publish/names.d.ts +28 -0
- package/dist/publish/names.d.ts.map +1 -0
- package/dist/publish/names.js +80 -0
- package/dist/publish/names.js.map +1 -0
- package/dist/publish/posts.d.ts.map +1 -1
- package/dist/publish/posts.js +46 -13
- package/dist/publish/posts.js.map +1 -1
- package/dist/publish/reserved.d.ts +49 -0
- package/dist/publish/reserved.d.ts.map +1 -0
- package/dist/publish/reserved.js +118 -0
- package/dist/publish/reserved.js.map +1 -0
- package/dist/publish/rewrite.d.ts +12 -0
- package/dist/publish/rewrite.d.ts.map +1 -1
- package/dist/publish/rewrite.js +22 -0
- package/dist/publish/rewrite.js.map +1 -1
- package/dist/publish/scan-docs.d.ts +10 -0
- package/dist/publish/scan-docs.d.ts.map +1 -0
- package/dist/publish/scan-docs.js +160 -0
- package/dist/publish/scan-docs.js.map +1 -0
- package/dist/publish/scan.d.ts +21 -17
- package/dist/publish/scan.d.ts.map +1 -1
- package/dist/publish/scan.js +99 -232
- package/dist/publish/scan.js.map +1 -1
- package/dist/publish/slots.d.ts +39 -0
- package/dist/publish/slots.d.ts.map +1 -0
- package/dist/publish/slots.js +64 -0
- package/dist/publish/slots.js.map +1 -0
- package/dist/publish/tags.d.ts +9 -0
- package/dist/publish/tags.d.ts.map +1 -0
- package/dist/publish/tags.js +194 -0
- package/dist/publish/tags.js.map +1 -0
- package/dist/publish/types.d.ts +62 -0
- package/dist/publish/types.d.ts.map +1 -1
- package/dist/publish/types.js +0 -10
- package/dist/publish/types.js.map +1 -1
- package/dist/run.d.ts +16 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +124 -117
- package/dist/run.js.map +1 -1
- package/dist/translations/command.d.ts +36 -0
- package/dist/translations/command.d.ts.map +1 -0
- package/dist/translations/command.js +411 -0
- package/dist/translations/command.js.map +1 -0
- package/dist/translations/extras.d.ts +29 -0
- package/dist/translations/extras.d.ts.map +1 -0
- package/dist/translations/extras.js +123 -0
- package/dist/translations/extras.js.map +1 -0
- package/dist/translations/files.d.ts +22 -0
- package/dist/translations/files.d.ts.map +1 -0
- package/dist/translations/files.js +75 -0
- package/dist/translations/files.js.map +1 -0
- package/dist/translations/sync.d.ts +89 -0
- package/dist/translations/sync.d.ts.map +1 -0
- package/dist/translations/sync.js +215 -0
- package/dist/translations/sync.js.map +1 -0
- package/dist/translations/target.d.ts +33 -0
- package/dist/translations/target.d.ts.map +1 -0
- package/dist/translations/target.js +54 -0
- package/dist/translations/target.js.map +1 -0
- package/dist/translations/xliff.d.ts +29 -0
- package/dist/translations/xliff.d.ts.map +1 -0
- package/dist/translations/xliff.js +62 -0
- package/dist/translations/xliff.js.map +1 -0
- package/package.json +6 -4
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GROUPS = void 0;
|
|
4
|
+
exports.findGroup = findGroup;
|
|
5
|
+
const groups_api_1 = require("./groups-api");
|
|
6
|
+
const groups_community_1 = require("./groups-community");
|
|
7
|
+
const groups_content_1 = require("./groups-content");
|
|
8
|
+
const groups_docs_1 = require("./groups-docs");
|
|
9
|
+
const groups_org_1 = require("./groups-org");
|
|
10
|
+
const groups_site_1 = require("./groups-site");
|
|
11
|
+
const groups_spaces_1 = require("./groups-spaces");
|
|
12
|
+
const groups_types_1 = require("./groups-types");
|
|
13
|
+
/**
|
|
14
|
+
* The resource commands, as data. Each verb is one operation in the bundled
|
|
15
|
+
* spec; `resource.ts` derives the flags. `operations.test.ts` asserts every
|
|
16
|
+
* operationId named here exists, so a renamed route breaks the build, not a
|
|
17
|
+
* customer's script.
|
|
18
|
+
*
|
|
19
|
+
* The verbs are the same everywhere — list, get, create, update, delete, and
|
|
20
|
+
* publish where a thing has a draft — because that is what `gh`, `stripe` and
|
|
21
|
+
* `vercel` taught people to type. A sub-resource is a two-word verb
|
|
22
|
+
* (`libraries keys rotate`, `docs schedule set`), never a third word.
|
|
23
|
+
*
|
|
24
|
+
* One file per domain (`groups-*.ts`), each with its own reason in its header;
|
|
25
|
+
* this one only puts them in the order `forumulate help` lists them.
|
|
26
|
+
*/
|
|
27
|
+
const SEARCH = {
|
|
28
|
+
name: 'search',
|
|
29
|
+
noun: 'result',
|
|
30
|
+
about: 'unified search across docs, forum and blog, and what it is missing',
|
|
31
|
+
verbs: {
|
|
32
|
+
query: {
|
|
33
|
+
op: 'UnifiedSearch_search_',
|
|
34
|
+
about: 'Search (--type docs|forum|blog, --limit); `search query <words>` for a verb word',
|
|
35
|
+
args: ['q...'],
|
|
36
|
+
columns: ['sourceType', 'title', 'url'],
|
|
37
|
+
},
|
|
38
|
+
semantic: {
|
|
39
|
+
op: 'UnifiedSearch_semanticSearch',
|
|
40
|
+
about: 'Search by meaning (your embedding provider; --mode)',
|
|
41
|
+
args: ['q...'],
|
|
42
|
+
columns: ['sourceType', 'title', 'url', 'score'],
|
|
43
|
+
},
|
|
44
|
+
recent: { op: 'UnifiedSearch_recent', about: 'Your recent searches' },
|
|
45
|
+
tags: { op: 'UnifiedSearch_tags', about: 'Every tag across the organization' },
|
|
46
|
+
tag: { op: 'UnifiedSearch_tagHub_', about: 'Everything carrying one tag', args: ['tag'] },
|
|
47
|
+
gaps: {
|
|
48
|
+
op: 'UnifiedSearch_gaps',
|
|
49
|
+
about: 'Searches that found nothing (--days)',
|
|
50
|
+
columns: ['query', 'count', 'lastSearchedAt'],
|
|
51
|
+
},
|
|
52
|
+
reindex: { op: 'UnifiedSearch_reindex', about: 'Rebuild the search index' },
|
|
53
|
+
},
|
|
54
|
+
defaultVerb: 'query',
|
|
55
|
+
bareArgs: true,
|
|
56
|
+
};
|
|
57
|
+
exports.GROUPS = [
|
|
58
|
+
...groups_org_1.ORG_GROUPS,
|
|
59
|
+
...groups_spaces_1.SPACE_GROUPS,
|
|
60
|
+
...groups_docs_1.DOCS_GROUPS,
|
|
61
|
+
...groups_api_1.API_GROUPS,
|
|
62
|
+
...groups_community_1.COMMUNITY_GROUPS,
|
|
63
|
+
...groups_types_1.TYPE_GROUPS,
|
|
64
|
+
...groups_content_1.CONTENT_GROUPS,
|
|
65
|
+
...groups_site_1.SITE_GROUPS,
|
|
66
|
+
SEARCH,
|
|
67
|
+
];
|
|
68
|
+
function findGroup(name) {
|
|
69
|
+
return exports.GROUPS.find((g) => g.name === name || g.aliases?.includes(name));
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groups.js","sourceRoot":"","sources":["../../src/commands/groups.ts"],"names":[],"mappings":";;;AAmEA,8BAEC;AArED,6CAA0C;AAC1C,yDAAsD;AACtD,qDAAkD;AAClD,+CAA4C;AAC5C,6CAA0C;AAC1C,+CAA4C;AAC5C,mDAA+C;AAC/C,iDAA6C;AAG7C;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,GAAa;IACvB,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,oEAAoE;IAC3E,KAAK,EAAE;QACL,KAAK,EAAE;YACL,EAAE,EAAE,uBAAuB;YAC3B,KAAK,EAAE,kFAAkF;YACzF,IAAI,EAAE,CAAC,MAAM,CAAC;YACd,OAAO,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC;SACxC;QACD,QAAQ,EAAE;YACR,EAAE,EAAE,8BAA8B;YAClC,KAAK,EAAE,qDAAqD;YAC5D,IAAI,EAAE,CAAC,MAAM,CAAC;YACd,OAAO,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC;SACjD;QACD,MAAM,EAAE,EAAE,EAAE,EAAE,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,EAAE;QACrE,IAAI,EAAE,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE,mCAAmC,EAAE;QAC9E,GAAG,EAAE,EAAE,EAAE,EAAE,uBAAuB,EAAE,KAAK,EAAE,6BAA6B,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE;QACzF,IAAI,EAAE;YACJ,EAAE,EAAE,oBAAoB;YACxB,KAAK,EAAE,sCAAsC;YAC7C,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC;SAC9C;QACD,OAAO,EAAE,EAAE,EAAE,EAAE,uBAAuB,EAAE,KAAK,EAAE,0BAA0B,EAAE;KAC5E;IACD,WAAW,EAAE,OAAO;IACpB,QAAQ,EAAE,IAAI;CACf,CAAC;AAEW,QAAA,MAAM,GAAe;IAChC,GAAG,uBAAU;IACb,GAAG,4BAAY;IACf,GAAG,yBAAW;IACd,GAAG,uBAAU;IACb,GAAG,mCAAgB;IACnB,GAAG,0BAAW;IACd,GAAG,+BAAc;IACjB,GAAG,yBAAW;IACd,MAAM;CACP,CAAC;AAEF,SAAgB,SAAS,CAAC,IAAY;IACpC,OAAO,cAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Http } from '../api/http';
|
|
2
|
+
/**
|
|
3
|
+
* The commands added for API parity — `api`, `config`, `completion`, and the
|
|
4
|
+
* resource groups — routed before the older `switch` in `run.ts`.
|
|
5
|
+
*
|
|
6
|
+
* Returns undefined for anything it does not own, and for the older
|
|
7
|
+
* positional forms (`spaces <orgId>`, `items <orgId> <spaceId>`,
|
|
8
|
+
* `search <orgId> <query…>`, `domains [verify] <orgId> <spaceId>`), which keep
|
|
9
|
+
* their exact output: scripts parse it.
|
|
10
|
+
*/
|
|
11
|
+
export interface RouteDeps {
|
|
12
|
+
out: (l: string) => void;
|
|
13
|
+
err: (l: string) => void;
|
|
14
|
+
env?: NodeJS.ProcessEnv;
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
http?: Http;
|
|
17
|
+
ask?: (q: string) => Promise<string>;
|
|
18
|
+
readFile?: (path: string) => string | Buffer;
|
|
19
|
+
writeFile?: (path: string, data: Buffer | string) => void;
|
|
20
|
+
readStdin?: () => Promise<string>;
|
|
21
|
+
userAgent?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function readAllStdin(): Promise<string>;
|
|
24
|
+
export declare function route(cmd: string, argv: string[], deps: RouteDeps): Promise<number | undefined>;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAe,MAAM,aAAa,CAAC;AAShD;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzB,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,CAAC;IAC7C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IAC1D,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAQ9C;AAmCD,wBAAsB,KAAK,CACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA8D7B"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readAllStdin = readAllStdin;
|
|
4
|
+
exports.route = route;
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const args_1 = require("../api/args");
|
|
7
|
+
const command_1 = require("../api/command");
|
|
8
|
+
const http_1 = require("../api/http");
|
|
9
|
+
const api_base_1 = require("../api-base");
|
|
10
|
+
const credentials_1 = require("../credentials");
|
|
11
|
+
const config_1 = require("./config");
|
|
12
|
+
const completion_1 = require("./completion");
|
|
13
|
+
const groups_1 = require("./groups");
|
|
14
|
+
const resource_1 = require("./resource");
|
|
15
|
+
function readAllStdin() {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
let text = '';
|
|
18
|
+
process.stdin.setEncoding('utf8');
|
|
19
|
+
process.stdin.on('data', (c) => (text += c));
|
|
20
|
+
process.stdin.on('end', () => resolve(text));
|
|
21
|
+
process.stdin.on('error', reject);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function commandDeps(argv, deps) {
|
|
25
|
+
const env = deps.env ?? process.env;
|
|
26
|
+
const config = (0, config_1.readConfig)(env);
|
|
27
|
+
const parsed = (0, args_1.parseArgs)(argv);
|
|
28
|
+
const baseUrl = deps.baseUrl ?? (0, api_base_1.apiBaseFromEnv)(env);
|
|
29
|
+
const onRetry = ({ waitMs, status }) => deps.err(`${status ? `HTTP ${status}` : 'Connection failed'}; retrying in ${Math.ceil(waitMs / 1000)}s…`);
|
|
30
|
+
const apiVersion = (0, config_1.setting)('api-version', (0, args_1.flag)(parsed, 'api-version'), env, config);
|
|
31
|
+
const http = deps.http
|
|
32
|
+
? new http_1.Http({ onRetry, ...deps.http.opts, ...(apiVersion ? { apiVersion } : {}) })
|
|
33
|
+
: new http_1.Http({
|
|
34
|
+
baseUrl,
|
|
35
|
+
token: (0, credentials_1.resolveToken)(baseUrl, env),
|
|
36
|
+
userAgent: deps.userAgent ?? '@forumulate/cli',
|
|
37
|
+
apiVersion,
|
|
38
|
+
onRetry,
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
http,
|
|
42
|
+
out: deps.out,
|
|
43
|
+
err: deps.err,
|
|
44
|
+
env,
|
|
45
|
+
config,
|
|
46
|
+
ask: deps.ask,
|
|
47
|
+
readFile: deps.readFile ?? ((p) => (0, node_fs_1.readFileSync)(p)),
|
|
48
|
+
writeFile: deps.writeFile ?? ((p, d) => (0, node_fs_1.writeFileSync)(p, d)),
|
|
49
|
+
readStdin: deps.readStdin ?? readAllStdin,
|
|
50
|
+
defaultOrg: (0, config_1.setting)('org', undefined, env, config),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async function route(cmd, argv, deps) {
|
|
54
|
+
// Everything after the command word; flags before it are kept.
|
|
55
|
+
const at = argv.indexOf(cmd);
|
|
56
|
+
const tail = [...argv.slice(0, at), ...argv.slice(at + 1)];
|
|
57
|
+
if (cmd === '__complete') {
|
|
58
|
+
for (const c of (0, completion_1.complete)(tail))
|
|
59
|
+
deps.out(c);
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
if (cmd === 'completion') {
|
|
63
|
+
const script = (0, completion_1.completionScript)(tail.find((a) => !a.startsWith('-')) ?? '');
|
|
64
|
+
if (!script) {
|
|
65
|
+
deps.err('Usage: forumulate completion bash|zsh|fish');
|
|
66
|
+
return 1;
|
|
67
|
+
}
|
|
68
|
+
deps.out(script);
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
if (cmd === 'config') {
|
|
72
|
+
const p = (0, args_1.parseArgs)(tail);
|
|
73
|
+
if ((0, args_1.has)(p, 'help')) {
|
|
74
|
+
deps.out(config_1.CONFIG_HELP);
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
return (0, config_1.runConfig)(p.positionals, (0, args_1.has)(p, 'json'), {
|
|
78
|
+
out: deps.out,
|
|
79
|
+
err: deps.err,
|
|
80
|
+
env: deps.env ?? process.env,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const group = (0, groups_1.findGroup)(cmd);
|
|
84
|
+
if (cmd !== 'api' && !group)
|
|
85
|
+
return undefined;
|
|
86
|
+
const ctx = commandDeps(tail, deps);
|
|
87
|
+
try {
|
|
88
|
+
if (cmd === 'api')
|
|
89
|
+
return await (0, command_1.runApi)(tail, ctx);
|
|
90
|
+
const orgKnown = (p) => Boolean((0, config_1.setting)('org', (0, args_1.flag)(p, 'org'), ctx.env, ctx.config));
|
|
91
|
+
const legacy = (p, isVerb) => {
|
|
92
|
+
if (isVerb)
|
|
93
|
+
return (group.name === 'domains' && p.positionals[0] === 'verify' && p.positionals.length >= 3);
|
|
94
|
+
const n = p.positionals.length;
|
|
95
|
+
switch (group.name) {
|
|
96
|
+
case 'orgs':
|
|
97
|
+
return n === 0;
|
|
98
|
+
case 'spaces':
|
|
99
|
+
return n > 0 || !orgKnown(p);
|
|
100
|
+
case 'items':
|
|
101
|
+
return n > 0;
|
|
102
|
+
case 'search':
|
|
103
|
+
return !orgKnown(p);
|
|
104
|
+
case 'domains':
|
|
105
|
+
return n >= 2;
|
|
106
|
+
default:
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
return await (0, resource_1.runGroup)(group, tail, ctx, legacy);
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
for (const l of (0, http_1.formatError)(e))
|
|
114
|
+
deps.err(l);
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type Parsed } from '../api/args';
|
|
2
|
+
import { type CommandDeps } from './context';
|
|
3
|
+
/**
|
|
4
|
+
* The resource commands — `spaces list`, `webhooks create`, `tokens rotate` —
|
|
5
|
+
* as DATA over the same operations `forumulate api` calls.
|
|
6
|
+
*
|
|
7
|
+
* Each verb names an operationId and how its positionals map; everything else
|
|
8
|
+
* is derived from the bundled spec, which is why there is no per-command code
|
|
9
|
+
* for flags: every query parameter of the operation is a flag (`--limit`,
|
|
10
|
+
* `--state`), every top-level body field is a flag (`--name`, `--visibility`),
|
|
11
|
+
* and `--data`/`--field` work as they do under `api`. A verb whose operation
|
|
12
|
+
* disappears from the spec fails `operations.test.ts` rather than at a
|
|
13
|
+
* customer's terminal.
|
|
14
|
+
*
|
|
15
|
+
* Consistent across every group:
|
|
16
|
+
* - `--org` (default from `forumulate config set org`), `--space`, `--library`
|
|
17
|
+
* accept an id or a slug.
|
|
18
|
+
* - `list`/`get`/`create`/`update`/`delete` are the verbs where they apply;
|
|
19
|
+
* `delete` asks first (`--yes` to skip; required with no terminal).
|
|
20
|
+
* - `--json` prints the API's answer untouched; `--paginate` walks a list.
|
|
21
|
+
*/
|
|
22
|
+
export interface VerbDef {
|
|
23
|
+
op: string;
|
|
24
|
+
about: string;
|
|
25
|
+
/**
|
|
26
|
+
* Positionals, in order. A path param of the operation fills it
|
|
27
|
+
* (`spaceId`), a query param becomes that flag (`q`), anything else fills
|
|
28
|
+
* that BODY field (`name`, `hostname`), so `spaces create Docs` reads as
|
|
29
|
+
* English. A trailing `...` joins the rest (`search <q...>`).
|
|
30
|
+
*/
|
|
31
|
+
args?: string[];
|
|
32
|
+
/** The body field `--file <markdown>` fills (front matter sets title/slug). */
|
|
33
|
+
markdown?: string;
|
|
34
|
+
/** With `--file`, send the body through this operation instead (items: PUT …/content). */
|
|
35
|
+
contentOp?: string;
|
|
36
|
+
destructive?: boolean;
|
|
37
|
+
columns?: string[];
|
|
38
|
+
/** Query defaults the operation needs to be useful here (`include=sections,body`). */
|
|
39
|
+
query?: Record<string, string>;
|
|
40
|
+
/** After a create: `--publish` calls this operation on the new id. */
|
|
41
|
+
publishOp?: string;
|
|
42
|
+
/** Print this key of the answer as the list (the status board's `incidents`). */
|
|
43
|
+
pick?: string;
|
|
44
|
+
/** A path param that may be given by name: listed through `listOp`, matched on `match`. */
|
|
45
|
+
lookup?: Record<string, {
|
|
46
|
+
listOp: string;
|
|
47
|
+
match: string[];
|
|
48
|
+
}>;
|
|
49
|
+
/**
|
|
50
|
+
* The multipart field a positional names a LOCAL FILE for (`assets upload
|
|
51
|
+
* ./logo.png`): its bytes are sent, not the path as text.
|
|
52
|
+
*/
|
|
53
|
+
upload?: string;
|
|
54
|
+
/**
|
|
55
|
+
* The answer is a file (an SDK archive, a PDF, a CSV export): kept as bytes,
|
|
56
|
+
* written to `--out <file>` (default: this name), or printed when it is
|
|
57
|
+
* text and no `--out` is given.
|
|
58
|
+
*/
|
|
59
|
+
download?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Query parameters the route reads but the published spec does not declare
|
|
62
|
+
* (`DELETE /translation-overrides?locale=&key=`). Sent as written, so the
|
|
63
|
+
* command works now; the spec gap is the API's to close.
|
|
64
|
+
*/
|
|
65
|
+
extraQuery?: string[];
|
|
66
|
+
}
|
|
67
|
+
export interface GroupDef {
|
|
68
|
+
name: string;
|
|
69
|
+
aliases?: string[];
|
|
70
|
+
/** Singular, for "delete space docs?". */
|
|
71
|
+
noun: string;
|
|
72
|
+
about: string;
|
|
73
|
+
verbs: Record<string, VerbDef>;
|
|
74
|
+
/** Verb used when none is given (e.g. `forumulate members` → list). */
|
|
75
|
+
defaultVerb?: string;
|
|
76
|
+
/** Positionals with no verb go to the default verb (`search rate limits`). */
|
|
77
|
+
bareArgs?: boolean;
|
|
78
|
+
}
|
|
79
|
+
export declare function groupHelp(g: GroupDef): string;
|
|
80
|
+
/**
|
|
81
|
+
* Run `forumulate <group> <verb> …`. Returns undefined when `legacy` claims
|
|
82
|
+
* the invocation, so the caller can run the older positional form
|
|
83
|
+
* (`forumulate spaces <orgId>`) that scripts already depend on.
|
|
84
|
+
*/
|
|
85
|
+
export declare function runGroup(g: GroupDef, argv: string[], deps: CommandDeps, legacy?: (parsed: Parsed, isVerb: boolean) => boolean): Promise<number | undefined>;
|
|
86
|
+
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/commands/resource.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAOhE,OAAO,EAAiC,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAE5E;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2FAA2F;IAC3F,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC7D;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAoBD,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAkB7C;AAgBD;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,CAAC,EAAE,QAAQ,EACX,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,EAAE,WAAW,EACjB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,OAAO,GACpD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAyC7B"}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.groupHelp = groupHelp;
|
|
4
|
+
exports.runGroup = runGroup;
|
|
5
|
+
const frontmatter_1 = require("../publish/frontmatter");
|
|
6
|
+
const args_1 = require("../api/args");
|
|
7
|
+
const output_1 = require("../api/output");
|
|
8
|
+
const request_1 = require("../api/request");
|
|
9
|
+
const send_1 = require("../api/send");
|
|
10
|
+
const spec_1 = require("../api/spec");
|
|
11
|
+
const config_1 = require("./config");
|
|
12
|
+
const context_1 = require("./context");
|
|
13
|
+
/** Flags the resource layer consumes; everything else is handed to the operation. */
|
|
14
|
+
const OWN = new Set([
|
|
15
|
+
'org',
|
|
16
|
+
'space',
|
|
17
|
+
'library',
|
|
18
|
+
'yes',
|
|
19
|
+
'file',
|
|
20
|
+
'json',
|
|
21
|
+
'columns',
|
|
22
|
+
'help',
|
|
23
|
+
'paginate',
|
|
24
|
+
'max-pages',
|
|
25
|
+
'dry-run',
|
|
26
|
+
'include-headers',
|
|
27
|
+
'publish',
|
|
28
|
+
'out',
|
|
29
|
+
]);
|
|
30
|
+
function groupHelp(g) {
|
|
31
|
+
const lines = [`forumulate ${g.name} — ${g.about}`, '', 'Usage:'];
|
|
32
|
+
for (const [verb, v] of Object.entries(g.verbs)) {
|
|
33
|
+
const op = (0, spec_1.findById)(v.op);
|
|
34
|
+
const args = (v.args ?? []).map((a) => `<${a.replace('...', '…')}>`).join(' ');
|
|
35
|
+
lines.push(` forumulate ${g.name} ${verb}${args ? ` ${args}` : ''}${op ? scopeFlags(op, v) : ''}`);
|
|
36
|
+
lines.push(` ${v.about}${op ? ` [${op.id}]` : ''}`);
|
|
37
|
+
}
|
|
38
|
+
lines.push('', 'Every query parameter and top-level body field of the operation is a flag', '(see `forumulate api describe <operationId>`). --json prints the raw answer,', '--paginate walks a list, --data/--field set a body as under `forumulate api`,', '--dry-run prints the request instead of sending it.');
|
|
39
|
+
return lines.join('\n');
|
|
40
|
+
}
|
|
41
|
+
function scopeFlags(op, v) {
|
|
42
|
+
const params = (0, spec_1.pathParams)(op);
|
|
43
|
+
const own = new Set(v.args ?? []);
|
|
44
|
+
const parts = [];
|
|
45
|
+
if (params.includes('orgId') && !own.has('orgId'))
|
|
46
|
+
parts.push('[--org <org>]');
|
|
47
|
+
if (params.includes('spaceId') && !own.has('spaceId'))
|
|
48
|
+
parts.push('--space <space>');
|
|
49
|
+
if (params.includes('libraryId') && !own.has('libraryId'))
|
|
50
|
+
parts.push('--library <library>');
|
|
51
|
+
if (v.markdown)
|
|
52
|
+
parts.push('[--file <file.md>]');
|
|
53
|
+
if (v.publishOp)
|
|
54
|
+
parts.push('[--publish]');
|
|
55
|
+
if (v.download)
|
|
56
|
+
parts.push(`[--out ${v.download}]`);
|
|
57
|
+
if (v.destructive)
|
|
58
|
+
parts.push('[--yes]');
|
|
59
|
+
return parts.length ? ` ${parts.join(' ')}` : '';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Run `forumulate <group> <verb> …`. Returns undefined when `legacy` claims
|
|
63
|
+
* the invocation, so the caller can run the older positional form
|
|
64
|
+
* (`forumulate spaces <orgId>`) that scripts already depend on.
|
|
65
|
+
*/
|
|
66
|
+
async function runGroup(g, argv, deps, legacy) {
|
|
67
|
+
const parsed = (0, args_1.parseArgs)(argv);
|
|
68
|
+
const [w0, w1, ...more] = parsed.positionals;
|
|
69
|
+
let verb;
|
|
70
|
+
let rest = [];
|
|
71
|
+
if (w0 && w1 && `${w0} ${w1}` in g.verbs) {
|
|
72
|
+
verb = `${w0} ${w1}`;
|
|
73
|
+
rest = more;
|
|
74
|
+
}
|
|
75
|
+
else if (w0 && w0 in g.verbs) {
|
|
76
|
+
verb = w0;
|
|
77
|
+
rest = parsed.positionals.slice(1);
|
|
78
|
+
}
|
|
79
|
+
if (w0 === 'help' || ((0, args_1.has)(parsed, 'help') && (!w0 || verb))) {
|
|
80
|
+
deps.out(groupHelp(g));
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
if (legacy?.(parsed, Boolean(verb)))
|
|
84
|
+
return undefined;
|
|
85
|
+
if (!verb) {
|
|
86
|
+
if (g.defaultVerb && (!w0 || g.bareArgs)) {
|
|
87
|
+
verb = g.defaultVerb;
|
|
88
|
+
rest = parsed.positionals;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const sub = Object.keys(g.verbs).filter((k) => k.startsWith(`${w0} `));
|
|
92
|
+
deps.err(w0
|
|
93
|
+
? `Unknown ${g.name} command: ${w0}${sub.length ? ` (try: ${sub.join(', ')})` : ''}`
|
|
94
|
+
: `Usage: forumulate ${g.name} <command>`);
|
|
95
|
+
deps.out(groupHelp(g));
|
|
96
|
+
return 1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
return await runVerb(g, verb, g.verbs[verb], parsed, rest, deps);
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
if (e instanceof request_1.UsageError) {
|
|
104
|
+
deps.err(`Usage: ${e.message}`);
|
|
105
|
+
return 1;
|
|
106
|
+
}
|
|
107
|
+
throw e;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const src = (deps) => ({ readFile: deps.readFile, readStdin: deps.readStdin });
|
|
111
|
+
async function runVerb(g, verb, v, parsed, positionals, deps) {
|
|
112
|
+
const op = (0, spec_1.findById)(v.op);
|
|
113
|
+
if (!op)
|
|
114
|
+
throw new request_1.UsageError(`${v.op} is not in this CLI's bundled spec`);
|
|
115
|
+
const params = (0, spec_1.pathParams)(op);
|
|
116
|
+
const queryNames = new Set((op.q ?? []).filter((p) => p.in === 'query').map((p) => p.n));
|
|
117
|
+
const bodyProps = op.b ? (0, spec_1.bodyProperties)(op) : {};
|
|
118
|
+
const preset = {};
|
|
119
|
+
const fields = [];
|
|
120
|
+
const queryArgs = {};
|
|
121
|
+
const extra = {};
|
|
122
|
+
for (const name of v.extraQuery ?? []) {
|
|
123
|
+
const given = (0, args_1.flag)(parsed, name);
|
|
124
|
+
if (given !== undefined)
|
|
125
|
+
extra[name] = given;
|
|
126
|
+
}
|
|
127
|
+
const place = (name, value) => {
|
|
128
|
+
if (params.includes(name))
|
|
129
|
+
preset[name] = value;
|
|
130
|
+
else if (queryNames.has(name))
|
|
131
|
+
queryArgs[name] = value;
|
|
132
|
+
else if (v.extraQuery?.includes(name))
|
|
133
|
+
extra[name] = value;
|
|
134
|
+
else if (name === v.upload)
|
|
135
|
+
fields.push(`${name}=@${value}`);
|
|
136
|
+
else
|
|
137
|
+
fields.push(`${name}=${value}`);
|
|
138
|
+
};
|
|
139
|
+
const queue = [...positionals];
|
|
140
|
+
for (const name of v.args ?? []) {
|
|
141
|
+
if (name.endsWith('...')) {
|
|
142
|
+
if (queue.length)
|
|
143
|
+
place(name.slice(0, -3), queue.join(' '));
|
|
144
|
+
queue.length = 0;
|
|
145
|
+
}
|
|
146
|
+
else if (queue.length)
|
|
147
|
+
place(name, queue.shift());
|
|
148
|
+
}
|
|
149
|
+
if (queue.length)
|
|
150
|
+
throw new request_1.UsageError(`unexpected argument "${queue.join(' ')}". ${usageLine(g, verb, v)}`);
|
|
151
|
+
const missing = (v.args ?? []).filter((a) => params.includes(a) && !preset[a]);
|
|
152
|
+
if (missing.length)
|
|
153
|
+
throw new request_1.UsageError(usageLine(g, verb, v));
|
|
154
|
+
if (params.includes('orgId') && !preset.orgId) {
|
|
155
|
+
const org = (0, config_1.setting)('org', (0, args_1.flag)(parsed, 'org'), deps.env, deps.config);
|
|
156
|
+
if (!org)
|
|
157
|
+
throw new request_1.UsageError(`${g.name} ${verb} needs --org <id|slug> (or: forumulate config set org <slug>)`);
|
|
158
|
+
preset.orgId = org;
|
|
159
|
+
}
|
|
160
|
+
for (const what of ['space', 'library']) {
|
|
161
|
+
const param = `${what}Id`;
|
|
162
|
+
const given = (0, config_1.setting)(what, (0, args_1.flag)(parsed, what), deps.env, deps.config);
|
|
163
|
+
if (params.includes(param)) {
|
|
164
|
+
const ref = preset[param] ?? given;
|
|
165
|
+
if (!ref)
|
|
166
|
+
throw new request_1.UsageError(`${g.name} ${verb} needs --${what} <id|slug>`);
|
|
167
|
+
preset[param] = await (0, context_1.resolveChild)(deps, what, preset.orgId, ref);
|
|
168
|
+
}
|
|
169
|
+
else if (param in bodyProps && (0, args_1.flag)(parsed, what) && preset.orgId) {
|
|
170
|
+
// `webhooks create --space docs`: the space is a body field there.
|
|
171
|
+
fields.push(`${param}=${await (0, context_1.resolveChild)(deps, what, preset.orgId, (0, args_1.flag)(parsed, what))}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for (const [param, how] of Object.entries(v.lookup ?? {}))
|
|
175
|
+
if (preset[param])
|
|
176
|
+
preset[param] = await lookup(deps, how, preset, preset[param]);
|
|
177
|
+
const forwarded = {
|
|
178
|
+
positionals: [],
|
|
179
|
+
flags: new Map([...parsed.flags].filter(([k]) => !OWN.has(k) && !v.extraQuery?.includes(k))),
|
|
180
|
+
};
|
|
181
|
+
for (const [k, val] of Object.entries({ ...v.query, ...queryArgs }))
|
|
182
|
+
if (!forwarded.flags.has(k) || k in queryArgs)
|
|
183
|
+
forwarded.flags.set(k, [val]);
|
|
184
|
+
// `--file page.md`: the body, and title/slug from its front matter unless given.
|
|
185
|
+
const file = (0, args_1.flag)(parsed, 'file');
|
|
186
|
+
let content;
|
|
187
|
+
if (file && !v.markdown)
|
|
188
|
+
throw new request_1.UsageError(`${g.name} ${verb} takes no --file`);
|
|
189
|
+
if (file) {
|
|
190
|
+
const { data, body } = (0, frontmatter_1.splitFront)(String(deps.readFile(file)));
|
|
191
|
+
content = body;
|
|
192
|
+
for (const k of ['title', 'slug']) {
|
|
193
|
+
const given = forwarded.flags.has(k) || fields.some((f) => f.startsWith(`${k}=`));
|
|
194
|
+
if (!given && typeof data[k] === 'string' && k in bodyProps)
|
|
195
|
+
fields.push(`${k}=${data[k]}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (content !== undefined && !v.contentOp)
|
|
199
|
+
fields.push(`${v.markdown}=${content}`);
|
|
200
|
+
if (fields.length)
|
|
201
|
+
forwarded.flags.set('field', [...fields, ...(forwarded.flags.get('field') ?? [])]);
|
|
202
|
+
const requests = [];
|
|
203
|
+
if (content !== undefined && v.contentOp) {
|
|
204
|
+
const cop = (0, spec_1.findById)(v.contentOp);
|
|
205
|
+
const contentFlags = {
|
|
206
|
+
positionals: [],
|
|
207
|
+
flags: new Map([['field', [`${v.markdown}=${content}`]]]),
|
|
208
|
+
};
|
|
209
|
+
requests.push((await (0, request_1.planRequest)(cop, contentFlags, [], src(deps), preset)).request);
|
|
210
|
+
}
|
|
211
|
+
// With `--file` and nothing else to change, the content write is the whole command.
|
|
212
|
+
if (!(v.contentOp && content !== undefined && forwarded.flags.size === 0))
|
|
213
|
+
requests.push((await (0, request_1.planRequest)(op, forwarded, [], src(deps), preset)).request);
|
|
214
|
+
const main = requests.at(-1);
|
|
215
|
+
if (Object.keys(extra).length)
|
|
216
|
+
main.query = { ...main.query, ...extra };
|
|
217
|
+
if (v.download)
|
|
218
|
+
main.raw = true;
|
|
219
|
+
if ((0, args_1.has)(parsed, 'dry-run')) {
|
|
220
|
+
for (const r of requests)
|
|
221
|
+
(0, send_1.printRequest)(deps.http, r, deps);
|
|
222
|
+
return 0;
|
|
223
|
+
}
|
|
224
|
+
if (v.destructive) {
|
|
225
|
+
const target = Object.entries(preset)
|
|
226
|
+
.filter(([k]) => k !== 'orgId')
|
|
227
|
+
.at(-1)?.[1] ?? preset.orgId;
|
|
228
|
+
if (!(await (0, context_1.confirm)(deps, (0, args_1.has)(parsed, 'yes'), `${verb} ${g.noun} ${target}?`)))
|
|
229
|
+
return 1;
|
|
230
|
+
}
|
|
231
|
+
const json = (0, args_1.has)(parsed, 'json');
|
|
232
|
+
const opts = {
|
|
233
|
+
json,
|
|
234
|
+
paginate: (0, args_1.has)(parsed, 'paginate'),
|
|
235
|
+
maxPages: Number((0, args_1.flag)(parsed, 'max-pages') ?? 1000),
|
|
236
|
+
columns: (0, args_1.flag)(parsed, 'columns')?.split(',') ?? v.columns,
|
|
237
|
+
includeHeaders: (0, args_1.has)(parsed, 'include-headers'),
|
|
238
|
+
};
|
|
239
|
+
if (v.download)
|
|
240
|
+
return download(deps, main, v.download, (0, args_1.flag)(parsed, 'out'));
|
|
241
|
+
let result;
|
|
242
|
+
for (const request of requests) {
|
|
243
|
+
if (v.pick && !opts.paginate) {
|
|
244
|
+
const res = await deps.http.send(request);
|
|
245
|
+
result = res.data;
|
|
246
|
+
const picked = res.data?.[v.pick];
|
|
247
|
+
(0, send_1.print)(json ? picked : { [v.pick]: picked ?? [] }, opts, deps);
|
|
248
|
+
}
|
|
249
|
+
else
|
|
250
|
+
result = await (0, send_1.sendAndPrint)(deps.http, request, opts, deps);
|
|
251
|
+
}
|
|
252
|
+
if (v.publishOp && (0, args_1.has)(parsed, 'publish')) {
|
|
253
|
+
const id = createdId(result);
|
|
254
|
+
const pub = (0, spec_1.findById)(v.publishOp);
|
|
255
|
+
if (!id || !pub)
|
|
256
|
+
throw new Error('Created, but the answer carried no id to publish.');
|
|
257
|
+
const last = (0, spec_1.pathParams)(pub).at(-1);
|
|
258
|
+
const { request } = await (0, request_1.planRequest)(pub, { positionals: [], flags: new Map() }, [], src(deps), { ...preset, [last]: id });
|
|
259
|
+
await deps.http.send(request);
|
|
260
|
+
if (!json)
|
|
261
|
+
deps.out(`Published ${id}.`);
|
|
262
|
+
}
|
|
263
|
+
return 0;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* A file answer: to `--out`, or to the terminal when it is text. A binary
|
|
267
|
+
* answer printed to a terminal is noise, and to a pipe it is corrupted by the
|
|
268
|
+
* line handling, so with no `--out` it lands in the suggested file instead.
|
|
269
|
+
*/
|
|
270
|
+
async function download(deps, request, suggested, out) {
|
|
271
|
+
const res = await deps.http.send(request);
|
|
272
|
+
const bytes = res.data;
|
|
273
|
+
const type = res.headers.get('content-type') ?? '';
|
|
274
|
+
const text = /^text\/|json|xml|csv|svg|markdown/.test(type);
|
|
275
|
+
if (!out && text) {
|
|
276
|
+
deps.out(bytes.toString('utf8').replace(/\n$/, ''));
|
|
277
|
+
return 0;
|
|
278
|
+
}
|
|
279
|
+
const file = out ?? suggested;
|
|
280
|
+
deps.writeFile(file, bytes);
|
|
281
|
+
deps.err(`Wrote ${bytes.length} bytes to ${file}.`);
|
|
282
|
+
return 0;
|
|
283
|
+
}
|
|
284
|
+
/** The id of what a create made: `data` (the uniform create envelope), else the named resource. */
|
|
285
|
+
function createdId(result) {
|
|
286
|
+
const r = result;
|
|
287
|
+
const data = r?.data;
|
|
288
|
+
if (data?.id)
|
|
289
|
+
return data.id;
|
|
290
|
+
for (const v of Object.values(r ?? {}))
|
|
291
|
+
if (v && typeof v === 'object' && typeof v.id === 'string')
|
|
292
|
+
return v.id;
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
/** `tokens revoke ci-deploy` → the token whose name is `ci-deploy`. */
|
|
296
|
+
async function lookup(deps, how, preset, ref) {
|
|
297
|
+
if ((0, context_1.isUuid)(ref))
|
|
298
|
+
return ref;
|
|
299
|
+
const listOp = (0, spec_1.findById)(how.listOp);
|
|
300
|
+
if (!listOp)
|
|
301
|
+
return ref;
|
|
302
|
+
const { request } = await (0, request_1.planRequest)(listOp, { positionals: [], flags: new Map() }, [], src(deps), preset);
|
|
303
|
+
const rows = ((0, output_1.rowsOf)((await deps.http.send(request)).data)?.rows ?? []);
|
|
304
|
+
const hits = rows.filter((r) => r.id === ref || how.match.some((m) => String(r[m] ?? '').toLowerCase() === ref.toLowerCase()));
|
|
305
|
+
if (hits.length === 1)
|
|
306
|
+
return String(hits[0].id);
|
|
307
|
+
if (hits.length > 1)
|
|
308
|
+
throw new request_1.UsageError(`"${ref}" matches ${hits.length}; pass the id`);
|
|
309
|
+
return ref; // Not a name we know: let the API answer for the id as given.
|
|
310
|
+
}
|
|
311
|
+
function usageLine(g, verb, v) {
|
|
312
|
+
return `forumulate ${g.name} ${verb}${(v.args ?? []).map((a) => ` <${a.replace('...', '…')}>`).join('')}`;
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=resource.js.map
|