design-embed 0.1.0 → 0.1.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.
Files changed (40) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +93 -2
  3. package/dist/cli.d.mts +1 -0
  4. package/dist/cli.mjs +469 -0
  5. package/dist/index.d.mts +400 -0
  6. package/dist/index.mjs +2 -0
  7. package/dist/src-D3fnqGCq.mjs +511 -0
  8. package/package.json +8 -13
  9. package/src/cli.ts +18 -1
  10. package/src/commands/compile.ts +46 -63
  11. package/src/commands/generateTests.ts +17 -17
  12. package/src/commands/init.ts +54 -54
  13. package/src/commands/plugin.ts +3 -7
  14. package/src/targets/html.ts +68 -0
  15. package/dist/args.js +0 -36
  16. package/dist/cli.js +0 -35
  17. package/dist/commands/check.js +0 -4
  18. package/dist/commands/compile.js +0 -157
  19. package/dist/commands/generateTests.js +0 -113
  20. package/dist/commands/init.js +0 -102
  21. package/dist/commands/plugin.js +0 -68
  22. package/dist/index.js +0 -2
  23. package/node_modules/@design-embed/config/README.md +0 -5
  24. package/node_modules/@design-embed/config/dist/index.js +0 -283
  25. package/node_modules/@design-embed/config/package.json +0 -19
  26. package/node_modules/@design-embed/config/src/index.ts +0 -518
  27. package/node_modules/@design-embed/core/README.md +0 -5
  28. package/node_modules/@design-embed/core/dist/diagnostics/diagnostic.js +0 -3
  29. package/node_modules/@design-embed/core/dist/diagnostics/jsonDiagnostic.js +0 -35
  30. package/node_modules/@design-embed/core/dist/index.js +0 -351
  31. package/node_modules/@design-embed/core/dist/pipeline/checkMode.js +0 -29
  32. package/node_modules/@design-embed/core/dist/plugins/pluginApi.js +0 -1
  33. package/node_modules/@design-embed/core/dist/plugins/pluginRegistry.js +0 -25
  34. package/node_modules/@design-embed/core/package.json +0 -19
  35. package/node_modules/@design-embed/core/src/diagnostics/diagnostic.ts +0 -18
  36. package/node_modules/@design-embed/core/src/diagnostics/jsonDiagnostic.ts +0 -51
  37. package/node_modules/@design-embed/core/src/index.ts +0 -591
  38. package/node_modules/@design-embed/core/src/pipeline/checkMode.ts +0 -46
  39. package/node_modules/@design-embed/core/src/plugins/pluginApi.ts +0 -78
  40. package/node_modules/@design-embed/core/src/plugins/pluginRegistry.ts +0 -37
