@uzum-tech/design-tokens-resolver 0.0.0-stage → 1.0.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/lib/index.mjs ADDED
@@ -0,0 +1,726 @@
1
+ // src/constants/design.constants.ts
2
+ var designPaths = {
3
+ release: "/dynamic/design/admin/token-releases/details",
4
+ releasePayload: "/dynamic/design/admin/token-release-payloads/details",
5
+ channel: "/dynamic/design/admin/token-channels/details"
6
+ };
7
+ var engineBaseUrls = {
8
+ local: "http://localhost:3003/api/v1",
9
+ development: "https://esb-data-engine-int-dev.kapitalbank.uz/api/v1",
10
+ production: "https://data-engine-int.kapitalbank.uz/api/v1"
11
+ };
12
+ var designConfigFiles = [
13
+ "design-tokens.config.mjs",
14
+ "design-tokens.config.js",
15
+ "design-tokens.config.cjs",
16
+ "design-tokens.config.json"
17
+ ];
18
+ var JSON_CONFIG_SUFFIX = ".json";
19
+ var designDefaults = {
20
+ env: "production",
21
+ requestTimeoutInMs: 3e4,
22
+ retryCount: 2,
23
+ retryDelayInMs: 500,
24
+ fileName: "tokens.json",
25
+ lockFileName: "tokens.lock.json",
26
+ authEnvHint: "DESIGN_TOKENS_API_KEY \u043B\u0438\u0431\u043E DESIGN_TOKENS_USERNAME \u0438 DESIGN_TOKENS_PASSWORD"
27
+ };
28
+ var JSON_INDENT = 2;
29
+ var LINE_BREAK = "\n";
30
+ var HASH_ALGORITHM = "sha256";
31
+ var HASH_ENCODING = "hex";
32
+
33
+ // src/types/error.types.ts
34
+ var ErrorTypes;
35
+ ((ErrorTypes2) => {
36
+ let Code;
37
+ ((Code2) => {
38
+ Code2["CONFIG_INVALID"] = "CONFIG_INVALID";
39
+ Code2["REQUEST_FAILED"] = "REQUEST_FAILED";
40
+ Code2["RELEASE_NOT_FOUND"] = "RELEASE_NOT_FOUND";
41
+ Code2["CHANNEL_EMPTY"] = "CHANNEL_EMPTY";
42
+ Code2["INTEGRITY_MISMATCH"] = "INTEGRITY_MISMATCH";
43
+ Code2["WRITE_FAILED"] = "WRITE_FAILED";
44
+ })(Code = ErrorTypes2.Code || (ErrorTypes2.Code = {}));
45
+ })(ErrorTypes || (ErrorTypes = {}));
46
+
47
+ // src/constants/regular-expressions.constants.ts
48
+ var regularExpressions = {
49
+ trailingSlashes: /\/+$/,
50
+ leadingSlashes: /^\/+/,
51
+ kebabSegment: /-([a-z])/g,
52
+ dtcgAlias: /^\{(.+)\}$/
53
+ };
54
+
55
+ // src/utils/url.utils.ts
56
+ var UrlUtils = class {
57
+ static join(...parts) {
58
+ const [head, ...rest] = parts.filter(Boolean);
59
+ const tail = rest.map((part) => part.replace(regularExpressions.leadingSlashes, "").replace(regularExpressions.trailingSlashes, "")).filter(Boolean);
60
+ const base = (head ?? "").replace(regularExpressions.trailingSlashes, "");
61
+ return [base, ...tail].join("/");
62
+ }
63
+ static toQuery(params) {
64
+ const search = new URLSearchParams();
65
+ for (const key of Object.keys(params)) {
66
+ const value = params[key];
67
+ if (!value) continue;
68
+ search.set(key, String(value));
69
+ }
70
+ const query = search.toString();
71
+ return query ? `?${query}` : "";
72
+ }
73
+ };
74
+
75
+ // src/constants/http.constants.ts
76
+ var httpHeaders = {
77
+ authorization: "authorization",
78
+ apiKey: "x-api-key"
79
+ };
80
+
81
+ // src/errors/resolver.error.ts
82
+ var ResolverError = class _ResolverError extends Error {
83
+ code;
84
+ statusCode;
85
+ body;
86
+ constructor(message, options) {
87
+ super(message, {
88
+ cause: options.cause
89
+ });
90
+ this.name = "ResolverError";
91
+ this.code = options.code;
92
+ this.statusCode = options.statusCode;
93
+ this.body = options.body;
94
+ Error.captureStackTrace?.(this, _ResolverError);
95
+ }
96
+ static is(error, code) {
97
+ const isResolverError = error instanceof _ResolverError;
98
+ return code ? isResolverError && error.code === code : isResolverError;
99
+ }
100
+ };
101
+
102
+ // src/types/http.types.ts
103
+ var HttpTypes;
104
+ ((HttpTypes2) => {
105
+ let Status;
106
+ ((Status2) => {
107
+ Status2[Status2["UNAUTHORIZED"] = 401] = "UNAUTHORIZED";
108
+ Status2[Status2["NOT_FOUND"] = 404] = "NOT_FOUND";
109
+ Status2[Status2["TOO_MANY_REQUESTS"] = 429] = "TOO_MANY_REQUESTS";
110
+ Status2[Status2["INTERNAL_SERVER_ERROR"] = 500] = "INTERNAL_SERVER_ERROR";
111
+ })(Status = HttpTypes2.Status || (HttpTypes2.Status = {}));
112
+ })(HttpTypes || (HttpTypes = {}));
113
+
114
+ // src/client/http.client.ts
115
+ var HttpClient = class _HttpClient {
116
+ constructor(config) {
117
+ this.config = config;
118
+ }
119
+ static isRetryable(status) {
120
+ return status === HttpTypes.Status.TOO_MANY_REQUESTS || status >= HttpTypes.Status.INTERNAL_SERVER_ERROR;
121
+ }
122
+ static wait(delayInMs) {
123
+ return new Promise((resolve2) => {
124
+ setTimeout(resolve2, delayInMs);
125
+ });
126
+ }
127
+ async getJson(path, notFoundCode) {
128
+ const response = await this.request(path, notFoundCode);
129
+ const body = await response.json();
130
+ return body.data ?? body;
131
+ }
132
+ async request(path, notFoundCode = ErrorTypes.Code.REQUEST_FAILED) {
133
+ const url = UrlUtils.join(this.config.baseUrl, path);
134
+ const response = await this.sendWithRetries(url);
135
+ if (response.ok) return response;
136
+ const status = response.status;
137
+ throw new ResolverError(
138
+ `Design tokens request failed: ${status} ${url}`,
139
+ {
140
+ code: status === HttpTypes.Status.NOT_FOUND ? notFoundCode : ErrorTypes.Code.REQUEST_FAILED,
141
+ statusCode: status,
142
+ body: await response.text()
143
+ }
144
+ );
145
+ }
146
+ async sendWithRetries(url) {
147
+ let attempt = 0;
148
+ while (true) {
149
+ const isLast = attempt >= this.config.retryCount;
150
+ try {
151
+ const response = await this.send(url);
152
+ if (isLast || !_HttpClient.isRetryable(response.status)) return response;
153
+ } catch (error) {
154
+ if (isLast) throw error;
155
+ }
156
+ attempt += 1;
157
+ await _HttpClient.wait(this.config.retryDelayInMs * attempt);
158
+ }
159
+ }
160
+ async send(url) {
161
+ try {
162
+ return await fetch(url, {
163
+ headers: this.toHeaders(),
164
+ signal: AbortSignal.timeout(this.config.requestTimeoutInMs)
165
+ });
166
+ } catch (error) {
167
+ throw new ResolverError(
168
+ `Design tokens request failed: ${url}`,
169
+ {
170
+ code: ErrorTypes.Code.REQUEST_FAILED,
171
+ cause: error
172
+ }
173
+ );
174
+ }
175
+ }
176
+ toHeaders() {
177
+ const headers = {};
178
+ if (this.config.apiKey) {
179
+ headers[httpHeaders.apiKey] = this.config.apiKey;
180
+ }
181
+ if (this.config.auth) {
182
+ const credentials = Buffer.from(`${this.config.auth.username}:${this.config.auth.password}`).toString("base64");
183
+ headers[httpHeaders.authorization] = `Basic ${credentials}`;
184
+ }
185
+ return headers;
186
+ }
187
+ };
188
+
189
+ // src/client/design.client.ts
190
+ var DesignClient = class extends HttpClient {
191
+ async getRelease(version) {
192
+ return this.getJson(
193
+ designPaths.release + UrlUtils.toQuery({
194
+ version
195
+ }),
196
+ ErrorTypes.Code.RELEASE_NOT_FOUND
197
+ );
198
+ }
199
+ async getChannel(slug) {
200
+ return this.getJson(
201
+ designPaths.channel + UrlUtils.toQuery({
202
+ slug
203
+ }),
204
+ ErrorTypes.Code.RELEASE_NOT_FOUND
205
+ );
206
+ }
207
+ async getDocument(version) {
208
+ const payload = await this.getJson(
209
+ designPaths.releasePayload + UrlUtils.toQuery({
210
+ version
211
+ }),
212
+ ErrorTypes.Code.RELEASE_NOT_FOUND
213
+ );
214
+ return payload.document;
215
+ }
216
+ };
217
+
218
+ // src/core/config.resolver.ts
219
+ var ConfigResolver = class _ConfigResolver {
220
+ static withDefaults(config) {
221
+ const baseUrl = _ConfigResolver.toBaseUrl(config);
222
+ _ConfigResolver.validateAuth(config);
223
+ return {
224
+ baseUrl,
225
+ auth: config.auth ?? null,
226
+ apiKey: config.apiKey ?? null,
227
+ requestTimeoutInMs: config.requestTimeoutInMs ?? designDefaults.requestTimeoutInMs,
228
+ retryCount: config.retryCount ?? designDefaults.retryCount,
229
+ retryDelayInMs: config.retryDelayInMs ?? designDefaults.retryDelayInMs
230
+ };
231
+ }
232
+ static toBaseUrl(config) {
233
+ if (config.baseUrl) return config.baseUrl;
234
+ const env = config.env ?? designDefaults.env;
235
+ const baseUrl = engineBaseUrls[env];
236
+ if (!baseUrl) {
237
+ throw new ResolverError(
238
+ `Unknown environment "${env}". Known: ${Object.keys(engineBaseUrls).join(", ")}`,
239
+ {
240
+ code: ErrorTypes.Code.CONFIG_INVALID
241
+ }
242
+ );
243
+ }
244
+ return baseUrl;
245
+ }
246
+ static validateAuth(config) {
247
+ if (!config.auth) return;
248
+ if (config.auth.username && config.auth.password) return;
249
+ throw new ResolverError(
250
+ 'Design tokens config is invalid: both "username" and "password" are required for basic auth',
251
+ {
252
+ code: ErrorTypes.Code.CONFIG_INVALID
253
+ }
254
+ );
255
+ }
256
+ };
257
+
258
+ // src/core/config-file.resolver.ts
259
+ import {
260
+ existsSync,
261
+ readFileSync
262
+ } from "node:fs";
263
+ import {
264
+ dirname,
265
+ join,
266
+ parse,
267
+ resolve
268
+ } from "node:path";
269
+ import { pathToFileURL } from "node:url";
270
+ var ConfigFileResolver = class _ConfigFileResolver {
271
+ static async load(startPath) {
272
+ const path = _ConfigFileResolver.find(startPath);
273
+ if (!path) return null;
274
+ return {
275
+ path,
276
+ config: await _ConfigFileResolver.read(path)
277
+ };
278
+ }
279
+ static find(startPath) {
280
+ let current = resolve(startPath);
281
+ const stopAt = parse(current).root;
282
+ let found = _ConfigFileResolver.findIn(current);
283
+ while (!found && current !== stopAt) {
284
+ current = dirname(current);
285
+ found = _ConfigFileResolver.findIn(current);
286
+ }
287
+ return found;
288
+ }
289
+ static findIn(directory) {
290
+ for (const name of designConfigFiles) {
291
+ const path = join(directory, name);
292
+ if (existsSync(path)) return path;
293
+ }
294
+ return null;
295
+ }
296
+ static async read(path) {
297
+ try {
298
+ return path.endsWith(JSON_CONFIG_SUFFIX) ? _ConfigFileResolver.readJson(path) : await _ConfigFileResolver.readModule(path);
299
+ } catch (error) {
300
+ if (ResolverError.is(error)) throw error;
301
+ throw new ResolverError(
302
+ `Failed to read design tokens config at ${path}`,
303
+ {
304
+ code: ErrorTypes.Code.CONFIG_INVALID,
305
+ cause: error
306
+ }
307
+ );
308
+ }
309
+ }
310
+ static readJson(path) {
311
+ return JSON.parse(readFileSync(path, "utf8"));
312
+ }
313
+ static async readModule(path) {
314
+ const imported = await import(pathToFileURL(path).href);
315
+ const exported = imported.default;
316
+ if (!exported) {
317
+ throw new ResolverError(
318
+ `Design tokens config at ${path} has no default export`,
319
+ {
320
+ code: ErrorTypes.Code.CONFIG_INVALID
321
+ }
322
+ );
323
+ }
324
+ return typeof exported === "function" ? await exported() : exported;
325
+ }
326
+ };
327
+
328
+ // src/constants/document.constants.ts
329
+ var DOCUMENT_PATH_SEPARATOR = ".";
330
+ var DOCUMENT_VALUE_KEY_SEPARATOR = ":";
331
+ var DOCUMENT_MAX_ALIAS_DEPTH = 20;
332
+ var DOCUMENT_ALIAS_VALUE_GROUP = 1;
333
+
334
+ // src/types/config.types.ts
335
+ var ConfigTypes;
336
+ ((ConfigTypes2) => {
337
+ let Format;
338
+ ((Format2) => {
339
+ Format2["FLAT"] = "FLAT";
340
+ Format2["DTCG"] = "DTCG";
341
+ })(Format = ConfigTypes2.Format || (ConfigTypes2.Format = {}));
342
+ let Env;
343
+ ((Env2) => {
344
+ Env2["LOCAL"] = "local";
345
+ Env2["DEVELOPMENT"] = "development";
346
+ Env2["PRODUCTION"] = "production";
347
+ })(Env = ConfigTypes2.Env || (ConfigTypes2.Env = {}));
348
+ })(ConfigTypes || (ConfigTypes = {}));
349
+
350
+ // src/mappers/resolve.mapper.ts
351
+ var ResolveMapper = class _ResolveMapper {
352
+ static toScope(document) {
353
+ const modes = {};
354
+ for (const collection of document.collections) {
355
+ const defaultMode = collection.modes.find((mode) => mode.isDefault) ?? collection.modes[0];
356
+ if (!defaultMode) continue;
357
+ modes[collection.slug] = {
358
+ slugs: new Set(collection.modes.map((mode) => mode.slug)),
359
+ defaultSlug: defaultMode.slug
360
+ };
361
+ }
362
+ const literals = {};
363
+ for (const token of document.tokens) {
364
+ literals[_ResolveMapper.toLiteralKey(token.collection, token.mode, token.path)] = token.$value;
365
+ }
366
+ return {
367
+ literals,
368
+ modes
369
+ };
370
+ }
371
+ static toLiteralKey(collection, mode, path) {
372
+ return [collection, mode, path].join(DOCUMENT_VALUE_KEY_SEPARATOR);
373
+ }
374
+ static toTarget(alias, state) {
375
+ const separatorIndex = alias.indexOf(DOCUMENT_PATH_SEPARATOR);
376
+ if (separatorIndex <= 0) return null;
377
+ const collection = alias.slice(0, separatorIndex);
378
+ const collectionModes = state.scope.modes[collection];
379
+ if (!collectionModes) return null;
380
+ return {
381
+ path: alias.slice(separatorIndex + 1),
382
+ point: {
383
+ collection,
384
+ mode: collectionModes.slugs.has(state.point.mode) ? state.point.mode : collectionModes.defaultSlug
385
+ }
386
+ };
387
+ }
388
+ };
389
+
390
+ // src/utils/resolve.utils.ts
391
+ var ResolveUtils = class _ResolveUtils {
392
+ static resolve(value, state) {
393
+ if (state.depth >= DOCUMENT_MAX_ALIAS_DEPTH) return value;
394
+ if (typeof value === "string") return _ResolveUtils.resolveAlias(value, state);
395
+ const deeper = {
396
+ ...state,
397
+ depth: state.depth + 1
398
+ };
399
+ if (Array.isArray(value)) {
400
+ return value.map((item) => _ResolveUtils.resolve(item, deeper));
401
+ }
402
+ if (value === null || typeof value !== "object") return value;
403
+ const result = {};
404
+ for (const key of Object.keys(value)) {
405
+ result[key] = _ResolveUtils.resolve(value[key], deeper);
406
+ }
407
+ return result;
408
+ }
409
+ static parseAlias(value) {
410
+ const match = value.trim().match(regularExpressions.dtcgAlias);
411
+ return match ? match[DOCUMENT_ALIAS_VALUE_GROUP].trim() : null;
412
+ }
413
+ static resolveAlias(value, state) {
414
+ const alias = _ResolveUtils.parseAlias(value);
415
+ if (!alias) return value;
416
+ const target = ResolveMapper.toTarget(alias, state);
417
+ if (!target) return value;
418
+ const literal = state.scope.literals[ResolveMapper.toLiteralKey(
419
+ target.point.collection,
420
+ target.point.mode,
421
+ target.path
422
+ )];
423
+ if (literal === void 0) return value;
424
+ return _ResolveUtils.resolve(literal, {
425
+ scope: state.scope,
426
+ point: target.point,
427
+ depth: state.depth + 1
428
+ });
429
+ }
430
+ };
431
+
432
+ // src/mappers/document.mapper.ts
433
+ var DocumentMapper = class _DocumentMapper {
434
+ static toJson(canonical, query) {
435
+ if (_DocumentMapper.isCanonical(query)) return canonical;
436
+ const document = JSON.parse(canonical);
437
+ const output = _DocumentMapper.toOutput(document, query);
438
+ return `${JSON.stringify(output, null, JSON_INDENT)}${LINE_BREAK}`;
439
+ }
440
+ static toOutput(document, query) {
441
+ if (query.format !== ConfigTypes.Format.DTCG) {
442
+ return _DocumentMapper.toFlatDocument(document, query);
443
+ }
444
+ if (query.collection) return _DocumentMapper.toDtcg(document, query);
445
+ const trees = {};
446
+ for (const collection of document.collections) {
447
+ trees[collection.slug] = _DocumentMapper.toDtcg(document, {
448
+ ...query,
449
+ collection: collection.slug
450
+ });
451
+ }
452
+ return trees;
453
+ }
454
+ static isCanonical(query) {
455
+ return !query.collection && !query.resolve && (!query.format || query.format === ConfigTypes.Format.FLAT);
456
+ }
457
+ static toFlatDocument(document, query) {
458
+ return {
459
+ schemaVersion: document.schemaVersion,
460
+ collections: query.collection ? document.collections.filter((item) => item.slug === query.collection) : document.collections,
461
+ tokens: _DocumentMapper.toTokens(document, query)
462
+ };
463
+ }
464
+ static toTokens(document, query) {
465
+ const tokens = query.collection ? document.tokens.filter((token) => token.collection === query.collection) : document.tokens;
466
+ if (!query.resolve) return tokens;
467
+ const scope = ResolveMapper.toScope(document);
468
+ return tokens.map((token) => ({
469
+ ...token,
470
+ $value: ResolveUtils.resolve(token.$value, {
471
+ scope,
472
+ point: {
473
+ collection: token.collection,
474
+ mode: token.mode
475
+ },
476
+ depth: 0
477
+ })
478
+ }));
479
+ }
480
+ static toDtcg(document, query) {
481
+ const collection = document.collections.find(
482
+ (item) => item.slug === query.collection
483
+ );
484
+ if (!collection) return {};
485
+ const byMode = _DocumentMapper.groupByMode(
486
+ _DocumentMapper.toTokens(document, query)
487
+ );
488
+ if (collection.modes.length <= 1) {
489
+ const [mode] = collection.modes;
490
+ return _DocumentMapper.toTree(byMode[mode?.slug] ?? []);
491
+ }
492
+ const root = {};
493
+ for (const mode of collection.modes) {
494
+ root[mode.name] = _DocumentMapper.toTree(byMode[mode.slug] ?? []);
495
+ }
496
+ return root;
497
+ }
498
+ static groupByMode(tokens) {
499
+ const grouped = {};
500
+ for (const token of tokens) {
501
+ grouped[token.mode] ??= [];
502
+ grouped[token.mode].push(token);
503
+ }
504
+ return grouped;
505
+ }
506
+ static toTree(tokens) {
507
+ const root = {};
508
+ for (const token of tokens) {
509
+ const segments = token.path.split(DOCUMENT_PATH_SEPARATOR);
510
+ const leaf = segments.pop();
511
+ if (!leaf) continue;
512
+ let cursor = root;
513
+ for (const segment of segments) {
514
+ const next = cursor[segment];
515
+ if (!next || typeof next !== "object") {
516
+ cursor[segment] = {};
517
+ }
518
+ cursor = cursor[segment];
519
+ }
520
+ cursor[leaf] = {
521
+ $type: token.$type,
522
+ $value: token.$value
523
+ };
524
+ }
525
+ return root;
526
+ }
527
+ };
528
+
529
+ // src/mappers/lock.mapper.ts
530
+ var LockMapper = class {
531
+ static toLock(release, source) {
532
+ return {
533
+ version: release.version,
534
+ contentHash: release.contentHash,
535
+ baseUrl: source.baseUrl,
536
+ byteSize: release.byteSize,
537
+ publishedAt: release.createdAt,
538
+ publishedBy: release.publishedBy,
539
+ sourceLabel: release.sourceLabel
540
+ };
541
+ }
542
+ static toJson(lock) {
543
+ return `${JSON.stringify(lock, null, JSON_INDENT)}${LINE_BREAK}`;
544
+ }
545
+ };
546
+
547
+ // src/utils/file.utils.ts
548
+ import {
549
+ mkdirSync,
550
+ writeFileSync
551
+ } from "node:fs";
552
+ import {
553
+ dirname as dirname2,
554
+ join as join2
555
+ } from "node:path";
556
+ var FileUtils = class {
557
+ static write(outputPath, fileName, body) {
558
+ const target = join2(outputPath, fileName);
559
+ try {
560
+ mkdirSync(dirname2(target), {
561
+ recursive: true
562
+ });
563
+ writeFileSync(target, body, "utf8");
564
+ return target;
565
+ } catch (error) {
566
+ throw new ResolverError(
567
+ `Failed to write design tokens to ${target}`,
568
+ {
569
+ code: ErrorTypes.Code.WRITE_FAILED,
570
+ cause: error
571
+ }
572
+ );
573
+ }
574
+ }
575
+ };
576
+
577
+ // src/utils/hash.utils.ts
578
+ import { createHash } from "node:crypto";
579
+ var HashUtils = class {
580
+ static toContentHash(body) {
581
+ return createHash(HASH_ALGORITHM).update(body, "utf8").digest(HASH_ENCODING);
582
+ }
583
+ };
584
+
585
+ // src/core/design-tokens-resolver.ts
586
+ var DesignTokensResolver = class _DesignTokensResolver {
587
+ client;
588
+ config;
589
+ constructor(config) {
590
+ this.config = ConfigResolver.withDefaults(config);
591
+ this.client = new DesignClient(this.config);
592
+ }
593
+ static checkIntegrity(release, canonical) {
594
+ const actual = HashUtils.toContentHash(canonical);
595
+ if (actual === release.contentHash) return;
596
+ throw new ResolverError(
597
+ `Design tokens integrity check failed for ${release.version}: expected ${release.contentHash}, got ${actual}`,
598
+ {
599
+ code: ErrorTypes.Code.INTEGRITY_MISMATCH
600
+ }
601
+ );
602
+ }
603
+ getSource() {
604
+ return {
605
+ baseUrl: this.config.baseUrl
606
+ };
607
+ }
608
+ async resolveVersion(target) {
609
+ if (target.version) return target.version;
610
+ if (!target.channel) {
611
+ throw new ResolverError(
612
+ 'Either "version" or "channel" must be provided',
613
+ {
614
+ code: ErrorTypes.Code.CONFIG_INVALID
615
+ }
616
+ );
617
+ }
618
+ const channel = await this.client.getChannel(target.channel);
619
+ if (channel.version) return channel.version;
620
+ throw new ResolverError(
621
+ `Channel "${target.channel}" does not point at any version yet`,
622
+ {
623
+ code: ErrorTypes.Code.CHANNEL_EMPTY
624
+ }
625
+ );
626
+ }
627
+ async fetchVerified(target) {
628
+ const version = await this.resolveVersion(target);
629
+ const release = await this.client.getRelease(version);
630
+ const canonical = await this.client.getDocument(version);
631
+ _DesignTokensResolver.checkIntegrity(release, canonical);
632
+ return {
633
+ release,
634
+ body: DocumentMapper.toJson(canonical, target)
635
+ };
636
+ }
637
+ async resolve(request) {
638
+ const verified = await this.fetchVerified(request);
639
+ const tokensPath = FileUtils.write(
640
+ request.outputPath,
641
+ request.fileName ?? designDefaults.fileName,
642
+ verified.body
643
+ );
644
+ const lockPath = request.lock === false ? null : FileUtils.write(
645
+ request.outputPath,
646
+ designDefaults.lockFileName,
647
+ LockMapper.toJson(LockMapper.toLock(verified.release, this.getSource()))
648
+ );
649
+ return {
650
+ release: verified.release,
651
+ source: this.getSource(),
652
+ tokensPath,
653
+ lockPath,
654
+ bytesWritten: Buffer.byteLength(verified.body, "utf8")
655
+ };
656
+ }
657
+ };
658
+
659
+ // src/constants/cli.constants.ts
660
+ var FLAG_PREFIX = "--";
661
+ var NEGATIVE_FLAG_PREFIX = "--no-";
662
+
663
+ // src/utils/args.utils.ts
664
+ var ArgsUtils = class _ArgsUtils {
665
+ static parse(args) {
666
+ const parsed = {};
667
+ for (let index = 0; index < args.length; index += 1) {
668
+ const token = args[index];
669
+ if (!token?.startsWith(FLAG_PREFIX)) continue;
670
+ if (token.startsWith(NEGATIVE_FLAG_PREFIX)) {
671
+ parsed[_ArgsUtils.toKey(token.slice(NEGATIVE_FLAG_PREFIX.length))] = false;
672
+ continue;
673
+ }
674
+ const name = _ArgsUtils.toKey(token.slice(FLAG_PREFIX.length));
675
+ const next = args[index + 1];
676
+ if (!next || next.startsWith(FLAG_PREFIX)) {
677
+ parsed[name] = true;
678
+ continue;
679
+ }
680
+ parsed[name] = next;
681
+ index += 1;
682
+ }
683
+ return parsed;
684
+ }
685
+ static toFormat(value) {
686
+ if (typeof value !== "string") return;
687
+ const normalized = value.trim().toUpperCase();
688
+ return normalized === ConfigTypes.Format.DTCG ? ConfigTypes.Format.DTCG : ConfigTypes.Format.FLAT;
689
+ }
690
+ static toEnv(value) {
691
+ return _ArgsUtils.toNormalized(value);
692
+ }
693
+ static toText(value) {
694
+ return typeof value === "string" ? value : void 0;
695
+ }
696
+ static toNormalized(value) {
697
+ if (typeof value !== "string") return;
698
+ return value.trim().toLowerCase();
699
+ }
700
+ static toKey(name) {
701
+ return name.replace(
702
+ regularExpressions.kebabSegment,
703
+ (_, letter) => letter.toUpperCase()
704
+ );
705
+ }
706
+ };
707
+ export {
708
+ ArgsUtils,
709
+ ConfigFileResolver,
710
+ ConfigResolver,
711
+ ConfigTypes,
712
+ DesignClient,
713
+ DesignTokensResolver,
714
+ DocumentMapper,
715
+ ErrorTypes,
716
+ FileUtils,
717
+ HashUtils,
718
+ HttpClient,
719
+ HttpTypes,
720
+ LockMapper,
721
+ ResolveMapper,
722
+ ResolveUtils,
723
+ ResolverError,
724
+ UrlUtils,
725
+ DesignTokensResolver as default
726
+ };