@tokens-studio/tokenscript-schemas 0.0.10
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 +152 -0
- package/bundled/functions/invert.json +23 -0
- package/bundled/functions.json +28 -0
- package/bundled/registry.json +212 -0
- package/bundled/types/hex-color.json +25 -0
- package/bundled/types/rgb-color.json +64 -0
- package/bundled/types/rgba-color.json +89 -0
- package/bundled/types.json +183 -0
- package/dist/cli/index.cjs +652 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +645 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.cjs +333 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +158 -0
- package/dist/index.d.ts +158 -0
- package/dist/index.js +326 -0
- package/dist/index.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var cac = require('cac');
|
|
5
|
+
var ulog = require('ulog');
|
|
6
|
+
var promises = require('fs/promises');
|
|
7
|
+
var path = require('path');
|
|
8
|
+
|
|
9
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var cac__default = /*#__PURE__*/_interopDefault(cac);
|
|
12
|
+
var ulog__default = /*#__PURE__*/_interopDefault(ulog);
|
|
13
|
+
|
|
14
|
+
async function bundleSchemaFromDirectory(schemaDir, options) {
|
|
15
|
+
const schemaJsonPath = path.join(schemaDir, "schema.json");
|
|
16
|
+
const schemaContent = await promises.readFile(schemaJsonPath, "utf-8");
|
|
17
|
+
const schema = JSON.parse(schemaContent);
|
|
18
|
+
if (schema.type === "function") {
|
|
19
|
+
return await inlineFunctionScriptReferences(
|
|
20
|
+
schemaDir,
|
|
21
|
+
schema,
|
|
22
|
+
options
|
|
23
|
+
);
|
|
24
|
+
} else {
|
|
25
|
+
return await inlineColorScriptReferences(schemaDir, schema, options);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function inlineColorScriptReferences(schemaDir, schema, options) {
|
|
29
|
+
const result = JSON.parse(JSON.stringify(schema));
|
|
30
|
+
for (const initializer of result.initializers) {
|
|
31
|
+
if (initializer.script.script.startsWith("./")) {
|
|
32
|
+
const scriptPath = path.join(schemaDir, initializer.script.script.slice(2));
|
|
33
|
+
const scriptContent = await promises.readFile(scriptPath, "utf-8");
|
|
34
|
+
initializer.script.script = scriptContent.trim();
|
|
35
|
+
}
|
|
36
|
+
if (options?.baseUrl) {
|
|
37
|
+
initializer.script.type = addBaseUrl(initializer.script.type, options.baseUrl);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const conversion of result.conversions) {
|
|
41
|
+
if (conversion.script.script.startsWith("./")) {
|
|
42
|
+
const scriptPath = path.join(schemaDir, conversion.script.script.slice(2));
|
|
43
|
+
const scriptContent = await promises.readFile(scriptPath, "utf-8");
|
|
44
|
+
conversion.script.script = scriptContent.trim();
|
|
45
|
+
}
|
|
46
|
+
if (options?.baseUrl) {
|
|
47
|
+
conversion.script.type = addBaseUrl(conversion.script.type, options.baseUrl);
|
|
48
|
+
if (conversion.source !== "$self") {
|
|
49
|
+
conversion.source = addBaseUrl(conversion.source, options.baseUrl);
|
|
50
|
+
}
|
|
51
|
+
if (conversion.target !== "$self") {
|
|
52
|
+
conversion.target = addBaseUrl(conversion.target, options.baseUrl);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
async function inlineFunctionScriptReferences(schemaDir, schema, options) {
|
|
59
|
+
const result = JSON.parse(JSON.stringify(schema));
|
|
60
|
+
if (result.script.script.startsWith("./")) {
|
|
61
|
+
const scriptPath = path.join(schemaDir, result.script.script.slice(2));
|
|
62
|
+
const scriptContent = await promises.readFile(scriptPath, "utf-8");
|
|
63
|
+
result.script.script = scriptContent.trim();
|
|
64
|
+
}
|
|
65
|
+
if (options?.baseUrl) {
|
|
66
|
+
result.script.type = addBaseUrl(result.script.type, options.baseUrl);
|
|
67
|
+
if (result.requirements) {
|
|
68
|
+
const baseUrl = options.baseUrl;
|
|
69
|
+
result.requirements = result.requirements.map((req) => addBaseUrl(req, baseUrl));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
function addBaseUrl(uri, baseUrl) {
|
|
75
|
+
if (uri.includes("://")) {
|
|
76
|
+
return uri;
|
|
77
|
+
}
|
|
78
|
+
if (uri.startsWith("/")) {
|
|
79
|
+
const cleanBaseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
80
|
+
return `${cleanBaseUrl}${uri}`;
|
|
81
|
+
}
|
|
82
|
+
return uri;
|
|
83
|
+
}
|
|
84
|
+
var LOG_LEVELS = {
|
|
85
|
+
error: 1,
|
|
86
|
+
warn: 2,
|
|
87
|
+
info: 3,
|
|
88
|
+
log: 4,
|
|
89
|
+
debug: 5
|
|
90
|
+
};
|
|
91
|
+
var log = ulog__default.default("schema-registry");
|
|
92
|
+
var logLevel = process.env.LOG_LEVEL || "error";
|
|
93
|
+
log.level = LOG_LEVELS[logLevel] || LOG_LEVELS.error;
|
|
94
|
+
|
|
95
|
+
// src/utils/type.ts
|
|
96
|
+
var isSome = (v) => {
|
|
97
|
+
return v != null;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// src/utils/schema-uri.ts
|
|
101
|
+
function safeParseInt(value) {
|
|
102
|
+
const parsed = Number.parseInt(value, 10);
|
|
103
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
104
|
+
}
|
|
105
|
+
function parseSemverFromString(versionString) {
|
|
106
|
+
const parts = versionString.split(".");
|
|
107
|
+
const numbers = [];
|
|
108
|
+
for (const part of parts) {
|
|
109
|
+
const num = safeParseInt(part);
|
|
110
|
+
if (num === null) return null;
|
|
111
|
+
numbers.push(num);
|
|
112
|
+
}
|
|
113
|
+
if (numbers.length !== parts.length) return null;
|
|
114
|
+
if (numbers.length === 3) {
|
|
115
|
+
return { major: numbers[0], minor: numbers[1], patch: numbers[2] };
|
|
116
|
+
}
|
|
117
|
+
if (numbers.length === 2) {
|
|
118
|
+
return { major: numbers[0], minor: numbers[1] };
|
|
119
|
+
}
|
|
120
|
+
if (numbers.length === 1) {
|
|
121
|
+
return { major: numbers[0] };
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
function parseVersionString(versionString) {
|
|
126
|
+
return versionString === "latest" ? "latest" : parseSemverFromString(versionString);
|
|
127
|
+
}
|
|
128
|
+
function parseSchemaUri(uri) {
|
|
129
|
+
let baseUrl = "";
|
|
130
|
+
let pathname = uri;
|
|
131
|
+
try {
|
|
132
|
+
const url = new URL(uri);
|
|
133
|
+
baseUrl = `${url.protocol}//${url.host}`;
|
|
134
|
+
pathname = url.pathname;
|
|
135
|
+
} catch {
|
|
136
|
+
if (uri.includes("://")) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
pathname = uri;
|
|
140
|
+
}
|
|
141
|
+
const pathParts = pathname.split("/").filter((part) => part !== "");
|
|
142
|
+
if (pathParts.length < 5) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
if (pathParts[0] !== "api" || !pathParts[1].startsWith("v")) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
const category = pathParts[2];
|
|
149
|
+
if (category !== "schema" && category !== "core" && category !== "function") {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
const name = pathParts[3];
|
|
153
|
+
const version = parseVersionString(pathParts[4]);
|
|
154
|
+
return {
|
|
155
|
+
baseUrl,
|
|
156
|
+
category,
|
|
157
|
+
name,
|
|
158
|
+
version
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function extractSchemaName(uri) {
|
|
162
|
+
const components = parseSchemaUri(uri);
|
|
163
|
+
return components?.name || null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/bundler/schema-dependency-resolver.ts
|
|
167
|
+
function extractRequirements(spec, options = {}) {
|
|
168
|
+
const requirements = [];
|
|
169
|
+
if (spec.type === "function") {
|
|
170
|
+
const funcSpec = spec;
|
|
171
|
+
if (funcSpec.requirements) {
|
|
172
|
+
requirements.push(...funcSpec.requirements);
|
|
173
|
+
}
|
|
174
|
+
} else if (spec.type === "color" && options.includeColorTypeDependencies) {
|
|
175
|
+
const colorSpec = spec;
|
|
176
|
+
for (const conversion of colorSpec.conversions || []) {
|
|
177
|
+
if (conversion.source !== "$self") {
|
|
178
|
+
requirements.push(conversion.source);
|
|
179
|
+
}
|
|
180
|
+
if (conversion.target !== "$self") {
|
|
181
|
+
requirements.push(conversion.target);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return requirements;
|
|
186
|
+
}
|
|
187
|
+
function resolveSchemaReference(uriOrName) {
|
|
188
|
+
const components = parseSchemaUri(uriOrName);
|
|
189
|
+
if (components) {
|
|
190
|
+
const type = components.category === "function" ? "function" : "type";
|
|
191
|
+
return {
|
|
192
|
+
slug: components.name,
|
|
193
|
+
type,
|
|
194
|
+
uri: uriOrName
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const extractedName = extractSchemaName(uriOrName);
|
|
198
|
+
if (extractedName) {
|
|
199
|
+
return {
|
|
200
|
+
slug: extractedName,
|
|
201
|
+
type: "type",
|
|
202
|
+
// Default to type if we can't determine
|
|
203
|
+
uri: uriOrName
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (uriOrName && !uriOrName.includes("/")) {
|
|
207
|
+
return {
|
|
208
|
+
slug: uriOrName,
|
|
209
|
+
type: "type",
|
|
210
|
+
// Default to type
|
|
211
|
+
uri: ""
|
|
212
|
+
// No URI, just a slug
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
async function collectRequiredSchemas(slugOrUri, type, options = {}) {
|
|
218
|
+
const { baseUrl, schemasDir, ...extractOptions } = options;
|
|
219
|
+
const visited = /* @__PURE__ */ new Set();
|
|
220
|
+
const typeSchemas = /* @__PURE__ */ new Set();
|
|
221
|
+
const functionSchemas = /* @__PURE__ */ new Set();
|
|
222
|
+
async function traverse(currentSlugOrUri, currentType) {
|
|
223
|
+
const ref = resolveSchemaReference(currentSlugOrUri);
|
|
224
|
+
if (!ref) {
|
|
225
|
+
log.warn(`Could not resolve schema reference: ${currentSlugOrUri}`);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const effectiveType = currentType || ref.type;
|
|
229
|
+
const slug = ref.slug;
|
|
230
|
+
const key = `${effectiveType}:${slug}`;
|
|
231
|
+
if (visited.has(key)) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
visited.add(key);
|
|
235
|
+
let spec;
|
|
236
|
+
try {
|
|
237
|
+
const categoryDir = effectiveType === "type" ? "types" : "functions";
|
|
238
|
+
const resolvedSchemasDir = schemasDir || process.env.SCHEMAS_DIR || path.join(process.cwd(), "src/schemas");
|
|
239
|
+
const schemaDir = path.join(resolvedSchemasDir, categoryDir, slug);
|
|
240
|
+
spec = await bundleSchemaFromDirectory(schemaDir, baseUrl ? { baseUrl } : void 0);
|
|
241
|
+
} catch (error) {
|
|
242
|
+
log.warn(`Failed to load schema ${slug} (${effectiveType}):`, error);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const requirements = extractRequirements(spec, extractOptions);
|
|
246
|
+
for (const reqUri of requirements) {
|
|
247
|
+
const reqRef = resolveSchemaReference(reqUri);
|
|
248
|
+
if (reqRef) {
|
|
249
|
+
if (reqRef.type === "function") {
|
|
250
|
+
functionSchemas.add(reqRef.slug);
|
|
251
|
+
} else {
|
|
252
|
+
typeSchemas.add(reqRef.slug);
|
|
253
|
+
}
|
|
254
|
+
await traverse(reqUri, reqRef.type);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
await traverse(slugOrUri, type);
|
|
259
|
+
return {
|
|
260
|
+
types: Array.from(typeSchemas),
|
|
261
|
+
functions: Array.from(functionSchemas)
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
async function collectRequiredSchemasForList(schemas, options = {}) {
|
|
265
|
+
const allTypes = /* @__PURE__ */ new Set();
|
|
266
|
+
const allFunctions = /* @__PURE__ */ new Set();
|
|
267
|
+
for (const schema of schemas) {
|
|
268
|
+
const deps = await collectRequiredSchemas(schema.slug, schema.type, options);
|
|
269
|
+
if (schema.type === "function") {
|
|
270
|
+
allFunctions.add(schema.slug);
|
|
271
|
+
} else {
|
|
272
|
+
allTypes.add(schema.slug);
|
|
273
|
+
}
|
|
274
|
+
for (const t of deps.types) {
|
|
275
|
+
allTypes.add(t);
|
|
276
|
+
}
|
|
277
|
+
for (const f of deps.functions) {
|
|
278
|
+
allFunctions.add(f);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
types: Array.from(allTypes),
|
|
283
|
+
functions: Array.from(allFunctions)
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
async function collectDependencyTree(schemas, options = {}) {
|
|
287
|
+
const { baseUrl, schemasDir, ...extractOptions } = options;
|
|
288
|
+
const tree = /* @__PURE__ */ new Map();
|
|
289
|
+
for (const schema of schemas) {
|
|
290
|
+
const categoryDir = schema.type === "type" ? "types" : "functions";
|
|
291
|
+
const resolvedSchemasDir = schemasDir || process.env.SCHEMAS_DIR || path.join(process.cwd(), "src/schemas");
|
|
292
|
+
const schemaDir = path.join(resolvedSchemasDir, categoryDir, schema.slug);
|
|
293
|
+
try {
|
|
294
|
+
const spec = await bundleSchemaFromDirectory(schemaDir, baseUrl ? { baseUrl } : void 0);
|
|
295
|
+
const requirements = extractRequirements(spec, extractOptions);
|
|
296
|
+
const dependencySlugs = requirements.map((uri) => {
|
|
297
|
+
const ref = resolveSchemaReference(uri);
|
|
298
|
+
return ref ? `${ref.type}:${ref.slug}` : uri;
|
|
299
|
+
});
|
|
300
|
+
const key = `${schema.type}:${schema.slug}`;
|
|
301
|
+
tree.set(key, {
|
|
302
|
+
slug: schema.slug,
|
|
303
|
+
type: schema.type,
|
|
304
|
+
dependencies: dependencySlugs
|
|
305
|
+
});
|
|
306
|
+
} catch (error) {
|
|
307
|
+
log.warn(`Failed to load schema ${schema.slug} (${schema.type}):`, error);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return tree;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/bundler/selective-bundler.ts
|
|
314
|
+
async function detectSchemaType(slug, schemasDir) {
|
|
315
|
+
const typeDir = path.join(schemasDir, "types", slug);
|
|
316
|
+
const functionDir = path.join(schemasDir, "functions", slug);
|
|
317
|
+
try {
|
|
318
|
+
await promises.access(typeDir);
|
|
319
|
+
return "type";
|
|
320
|
+
} catch {
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
await promises.access(functionDir);
|
|
324
|
+
return "function";
|
|
325
|
+
} catch {
|
|
326
|
+
}
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
async function bundleSelectiveSchemas(options) {
|
|
330
|
+
const schemasDir = options.schemasDir || path.join(process.cwd(), "src/schemas");
|
|
331
|
+
const baseUrl = options.baseUrl || "https://schema.tokenscript.dev.gcp.tokens.studio";
|
|
332
|
+
const parsedSchemas = await Promise.all(
|
|
333
|
+
options.schemas.map(async (slug) => {
|
|
334
|
+
if (slug.includes(":")) {
|
|
335
|
+
const [type, name] = slug.split(":");
|
|
336
|
+
return {
|
|
337
|
+
slug: name,
|
|
338
|
+
type: type === "function" ? "function" : "type"
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
const detectedType = await detectSchemaType(slug, schemasDir);
|
|
342
|
+
if (detectedType === null) {
|
|
343
|
+
throw new Error(
|
|
344
|
+
`Schema '${slug}' not found in types or functions directories. Use 'function:${slug}' or 'type:${slug}' prefix to be explicit.`
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
return { slug, type: detectedType };
|
|
348
|
+
})
|
|
349
|
+
);
|
|
350
|
+
const deps = await collectRequiredSchemasForList(parsedSchemas, {
|
|
351
|
+
baseUrl,
|
|
352
|
+
schemasDir,
|
|
353
|
+
includeColorTypeDependencies: true
|
|
354
|
+
});
|
|
355
|
+
const allParsedSchemas = [
|
|
356
|
+
...deps.types.map((slug) => ({ slug, type: "type" })),
|
|
357
|
+
...deps.functions.map((slug) => ({ slug, type: "function" }))
|
|
358
|
+
];
|
|
359
|
+
const dependencyTree = await collectDependencyTree(allParsedSchemas, {
|
|
360
|
+
baseUrl,
|
|
361
|
+
schemasDir,
|
|
362
|
+
includeColorTypeDependencies: true
|
|
363
|
+
});
|
|
364
|
+
const allSchemas = [.../* @__PURE__ */ new Set([...deps.types, ...deps.functions])];
|
|
365
|
+
const bundledSchemas = [];
|
|
366
|
+
for (const typeSlug of deps.types) {
|
|
367
|
+
const schemaDir = path.join(schemasDir, "types", typeSlug);
|
|
368
|
+
const bundled = await bundleSchemaFromDirectory(schemaDir, { baseUrl });
|
|
369
|
+
if (bundled.type === "color") {
|
|
370
|
+
const uri = `${baseUrl}/api/v1/core/${typeSlug}/0/`;
|
|
371
|
+
bundledSchemas.push({
|
|
372
|
+
uri,
|
|
373
|
+
schema: bundled
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
for (const funcSlug of deps.functions) {
|
|
378
|
+
const schemaDir = path.join(schemasDir, "functions", funcSlug);
|
|
379
|
+
const bundled = await bundleSchemaFromDirectory(schemaDir, { baseUrl });
|
|
380
|
+
if (bundled.type === "function") {
|
|
381
|
+
const uri = `${baseUrl}/api/v1/function/${funcSlug}/0/`;
|
|
382
|
+
bundledSchemas.push({
|
|
383
|
+
uri,
|
|
384
|
+
schema: bundled
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
schemas: bundledSchemas,
|
|
390
|
+
metadata: {
|
|
391
|
+
requestedSchemas: options.schemas,
|
|
392
|
+
resolvedDependencies: allSchemas,
|
|
393
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
394
|
+
},
|
|
395
|
+
dependencyTree
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/cli/config-schema.ts
|
|
400
|
+
function validateBundleConfig(data) {
|
|
401
|
+
if (typeof data !== "object" || data === null) {
|
|
402
|
+
throw new Error("Config must be an object");
|
|
403
|
+
}
|
|
404
|
+
const config = data;
|
|
405
|
+
if (!Array.isArray(config.schemas)) {
|
|
406
|
+
throw new Error("Config must have a 'schemas' array");
|
|
407
|
+
}
|
|
408
|
+
if (!config.schemas.every((s) => typeof s === "string")) {
|
|
409
|
+
throw new Error("All schemas must be strings");
|
|
410
|
+
}
|
|
411
|
+
if (config.output !== void 0 && typeof config.output !== "string") {
|
|
412
|
+
throw new Error("Config 'output' must be a string if provided");
|
|
413
|
+
}
|
|
414
|
+
return {
|
|
415
|
+
schemas: config.schemas,
|
|
416
|
+
output: config.output
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// src/cli/output-generator.ts
|
|
421
|
+
function generateOutput(options) {
|
|
422
|
+
const { schemas, includeHelper = true } = options;
|
|
423
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
424
|
+
const schemaList = schemas.map((s) => s.uri).join(", ");
|
|
425
|
+
const lines = [];
|
|
426
|
+
lines.push("// Auto-generated by @tokens-studio/tokenscript-schemas");
|
|
427
|
+
lines.push(`// Generated: ${timestamp}`);
|
|
428
|
+
lines.push(`// Schemas: ${schemaList}`);
|
|
429
|
+
lines.push("");
|
|
430
|
+
lines.push('import { Config } from "@tokens-studio/tokenscript-interpreter";');
|
|
431
|
+
lines.push("");
|
|
432
|
+
lines.push("export const SCHEMAS = [");
|
|
433
|
+
for (const entry of schemas) {
|
|
434
|
+
const schemaJson = JSON.stringify(entry.schema, null, 2);
|
|
435
|
+
const uriJson = JSON.stringify(entry.uri);
|
|
436
|
+
const indentedSchema = schemaJson.split("\n").map((line) => ` ${line}`).join("\n");
|
|
437
|
+
lines.push(` {`);
|
|
438
|
+
lines.push(` uri: ${uriJson},`);
|
|
439
|
+
lines.push(` schema: ${indentedSchema.trim()}`);
|
|
440
|
+
lines.push(` },`);
|
|
441
|
+
}
|
|
442
|
+
lines.push("];");
|
|
443
|
+
lines.push("");
|
|
444
|
+
if (includeHelper) {
|
|
445
|
+
lines.push("export function makeConfig() {");
|
|
446
|
+
lines.push(" return new Config().registerSchemas(SCHEMAS);");
|
|
447
|
+
lines.push("}");
|
|
448
|
+
lines.push("");
|
|
449
|
+
}
|
|
450
|
+
return lines.join("\n");
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// src/cli/commands/bundle.ts
|
|
454
|
+
var log2 = ulog__default.default("bundle");
|
|
455
|
+
async function loadConfig(configPath) {
|
|
456
|
+
try {
|
|
457
|
+
const content = await promises.readFile(configPath, "utf-8");
|
|
458
|
+
const parsed = JSON.parse(content);
|
|
459
|
+
return validateBundleConfig(parsed);
|
|
460
|
+
} catch (error) {
|
|
461
|
+
if (error.code === "ENOENT") {
|
|
462
|
+
throw new Error(`Config file not found: ${configPath}`);
|
|
463
|
+
}
|
|
464
|
+
throw error;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function formatDependencyTree(tree, requestedSchemas) {
|
|
468
|
+
const lines = [];
|
|
469
|
+
const visited = /* @__PURE__ */ new Set();
|
|
470
|
+
lines.push("Dependency tree:");
|
|
471
|
+
lines.push("");
|
|
472
|
+
const formatNode = (key, indent = "", isLast = true) => {
|
|
473
|
+
if (visited.has(key)) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
visited.add(key);
|
|
477
|
+
const node = tree.get(key);
|
|
478
|
+
if (!node) return;
|
|
479
|
+
const prefix = indent + (isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ");
|
|
480
|
+
const label = `${node.type}:${node.slug}`;
|
|
481
|
+
lines.push(prefix + label);
|
|
482
|
+
if (node.dependencies.length > 0) {
|
|
483
|
+
const childIndent = indent + (isLast ? " " : "\u2502 ");
|
|
484
|
+
node.dependencies.forEach((dep, idx) => {
|
|
485
|
+
const isLastChild = idx === node.dependencies.length - 1;
|
|
486
|
+
const childKey = dep;
|
|
487
|
+
if (visited.has(childKey)) {
|
|
488
|
+
const childPrefix = childIndent + (isLastChild ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ");
|
|
489
|
+
lines.push(`${childPrefix + childKey} (already visited)`);
|
|
490
|
+
} else {
|
|
491
|
+
formatNode(childKey, childIndent, isLastChild);
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
requestedSchemas.forEach((schema, idx) => {
|
|
497
|
+
const typeKey = `type:${schema}`;
|
|
498
|
+
const funcKey = `function:${schema}`;
|
|
499
|
+
const key = tree.has(typeKey) ? typeKey : tree.has(funcKey) ? funcKey : schema;
|
|
500
|
+
formatNode(key, "", idx === requestedSchemas.length - 1);
|
|
501
|
+
});
|
|
502
|
+
return lines.join("\n");
|
|
503
|
+
}
|
|
504
|
+
function formatDryRunOutput(schemas, resolvedDependencies) {
|
|
505
|
+
const lines = [];
|
|
506
|
+
lines.push("Bundle preview:");
|
|
507
|
+
lines.push("");
|
|
508
|
+
lines.push(`Requested schemas: ${schemas.join(", ")}`);
|
|
509
|
+
lines.push(`Total schemas (with dependencies): ${resolvedDependencies.length}`);
|
|
510
|
+
lines.push("");
|
|
511
|
+
lines.push("Schemas to be bundled:");
|
|
512
|
+
for (const schema of resolvedDependencies.sort()) {
|
|
513
|
+
lines.push(` - ${schema}`);
|
|
514
|
+
}
|
|
515
|
+
return lines.join("\n");
|
|
516
|
+
}
|
|
517
|
+
async function bundleSchemas(schemas) {
|
|
518
|
+
const schemasDir = path.join(process.cwd(), "src/schemas");
|
|
519
|
+
log2.info("Bundling schemas:", schemas);
|
|
520
|
+
const result = await bundleSelectiveSchemas({
|
|
521
|
+
schemas,
|
|
522
|
+
schemasDir
|
|
523
|
+
});
|
|
524
|
+
log2.info(
|
|
525
|
+
`Resolved ${result.metadata.resolvedDependencies.length} schemas (including dependencies)`
|
|
526
|
+
);
|
|
527
|
+
const output = generateOutput({
|
|
528
|
+
schemas: result.schemas,
|
|
529
|
+
includeHelper: true
|
|
530
|
+
});
|
|
531
|
+
return {
|
|
532
|
+
output,
|
|
533
|
+
metadata: result.metadata,
|
|
534
|
+
dependencyTree: result.dependencyTree
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
async function handleBundleCommand(schemas, options = {}) {
|
|
538
|
+
try {
|
|
539
|
+
let configSchemas = schemas;
|
|
540
|
+
let outputPath = options.output || "./tokenscript-schemas.js";
|
|
541
|
+
if (isSome(options.config)) {
|
|
542
|
+
log2.info(`Loading config from ${options.config}`);
|
|
543
|
+
const config = await loadConfig(options.config);
|
|
544
|
+
configSchemas = config.schemas;
|
|
545
|
+
if (config.output) {
|
|
546
|
+
outputPath = config.output;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (!configSchemas || configSchemas.length === 0) {
|
|
550
|
+
throw new Error("No schemas specified. Provide schemas as arguments or via --config");
|
|
551
|
+
}
|
|
552
|
+
const { output, metadata, dependencyTree } = await bundleSchemas(configSchemas);
|
|
553
|
+
console.log("");
|
|
554
|
+
console.log(formatDependencyTree(dependencyTree, metadata.requestedSchemas));
|
|
555
|
+
console.log("");
|
|
556
|
+
if (options.dryRun) {
|
|
557
|
+
const preview = formatDryRunOutput(metadata.requestedSchemas, metadata.resolvedDependencies);
|
|
558
|
+
console.log(preview);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
await promises.mkdir(path.dirname(outputPath), { recursive: true });
|
|
562
|
+
await promises.writeFile(outputPath, output, "utf-8");
|
|
563
|
+
log2.info(`Successfully bundled ${metadata.resolvedDependencies.length} schemas`);
|
|
564
|
+
log2.info(`Output written to: ${outputPath}`);
|
|
565
|
+
console.log(`\u2713 Bundled ${metadata.resolvedDependencies.length} schemas \u2192 ${outputPath}`);
|
|
566
|
+
} catch (error) {
|
|
567
|
+
log2.error("Bundle failed:", error);
|
|
568
|
+
throw error;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
var log3 = ulog__default.default("list");
|
|
572
|
+
async function listSchemas(schemasDir = path.join(process.cwd(), "src/schemas"), options = {}) {
|
|
573
|
+
const showTypes = options.types || !options.types && !options.functions;
|
|
574
|
+
const showFunctions = options.functions || !options.types && !options.functions;
|
|
575
|
+
const types = [];
|
|
576
|
+
const functions = [];
|
|
577
|
+
if (showTypes) {
|
|
578
|
+
try {
|
|
579
|
+
const typesDir = path.join(schemasDir, "types");
|
|
580
|
+
const typeEntries = await promises.readdir(typesDir, { withFileTypes: true });
|
|
581
|
+
types.push(
|
|
582
|
+
...typeEntries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort()
|
|
583
|
+
);
|
|
584
|
+
} catch (error) {
|
|
585
|
+
log3.warn("Could not read types directory:", error);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (showFunctions) {
|
|
589
|
+
try {
|
|
590
|
+
const functionsDir = path.join(schemasDir, "functions");
|
|
591
|
+
const funcEntries = await promises.readdir(functionsDir, { withFileTypes: true });
|
|
592
|
+
functions.push(
|
|
593
|
+
...funcEntries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort()
|
|
594
|
+
);
|
|
595
|
+
} catch (error) {
|
|
596
|
+
log3.warn("Could not read functions directory:", error);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return { types, functions };
|
|
600
|
+
}
|
|
601
|
+
function formatListOutput(result, options = {}) {
|
|
602
|
+
const lines = [];
|
|
603
|
+
const showTypes = options.types || !options.types && !options.functions;
|
|
604
|
+
const showFunctions = options.functions || !options.types && !options.functions;
|
|
605
|
+
if (showTypes && result.types.length > 0) {
|
|
606
|
+
lines.push("Types:");
|
|
607
|
+
for (const type of result.types) {
|
|
608
|
+
lines.push(` ${type}`);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (showFunctions && result.functions.length > 0) {
|
|
612
|
+
if (lines.length > 0) lines.push("");
|
|
613
|
+
lines.push("Functions:");
|
|
614
|
+
for (const func of result.functions) {
|
|
615
|
+
lines.push(` function:${func}`);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (lines.length === 0) {
|
|
619
|
+
lines.push("No schemas found.");
|
|
620
|
+
}
|
|
621
|
+
return lines.join("\n");
|
|
622
|
+
}
|
|
623
|
+
async function handleListCommand(options = {}) {
|
|
624
|
+
const result = await listSchemas(void 0, options);
|
|
625
|
+
const output = formatListOutput(result, options);
|
|
626
|
+
console.log(output);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// src/cli/index.ts
|
|
630
|
+
var log4 = ulog__default.default("cli");
|
|
631
|
+
var cli = cac__default.default("tokenscript-schemas");
|
|
632
|
+
cli.command("bundle [...schemas]", "Bundle schemas into a JS file").option("-c, --config <path>", "Path to config file").option("-o, --output <path>", "Output file path", { default: "./tokenscript-schemas.js" }).option("-d, --dry-run", "Preview what would be bundled without writing").action(async (schemas, options) => {
|
|
633
|
+
try {
|
|
634
|
+
await handleBundleCommand(schemas, options);
|
|
635
|
+
} catch (error) {
|
|
636
|
+
log4.error("Error:", error);
|
|
637
|
+
process.exit(1);
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
cli.command("list", "List available schemas").option("--types", "List only type schemas").option("--functions", "List only function schemas").action(async (options) => {
|
|
641
|
+
try {
|
|
642
|
+
await handleListCommand(options);
|
|
643
|
+
} catch (error) {
|
|
644
|
+
log4.error("Error:", error);
|
|
645
|
+
process.exit(1);
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
cli.help();
|
|
649
|
+
cli.version("0.0.10");
|
|
650
|
+
cli.parse();
|
|
651
|
+
//# sourceMappingURL=index.cjs.map
|
|
652
|
+
//# sourceMappingURL=index.cjs.map
|