@@ -0,0 +1,511 @@
1
+ import { existsSync } from "node:fs";
2
+ import { isAbsolute, resolve } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ //#region packages/config/src/index.ts
5
+ /**
6
+ * Helper to define configuration with type safety.
7
+ *
8
+ * @param config - The configuration object.
9
+ * @returns The same configuration object.
10
+ *
11
+ * @example
12
+ * export default defineConfig({
13
+ * output: { target: reactTarget }
14
+ * });
15
+ */
16
+ function defineConfig(config) {
17
+ return config;
18
+ }
19
+ /**
20
+ * Asynchronously loads a configuration file from disk.
21
+ * Supports .ts, .js, and .mjs files via dynamic import.
22
+ *
23
+ * @param configPath - Path to the config file.
24
+ * @param cwd - Current working directory.
25
+ * @returns A promise resolving to the load result.
26
+ */
27
+ async function loadConfig(configPath, cwd = process.cwd()) {
28
+ const diagnostics = [];
29
+ const resolvedPath = isAbsolute(configPath) ? configPath : resolve(cwd, configPath);
30
+ if (!existsSync(resolvedPath)) return { diagnostics: [{
31
+ code: "CONFIG_NOT_FOUND",
32
+ message: `Config file not found: ${resolvedPath}`,
33
+ severity: "error"
34
+ }] };
35
+ if (!/\.(ts|js|mjs)$/.test(resolvedPath)) return { diagnostics: [{
36
+ code: "CONFIG_UNSUPPORTED_FORMAT",
37
+ message: `Unsupported config format: ${resolvedPath}. Only .ts, .js, and .mjs are supported.`,
38
+ severity: "error"
39
+ }] };
40
+ try {
41
+ const module = await import(pathToFileURL(resolvedPath).href);
42
+ const config = module.default ?? module.config;
43
+ if (!config) return { diagnostics: [{
44
+ code: "CONFIG_INVALID",
45
+ message: `Config file must export a default object or a named 'config' object: ${resolvedPath}`,
46
+ severity: "error"
47
+ }] };
48
+ diagnostics.push(...validateConfig(config));
49
+ return {
50
+ config,
51
+ diagnostics
52
+ };
53
+ } catch (error) {
54
+ return { diagnostics: [{
55
+ code: "CONFIG_INVALID",
56
+ message: `Failed to load config file: ${error instanceof Error ? error.message : String(error)}`,
57
+ severity: "error"
58
+ }] };
59
+ }
60
+ }
61
+ function validateConfig(config) {
62
+ const diagnostics = [];
63
+ const target = config.output?.target;
64
+ const styleMode = config.output?.styleMode;
65
+ if (target && target !== "html" && (typeof target !== "object" || typeof target.emit !== "function")) diagnostics.push({
66
+ code: "TARGET_ADAPTER_INVALID",
67
+ message: "output.target must be a target adapter with emit().",
68
+ severity: "error"
69
+ });
70
+ if (styleMode && styleMode !== "inline" && styleMode !== "css-modules" && styleMode !== "tailwind") diagnostics.push({
71
+ code: "STYLE_MODE_UNSUPPORTED",
72
+ message: `Unsupported style mode: ${styleMode}`,
73
+ severity: "error"
74
+ });
75
+ for (const [index, component] of (config.components ?? []).entries()) {
76
+ if (!component.selector || typeof component.selector !== "string") diagnostics.push({
77
+ code: "COMPONENT_SELECTOR_INVALID",
78
+ message: `Component mapping ${index} must include a selector.`,
79
+ severity: "error"
80
+ });
81
+ if (!component.component || typeof component.component !== "string") diagnostics.push({
82
+ code: "COMPONENT_IMPORT_INVALID",
83
+ message: `Component mapping ${index} must include a component path.`,
84
+ severity: "error"
85
+ });
86
+ }
87
+ const spacing = config.tokens?.spacing;
88
+ if (spacing?.unit && spacing.unit !== "px" && spacing.unit !== "rem") diagnostics.push({
89
+ code: "TOKEN_SPACING_UNIT_INVALID",
90
+ message: `Unsupported spacing unit: ${spacing.unit}`,
91
+ severity: "error"
92
+ });
93
+ if (spacing?.threshold !== void 0 && !Number.isFinite(spacing.threshold)) diagnostics.push({
94
+ code: "TOKEN_SPACING_THRESHOLD_INVALID",
95
+ message: "Spacing threshold must be a finite number.",
96
+ severity: "error"
97
+ });
98
+ for (const [name, value] of Object.entries(spacing?.values ?? {})) if (!Number.isFinite(value)) diagnostics.push({
99
+ code: "TOKEN_SPACING_VALUE_INVALID",
100
+ message: `Spacing token ${name} must be a finite number.`,
101
+ severity: "error"
102
+ });
103
+ for (const [name, value] of Object.entries(config.tokens?.colors ?? {})) if (!/^#[0-9a-f]{3}([0-9a-f]{3})?$/i.test(value)) diagnostics.push({
104
+ code: "TOKEN_COLOR_INVALID",
105
+ message: `Color token ${name} must be a hex color.`,
106
+ severity: "error"
107
+ });
108
+ if (config.tokens?.colorThreshold !== void 0 && !Number.isFinite(config.tokens.colorThreshold)) diagnostics.push({
109
+ code: "TOKEN_COLOR_THRESHOLD_INVALID",
110
+ message: "Color threshold must be a finite number.",
111
+ severity: "error"
112
+ });
113
+ for (const [groupName, group] of Object.entries({
114
+ sizing: config.tokens?.sizing,
115
+ typography: config.tokens?.typography
116
+ })) {
117
+ if (!group) continue;
118
+ if (group.unit && group.unit !== "px" && group.unit !== "rem") diagnostics.push({
119
+ code: "TOKEN_NUMERIC_UNIT_INVALID",
120
+ message: `Unsupported ${groupName} unit: ${group.unit}`,
121
+ severity: "error"
122
+ });
123
+ if (group.threshold !== void 0 && !Number.isFinite(group.threshold)) diagnostics.push({
124
+ code: "TOKEN_NUMERIC_THRESHOLD_INVALID",
125
+ message: `${groupName} threshold must be a finite number.`,
126
+ severity: "error"
127
+ });
128
+ for (const [name, value] of Object.entries(group.values ?? {})) if (!Number.isFinite(value)) diagnostics.push({
129
+ code: "TOKEN_NUMERIC_VALUE_INVALID",
130
+ message: `${groupName} token ${name} must be a finite number.`,
131
+ severity: "error"
132
+ });
133
+ }
134
+ validateTestGeneration(config.tests, diagnostics);
135
+ return diagnostics;
136
+ }
137
+ function validateTestGeneration(tests, diagnostics) {
138
+ if (!tests) return;
139
+ if (tests.runner && tests.runner !== "playwright") diagnostics.push({
140
+ code: "TEST_RUNNER_UNSUPPORTED",
141
+ message: `Unsupported test runner: ${tests.runner}`,
142
+ severity: "error"
143
+ });
144
+ for (const [index, viewport] of (tests.viewports ?? []).entries()) {
145
+ if (!Number.isFinite(viewport.width) || viewport.width <= 0) diagnostics.push({
146
+ code: "TEST_VIEWPORT_WIDTH_INVALID",
147
+ message: `Test viewport ${index} width must be a positive finite number.`,
148
+ severity: "error"
149
+ });
150
+ if (!Number.isFinite(viewport.height) || viewport.height <= 0) diagnostics.push({
151
+ code: "TEST_VIEWPORT_HEIGHT_INVALID",
152
+ message: `Test viewport ${index} height must be a positive finite number.`,
153
+ severity: "error"
154
+ });
155
+ }
156
+ for (const [index, state] of (tests.states ?? []).entries()) if (!state.name || typeof state.name !== "string") diagnostics.push({
157
+ code: "TEST_STATE_NAME_INVALID",
158
+ message: `Test state ${index} must include a name.`,
159
+ severity: "error"
160
+ });
161
+ if (tests.assertions?.layoutTolerance !== void 0 && (!Number.isFinite(tests.assertions.layoutTolerance) || tests.assertions.layoutTolerance < 0)) diagnostics.push({
162
+ code: "TEST_LAYOUT_TOLERANCE_INVALID",
163
+ message: "Test layout tolerance must be a finite number greater than or equal to 0.",
164
+ severity: "error"
165
+ });
166
+ }
167
+ //#endregion
168
+ //#region packages/core/src/diagnostics/jsonDiagnostic.ts
169
+ function toJsonDiagnostic(diagnostic) {
170
+ const details = {
171
+ ...diagnostic.details,
172
+ ...diagnostic.selector ? { selector: diagnostic.selector } : {},
173
+ ...diagnostic.property ? { property: diagnostic.property } : {}
174
+ };
175
+ return {
176
+ code: diagnostic.code,
177
+ severity: diagnostic.severity,
178
+ message: redactSecrets(diagnostic.message),
179
+ ...diagnostic.file ? { file: diagnostic.file } : {},
180
+ ...diagnostic.source ? { line: diagnostic.source.line } : {},
181
+ ...diagnostic.source ? { column: diagnostic.source.column } : {},
182
+ ...Object.keys(details).length > 0 ? { details } : {}
183
+ };
184
+ }
185
+ function toJsonDiagnostics(diagnostics) {
186
+ return diagnostics.map(toJsonDiagnostic);
187
+ }
188
+ function formatDiagnosticText(diagnostic) {
189
+ const location = [
190
+ diagnostic.file,
191
+ diagnostic.source?.line,
192
+ diagnostic.source?.column
193
+ ].filter((part) => part !== void 0).join(":");
194
+ return `${location ? `${location}: ` : ""}${diagnostic.severity}: ${diagnostic.code}: ${redactSecrets(diagnostic.message)}`;
195
+ }
196
+ function redactSecrets(value) {
197
+ return value.replace(/figma[_-]?token\s*[:=]\s*[^\s]+/gi, "FIGMA_TOKEN=[redacted]").replace(/bearer\s+[a-z0-9._-]+/gi, "Bearer [redacted]");
198
+ }
199
+ //#endregion
200
+ //#region packages/core/src/pipeline/checkMode.ts
201
+ function checkGeneratedFiles(input) {
202
+ const diagnostics = [];
203
+ for (const file of input.files) {
204
+ const absolutePath = resolve(input.cwd, file.path);
205
+ const current = input.readFile(absolutePath);
206
+ if (current === void 0) {
207
+ diagnostics.push({
208
+ code: "CHECK_FILE_MISSING",
209
+ message: `Generated file is missing: ${file.path}`,
210
+ severity: "error",
211
+ file: file.path
212
+ });
213
+ continue;
214
+ }
215
+ if (current !== file.contents) diagnostics.push({
216
+ code: "CHECK_FILE_STALE",
217
+ message: `Generated file is stale: ${file.path}`,
218
+ severity: "error",
219
+ file: file.path
220
+ });
221
+ }
222
+ return {
223
+ ok: diagnostics.length === 0,
224
+ diagnostics
225
+ };
226
+ }
227
+ //#endregion
228
+ //#region packages/core/src/plugins/pluginRegistry.ts
229
+ var PluginRegistry = class {
230
+ #sourcePlugins = /* @__PURE__ */ new Map();
231
+ registerSource(plugin) {
232
+ this.#sourcePlugins.set(plugin.name, plugin);
233
+ }
234
+ getSource(name) {
235
+ return this.#sourcePlugins.get(name);
236
+ }
237
+ listSources() {
238
+ return [...this.#sourcePlugins.values()].sort((left, right) => left.name.localeCompare(right.name));
239
+ }
240
+ };
241
+ //#endregion
242
+ //#region packages/core/src/index.ts
243
+ /**
244
+ * The main compiler entry point.
245
+ * Parses HTML, applies component mappings, and emits files.
246
+ *
247
+ * @param input - The compilation input.
248
+ * @returns A promise resolving to the compilation result.
249
+ *
250
+ * @example
251
+ * const result = await embed({
252
+ * html: '<div class="btn">Click me</div>',
253
+ * config: myConfig,
254
+ * targetEmitter: reactEmitter
255
+ * });
256
+ */
257
+ async function embed(input) {
258
+ const ast = parseHtml(input.html);
259
+ const diagnostics = validateComponentMappings(input.config?.components ?? []);
260
+ if (diagnostics.some((d) => d.severity === "error")) return {
261
+ files: [],
262
+ diagnostics
263
+ };
264
+ const mappedNodes = applyComponentMappings(ast, input.config?.components ?? [], diagnostics);
265
+ const { files } = input.targetEmitter.emit({
266
+ nodes: mappedNodes,
267
+ css: input.css,
268
+ config: input.config,
269
+ diagnostics
270
+ });
271
+ return {
272
+ files,
273
+ diagnostics
274
+ };
275
+ }
276
+ function applyComponentMappings(nodes, mappings, diagnostics = []) {
277
+ const parsedMappings = mappings.map((mapping, index) => ({
278
+ index,
279
+ mapping,
280
+ selector: parseSelector(mapping.selector)
281
+ })).filter(({ selector }) => selector !== void 0);
282
+ return nodes.map((node) => {
283
+ if (node.kind !== "element") return node;
284
+ const match = parsedMappings.find(({ selector }) => matchesSelector(node, selector));
285
+ if (match) {
286
+ const props = extractProps(node, match.mapping, diagnostics);
287
+ return {
288
+ kind: "component",
289
+ component: match.mapping.importName ?? inferImportName(match.mapping),
290
+ importName: match.mapping.importName ?? inferImportName(match.mapping),
291
+ importPath: match.mapping.component,
292
+ props,
293
+ children: props.children?.kind === "children" ? void 0 : applyComponentMappings(node.children ?? [], mappings, diagnostics),
294
+ source: node.source
295
+ };
296
+ }
297
+ return {
298
+ ...node,
299
+ children: applyComponentMappings(node.children ?? [], mappings, diagnostics)
300
+ };
301
+ });
302
+ }
303
+ function parseSelector(selector) {
304
+ const trimmed = selector.trim();
305
+ if (!trimmed || /[\s>+~,:]/.test(trimmed)) return;
306
+ const parsed = {
307
+ classes: [],
308
+ attributes: {}
309
+ };
310
+ let rest = trimmed;
311
+ const tagMatch = rest.match(/^[a-zA-Z][a-zA-Z0-9-]*/);
312
+ if (tagMatch?.[0]) {
313
+ parsed.tagName = tagMatch[0].toLowerCase();
314
+ rest = rest.slice(tagMatch[0].length);
315
+ }
316
+ while (rest) {
317
+ if (rest.startsWith(".")) {
318
+ const match = rest.match(/^\.([a-zA-Z_][a-zA-Z0-9_-]*)/);
319
+ if (!match?.[1]) return;
320
+ parsed.classes.push(match[1]);
321
+ rest = rest.slice(match[0].length);
322
+ continue;
323
+ }
324
+ if (rest.startsWith("#")) {
325
+ const match = rest.match(/^#([a-zA-Z_][a-zA-Z0-9_-]*)/);
326
+ if (!match?.[1] || parsed.id) return;
327
+ parsed.id = match[1];
328
+ rest = rest.slice(match[0].length);
329
+ continue;
330
+ }
331
+ if (rest.startsWith("[")) {
332
+ const match = rest.match(/^\[([a-zA-Z_][a-zA-Z0-9_.:-]*)(?:=(?:"([^"]*)"|'([^']*)'|([^\]]+)))?\]/);
333
+ if (!match?.[1]) return;
334
+ parsed.attributes[match[1]] = match[2] ?? match[3] ?? match[4] ?? "";
335
+ rest = rest.slice(match[0].length);
336
+ continue;
337
+ }
338
+ return;
339
+ }
340
+ return parsed;
341
+ }
342
+ function matchesSelector(node, selector) {
343
+ if (node.kind !== "element") return false;
344
+ const attributes = node.attributes ?? {};
345
+ if (selector.tagName && node.tagName !== selector.tagName) return false;
346
+ if (selector.id && attributes.id !== selector.id) return false;
347
+ const classNames = new Set((attributes.class ?? "").split(/\s+/).filter(Boolean));
348
+ for (const className of selector.classes) if (!classNames.has(className)) return false;
349
+ for (const [name, value] of Object.entries(selector.attributes)) {
350
+ if (!(name in attributes)) return false;
351
+ if (value !== "" && attributes[name] !== value) return false;
352
+ }
353
+ return true;
354
+ }
355
+ function parseHtml(html) {
356
+ const root = {
357
+ kind: "element",
358
+ tagName: "root",
359
+ attributes: {},
360
+ styles: {},
361
+ children: []
362
+ };
363
+ const stack = [root];
364
+ const tokens = html.matchAll(/<!--[\s\S]*?-->|<\/?[a-zA-Z][^>]*>|[^<]+/g);
365
+ for (const token of tokens) {
366
+ const value = token[0];
367
+ const offset = token.index;
368
+ const source = getSourceLocation(html, offset);
369
+ if (value.startsWith("<!--")) continue;
370
+ if (value.startsWith("</")) {
371
+ const tagName = value.slice(2, -1).trim().toLowerCase();
372
+ while (stack.length > 1) if (stack.pop()?.tagName === tagName) break;
373
+ continue;
374
+ }
375
+ if (value.startsWith("<")) {
376
+ const selfClosing = /\/>$/.test(value) || isVoidElement(value);
377
+ const node = parseElement(value, source);
378
+ currentParent(stack).children?.push(node);
379
+ if (!selfClosing) stack.push(node);
380
+ continue;
381
+ }
382
+ if (value.trim()) currentParent(stack).children?.push({
383
+ kind: "text",
384
+ text: collapseWhitespace(value),
385
+ source
386
+ });
387
+ }
388
+ return root.children ?? [];
389
+ }
390
+ function parseInlineStyle(style) {
391
+ const styles = {};
392
+ if (!style) return styles;
393
+ for (const declaration of style.split(";")) {
394
+ const [property, ...valueParts] = declaration.split(":");
395
+ const value = valueParts.join(":").trim();
396
+ if (!property?.trim() || !value) continue;
397
+ styles[property.trim().toLowerCase()] = value;
398
+ }
399
+ return styles;
400
+ }
401
+ function parseElement(rawTag, source) {
402
+ const tagBody = rawTag.replace(/^</, "").replace(/\/?>$/, "").trim();
403
+ const tagName = tagBody.split(/\s+/, 1)[0]?.toLowerCase() ?? "div";
404
+ const attributes = parseAttributes(tagBody.slice(tagName.length).trim());
405
+ return {
406
+ kind: "element",
407
+ tagName,
408
+ attributes,
409
+ styles: parseInlineStyle(attributes.style),
410
+ children: [],
411
+ source
412
+ };
413
+ }
414
+ function parseAttributes(source) {
415
+ const attributes = {};
416
+ for (const match of source.matchAll(/([:@a-zA-Z_][:@a-zA-Z0-9_.-]*)(?:\s*=\s*("([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g)) {
417
+ const name = match[1];
418
+ if (!name) continue;
419
+ attributes[name] = match[3] ?? match[4] ?? match[5] ?? "";
420
+ }
421
+ return attributes;
422
+ }
423
+ function validateComponentMappings(mappings) {
424
+ const diagnostics = [];
425
+ for (const [index, mapping] of mappings.entries()) {
426
+ if (mapping.selector && !parseSelector(mapping.selector)) diagnostics.push({
427
+ code: "SELECTOR_UNSUPPORTED",
428
+ message: `Component mapping ${index} uses an unsupported selector: ${mapping.selector}`,
429
+ severity: "error"
430
+ });
431
+ for (const [propName, expression] of Object.entries(mapping.props ?? {})) if (!isSupportedPropExpression(expression)) diagnostics.push({
432
+ code: "PROP_EXPRESSION_UNSUPPORTED",
433
+ message: `Component mapping ${index} prop "${propName}" uses an unsupported expression: ${expression}`,
434
+ severity: "error"
435
+ });
436
+ }
437
+ return diagnostics;
438
+ }
439
+ function isSupportedPropExpression(expression) {
440
+ return !expression.startsWith("$") || expression === "$text" || expression === "$children" || /^\$attr\.[a-zA-Z_][a-zA-Z0-9_.:-]*$/.test(expression);
441
+ }
442
+ function extractProps(node, mapping, diagnostics) {
443
+ const props = {};
444
+ for (const [propName, expression] of Object.entries(mapping.props ?? {})) {
445
+ if (expression === "$text") {
446
+ props[propName] = {
447
+ kind: "text",
448
+ value: collectText(node)
449
+ };
450
+ continue;
451
+ }
452
+ if (expression === "$children") {
453
+ props[propName] = {
454
+ kind: "children",
455
+ value: node.children ?? []
456
+ };
457
+ continue;
458
+ }
459
+ if (expression.startsWith("$attr.")) {
460
+ const attributeName = expression.slice(6);
461
+ const value = node.attributes?.[attributeName];
462
+ if (value === void 0) {
463
+ diagnostics.push({
464
+ code: "PROP_ATTRIBUTE_MISSING",
465
+ message: `Attribute "${attributeName}" is missing for prop "${propName}".`,
466
+ severity: "warning"
467
+ });
468
+ continue;
469
+ }
470
+ props[propName] = {
471
+ kind: "literal",
472
+ value
473
+ };
474
+ continue;
475
+ }
476
+ props[propName] = {
477
+ kind: "literal",
478
+ value: expression
479
+ };
480
+ }
481
+ return props;
482
+ }
483
+ function collectText(node) {
484
+ if (node.kind === "text") return node.text ?? "";
485
+ return (node.children ?? []).map((child) => collectText(child)).filter(Boolean).join(" ").trim();
486
+ }
487
+ function inferImportName(mapping) {
488
+ const lastSegment = mapping.component.split("/").filter(Boolean).at(-1);
489
+ return mapping.importName ?? lastSegment ?? "Component";
490
+ }
491
+ function currentParent(stack) {
492
+ const parent = stack[stack.length - 1];
493
+ if (!parent) throw new Error("HTML parser stack is empty.");
494
+ return parent;
495
+ }
496
+ function getSourceLocation(source, offset) {
497
+ const lines = source.slice(0, offset).split(/\r?\n/);
498
+ return {
499
+ offset,
500
+ line: lines.length,
501
+ column: (lines[lines.length - 1]?.length ?? 0) + 1
502
+ };
503
+ }
504
+ function collapseWhitespace(value) {
505
+ return value.replace(/\s+/g, " ").trim();
506
+ }
507
+ function isVoidElement(tag) {
508
+ return /^<(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)(\s|>|\/)/i.test(tag);
509
+ }
510
+ //#endregion
511
+ export { parseInlineStyle as a, checkGeneratedFiles as c, toJsonDiagnostics as d, defineConfig as f, parseHtml as i, formatDiagnosticText as l, validateConfig as m, embed as n, parseSelector as o, loadConfig as p, matchesSelector as r, PluginRegistry as s, applyComponentMappings as t, toJsonDiagnostic as u };
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "design-embed",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "publishConfig": {
7
- "access": "public"
7
+ "access": "public",
8
+ "provenance": true
8
9
  },
9
10
  "exports": {
10
11
  ".": {
11
12
  "types": "./src/index.ts",
12
13
  "development": "./src/index.ts",
13
- "default": "./dist/index.js"
14
+ "default": "./dist/index.mjs"
14
15
  }
15
16
  },
16
17
  "files": [
@@ -20,18 +21,12 @@
20
21
  "README.md"
21
22
  ],
22
23
  "bin": {
23
- "design-embed": "./dist/cli.js"
24
+ "design-embed": "./dist/cli.mjs"
24
25
  },
25
- "dependencies": {
26
- "@design-embed/config": "0.1.0",
27
- "@design-embed/core": "0.1.0",
28
- "@design-embed/target-html": "0.1.0",
29
- "@design-embed/target-react": "0.1.0"
26
+ "devDependencies": {
27
+ "@design-embed/config": "0.1.1",
28
+ "@design-embed/core": "0.1.1"
30
29
  },
31
- "bundledDependencies": [
32
- "@design-embed/config",
33
- "@design-embed/core"
34
- ],
35
30
  "scripts": {
36
31
  "dev": "node src/cli.ts",
37
32
  "compile:react": "node src/cli.ts react",
package/src/cli.ts CHANGED
@@ -26,7 +26,24 @@ async function main(): Promise<number> {
26
26
  return runInitCommand(parsed.flags);
27
27
  }
28
28
 
29
- return runCompileCommand(parsed.flags);
29
+ const flags =
30
+ args[0] && !args[0].startsWith("--")
31
+ ? { ...parsed.flags, "--": args[0] }
32
+ : parsed.flags;
33
+ if (getOutPath(flags) && !hasInput(flags)) {
34
+ return runPluginCommand(undefined, flags);
35
+ }
36
+ return runCompileCommand(flags);
37
+ }
38
+
39
+ function getOutPath(flags: Record<string, string | boolean>): boolean {
40
+ return typeof flags["--out"] === "string";
41
+ }
42
+
43
+ function hasInput(flags: Record<string, string | boolean>): boolean {
44
+ return (
45
+ typeof flags["--input"] === "string" || typeof flags["--"] === "string"
46
+ );
30
47
  }
31
48
 
32
49
  main()