@fourtwelvelabs/fetch-contentful 0.1.0 → 0.3.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/CHANGELOG.md +102 -0
- package/README.md +124 -7
- package/dist/cli/index.mjs +949 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/index.cjs +23 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +98 -12
- package/dist/index.d.ts +98 -12
- package/dist/index.mjs +23 -27
- package/dist/index.mjs.map +1 -1
- package/dist/tada/index.cjs +4 -0
- package/dist/tada/index.cjs.map +1 -0
- package/dist/tada/index.d.cts +106 -0
- package/dist/tada/index.d.ts +106 -0
- package/dist/tada/index.mjs +3 -0
- package/dist/tada/index.mjs.map +1 -0
- package/docs/tada.md +327 -0
- package/package.json +28 -2
|
@@ -0,0 +1,949 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdirSync, writeFileSync, existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { resolve, dirname, relative, isAbsolute, sep, join } from 'path';
|
|
4
|
+
import { getIntrospectionQuery, printSchema, buildClientSchema } from 'graphql';
|
|
5
|
+
|
|
6
|
+
// src/env.ts
|
|
7
|
+
function orUndefined(value) {
|
|
8
|
+
return value || void 0;
|
|
9
|
+
}
|
|
10
|
+
function readEnvSettings() {
|
|
11
|
+
if (typeof process === "undefined" || !process.env) {
|
|
12
|
+
return {
|
|
13
|
+
space: void 0,
|
|
14
|
+
environment: void 0,
|
|
15
|
+
token: void 0,
|
|
16
|
+
previewToken: void 0
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
space: orUndefined(
|
|
21
|
+
process.env.CONTENTFUL_SPACE_ID || process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID
|
|
22
|
+
),
|
|
23
|
+
environment: orUndefined(
|
|
24
|
+
process.env.CONTENTFUL_ENVIRONMENT || process.env.NEXT_PUBLIC_CONTENTFUL_ENVIRONMENT
|
|
25
|
+
),
|
|
26
|
+
token: orUndefined(
|
|
27
|
+
process.env.CONTENTFUL_ACCESS_TOKEN || process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN
|
|
28
|
+
),
|
|
29
|
+
previewToken: orUndefined(
|
|
30
|
+
process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN || process.env.NEXT_PUBLIC_CONTENTFUL_PREVIEW_ACCESS_TOKEN
|
|
31
|
+
)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/cli/errors.ts
|
|
36
|
+
var CliError = class extends Error {
|
|
37
|
+
name = "CliError";
|
|
38
|
+
};
|
|
39
|
+
function redact(text, token) {
|
|
40
|
+
if (!token) return text;
|
|
41
|
+
return text.split(token).join("[redacted]");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/cli/args.ts
|
|
45
|
+
var BOOLEAN_FLAGS = ["dry-run", "force", "help"];
|
|
46
|
+
var VALUE_FLAGS = [
|
|
47
|
+
"space",
|
|
48
|
+
"environment",
|
|
49
|
+
"token",
|
|
50
|
+
"schema-path",
|
|
51
|
+
"tada-output",
|
|
52
|
+
"graphql-file",
|
|
53
|
+
"tsconfig",
|
|
54
|
+
"cwd"
|
|
55
|
+
];
|
|
56
|
+
function isBooleanFlag(name) {
|
|
57
|
+
return BOOLEAN_FLAGS.includes(name);
|
|
58
|
+
}
|
|
59
|
+
function isValueFlag(name) {
|
|
60
|
+
return VALUE_FLAGS.includes(name);
|
|
61
|
+
}
|
|
62
|
+
function parseArgs(argv) {
|
|
63
|
+
const parsed = {
|
|
64
|
+
positionals: [],
|
|
65
|
+
values: {},
|
|
66
|
+
flags: /* @__PURE__ */ new Set()
|
|
67
|
+
};
|
|
68
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
69
|
+
const argument = argv[index];
|
|
70
|
+
if (argument === "-h") {
|
|
71
|
+
parsed.flags.add("help");
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (!argument.startsWith("--")) {
|
|
75
|
+
parsed.positionals.push(argument);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const equals = argument.indexOf("=");
|
|
79
|
+
const name = argument.slice(2, equals === -1 ? void 0 : equals);
|
|
80
|
+
const inlineValue = equals === -1 ? void 0 : argument.slice(equals + 1);
|
|
81
|
+
if (isBooleanFlag(name)) {
|
|
82
|
+
if (inlineValue !== void 0) {
|
|
83
|
+
throw new CliError(`--${name} does not take a value.`);
|
|
84
|
+
}
|
|
85
|
+
parsed.flags.add(name);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (!isValueFlag(name)) {
|
|
89
|
+
throw new CliError(`Unknown option "--${name}".`);
|
|
90
|
+
}
|
|
91
|
+
const value = inlineValue ?? argv[++index];
|
|
92
|
+
if (value === void 0) {
|
|
93
|
+
throw new CliError(`--${name} needs a value.`);
|
|
94
|
+
}
|
|
95
|
+
parsed.values[name] = value;
|
|
96
|
+
}
|
|
97
|
+
return parsed;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/cli/diff.ts
|
|
101
|
+
var MAX_LINES = 400;
|
|
102
|
+
function lcsTable(before, after) {
|
|
103
|
+
const table = Array.from(
|
|
104
|
+
{ length: before.length + 1 },
|
|
105
|
+
() => new Array(after.length + 1).fill(0)
|
|
106
|
+
);
|
|
107
|
+
for (let i = before.length - 1; i >= 0; i -= 1) {
|
|
108
|
+
for (let j = after.length - 1; j >= 0; j -= 1) {
|
|
109
|
+
const row = table[i];
|
|
110
|
+
const next = table[i + 1];
|
|
111
|
+
row[j] = before[i] === after[j] ? next[j + 1] + 1 : Math.max(next[j], row[j + 1]);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return table;
|
|
115
|
+
}
|
|
116
|
+
function lineDiff(before, after) {
|
|
117
|
+
if (before === after) return [];
|
|
118
|
+
const beforeLines = before.split("\n");
|
|
119
|
+
const afterLines = after.split("\n");
|
|
120
|
+
if (beforeLines.length + afterLines.length > MAX_LINES * 2) {
|
|
121
|
+
return [
|
|
122
|
+
` (${String(beforeLines.length)} lines \u2192 ${String(
|
|
123
|
+
afterLines.length
|
|
124
|
+
)} lines; too large to diff)`
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
const table = lcsTable(beforeLines, afterLines);
|
|
128
|
+
const output = [];
|
|
129
|
+
let i = 0;
|
|
130
|
+
let j = 0;
|
|
131
|
+
while (i < beforeLines.length && j < afterLines.length) {
|
|
132
|
+
if (beforeLines[i] === afterLines[j]) {
|
|
133
|
+
output.push(` ${beforeLines[i]}`);
|
|
134
|
+
i += 1;
|
|
135
|
+
j += 1;
|
|
136
|
+
} else if (table[i + 1][j] >= table[i][j + 1]) {
|
|
137
|
+
output.push(` - ${beforeLines[i]}`);
|
|
138
|
+
i += 1;
|
|
139
|
+
} else {
|
|
140
|
+
output.push(` + ${afterLines[j]}`);
|
|
141
|
+
j += 1;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
while (i < beforeLines.length) {
|
|
145
|
+
output.push(` - ${beforeLines[i]}`);
|
|
146
|
+
i += 1;
|
|
147
|
+
}
|
|
148
|
+
while (j < afterLines.length) {
|
|
149
|
+
output.push(` + ${afterLines[j]}`);
|
|
150
|
+
j += 1;
|
|
151
|
+
}
|
|
152
|
+
return output;
|
|
153
|
+
}
|
|
154
|
+
function formatBytes(bytes) {
|
|
155
|
+
if (bytes < 1024) return `${String(bytes)} B`;
|
|
156
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} kB`;
|
|
157
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
158
|
+
}
|
|
159
|
+
var PACKAGE_NAME = "@fourtwelvelabs/fetch-contentful";
|
|
160
|
+
function relativeSpecifier(fromFile, toFile) {
|
|
161
|
+
const path = relative(dirname(fromFile), toFile).split(sep).join("/");
|
|
162
|
+
return path.startsWith(".") ? path : `./${path}`;
|
|
163
|
+
}
|
|
164
|
+
function renderGraphqlModule(introspectionImport) {
|
|
165
|
+
return `/**
|
|
166
|
+
* gql.tada, bound to this space's schema.
|
|
167
|
+
*
|
|
168
|
+
* Generated by \`fetch-contentful tada-init\`. Safe to edit and to commit;
|
|
169
|
+
* re-running \`tada-init\` will not overwrite it without \`--force\`.
|
|
170
|
+
*
|
|
171
|
+
* Refresh the schema after a content-model change with:
|
|
172
|
+
* fetch-contentful tada-refresh
|
|
173
|
+
*/
|
|
174
|
+
import { initGraphQLTada } from 'gql.tada';
|
|
175
|
+
import type { ContentfulScalars } from '${PACKAGE_NAME}/tada';
|
|
176
|
+
import type { introspection } from '${introspectionImport}';
|
|
177
|
+
|
|
178
|
+
export const graphql = initGraphQLTada<{
|
|
179
|
+
introspection: introspection;
|
|
180
|
+
scalars: ContentfulScalars;
|
|
181
|
+
}>();
|
|
182
|
+
|
|
183
|
+
export { readFragment } from 'gql.tada';
|
|
184
|
+
export type { FragmentOf, ResultOf, VariablesOf } from 'gql.tada';
|
|
185
|
+
`;
|
|
186
|
+
}
|
|
187
|
+
function graphqlEndpoint(space, environment) {
|
|
188
|
+
return `https://graphql.contentful.com/content/v1/spaces/${encodeURIComponent(
|
|
189
|
+
space
|
|
190
|
+
)}/environments/${encodeURIComponent(environment)}`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// src/cli/introspect.ts
|
|
194
|
+
function bodySnippet(body, token) {
|
|
195
|
+
const cleaned = redact(body, token).trim();
|
|
196
|
+
if (cleaned === "") return "(empty response body)";
|
|
197
|
+
return cleaned.length > 300 ? `${cleaned.slice(0, 300)}\u2026` : cleaned;
|
|
198
|
+
}
|
|
199
|
+
async function fetchSchemaSdl(options) {
|
|
200
|
+
const url = graphqlEndpoint(options.space, options.environment);
|
|
201
|
+
let response;
|
|
202
|
+
try {
|
|
203
|
+
response = await options.fetch(url, {
|
|
204
|
+
method: "POST",
|
|
205
|
+
headers: {
|
|
206
|
+
"Content-Type": "application/json",
|
|
207
|
+
Authorization: `Bearer ${options.token}`
|
|
208
|
+
},
|
|
209
|
+
body: JSON.stringify({ query: getIntrospectionQuery() })
|
|
210
|
+
});
|
|
211
|
+
} catch (cause) {
|
|
212
|
+
throw new CliError(
|
|
213
|
+
`Could not reach Contentful at ${url}: ${redact(
|
|
214
|
+
String(cause),
|
|
215
|
+
options.token
|
|
216
|
+
)}`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
if (response.status === 401 || response.status === 403) {
|
|
220
|
+
throw new CliError(
|
|
221
|
+
`Contentful rejected the access token (HTTP ${String(
|
|
222
|
+
response.status
|
|
223
|
+
)}).
|
|
224
|
+
Check that the token is a Content Delivery API token for space "${options.space}", and that it has access to environment "${options.environment}".`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (!response.ok) {
|
|
228
|
+
const body = bodySnippet(await response.text().catch(() => ""), options.token);
|
|
229
|
+
throw new CliError(
|
|
230
|
+
`Contentful responded with HTTP ${String(response.status)}.
|
|
231
|
+
${body}`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
let payload;
|
|
235
|
+
try {
|
|
236
|
+
payload = await response.json();
|
|
237
|
+
} catch {
|
|
238
|
+
throw new CliError("Contentful returned an unreadable response body.");
|
|
239
|
+
}
|
|
240
|
+
if (payload.errors && payload.errors.length > 0) {
|
|
241
|
+
const messages = payload.errors.map((error) => error.message ?? "unknown error").join("; ");
|
|
242
|
+
throw new CliError(
|
|
243
|
+
`Contentful returned GraphQL errors during introspection: ${redact(
|
|
244
|
+
messages,
|
|
245
|
+
options.token
|
|
246
|
+
)}`
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
if (!payload.data) {
|
|
250
|
+
throw new CliError(
|
|
251
|
+
"Contentful returned no introspection data. Check the space and environment ids."
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
return `${printSchema(buildClientSchema(payload.data))}
|
|
256
|
+
`;
|
|
257
|
+
} catch (cause) {
|
|
258
|
+
throw new CliError(
|
|
259
|
+
`Could not build a schema from Contentful's introspection response: ${String(
|
|
260
|
+
cause
|
|
261
|
+
)}`
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
var LOCKFILES = [
|
|
266
|
+
["bun", "bun.lock"],
|
|
267
|
+
["bun", "bun.lockb"],
|
|
268
|
+
["pnpm", "pnpm-lock.yaml"],
|
|
269
|
+
["yarn", "yarn.lock"],
|
|
270
|
+
["npm", "package-lock.json"]
|
|
271
|
+
];
|
|
272
|
+
function detectPackageManager(cwd) {
|
|
273
|
+
for (const [manager, lockfile] of LOCKFILES) {
|
|
274
|
+
if (existsSync(join(cwd, lockfile))) return manager;
|
|
275
|
+
}
|
|
276
|
+
return "npm";
|
|
277
|
+
}
|
|
278
|
+
function installCommand(manager, packages) {
|
|
279
|
+
const list = packages.join(" ");
|
|
280
|
+
switch (manager) {
|
|
281
|
+
case "bun":
|
|
282
|
+
return `bun add -d ${list}`;
|
|
283
|
+
case "pnpm":
|
|
284
|
+
return `pnpm add -D ${list}`;
|
|
285
|
+
case "yarn":
|
|
286
|
+
return `yarn add -D ${list}`;
|
|
287
|
+
case "npm":
|
|
288
|
+
return `npm install -D ${list}`;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function missingDependencies(cwd, packages) {
|
|
292
|
+
let manifest;
|
|
293
|
+
try {
|
|
294
|
+
manifest = JSON.parse(
|
|
295
|
+
readFileSync(join(cwd, "package.json"), "utf8")
|
|
296
|
+
);
|
|
297
|
+
} catch {
|
|
298
|
+
return [...packages];
|
|
299
|
+
}
|
|
300
|
+
const declared = /* @__PURE__ */ new Set();
|
|
301
|
+
for (const field of [
|
|
302
|
+
"dependencies",
|
|
303
|
+
"devDependencies",
|
|
304
|
+
"peerDependencies",
|
|
305
|
+
"optionalDependencies"
|
|
306
|
+
]) {
|
|
307
|
+
const section = manifest[field];
|
|
308
|
+
if (typeof section === "object" && section !== null) {
|
|
309
|
+
for (const name of Object.keys(section)) declared.add(name);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return packages.filter((name) => !declared.has(name));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// src/cli/jsonc.ts
|
|
316
|
+
var JsoncError = class extends Error {
|
|
317
|
+
name = "JsoncError";
|
|
318
|
+
};
|
|
319
|
+
var WHITESPACE = " \n\r";
|
|
320
|
+
var Scanner = class {
|
|
321
|
+
constructor(source) {
|
|
322
|
+
this.source = source;
|
|
323
|
+
}
|
|
324
|
+
source;
|
|
325
|
+
index = 0;
|
|
326
|
+
/** Skips whitespace, `//` line comments and `/* *\/` block comments. */
|
|
327
|
+
skipTrivia() {
|
|
328
|
+
for (; ; ) {
|
|
329
|
+
while (this.index < this.source.length && WHITESPACE.includes(this.source[this.index])) {
|
|
330
|
+
this.index += 1;
|
|
331
|
+
}
|
|
332
|
+
if (this.source.startsWith("//", this.index)) {
|
|
333
|
+
const newline = this.source.indexOf("\n", this.index);
|
|
334
|
+
this.index = newline === -1 ? this.source.length : newline + 1;
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (this.source.startsWith("/*", this.index)) {
|
|
338
|
+
const close = this.source.indexOf("*/", this.index + 2);
|
|
339
|
+
if (close === -1) {
|
|
340
|
+
throw new JsoncError("Unterminated block comment.");
|
|
341
|
+
}
|
|
342
|
+
this.index = close + 2;
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
peek() {
|
|
349
|
+
this.skipTrivia();
|
|
350
|
+
if (this.index >= this.source.length) {
|
|
351
|
+
throw new JsoncError("Unexpected end of input.");
|
|
352
|
+
}
|
|
353
|
+
return this.source[this.index];
|
|
354
|
+
}
|
|
355
|
+
expect(character) {
|
|
356
|
+
if (this.peek() !== character) {
|
|
357
|
+
throw new JsoncError(
|
|
358
|
+
`Expected "${character}" at offset ${String(this.index)}.`
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
this.index += 1;
|
|
362
|
+
}
|
|
363
|
+
parseRoot() {
|
|
364
|
+
const node = this.parseValue();
|
|
365
|
+
this.skipTrivia();
|
|
366
|
+
if (this.index !== this.source.length) {
|
|
367
|
+
throw new JsoncError(
|
|
368
|
+
`Unexpected trailing content at offset ${String(this.index)}.`
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
return node;
|
|
372
|
+
}
|
|
373
|
+
parseValue() {
|
|
374
|
+
const character = this.peek();
|
|
375
|
+
if (character === "{") return this.parseObject();
|
|
376
|
+
if (character === "[") return this.parseArray();
|
|
377
|
+
if (character === '"') return this.parseString();
|
|
378
|
+
return this.parseLiteral();
|
|
379
|
+
}
|
|
380
|
+
parseObject() {
|
|
381
|
+
const start = this.index;
|
|
382
|
+
this.expect("{");
|
|
383
|
+
const members = [];
|
|
384
|
+
for (; ; ) {
|
|
385
|
+
if (this.peek() === "}") {
|
|
386
|
+
this.index += 1;
|
|
387
|
+
return { kind: "object", start, end: this.index, members };
|
|
388
|
+
}
|
|
389
|
+
const memberStart = this.index;
|
|
390
|
+
const key = this.parseString();
|
|
391
|
+
this.expect(":");
|
|
392
|
+
const value = this.parseValue();
|
|
393
|
+
members.push({
|
|
394
|
+
key: key.value,
|
|
395
|
+
start: memberStart,
|
|
396
|
+
end: value.end,
|
|
397
|
+
value
|
|
398
|
+
});
|
|
399
|
+
if (this.peek() === ",") {
|
|
400
|
+
this.index += 1;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
parseArray() {
|
|
405
|
+
const start = this.index;
|
|
406
|
+
this.expect("[");
|
|
407
|
+
const elements = [];
|
|
408
|
+
for (; ; ) {
|
|
409
|
+
if (this.peek() === "]") {
|
|
410
|
+
this.index += 1;
|
|
411
|
+
return { kind: "array", start, end: this.index, elements };
|
|
412
|
+
}
|
|
413
|
+
elements.push(this.parseValue());
|
|
414
|
+
if (this.peek() === ",") {
|
|
415
|
+
this.index += 1;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
parseString() {
|
|
420
|
+
this.skipTrivia();
|
|
421
|
+
const start = this.index;
|
|
422
|
+
if (this.source[start] !== '"') {
|
|
423
|
+
throw new JsoncError(`Expected a string at offset ${String(start)}.`);
|
|
424
|
+
}
|
|
425
|
+
this.index += 1;
|
|
426
|
+
while (this.index < this.source.length) {
|
|
427
|
+
const character = this.source[this.index];
|
|
428
|
+
if (character === "\\") {
|
|
429
|
+
this.index += 2;
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
this.index += 1;
|
|
433
|
+
if (character === '"') {
|
|
434
|
+
const end = this.index;
|
|
435
|
+
return {
|
|
436
|
+
kind: "string",
|
|
437
|
+
start,
|
|
438
|
+
end,
|
|
439
|
+
value: JSON.parse(this.source.slice(start, end))
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
throw new JsoncError(`Unterminated string at offset ${String(start)}.`);
|
|
444
|
+
}
|
|
445
|
+
/** Numbers, `true`, `false` and `null` — read as an opaque token. */
|
|
446
|
+
parseLiteral() {
|
|
447
|
+
this.skipTrivia();
|
|
448
|
+
const start = this.index;
|
|
449
|
+
while (this.index < this.source.length && !",]}".includes(this.source[this.index]) && !WHITESPACE.includes(this.source[this.index])) {
|
|
450
|
+
this.index += 1;
|
|
451
|
+
}
|
|
452
|
+
if (this.index === start) {
|
|
453
|
+
throw new JsoncError(`Unexpected character at offset ${String(start)}.`);
|
|
454
|
+
}
|
|
455
|
+
return { kind: "literal", start, end: this.index };
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
function parseJsonc(source) {
|
|
459
|
+
return new Scanner(source).parseRoot();
|
|
460
|
+
}
|
|
461
|
+
function findMember(node, key) {
|
|
462
|
+
if (node.kind !== "object") return void 0;
|
|
463
|
+
return node.members.find((member) => member.key === key);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// src/cli/tsconfig.ts
|
|
467
|
+
var GRAPHQLSP_PLUGIN = "@0no-co/graphqlsp";
|
|
468
|
+
function applyEdits(source, edits) {
|
|
469
|
+
let result = source;
|
|
470
|
+
for (const edit of [...edits].sort((a, b) => b.start - a.start)) {
|
|
471
|
+
result = result.slice(0, edit.start) + edit.text + result.slice(edit.end);
|
|
472
|
+
}
|
|
473
|
+
return result;
|
|
474
|
+
}
|
|
475
|
+
function indentAt(source, offset) {
|
|
476
|
+
const lineStart = source.lastIndexOf("\n", offset - 1) + 1;
|
|
477
|
+
const line = source.slice(lineStart, offset);
|
|
478
|
+
return line.slice(0, line.length - line.trimStart().length);
|
|
479
|
+
}
|
|
480
|
+
function detectIndentUnit(source) {
|
|
481
|
+
const match = /\n([ \t]+)\S/.exec(source);
|
|
482
|
+
return match?.[1] ?? " ";
|
|
483
|
+
}
|
|
484
|
+
function renderPluginEntry(indent, unit, config) {
|
|
485
|
+
return [
|
|
486
|
+
"{",
|
|
487
|
+
`${indent}${unit}"name": ${JSON.stringify(GRAPHQLSP_PLUGIN)},`,
|
|
488
|
+
`${indent}${unit}"schema": ${JSON.stringify(config.schema)},`,
|
|
489
|
+
`${indent}${unit}"tadaOutputLocation": ${JSON.stringify(
|
|
490
|
+
config.tadaOutputLocation
|
|
491
|
+
)}`,
|
|
492
|
+
`${indent}}`
|
|
493
|
+
].join("\n");
|
|
494
|
+
}
|
|
495
|
+
function insertMember(source, object, key, renderValue, unit) {
|
|
496
|
+
const last = object.members[object.members.length - 1];
|
|
497
|
+
if (last) {
|
|
498
|
+
const indent2 = indentAt(source, last.start);
|
|
499
|
+
return {
|
|
500
|
+
start: last.end,
|
|
501
|
+
end: last.end,
|
|
502
|
+
text: `,
|
|
503
|
+
${indent2}"${key}": ${renderValue(indent2)}`
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
const closeIndent = indentAt(source, object.start);
|
|
507
|
+
const indent = `${closeIndent}${unit}`;
|
|
508
|
+
return {
|
|
509
|
+
start: object.start + 1,
|
|
510
|
+
end: object.end - 1,
|
|
511
|
+
text: `
|
|
512
|
+
${indent}"${key}": ${renderValue(indent)}
|
|
513
|
+
${closeIndent}`
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
function renderPluginsArray(indent, unit, config) {
|
|
517
|
+
const entryIndent = `${indent}${unit}`;
|
|
518
|
+
return `[
|
|
519
|
+
${entryIndent}${renderPluginEntry(
|
|
520
|
+
entryIndent,
|
|
521
|
+
unit,
|
|
522
|
+
config
|
|
523
|
+
)}
|
|
524
|
+
${indent}]`;
|
|
525
|
+
}
|
|
526
|
+
function patchTsconfig(source, config) {
|
|
527
|
+
let root;
|
|
528
|
+
try {
|
|
529
|
+
root = parseJsonc(source);
|
|
530
|
+
} catch (cause) {
|
|
531
|
+
const reason = cause instanceof JsoncError ? cause.message : String(cause);
|
|
532
|
+
return { status: "manual", reason: `could not be parsed (${reason})` };
|
|
533
|
+
}
|
|
534
|
+
if (root.kind !== "object") {
|
|
535
|
+
return { status: "manual", reason: "its root is not an object" };
|
|
536
|
+
}
|
|
537
|
+
const unit = detectIndentUnit(source);
|
|
538
|
+
const compilerOptions = findMember(root, "compilerOptions");
|
|
539
|
+
if (!compilerOptions) {
|
|
540
|
+
const edit = insertMember(
|
|
541
|
+
source,
|
|
542
|
+
root,
|
|
543
|
+
"compilerOptions",
|
|
544
|
+
(indent) => `{
|
|
545
|
+
${indent}${unit}"plugins": ${renderPluginsArray(
|
|
546
|
+
`${indent}${unit}`,
|
|
547
|
+
unit,
|
|
548
|
+
config
|
|
549
|
+
)}
|
|
550
|
+
${indent}}`,
|
|
551
|
+
unit
|
|
552
|
+
);
|
|
553
|
+
return { status: "patched", source: applyEdits(source, [edit]) };
|
|
554
|
+
}
|
|
555
|
+
if (compilerOptions.value.kind !== "object") {
|
|
556
|
+
return { status: "manual", reason: '"compilerOptions" is not an object' };
|
|
557
|
+
}
|
|
558
|
+
const plugins = findMember(compilerOptions.value, "plugins");
|
|
559
|
+
if (!plugins) {
|
|
560
|
+
const edit = insertMember(
|
|
561
|
+
source,
|
|
562
|
+
compilerOptions.value,
|
|
563
|
+
"plugins",
|
|
564
|
+
(indent) => renderPluginsArray(indent, unit, config),
|
|
565
|
+
unit
|
|
566
|
+
);
|
|
567
|
+
return { status: "patched", source: applyEdits(source, [edit]) };
|
|
568
|
+
}
|
|
569
|
+
if (plugins.value.kind !== "array") {
|
|
570
|
+
return { status: "manual", reason: '"compilerOptions.plugins" is not an array' };
|
|
571
|
+
}
|
|
572
|
+
const existing = plugins.value.elements.find((element) => {
|
|
573
|
+
const name = findMember(element, "name");
|
|
574
|
+
return name?.value.kind === "string" && name.value.value === GRAPHQLSP_PLUGIN;
|
|
575
|
+
});
|
|
576
|
+
if (existing) {
|
|
577
|
+
if (existing.kind !== "object") {
|
|
578
|
+
return { status: "manual", reason: "its graphqlsp plugin entry is not an object" };
|
|
579
|
+
}
|
|
580
|
+
const edits = [];
|
|
581
|
+
for (const [key, value] of [
|
|
582
|
+
["schema", config.schema],
|
|
583
|
+
["tadaOutputLocation", config.tadaOutputLocation]
|
|
584
|
+
]) {
|
|
585
|
+
const member = findMember(existing, key);
|
|
586
|
+
if (member) {
|
|
587
|
+
edits.push({
|
|
588
|
+
start: member.value.start,
|
|
589
|
+
end: member.value.end,
|
|
590
|
+
text: JSON.stringify(value)
|
|
591
|
+
});
|
|
592
|
+
} else {
|
|
593
|
+
edits.push(
|
|
594
|
+
insertMember(source, existing, key, () => JSON.stringify(value), unit)
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
const patched = applyEdits(source, edits);
|
|
599
|
+
return patched === source ? { status: "unchanged" } : { status: "patched", source: patched };
|
|
600
|
+
}
|
|
601
|
+
const last = plugins.value.elements[plugins.value.elements.length - 1];
|
|
602
|
+
if (last) {
|
|
603
|
+
const indent = indentAt(source, last.start);
|
|
604
|
+
return {
|
|
605
|
+
status: "patched",
|
|
606
|
+
source: applyEdits(source, [
|
|
607
|
+
{
|
|
608
|
+
start: last.end,
|
|
609
|
+
end: last.end,
|
|
610
|
+
text: `,
|
|
611
|
+
${indent}${renderPluginEntry(indent, unit, config)}`
|
|
612
|
+
}
|
|
613
|
+
])
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
const closeIndent = indentAt(source, plugins.value.start);
|
|
617
|
+
const entryIndent = `${closeIndent}${unit}`;
|
|
618
|
+
return {
|
|
619
|
+
status: "patched",
|
|
620
|
+
source: applyEdits(source, [
|
|
621
|
+
{
|
|
622
|
+
start: plugins.value.start + 1,
|
|
623
|
+
end: plugins.value.end - 1,
|
|
624
|
+
text: `
|
|
625
|
+
${entryIndent}${renderPluginEntry(
|
|
626
|
+
entryIndent,
|
|
627
|
+
unit,
|
|
628
|
+
config
|
|
629
|
+
)}
|
|
630
|
+
${closeIndent}`
|
|
631
|
+
}
|
|
632
|
+
])
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
function manualPluginBlock(config) {
|
|
636
|
+
return renderPluginEntry("", " ", config);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// src/cli/run.ts
|
|
640
|
+
var REQUIRED_PEERS = ["gql.tada", GRAPHQLSP_PLUGIN];
|
|
641
|
+
var DEFAULTS = {
|
|
642
|
+
schemaPath: "./contentful-schema.graphql",
|
|
643
|
+
tadaOutput: "./src/contentful-env.d.ts",
|
|
644
|
+
graphqlFile: "./src/graphql.ts",
|
|
645
|
+
tsconfig: "./tsconfig.json"
|
|
646
|
+
};
|
|
647
|
+
var VERB_WIDTH = 12;
|
|
648
|
+
var HELP = `fetch-contentful \u2014 gql.tada setup for a Contentful space
|
|
649
|
+
|
|
650
|
+
Usage:
|
|
651
|
+
fetch-contentful tada-init [options] Set up gql.tada in this project
|
|
652
|
+
fetch-contentful tada-refresh [options] Re-download the schema only
|
|
653
|
+
|
|
654
|
+
Configuration (flags win over environment variables):
|
|
655
|
+
--space <id> CONTENTFUL_SPACE_ID
|
|
656
|
+
--environment <id> CONTENTFUL_ENVIRONMENT (default "master")
|
|
657
|
+
--token <token> CONTENTFUL_ACCESS_TOKEN (Content Delivery API)
|
|
658
|
+
|
|
659
|
+
Paths (relative to the working directory):
|
|
660
|
+
--schema-path <path> default ${DEFAULTS.schemaPath}
|
|
661
|
+
--tada-output <path> default ${DEFAULTS.tadaOutput}
|
|
662
|
+
--graphql-file <path> default ${DEFAULTS.graphqlFile}
|
|
663
|
+
--tsconfig <path> default ${DEFAULTS.tsconfig}
|
|
664
|
+
|
|
665
|
+
Other:
|
|
666
|
+
--dry-run Show what would change; write nothing
|
|
667
|
+
--force Overwrite an existing graphql file (tada-init)
|
|
668
|
+
--cwd <path> Run against another directory
|
|
669
|
+
-h, --help Show this help
|
|
670
|
+
|
|
671
|
+
The NEXT_PUBLIC_-prefixed variable names are read as fallbacks, exactly as
|
|
672
|
+
the library reads them at runtime.`;
|
|
673
|
+
function resolveConfig(args) {
|
|
674
|
+
const env = readEnvSettings();
|
|
675
|
+
const space = args.values.space ?? env.space;
|
|
676
|
+
const token = args.values.token ?? env.token;
|
|
677
|
+
const environment = args.values.environment ?? env.environment ?? "master";
|
|
678
|
+
const missing = [];
|
|
679
|
+
if (!space) {
|
|
680
|
+
missing.push(
|
|
681
|
+
"space (pass --space, or set CONTENTFUL_SPACE_ID / NEXT_PUBLIC_CONTENTFUL_SPACE_ID)"
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
if (!token) {
|
|
685
|
+
missing.push(
|
|
686
|
+
"access token (pass --token, or set CONTENTFUL_ACCESS_TOKEN / NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN)"
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
if (!space || !token) {
|
|
690
|
+
throw new CliError(
|
|
691
|
+
`Missing required Contentful configuration:
|
|
692
|
+
- ${missing.join(
|
|
693
|
+
"\n - "
|
|
694
|
+
)}`
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
return { space, environment, token };
|
|
698
|
+
}
|
|
699
|
+
function resolvePaths(args, io) {
|
|
700
|
+
const root = resolve(io.cwd, args.values.cwd ?? ".");
|
|
701
|
+
const at = (value, fallback) => resolve(root, value ?? fallback);
|
|
702
|
+
return {
|
|
703
|
+
root,
|
|
704
|
+
schema: at(args.values["schema-path"], DEFAULTS.schemaPath),
|
|
705
|
+
tadaOutput: at(args.values["tada-output"], DEFAULTS.tadaOutput),
|
|
706
|
+
graphqlFile: at(args.values["graphql-file"], DEFAULTS.graphqlFile),
|
|
707
|
+
tsconfig: at(args.values.tsconfig, DEFAULTS.tsconfig)
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
function display(root, path) {
|
|
711
|
+
const shown = relative(root, path);
|
|
712
|
+
return shown === "" || shown.startsWith("..") || isAbsolute(shown) ? path : shown;
|
|
713
|
+
}
|
|
714
|
+
function readIfExists(path) {
|
|
715
|
+
return existsSync(path) ? readFileSync(path, "utf8") : void 0;
|
|
716
|
+
}
|
|
717
|
+
function planSchema(sdl, paths) {
|
|
718
|
+
const before = readIfExists(paths.schema);
|
|
719
|
+
if (before === sdl) return { kind: "unchanged", path: paths.schema };
|
|
720
|
+
return {
|
|
721
|
+
kind: "write",
|
|
722
|
+
path: paths.schema,
|
|
723
|
+
before,
|
|
724
|
+
after: sdl,
|
|
725
|
+
preview: "size"
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
function planTsconfig(paths) {
|
|
729
|
+
const before = readIfExists(paths.tsconfig);
|
|
730
|
+
if (before === void 0) {
|
|
731
|
+
throw new CliError(
|
|
732
|
+
`No tsconfig at ${display(paths.root, paths.tsconfig)}. Pass --tsconfig if it lives elsewhere.`
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
const config = {
|
|
736
|
+
schema: relativeSpecifier(paths.tsconfig, paths.schema),
|
|
737
|
+
tadaOutputLocation: relativeSpecifier(paths.tsconfig, paths.tadaOutput)
|
|
738
|
+
};
|
|
739
|
+
const result = patchTsconfig(before, config);
|
|
740
|
+
if (result.status === "unchanged") {
|
|
741
|
+
return { kind: "unchanged", path: paths.tsconfig };
|
|
742
|
+
}
|
|
743
|
+
if (result.status === "manual") {
|
|
744
|
+
return {
|
|
745
|
+
kind: "manual",
|
|
746
|
+
path: paths.tsconfig,
|
|
747
|
+
reason: result.reason,
|
|
748
|
+
block: manualPluginBlock(config)
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
return {
|
|
752
|
+
kind: "write",
|
|
753
|
+
path: paths.tsconfig,
|
|
754
|
+
before,
|
|
755
|
+
after: result.source,
|
|
756
|
+
preview: "diff"
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
function planGraphqlModule(paths, force) {
|
|
760
|
+
const before = readIfExists(paths.graphqlFile);
|
|
761
|
+
const after = renderGraphqlModule(
|
|
762
|
+
relativeSpecifier(paths.graphqlFile, paths.tadaOutput)
|
|
763
|
+
);
|
|
764
|
+
if (before !== void 0 && !force) {
|
|
765
|
+
return {
|
|
766
|
+
kind: "skip",
|
|
767
|
+
path: paths.graphqlFile,
|
|
768
|
+
reason: "already exists; pass --force to overwrite"
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
if (before === after) return { kind: "unchanged", path: paths.graphqlFile };
|
|
772
|
+
return {
|
|
773
|
+
kind: "write",
|
|
774
|
+
path: paths.graphqlFile,
|
|
775
|
+
before,
|
|
776
|
+
after,
|
|
777
|
+
preview: "content"
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
function logAction(io, verb, detail) {
|
|
781
|
+
io.stdout(` ${verb.padEnd(VERB_WIDTH)} ${detail}`);
|
|
782
|
+
}
|
|
783
|
+
function report(action, paths, dryRun, io) {
|
|
784
|
+
const name = display(paths.root, action.path);
|
|
785
|
+
if (action.kind === "unchanged") {
|
|
786
|
+
logAction(io, "unchanged", name);
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
if (action.kind === "skip") {
|
|
790
|
+
logAction(io, "skipped", `${name} (${action.reason})`);
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
if (action.kind === "manual") {
|
|
794
|
+
logAction(io, "manual", `${name} (${action.reason})`);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
const created = action.before === void 0;
|
|
798
|
+
const verb = dryRun ? created ? "would create" : "would update" : created ? "created" : "updated";
|
|
799
|
+
const size = action.preview === "size" ? ` (${formatBytes(Buffer.byteLength(action.after))})` : "";
|
|
800
|
+
logAction(io, verb, `${name}${size}`);
|
|
801
|
+
if (!dryRun) return;
|
|
802
|
+
if (action.preview === "content") {
|
|
803
|
+
for (const line of action.after.replace(/\n$/, "").split("\n")) {
|
|
804
|
+
io.stdout(` + ${line}`);
|
|
805
|
+
}
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
if (action.before === void 0) return;
|
|
809
|
+
if (action.preview === "diff") {
|
|
810
|
+
for (const line of lineDiff(action.before, action.after)) {
|
|
811
|
+
io.stdout(` ${line}`);
|
|
812
|
+
}
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
const beforeBytes = Buffer.byteLength(action.before);
|
|
816
|
+
const afterBytes = Buffer.byteLength(action.after);
|
|
817
|
+
const delta = afterBytes - beforeBytes;
|
|
818
|
+
io.stdout(
|
|
819
|
+
` ${String(beforeBytes)} \u2192 ${String(afterBytes)} bytes (${delta >= 0 ? "+" : ""}${String(delta)})`
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
function apply(action) {
|
|
823
|
+
if (action.kind !== "write") return;
|
|
824
|
+
mkdirSync(dirname(action.path), { recursive: true });
|
|
825
|
+
writeFileSync(action.path, action.after, "utf8");
|
|
826
|
+
}
|
|
827
|
+
function reportManual(action, paths, io) {
|
|
828
|
+
if (action.kind !== "manual") return;
|
|
829
|
+
io.stdout("");
|
|
830
|
+
io.stdout(
|
|
831
|
+
`${display(paths.root, action.path)} was left untouched because ${action.reason}.`
|
|
832
|
+
);
|
|
833
|
+
io.stdout('Add this entry to "compilerOptions.plugins" by hand:');
|
|
834
|
+
io.stdout("");
|
|
835
|
+
for (const line of action.block.split("\n")) io.stdout(` ${line}`);
|
|
836
|
+
}
|
|
837
|
+
function reportPeers(paths, io) {
|
|
838
|
+
const missing = missingDependencies(paths.root, REQUIRED_PEERS);
|
|
839
|
+
if (missing.length === 0) return;
|
|
840
|
+
io.stdout("");
|
|
841
|
+
io.stdout(`Install the packages the generated setup needs:`);
|
|
842
|
+
io.stdout(` ${installCommand(detectPackageManager(paths.root), missing)}`);
|
|
843
|
+
}
|
|
844
|
+
async function tadaInit(args, io) {
|
|
845
|
+
const config = resolveConfig(args);
|
|
846
|
+
const paths = resolvePaths(args, io);
|
|
847
|
+
const dryRun = args.flags.has("dry-run");
|
|
848
|
+
const tsconfigAction = planTsconfig(paths);
|
|
849
|
+
const sdl = await fetchSchemaSdl({ ...config, fetch: io.fetch });
|
|
850
|
+
const actions = [
|
|
851
|
+
planSchema(sdl, paths),
|
|
852
|
+
tsconfigAction,
|
|
853
|
+
planGraphqlModule(paths, args.flags.has("force"))
|
|
854
|
+
];
|
|
855
|
+
io.stdout(
|
|
856
|
+
dryRun ? `Dry run \u2014 nothing will be written (space ${config.space}, environment ${config.environment}).` : `Configuring gql.tada for space ${config.space}, environment ${config.environment}.`
|
|
857
|
+
);
|
|
858
|
+
for (const action of actions) {
|
|
859
|
+
if (!dryRun) apply(action);
|
|
860
|
+
report(action, paths, dryRun, io);
|
|
861
|
+
}
|
|
862
|
+
for (const action of actions) reportManual(action, paths, io);
|
|
863
|
+
reportPeers(paths, io);
|
|
864
|
+
if (dryRun) return 0;
|
|
865
|
+
io.stdout("");
|
|
866
|
+
io.stdout("Next steps:");
|
|
867
|
+
io.stdout(` 1. Restart the TypeScript server so ${GRAPHQLSP_PLUGIN} loads.`);
|
|
868
|
+
io.stdout(
|
|
869
|
+
` 2. Write a query with the \`graphql\` helper from ${display(
|
|
870
|
+
paths.root,
|
|
871
|
+
paths.graphqlFile
|
|
872
|
+
)},`
|
|
873
|
+
);
|
|
874
|
+
io.stdout(
|
|
875
|
+
` then pass it to fetchContentful from ${PACKAGE_NAME}.`
|
|
876
|
+
);
|
|
877
|
+
io.stdout(" Result and variable types are inferred from the document.");
|
|
878
|
+
io.stdout(
|
|
879
|
+
" 3. After a content-model change, run `fetch-contentful tada-refresh`."
|
|
880
|
+
);
|
|
881
|
+
return 0;
|
|
882
|
+
}
|
|
883
|
+
async function tadaRefresh(args, io) {
|
|
884
|
+
const config = resolveConfig(args);
|
|
885
|
+
const paths = resolvePaths(args, io);
|
|
886
|
+
const dryRun = args.flags.has("dry-run");
|
|
887
|
+
const sdl = await fetchSchemaSdl({ ...config, fetch: io.fetch });
|
|
888
|
+
const action = planSchema(sdl, paths);
|
|
889
|
+
if (action.kind === "unchanged") {
|
|
890
|
+
io.stdout(
|
|
891
|
+
`Schema is already up to date \u2014 ${display(
|
|
892
|
+
paths.root,
|
|
893
|
+
paths.schema
|
|
894
|
+
)} left untouched.`
|
|
895
|
+
);
|
|
896
|
+
return 0;
|
|
897
|
+
}
|
|
898
|
+
if (!dryRun) apply(action);
|
|
899
|
+
report(action, paths, dryRun, io);
|
|
900
|
+
return 0;
|
|
901
|
+
}
|
|
902
|
+
async function dispatch(argv, io) {
|
|
903
|
+
const args = parseArgs(argv);
|
|
904
|
+
const command = args.positionals.join("-");
|
|
905
|
+
if (args.flags.has("help") || command === "" || command === "help") {
|
|
906
|
+
io.stdout(HELP);
|
|
907
|
+
return 0;
|
|
908
|
+
}
|
|
909
|
+
if (command === "tada-init") return tadaInit(args, io);
|
|
910
|
+
if (command === "tada-refresh") return tadaRefresh(args, io);
|
|
911
|
+
throw new CliError(
|
|
912
|
+
`Unknown command "${args.positionals.join(
|
|
913
|
+
" "
|
|
914
|
+
)}". Run with --help to see the available commands.`
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
function knownTokens(argv) {
|
|
918
|
+
const env = readEnvSettings();
|
|
919
|
+
const tokens = [env.token, env.previewToken];
|
|
920
|
+
for (const [index, argument] of argv.entries()) {
|
|
921
|
+
if (argument.startsWith("--token=")) tokens.push(argument.slice(8));
|
|
922
|
+
else if (argument === "--token") tokens.push(argv[index + 1]);
|
|
923
|
+
}
|
|
924
|
+
return tokens;
|
|
925
|
+
}
|
|
926
|
+
async function run(argv, io) {
|
|
927
|
+
try {
|
|
928
|
+
return await dispatch(argv, io);
|
|
929
|
+
} catch (error) {
|
|
930
|
+
const raw = error instanceof CliError ? error.message : `Unexpected failure: ${String(error)}`;
|
|
931
|
+
let message = raw;
|
|
932
|
+
for (const token of knownTokens(argv)) message = redact(message, token);
|
|
933
|
+
io.stderr(`error: ${message}`);
|
|
934
|
+
return 1;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// src/cli/index.ts
|
|
939
|
+
var code = await run(process.argv.slice(2), {
|
|
940
|
+
cwd: process.cwd(),
|
|
941
|
+
fetch: globalThis.fetch,
|
|
942
|
+
stdout: (line) => process.stdout.write(`${line}
|
|
943
|
+
`),
|
|
944
|
+
stderr: (line) => process.stderr.write(`${line}
|
|
945
|
+
`)
|
|
946
|
+
});
|
|
947
|
+
process.exitCode = code;
|
|
948
|
+
//# sourceMappingURL=index.mjs.map
|
|
949
|
+
//# sourceMappingURL=index.mjs.map
|