@unbyte/ccc 0.0.1
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/lib/index.js +709 -0
- package/package.json +32 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var child_process = require('child_process');
|
|
5
|
+
var os = require('os');
|
|
6
|
+
var path = require('path');
|
|
7
|
+
var promises = require('fs/promises');
|
|
8
|
+
|
|
9
|
+
var DEFAULT_CONFIG = {
|
|
10
|
+
lang: void 0,
|
|
11
|
+
message: void 0,
|
|
12
|
+
abortEarly: void 0,
|
|
13
|
+
abortPipeEarly: void 0
|
|
14
|
+
};
|
|
15
|
+
// @__NO_SIDE_EFFECTS__
|
|
16
|
+
function getGlobalConfig(config$1) {
|
|
17
|
+
return DEFAULT_CONFIG;
|
|
18
|
+
}
|
|
19
|
+
var store$3;
|
|
20
|
+
// @__NO_SIDE_EFFECTS__
|
|
21
|
+
function getGlobalMessage(lang) {
|
|
22
|
+
return store$3?.get(lang);
|
|
23
|
+
}
|
|
24
|
+
var store$2;
|
|
25
|
+
// @__NO_SIDE_EFFECTS__
|
|
26
|
+
function getSchemaMessage(lang) {
|
|
27
|
+
return store$2?.get(lang);
|
|
28
|
+
}
|
|
29
|
+
var store$1;
|
|
30
|
+
// @__NO_SIDE_EFFECTS__
|
|
31
|
+
function getSpecificMessage(reference, lang) {
|
|
32
|
+
return store$1?.get(reference)?.get(lang);
|
|
33
|
+
}
|
|
34
|
+
// @__NO_SIDE_EFFECTS__
|
|
35
|
+
function _stringify(input) {
|
|
36
|
+
const type = typeof input;
|
|
37
|
+
if (type === "string") return `"${input}"`;
|
|
38
|
+
if (type === "number" || type === "bigint" || type === "boolean") return `${input}`;
|
|
39
|
+
if (type === "object" || type === "function") return (input && Object.getPrototypeOf(input)?.constructor?.name) ?? "null";
|
|
40
|
+
return type;
|
|
41
|
+
}
|
|
42
|
+
function _addIssue(context, label, dataset, config$1, other) {
|
|
43
|
+
const input = other && "input" in other ? other.input : dataset.value;
|
|
44
|
+
const expected = other?.expected ?? context.expects ?? null;
|
|
45
|
+
const received = other?.received ?? /* @__PURE__ */ _stringify(input);
|
|
46
|
+
const issue = {
|
|
47
|
+
kind: context.kind,
|
|
48
|
+
type: context.type,
|
|
49
|
+
input,
|
|
50
|
+
expected,
|
|
51
|
+
received,
|
|
52
|
+
message: `Invalid ${label}: ${expected ? `Expected ${expected} but r` : "R"}eceived ${received}`,
|
|
53
|
+
requirement: context.requirement,
|
|
54
|
+
path: other?.path,
|
|
55
|
+
issues: other?.issues,
|
|
56
|
+
lang: config$1.lang,
|
|
57
|
+
abortEarly: config$1.abortEarly,
|
|
58
|
+
abortPipeEarly: config$1.abortPipeEarly
|
|
59
|
+
};
|
|
60
|
+
const isSchema = context.kind === "schema";
|
|
61
|
+
const message$1 = other?.message ?? context.message ?? /* @__PURE__ */ getSpecificMessage(context.reference, issue.lang) ?? (isSchema ? /* @__PURE__ */ getSchemaMessage(issue.lang) : null) ?? config$1.message ?? /* @__PURE__ */ getGlobalMessage(issue.lang);
|
|
62
|
+
if (message$1 !== void 0) issue.message = typeof message$1 === "function" ? message$1(issue) : message$1;
|
|
63
|
+
if (isSchema) dataset.typed = false;
|
|
64
|
+
if (dataset.issues) dataset.issues.push(issue);
|
|
65
|
+
else dataset.issues = [issue];
|
|
66
|
+
}
|
|
67
|
+
var _standardCache = /* @__PURE__ */ new WeakMap();
|
|
68
|
+
// @__NO_SIDE_EFFECTS__
|
|
69
|
+
function _getStandardProps(context) {
|
|
70
|
+
let cached = _standardCache.get(context);
|
|
71
|
+
if (!cached) {
|
|
72
|
+
cached = {
|
|
73
|
+
version: 1,
|
|
74
|
+
vendor: "valibot",
|
|
75
|
+
validate(value$1) {
|
|
76
|
+
return context["~run"]({ value: value$1 }, /* @__PURE__ */ getGlobalConfig());
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
_standardCache.set(context, cached);
|
|
80
|
+
}
|
|
81
|
+
return cached;
|
|
82
|
+
}
|
|
83
|
+
// @__NO_SIDE_EFFECTS__
|
|
84
|
+
function _isValidObjectKey(object$1, key) {
|
|
85
|
+
return Object.prototype.hasOwnProperty.call(object$1, key) && key !== "__proto__" && key !== "prototype" && key !== "constructor";
|
|
86
|
+
}
|
|
87
|
+
// @__NO_SIDE_EFFECTS__
|
|
88
|
+
function _joinExpects(values$1, separator) {
|
|
89
|
+
const list = [...new Set(values$1)];
|
|
90
|
+
if (list.length > 1) return `(${list.join(` ${separator} `)})`;
|
|
91
|
+
return list[0] ?? "never";
|
|
92
|
+
}
|
|
93
|
+
// @__NO_SIDE_EFFECTS__
|
|
94
|
+
function getDotPath(issue) {
|
|
95
|
+
if (issue.path) {
|
|
96
|
+
let key = "";
|
|
97
|
+
for (const item of issue.path) if (typeof item.key === "string" || typeof item.key === "number") if (key) key += `.${item.key}`;
|
|
98
|
+
else key += item.key;
|
|
99
|
+
else return null;
|
|
100
|
+
return key;
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
// @__NO_SIDE_EFFECTS__
|
|
105
|
+
function parseJson(config$1, message$1) {
|
|
106
|
+
return {
|
|
107
|
+
kind: "transformation",
|
|
108
|
+
type: "parse_json",
|
|
109
|
+
reference: parseJson,
|
|
110
|
+
config: config$1,
|
|
111
|
+
message: message$1,
|
|
112
|
+
async: false,
|
|
113
|
+
"~run"(dataset, config$2) {
|
|
114
|
+
try {
|
|
115
|
+
dataset.value = JSON.parse(dataset.value, this.config?.reviver);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (error instanceof Error) {
|
|
118
|
+
_addIssue(this, "JSON", dataset, config$2, { received: `"${error.message}"` });
|
|
119
|
+
dataset.typed = false;
|
|
120
|
+
} else throw error;
|
|
121
|
+
}
|
|
122
|
+
return dataset;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// @__NO_SIDE_EFFECTS__
|
|
127
|
+
function transform(operation) {
|
|
128
|
+
return {
|
|
129
|
+
kind: "transformation",
|
|
130
|
+
type: "transform",
|
|
131
|
+
reference: transform,
|
|
132
|
+
async: false,
|
|
133
|
+
operation,
|
|
134
|
+
"~run"(dataset) {
|
|
135
|
+
dataset.value = this.operation(dataset.value);
|
|
136
|
+
return dataset;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// @__NO_SIDE_EFFECTS__
|
|
141
|
+
function url(message$1) {
|
|
142
|
+
return {
|
|
143
|
+
kind: "validation",
|
|
144
|
+
type: "url",
|
|
145
|
+
reference: url,
|
|
146
|
+
async: false,
|
|
147
|
+
expects: null,
|
|
148
|
+
requirement(input) {
|
|
149
|
+
try {
|
|
150
|
+
new URL(input);
|
|
151
|
+
return true;
|
|
152
|
+
} catch {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
message: message$1,
|
|
157
|
+
"~run"(dataset, config$1) {
|
|
158
|
+
if (dataset.typed && !this.requirement(dataset.value)) _addIssue(this, "URL", dataset, config$1);
|
|
159
|
+
return dataset;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
// @__NO_SIDE_EFFECTS__
|
|
164
|
+
function getFallback(schema, dataset, config$1) {
|
|
165
|
+
return typeof schema.fallback === "function" ? schema.fallback(dataset, config$1) : schema.fallback;
|
|
166
|
+
}
|
|
167
|
+
// @__NO_SIDE_EFFECTS__
|
|
168
|
+
function flatten(issues) {
|
|
169
|
+
const flatErrors = {};
|
|
170
|
+
for (const issue of issues) if (issue.path) {
|
|
171
|
+
const dotPath = /* @__PURE__ */ getDotPath(issue);
|
|
172
|
+
if (dotPath) {
|
|
173
|
+
if (!flatErrors.nested) flatErrors.nested = {};
|
|
174
|
+
if (flatErrors.nested[dotPath]) flatErrors.nested[dotPath].push(issue.message);
|
|
175
|
+
else flatErrors.nested[dotPath] = [issue.message];
|
|
176
|
+
} else if (flatErrors.other) flatErrors.other.push(issue.message);
|
|
177
|
+
else flatErrors.other = [issue.message];
|
|
178
|
+
} else if (flatErrors.root) flatErrors.root.push(issue.message);
|
|
179
|
+
else flatErrors.root = [issue.message];
|
|
180
|
+
return flatErrors;
|
|
181
|
+
}
|
|
182
|
+
// @__NO_SIDE_EFFECTS__
|
|
183
|
+
function getDefault(schema, dataset, config$1) {
|
|
184
|
+
return typeof schema.default === "function" ? schema.default(dataset, config$1) : schema.default;
|
|
185
|
+
}
|
|
186
|
+
// @__NO_SIDE_EFFECTS__
|
|
187
|
+
function array(item, message$1) {
|
|
188
|
+
return {
|
|
189
|
+
kind: "schema",
|
|
190
|
+
type: "array",
|
|
191
|
+
reference: array,
|
|
192
|
+
expects: "Array",
|
|
193
|
+
async: false,
|
|
194
|
+
item,
|
|
195
|
+
message: message$1,
|
|
196
|
+
get "~standard"() {
|
|
197
|
+
return /* @__PURE__ */ _getStandardProps(this);
|
|
198
|
+
},
|
|
199
|
+
"~run"(dataset, config$1) {
|
|
200
|
+
const input = dataset.value;
|
|
201
|
+
if (Array.isArray(input)) {
|
|
202
|
+
dataset.typed = true;
|
|
203
|
+
dataset.value = [];
|
|
204
|
+
for (let key = 0; key < input.length; key++) {
|
|
205
|
+
const value$1 = input[key];
|
|
206
|
+
const itemDataset = this.item["~run"]({ value: value$1 }, config$1);
|
|
207
|
+
if (itemDataset.issues) {
|
|
208
|
+
const pathItem = {
|
|
209
|
+
type: "array",
|
|
210
|
+
origin: "value",
|
|
211
|
+
input,
|
|
212
|
+
key,
|
|
213
|
+
value: value$1
|
|
214
|
+
};
|
|
215
|
+
for (const issue of itemDataset.issues) {
|
|
216
|
+
if (issue.path) issue.path.unshift(pathItem);
|
|
217
|
+
else issue.path = [pathItem];
|
|
218
|
+
dataset.issues?.push(issue);
|
|
219
|
+
}
|
|
220
|
+
if (!dataset.issues) dataset.issues = itemDataset.issues;
|
|
221
|
+
if (config$1.abortEarly) {
|
|
222
|
+
dataset.typed = false;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (!itemDataset.typed) dataset.typed = false;
|
|
227
|
+
dataset.value.push(itemDataset.value);
|
|
228
|
+
}
|
|
229
|
+
} else _addIssue(this, "type", dataset, config$1);
|
|
230
|
+
return dataset;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// @__NO_SIDE_EFFECTS__
|
|
235
|
+
function boolean(message$1) {
|
|
236
|
+
return {
|
|
237
|
+
kind: "schema",
|
|
238
|
+
type: "boolean",
|
|
239
|
+
reference: boolean,
|
|
240
|
+
expects: "boolean",
|
|
241
|
+
async: false,
|
|
242
|
+
message: message$1,
|
|
243
|
+
get "~standard"() {
|
|
244
|
+
return /* @__PURE__ */ _getStandardProps(this);
|
|
245
|
+
},
|
|
246
|
+
"~run"(dataset, config$1) {
|
|
247
|
+
if (typeof dataset.value === "boolean") dataset.typed = true;
|
|
248
|
+
else _addIssue(this, "type", dataset, config$1);
|
|
249
|
+
return dataset;
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
// @__NO_SIDE_EFFECTS__
|
|
254
|
+
function object(entries$1, message$1) {
|
|
255
|
+
return {
|
|
256
|
+
kind: "schema",
|
|
257
|
+
type: "object",
|
|
258
|
+
reference: object,
|
|
259
|
+
expects: "Object",
|
|
260
|
+
async: false,
|
|
261
|
+
entries: entries$1,
|
|
262
|
+
message: message$1,
|
|
263
|
+
get "~standard"() {
|
|
264
|
+
return /* @__PURE__ */ _getStandardProps(this);
|
|
265
|
+
},
|
|
266
|
+
"~run"(dataset, config$1) {
|
|
267
|
+
const input = dataset.value;
|
|
268
|
+
if (input && typeof input === "object") {
|
|
269
|
+
dataset.typed = true;
|
|
270
|
+
dataset.value = {};
|
|
271
|
+
for (const key in this.entries) {
|
|
272
|
+
const valueSchema = this.entries[key];
|
|
273
|
+
if (key in input || (valueSchema.type === "exact_optional" || valueSchema.type === "optional" || valueSchema.type === "nullish") && valueSchema.default !== void 0) {
|
|
274
|
+
const value$1 = key in input ? input[key] : /* @__PURE__ */ getDefault(valueSchema);
|
|
275
|
+
const valueDataset = valueSchema["~run"]({ value: value$1 }, config$1);
|
|
276
|
+
if (valueDataset.issues) {
|
|
277
|
+
const pathItem = {
|
|
278
|
+
type: "object",
|
|
279
|
+
origin: "value",
|
|
280
|
+
input,
|
|
281
|
+
key,
|
|
282
|
+
value: value$1
|
|
283
|
+
};
|
|
284
|
+
for (const issue of valueDataset.issues) {
|
|
285
|
+
if (issue.path) issue.path.unshift(pathItem);
|
|
286
|
+
else issue.path = [pathItem];
|
|
287
|
+
dataset.issues?.push(issue);
|
|
288
|
+
}
|
|
289
|
+
if (!dataset.issues) dataset.issues = valueDataset.issues;
|
|
290
|
+
if (config$1.abortEarly) {
|
|
291
|
+
dataset.typed = false;
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (!valueDataset.typed) dataset.typed = false;
|
|
296
|
+
dataset.value[key] = valueDataset.value;
|
|
297
|
+
} else if (valueSchema.fallback !== void 0) dataset.value[key] = /* @__PURE__ */ getFallback(valueSchema);
|
|
298
|
+
else if (valueSchema.type !== "exact_optional" && valueSchema.type !== "optional" && valueSchema.type !== "nullish") {
|
|
299
|
+
_addIssue(this, "key", dataset, config$1, {
|
|
300
|
+
input: void 0,
|
|
301
|
+
expected: `"${key}"`,
|
|
302
|
+
path: [{
|
|
303
|
+
type: "object",
|
|
304
|
+
origin: "key",
|
|
305
|
+
input,
|
|
306
|
+
key,
|
|
307
|
+
value: input[key]
|
|
308
|
+
}]
|
|
309
|
+
});
|
|
310
|
+
if (config$1.abortEarly) break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
} else _addIssue(this, "type", dataset, config$1);
|
|
314
|
+
return dataset;
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
// @__NO_SIDE_EFFECTS__
|
|
319
|
+
function optional(wrapped, default_) {
|
|
320
|
+
return {
|
|
321
|
+
kind: "schema",
|
|
322
|
+
type: "optional",
|
|
323
|
+
reference: optional,
|
|
324
|
+
expects: `(${wrapped.expects} | undefined)`,
|
|
325
|
+
async: false,
|
|
326
|
+
wrapped,
|
|
327
|
+
default: default_,
|
|
328
|
+
get "~standard"() {
|
|
329
|
+
return /* @__PURE__ */ _getStandardProps(this);
|
|
330
|
+
},
|
|
331
|
+
"~run"(dataset, config$1) {
|
|
332
|
+
if (dataset.value === void 0) {
|
|
333
|
+
if (this.default !== void 0) dataset.value = /* @__PURE__ */ getDefault(this, dataset, config$1);
|
|
334
|
+
if (dataset.value === void 0) {
|
|
335
|
+
dataset.typed = true;
|
|
336
|
+
return dataset;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return this.wrapped["~run"](dataset, config$1);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
// @__NO_SIDE_EFFECTS__
|
|
344
|
+
function picklist(options, message$1) {
|
|
345
|
+
return {
|
|
346
|
+
kind: "schema",
|
|
347
|
+
type: "picklist",
|
|
348
|
+
reference: picklist,
|
|
349
|
+
expects: /* @__PURE__ */ _joinExpects(options.map(_stringify), "|"),
|
|
350
|
+
async: false,
|
|
351
|
+
options,
|
|
352
|
+
message: message$1,
|
|
353
|
+
get "~standard"() {
|
|
354
|
+
return /* @__PURE__ */ _getStandardProps(this);
|
|
355
|
+
},
|
|
356
|
+
"~run"(dataset, config$1) {
|
|
357
|
+
if (this.options.includes(dataset.value)) dataset.typed = true;
|
|
358
|
+
else _addIssue(this, "type", dataset, config$1);
|
|
359
|
+
return dataset;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
// @__NO_SIDE_EFFECTS__
|
|
364
|
+
function record(key, value$1, message$1) {
|
|
365
|
+
return {
|
|
366
|
+
kind: "schema",
|
|
367
|
+
type: "record",
|
|
368
|
+
reference: record,
|
|
369
|
+
expects: "Object",
|
|
370
|
+
async: false,
|
|
371
|
+
key,
|
|
372
|
+
value: value$1,
|
|
373
|
+
message: message$1,
|
|
374
|
+
get "~standard"() {
|
|
375
|
+
return /* @__PURE__ */ _getStandardProps(this);
|
|
376
|
+
},
|
|
377
|
+
"~run"(dataset, config$1) {
|
|
378
|
+
const input = dataset.value;
|
|
379
|
+
if (input && typeof input === "object") {
|
|
380
|
+
dataset.typed = true;
|
|
381
|
+
dataset.value = {};
|
|
382
|
+
for (const entryKey in input) if (/* @__PURE__ */ _isValidObjectKey(input, entryKey)) {
|
|
383
|
+
const entryValue = input[entryKey];
|
|
384
|
+
const keyDataset = this.key["~run"]({ value: entryKey }, config$1);
|
|
385
|
+
if (keyDataset.issues) {
|
|
386
|
+
const pathItem = {
|
|
387
|
+
type: "object",
|
|
388
|
+
origin: "key",
|
|
389
|
+
input,
|
|
390
|
+
key: entryKey,
|
|
391
|
+
value: entryValue
|
|
392
|
+
};
|
|
393
|
+
for (const issue of keyDataset.issues) {
|
|
394
|
+
issue.path = [pathItem];
|
|
395
|
+
dataset.issues?.push(issue);
|
|
396
|
+
}
|
|
397
|
+
if (!dataset.issues) dataset.issues = keyDataset.issues;
|
|
398
|
+
if (config$1.abortEarly) {
|
|
399
|
+
dataset.typed = false;
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const valueDataset = this.value["~run"]({ value: entryValue }, config$1);
|
|
404
|
+
if (valueDataset.issues) {
|
|
405
|
+
const pathItem = {
|
|
406
|
+
type: "object",
|
|
407
|
+
origin: "value",
|
|
408
|
+
input,
|
|
409
|
+
key: entryKey,
|
|
410
|
+
value: entryValue
|
|
411
|
+
};
|
|
412
|
+
for (const issue of valueDataset.issues) {
|
|
413
|
+
if (issue.path) issue.path.unshift(pathItem);
|
|
414
|
+
else issue.path = [pathItem];
|
|
415
|
+
dataset.issues?.push(issue);
|
|
416
|
+
}
|
|
417
|
+
if (!dataset.issues) dataset.issues = valueDataset.issues;
|
|
418
|
+
if (config$1.abortEarly) {
|
|
419
|
+
dataset.typed = false;
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (!keyDataset.typed || !valueDataset.typed) dataset.typed = false;
|
|
424
|
+
if (keyDataset.typed) dataset.value[keyDataset.value] = valueDataset.value;
|
|
425
|
+
}
|
|
426
|
+
} else _addIssue(this, "type", dataset, config$1);
|
|
427
|
+
return dataset;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
// @__NO_SIDE_EFFECTS__
|
|
432
|
+
function string(message$1) {
|
|
433
|
+
return {
|
|
434
|
+
kind: "schema",
|
|
435
|
+
type: "string",
|
|
436
|
+
reference: string,
|
|
437
|
+
expects: "string",
|
|
438
|
+
async: false,
|
|
439
|
+
message: message$1,
|
|
440
|
+
get "~standard"() {
|
|
441
|
+
return /* @__PURE__ */ _getStandardProps(this);
|
|
442
|
+
},
|
|
443
|
+
"~run"(dataset, config$1) {
|
|
444
|
+
if (typeof dataset.value === "string") dataset.typed = true;
|
|
445
|
+
else _addIssue(this, "type", dataset, config$1);
|
|
446
|
+
return dataset;
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
// @__NO_SIDE_EFFECTS__
|
|
451
|
+
function _subIssues(datasets) {
|
|
452
|
+
let issues;
|
|
453
|
+
if (datasets) for (const dataset of datasets) if (issues) for (const issue of dataset.issues) issues.push(issue);
|
|
454
|
+
else issues = dataset.issues;
|
|
455
|
+
return issues;
|
|
456
|
+
}
|
|
457
|
+
// @__NO_SIDE_EFFECTS__
|
|
458
|
+
function union(options, message$1) {
|
|
459
|
+
return {
|
|
460
|
+
kind: "schema",
|
|
461
|
+
type: "union",
|
|
462
|
+
reference: union,
|
|
463
|
+
expects: /* @__PURE__ */ _joinExpects(options.map((option) => option.expects), "|"),
|
|
464
|
+
async: false,
|
|
465
|
+
options,
|
|
466
|
+
message: message$1,
|
|
467
|
+
get "~standard"() {
|
|
468
|
+
return /* @__PURE__ */ _getStandardProps(this);
|
|
469
|
+
},
|
|
470
|
+
"~run"(dataset, config$1) {
|
|
471
|
+
let validDataset;
|
|
472
|
+
let typedDatasets;
|
|
473
|
+
let untypedDatasets;
|
|
474
|
+
for (const schema of this.options) {
|
|
475
|
+
const optionDataset = schema["~run"]({ value: dataset.value }, config$1);
|
|
476
|
+
if (optionDataset.typed) if (optionDataset.issues) if (typedDatasets) typedDatasets.push(optionDataset);
|
|
477
|
+
else typedDatasets = [optionDataset];
|
|
478
|
+
else {
|
|
479
|
+
validDataset = optionDataset;
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
else if (untypedDatasets) untypedDatasets.push(optionDataset);
|
|
483
|
+
else untypedDatasets = [optionDataset];
|
|
484
|
+
}
|
|
485
|
+
if (validDataset) return validDataset;
|
|
486
|
+
if (typedDatasets) {
|
|
487
|
+
if (typedDatasets.length === 1) return typedDatasets[0];
|
|
488
|
+
_addIssue(this, "type", dataset, config$1, { issues: /* @__PURE__ */ _subIssues(typedDatasets) });
|
|
489
|
+
dataset.typed = true;
|
|
490
|
+
} else if (untypedDatasets?.length === 1) return untypedDatasets[0];
|
|
491
|
+
else _addIssue(this, "type", dataset, config$1, { issues: /* @__PURE__ */ _subIssues(untypedDatasets) });
|
|
492
|
+
return dataset;
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
// @__NO_SIDE_EFFECTS__
|
|
497
|
+
function unknown() {
|
|
498
|
+
return {
|
|
499
|
+
kind: "schema",
|
|
500
|
+
type: "unknown",
|
|
501
|
+
reference: unknown,
|
|
502
|
+
expects: "unknown",
|
|
503
|
+
async: false,
|
|
504
|
+
get "~standard"() {
|
|
505
|
+
return /* @__PURE__ */ _getStandardProps(this);
|
|
506
|
+
},
|
|
507
|
+
"~run"(dataset) {
|
|
508
|
+
dataset.typed = true;
|
|
509
|
+
return dataset;
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
// @__NO_SIDE_EFFECTS__
|
|
514
|
+
function pipe(...pipe$1) {
|
|
515
|
+
return {
|
|
516
|
+
...pipe$1[0],
|
|
517
|
+
pipe: pipe$1,
|
|
518
|
+
get "~standard"() {
|
|
519
|
+
return /* @__PURE__ */ _getStandardProps(this);
|
|
520
|
+
},
|
|
521
|
+
"~run"(dataset, config$1) {
|
|
522
|
+
for (const item of pipe$1) if (item.kind !== "metadata") {
|
|
523
|
+
if (dataset.issues && (item.kind === "schema" || item.kind === "transformation")) {
|
|
524
|
+
dataset.typed = false;
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
if (!dataset.issues || !config$1.abortEarly && !config$1.abortPipeEarly) dataset = item["~run"](dataset, config$1);
|
|
528
|
+
}
|
|
529
|
+
return dataset;
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
// @__NO_SIDE_EFFECTS__
|
|
534
|
+
function safeParse(schema, input, config$1) {
|
|
535
|
+
const dataset = schema["~run"]({ value: input }, /* @__PURE__ */ getGlobalConfig());
|
|
536
|
+
return {
|
|
537
|
+
typed: dataset.typed,
|
|
538
|
+
success: !dataset.issues,
|
|
539
|
+
output: dataset.value,
|
|
540
|
+
issues: dataset.issues
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// src/config.ts
|
|
545
|
+
var EffortLevelSchema = picklist(["low", "medium", "high", "xhigh", "max"]);
|
|
546
|
+
var ConfigSchema = object({
|
|
547
|
+
id: string(),
|
|
548
|
+
models: optional(
|
|
549
|
+
union([
|
|
550
|
+
object({
|
|
551
|
+
default: optional(string()),
|
|
552
|
+
subagent: optional(string()),
|
|
553
|
+
haiku: optional(string()),
|
|
554
|
+
sonnet: optional(string()),
|
|
555
|
+
opus: optional(string())
|
|
556
|
+
}),
|
|
557
|
+
pipe(
|
|
558
|
+
string(),
|
|
559
|
+
transform((model) => ({
|
|
560
|
+
default: model,
|
|
561
|
+
subagent: model,
|
|
562
|
+
haiku: model,
|
|
563
|
+
sonnet: model,
|
|
564
|
+
opus: model
|
|
565
|
+
}))
|
|
566
|
+
)
|
|
567
|
+
])
|
|
568
|
+
),
|
|
569
|
+
thinking: optional(
|
|
570
|
+
object({
|
|
571
|
+
effort: optional(EffortLevelSchema)
|
|
572
|
+
})
|
|
573
|
+
),
|
|
574
|
+
api: pipe(string(), url()),
|
|
575
|
+
apiKey: optional(string()),
|
|
576
|
+
default: optional(boolean()),
|
|
577
|
+
env: optional(record(string(), string())),
|
|
578
|
+
settings: optional(record(string(), unknown()))
|
|
579
|
+
});
|
|
580
|
+
var ConfigListSchema = array(ConfigSchema);
|
|
581
|
+
var ConfigListFileSchema = pipe(string(), parseJson(), ConfigListSchema);
|
|
582
|
+
function parse(raw) {
|
|
583
|
+
const parsed = safeParse(ConfigListFileSchema, raw);
|
|
584
|
+
if (parsed.success) {
|
|
585
|
+
return {
|
|
586
|
+
success: true,
|
|
587
|
+
list: parsed.output
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
success: false,
|
|
592
|
+
error: flatten(parsed.issues).nested
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// src/config-manager.ts
|
|
597
|
+
var LoadError = class extends Error {
|
|
598
|
+
constructor(lines, configFile) {
|
|
599
|
+
super([...lines, `please fix the config file at ${configFile}`].join("\n"));
|
|
600
|
+
this.name = "LoadError";
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
async function exists(path) {
|
|
604
|
+
try {
|
|
605
|
+
await promises.access(path, promises.constants.F_OK);
|
|
606
|
+
return true;
|
|
607
|
+
} catch {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
async function load(configFile) {
|
|
612
|
+
let content;
|
|
613
|
+
try {
|
|
614
|
+
await promises.mkdir(path.dirname(configFile), { recursive: true });
|
|
615
|
+
if (!await exists(configFile)) {
|
|
616
|
+
await promises.writeFile(configFile, "[]", "utf-8");
|
|
617
|
+
}
|
|
618
|
+
content = await promises.readFile(configFile, "utf-8");
|
|
619
|
+
} catch (error) {
|
|
620
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
621
|
+
throw new LoadError(["failed to load config file:", detail], configFile);
|
|
622
|
+
}
|
|
623
|
+
const parsed = parse(content);
|
|
624
|
+
if (!parsed.success) {
|
|
625
|
+
const detail = JSON.stringify(parsed.error, null, 2);
|
|
626
|
+
throw new LoadError(["invalid config file format:", detail], configFile);
|
|
627
|
+
}
|
|
628
|
+
const { list } = parsed;
|
|
629
|
+
if (list.length === 0) {
|
|
630
|
+
throw new LoadError(["config file is empty."], configFile);
|
|
631
|
+
}
|
|
632
|
+
const defaults = list.filter((config) => config.default);
|
|
633
|
+
if (defaults.length > 1) {
|
|
634
|
+
const message = ["multiple default configs found:"];
|
|
635
|
+
for (const config of defaults) {
|
|
636
|
+
message.push(`- ${config.id}`);
|
|
637
|
+
}
|
|
638
|
+
throw new LoadError(message, configFile);
|
|
639
|
+
}
|
|
640
|
+
return list;
|
|
641
|
+
}
|
|
642
|
+
function pick(list, id) {
|
|
643
|
+
if (id == null) {
|
|
644
|
+
return list.find((config) => config.default) ?? list[0];
|
|
645
|
+
}
|
|
646
|
+
return list.find((config) => config.id === id);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// src/index.ts
|
|
650
|
+
var CONFIG_FILE = path.join(os.homedir(), ".ccc", "config.json");
|
|
651
|
+
function run(config, _args) {
|
|
652
|
+
const args = [..._args];
|
|
653
|
+
const env = {
|
|
654
|
+
...process.env,
|
|
655
|
+
ANTHROPIC_BASE_URL: config.api,
|
|
656
|
+
ANTHROPIC_AUTH_TOKEN: config.apiKey || "no-auth"
|
|
657
|
+
};
|
|
658
|
+
if (config.models) {
|
|
659
|
+
const { models } = config;
|
|
660
|
+
if (models.default) env.ANTHROPIC_MODEL = models.default;
|
|
661
|
+
if (models.subagent) env.CLAUDE_CODE_SUBAGENT_MODEL = models.subagent;
|
|
662
|
+
if (models.haiku) {
|
|
663
|
+
env.ANTHROPIC_DEFAULT_HAIKU_MODEL = models.haiku;
|
|
664
|
+
env.ANTHROPIC_SMALL_FAST_MODEL = models.haiku;
|
|
665
|
+
}
|
|
666
|
+
if (models.sonnet) env.ANTHROPIC_DEFAULT_SONNET_MODEL = models.sonnet;
|
|
667
|
+
if (models.opus) env.ANTHROPIC_DEFAULT_OPUS_MODEL = models.opus;
|
|
668
|
+
}
|
|
669
|
+
if (config.thinking) {
|
|
670
|
+
const { thinking } = config;
|
|
671
|
+
if (thinking.effort) env.CLAUDE_CODE_EFFORT_LEVEL = thinking.effort;
|
|
672
|
+
}
|
|
673
|
+
if (config.env) {
|
|
674
|
+
Object.assign(env, config.env);
|
|
675
|
+
}
|
|
676
|
+
if (config.settings) {
|
|
677
|
+
args.unshift("--settings", JSON.stringify(config.settings));
|
|
678
|
+
}
|
|
679
|
+
console.log("\u{1F680} config:", config.id);
|
|
680
|
+
child_process.spawn("claude", args, {
|
|
681
|
+
env,
|
|
682
|
+
stdio: "inherit"
|
|
683
|
+
}).on("error", (error) => {
|
|
684
|
+
console.error("failed to start claude code:");
|
|
685
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
686
|
+
process.exit(1);
|
|
687
|
+
}).on("close", (code) => {
|
|
688
|
+
process.exit(code ?? 0);
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
async function main() {
|
|
692
|
+
const args = process.argv.slice(2);
|
|
693
|
+
const list = await load(CONFIG_FILE);
|
|
694
|
+
let config;
|
|
695
|
+
let runArgs = [];
|
|
696
|
+
if (args[0]) {
|
|
697
|
+
config = pick(list, args[0]);
|
|
698
|
+
runArgs = args.slice(1);
|
|
699
|
+
}
|
|
700
|
+
if (config == null) {
|
|
701
|
+
config = pick(list);
|
|
702
|
+
runArgs = args;
|
|
703
|
+
}
|
|
704
|
+
run(config, runArgs);
|
|
705
|
+
}
|
|
706
|
+
main().catch((error) => {
|
|
707
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
708
|
+
process.exit(1);
|
|
709
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unbyte/ccc",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"files": [
|
|
5
|
+
"lib"
|
|
6
|
+
],
|
|
7
|
+
"bin": {
|
|
8
|
+
"ccc": "./lib/index.js"
|
|
9
|
+
},
|
|
10
|
+
"author": {
|
|
11
|
+
"name": "unbyte",
|
|
12
|
+
"url": "https://github.com/unbyte"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"ai",
|
|
17
|
+
"claude",
|
|
18
|
+
"claude code",
|
|
19
|
+
"config",
|
|
20
|
+
"configuration",
|
|
21
|
+
"switch"
|
|
22
|
+
],
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"valibot": "^1.4.0"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup"
|
|
31
|
+
}
|
|
32
|
+
}
|