@nghitrum/dsforge 0.1.5-alpha.5 → 0.1.5-alpha.6
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/dist/chunk-OAMEFG6Q.js +28 -0
- package/dist/{chunk-RI3XDGKU.js → chunk-QHE35QQQ.js} +1 -1
- package/dist/cli/index.js +47 -27
- package/dist/{emitter-ZNRPJ4D6.js → emitter-KNYIQTS5.js} +1 -1
- package/dist/{html-6SIG34W5.js → html-BJBKRTSX.js} +64 -26
- package/dist/index.js +5 -1
- package/package.json +1 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// src/lib/license.ts
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
function readKeyFromDotEnv() {
|
|
5
|
+
try {
|
|
6
|
+
const content = readFileSync(join(process.cwd(), ".env"), "utf8");
|
|
7
|
+
for (const raw of content.split("\n")) {
|
|
8
|
+
const line = raw.trim();
|
|
9
|
+
if (!line || line.startsWith("#")) continue;
|
|
10
|
+
const eq = line.indexOf("=");
|
|
11
|
+
if (eq === -1) continue;
|
|
12
|
+
const key = line.slice(0, eq).trim();
|
|
13
|
+
if (key !== "DSFORGE_KEY") continue;
|
|
14
|
+
const val = line.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
15
|
+
return val || void 0;
|
|
16
|
+
}
|
|
17
|
+
} catch {
|
|
18
|
+
}
|
|
19
|
+
return void 0;
|
|
20
|
+
}
|
|
21
|
+
function isProUnlocked() {
|
|
22
|
+
const key = process.env["DSFORGE_KEY"] ?? readKeyFromDotEnv();
|
|
23
|
+
return typeof key === "string" && key.length > 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
isProUnlocked
|
|
28
|
+
};
|
|
@@ -27,7 +27,7 @@ function generatePackageJson(config, componentNames) {
|
|
|
27
27
|
componentNames.map((c) => [`./metadata/${c}`, `./metadata/${c}.json`])
|
|
28
28
|
)
|
|
29
29
|
},
|
|
30
|
-
files: ["dist", "tokens", "metadata", "
|
|
30
|
+
files: ["dist", "tokens", "metadata", "CHANGELOG.md"],
|
|
31
31
|
scripts: {
|
|
32
32
|
build: "tsc",
|
|
33
33
|
prepublishOnly: "npm run build"
|
package/dist/cli/index.js
CHANGED
|
@@ -3,7 +3,10 @@ import {
|
|
|
3
3
|
generateChangelog,
|
|
4
4
|
generatePackageJson,
|
|
5
5
|
generateTsConfig
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-QHE35QQQ.js";
|
|
7
|
+
import {
|
|
8
|
+
isProUnlocked
|
|
9
|
+
} from "../chunk-OAMEFG6Q.js";
|
|
7
10
|
|
|
8
11
|
// src/cli/index.ts
|
|
9
12
|
import { program } from "commander";
|
|
@@ -436,6 +439,32 @@ var RADIUS_PRESETS = {
|
|
|
436
439
|
comfortable: { none: 0, sm: 2, md: 4, lg: 8, xl: 16, full: 9999 },
|
|
437
440
|
spacious: { none: 0, sm: 3, md: 6, lg: 12, xl: 20, full: 9999 }
|
|
438
441
|
};
|
|
442
|
+
function applyPreset(config, preset) {
|
|
443
|
+
const spacing = SPACING_PRESETS[preset];
|
|
444
|
+
const radius = RADIUS_PRESETS[preset];
|
|
445
|
+
const baseUnit = preset === "compact" ? 2 : preset === "spacious" ? 6 : 4;
|
|
446
|
+
config.spacing = {
|
|
447
|
+
...config.spacing,
|
|
448
|
+
baseUnit,
|
|
449
|
+
scale: spacing,
|
|
450
|
+
semantic: {
|
|
451
|
+
"component-padding-xs": `${spacing["1"]}`,
|
|
452
|
+
"component-padding-sm": `${spacing["2"]}`,
|
|
453
|
+
"component-padding-md": `${spacing["4"]}`,
|
|
454
|
+
"component-padding-lg": `${spacing["5"]}`,
|
|
455
|
+
"layout-gap-xs": `${spacing["2"]}`,
|
|
456
|
+
"layout-gap-sm": `${spacing["3"]}`,
|
|
457
|
+
"layout-gap-md": `${spacing["5"]}`,
|
|
458
|
+
"layout-gap-lg": `${spacing["6"]}`,
|
|
459
|
+
"layout-section": `${spacing["7"]}`
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
config.radius = { ...config.radius, ...radius };
|
|
463
|
+
config.philosophy = {
|
|
464
|
+
...config.philosophy,
|
|
465
|
+
density: preset
|
|
466
|
+
};
|
|
467
|
+
}
|
|
439
468
|
function buildInitialConfig(name, preset = "comfortable") {
|
|
440
469
|
const spacing = SPACING_PRESETS[preset];
|
|
441
470
|
const radius = RADIUS_PRESETS[preset];
|
|
@@ -775,7 +804,15 @@ async function runInit(cwd, options) {
|
|
|
775
804
|
}
|
|
776
805
|
const name = rawName.replace(/\s+/g, "-").toLowerCase();
|
|
777
806
|
let preset;
|
|
778
|
-
if (
|
|
807
|
+
if (!isProUnlocked()) {
|
|
808
|
+
if (options.preset && options.preset !== "comfortable") {
|
|
809
|
+
logger.hint(
|
|
810
|
+
`Preset "${options.preset}" requires dsforge Pro`,
|
|
811
|
+
`Set DSFORGE_KEY to unlock compact and spacious. Using comfortable.`
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
preset = "comfortable";
|
|
815
|
+
} else if (options.preset && VALID_PRESETS.includes(options.preset)) {
|
|
779
816
|
preset = options.preset;
|
|
780
817
|
} else {
|
|
781
818
|
const answer = await ask(
|
|
@@ -4761,6 +4798,10 @@ async function runGenerate(cwd, options) {
|
|
|
4761
4798
|
options.debug ?? false
|
|
4762
4799
|
);
|
|
4763
4800
|
}
|
|
4801
|
+
const presetValue = config.meta.preset;
|
|
4802
|
+
if (presetValue === "compact" || presetValue === "comfortable" || presetValue === "spacious") {
|
|
4803
|
+
applyPreset(config, presetValue);
|
|
4804
|
+
}
|
|
4764
4805
|
const fullRules = Object.fromEntries(
|
|
4765
4806
|
REACT_COMPONENTS.map((name) => [name, rules[name] ?? {}])
|
|
4766
4807
|
);
|
|
@@ -4855,7 +4896,7 @@ async function runGenerate(cwd, options) {
|
|
|
4855
4896
|
logger.dim(` \u2192 src/${idxFile}`);
|
|
4856
4897
|
logger.success(`${generatedNames.length} components generated`);
|
|
4857
4898
|
}
|
|
4858
|
-
if (!only || only === "metadata") {
|
|
4899
|
+
if (isProUnlocked() && (!only || only === "metadata")) {
|
|
4859
4900
|
logger.step("Writing AI metadata...");
|
|
4860
4901
|
const metaDir = path3.join(outRoot, "metadata");
|
|
4861
4902
|
await ensureDir(metaDir);
|
|
@@ -4866,27 +4907,6 @@ async function runGenerate(cwd, options) {
|
|
|
4866
4907
|
}
|
|
4867
4908
|
logger.success(`Metadata written (${metaFiles.length} files)`);
|
|
4868
4909
|
}
|
|
4869
|
-
if (!only || only === "docs") {
|
|
4870
|
-
logger.step("Generating docs...");
|
|
4871
|
-
const docsDir = path3.join(outRoot, "docs");
|
|
4872
|
-
await ensureDir(docsDir);
|
|
4873
|
-
const metadataFiles = generateMetadata(config, fullRules, tokenCount);
|
|
4874
|
-
const metadataMap = {};
|
|
4875
|
-
for (const { filename, content } of metadataFiles) {
|
|
4876
|
-
const name = filename.replace(".json", "");
|
|
4877
|
-
if (name !== "index") {
|
|
4878
|
-
metadataMap[name] = JSON.parse(
|
|
4879
|
-
content
|
|
4880
|
-
);
|
|
4881
|
-
}
|
|
4882
|
-
}
|
|
4883
|
-
const docFiles = reactAdapter.generateDocs(config, fullRules, metadataMap);
|
|
4884
|
-
for (const { filename, content } of docFiles) {
|
|
4885
|
-
await writeFile(path3.join(docsDir, filename), content);
|
|
4886
|
-
logger.dim(` \u2192 docs/${filename}`);
|
|
4887
|
-
}
|
|
4888
|
-
logger.success(`Docs written (${docFiles.length} files)`);
|
|
4889
|
-
}
|
|
4890
4910
|
if (!only) {
|
|
4891
4911
|
logger.step("Writing package files...");
|
|
4892
4912
|
const componentNames = Object.keys(fullRules);
|
|
@@ -4896,7 +4916,7 @@ async function runGenerate(cwd, options) {
|
|
|
4896
4916
|
const tsConfig = generateTsConfig();
|
|
4897
4917
|
await writeFile(path3.join(outRoot, "tsconfig.json"), tsConfig);
|
|
4898
4918
|
logger.dim(` \u2192 tsconfig.json`);
|
|
4899
|
-
const { generateReadme } = await import("../emitter-
|
|
4919
|
+
const { generateReadme } = await import("../emitter-KNYIQTS5.js");
|
|
4900
4920
|
await writeFile(
|
|
4901
4921
|
path3.join(outRoot, "README.md"),
|
|
4902
4922
|
generateReadme(config, componentNames)
|
|
@@ -4912,7 +4932,7 @@ async function runGenerate(cwd, options) {
|
|
|
4912
4932
|
logger.success(`Package files written`);
|
|
4913
4933
|
}
|
|
4914
4934
|
logger.step("Generating showcase...");
|
|
4915
|
-
const { generateShowcase } = await import("../html-
|
|
4935
|
+
const { generateShowcase } = await import("../html-BJBKRTSX.js");
|
|
4916
4936
|
const showcaseHtml = generateShowcase(config, resolution);
|
|
4917
4937
|
await writeFile(path3.join(outRoot, "showcase.html"), showcaseHtml);
|
|
4918
4938
|
logger.dim(` \u2192 showcase.html`);
|
|
@@ -5299,7 +5319,7 @@ async function runMenu() {
|
|
|
5299
5319
|
// package.json
|
|
5300
5320
|
var package_default = {
|
|
5301
5321
|
name: "@nghitrum/dsforge",
|
|
5302
|
-
version: "0.1.5-alpha.
|
|
5322
|
+
version: "0.1.5-alpha.6",
|
|
5303
5323
|
description: "AI-native design system generator \u2014 tokens \u2192 components \u2192 docs \u2192 npm",
|
|
5304
5324
|
keywords: [
|
|
5305
5325
|
"design-system",
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isProUnlocked
|
|
3
|
+
} from "./chunk-OAMEFG6Q.js";
|
|
4
|
+
|
|
1
5
|
// src/generators/showcase/types.ts
|
|
2
6
|
function esc(s) {
|
|
3
7
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -32,31 +36,6 @@ function componentTokens(config, tokens) {
|
|
|
32
36
|
};
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
// src/lib/license.ts
|
|
36
|
-
import { readFileSync } from "fs";
|
|
37
|
-
import { join } from "path";
|
|
38
|
-
function readKeyFromDotEnv() {
|
|
39
|
-
try {
|
|
40
|
-
const content = readFileSync(join(process.cwd(), ".env"), "utf8");
|
|
41
|
-
for (const raw of content.split("\n")) {
|
|
42
|
-
const line = raw.trim();
|
|
43
|
-
if (!line || line.startsWith("#")) continue;
|
|
44
|
-
const eq = line.indexOf("=");
|
|
45
|
-
if (eq === -1) continue;
|
|
46
|
-
const key = line.slice(0, eq).trim();
|
|
47
|
-
if (key !== "DSFORGE_KEY") continue;
|
|
48
|
-
const val = line.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
49
|
-
return val || void 0;
|
|
50
|
-
}
|
|
51
|
-
} catch {
|
|
52
|
-
}
|
|
53
|
-
return void 0;
|
|
54
|
-
}
|
|
55
|
-
function isProUnlocked() {
|
|
56
|
-
const key = process.env["DSFORGE_KEY"] ?? readKeyFromDotEnv();
|
|
57
|
-
return typeof key === "string" && key.length > 0;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
39
|
// src/generators/showcase/foundations.ts
|
|
61
40
|
function buildColorSection(config, tokens) {
|
|
62
41
|
const groups = [];
|
|
@@ -231,7 +210,9 @@ var lockedPanel = (label) => `
|
|
|
231
210
|
function buildComponentPage(def, isPro) {
|
|
232
211
|
const tabId = (tab) => `${def.id}-tab-${tab}`;
|
|
233
212
|
const panelId = (tab) => `${def.id}-panel-${tab}`;
|
|
234
|
-
const overviewHtml =
|
|
213
|
+
const overviewHtml = `
|
|
214
|
+
<div class="comp-overview">${def.overviewHtml}</div>
|
|
215
|
+
<p class="component-description">${esc(def.description)}</p>`;
|
|
235
216
|
const propsTable = `
|
|
236
217
|
<table class="props-table">
|
|
237
218
|
<thead>
|
|
@@ -366,6 +347,9 @@ function buttonDef(config, tokens) {
|
|
|
366
347
|
id: "button",
|
|
367
348
|
label: "Button",
|
|
368
349
|
description: "Triggers an action or event. Use for form submissions, dialogs, and in-page actions.",
|
|
350
|
+
usageExample: `<Button variant="primary" size="md" onClick={() => {}}>
|
|
351
|
+
Save changes
|
|
352
|
+
</Button>`,
|
|
369
353
|
overviewHtml: `
|
|
370
354
|
<div class="comp-overview-section">
|
|
371
355
|
<div class="comp-overview-label">Variants</div>
|
|
@@ -552,6 +536,13 @@ function inputDef(config, tokens) {
|
|
|
552
536
|
id: "input",
|
|
553
537
|
label: "Input",
|
|
554
538
|
description: "Single-line text field. Covers all standard input types with label, helper text, and validation states.",
|
|
539
|
+
usageExample: `<Input
|
|
540
|
+
label="Email"
|
|
541
|
+
placeholder="you@example.com"
|
|
542
|
+
value={email}
|
|
543
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
544
|
+
error={emailError}
|
|
545
|
+
/>`,
|
|
555
546
|
overviewHtml: `
|
|
556
547
|
<div class="comp-overview-section">
|
|
557
548
|
<div class="comp-overview-label">States</div>
|
|
@@ -757,6 +748,10 @@ function cardDef(config, tokens) {
|
|
|
757
748
|
id: "card",
|
|
758
749
|
label: "Card",
|
|
759
750
|
description: "A surface that groups related content. Supports header, body, and optional footer slots.",
|
|
751
|
+
usageExample: `<Card padding="lg">
|
|
752
|
+
<h2>Card title</h2>
|
|
753
|
+
<p>Card content goes here.</p>
|
|
754
|
+
</Card>`,
|
|
760
755
|
overviewHtml: `
|
|
761
756
|
<div class="comp-overview-section">
|
|
762
757
|
<div class="comp-overview-label">Variants</div>
|
|
@@ -913,6 +908,8 @@ function badgeDef(config, tokens) {
|
|
|
913
908
|
id: "badge",
|
|
914
909
|
label: "Badge",
|
|
915
910
|
description: "Compact label for status, categories, or counts. Display-only \u2014 not interactive.",
|
|
911
|
+
usageExample: `<Badge variant="success">Active</Badge>
|
|
912
|
+
<Badge variant="warning">Pending</Badge>`,
|
|
916
913
|
overviewHtml: `
|
|
917
914
|
<div class="comp-overview-section">
|
|
918
915
|
<div class="comp-overview-label">Variants</div>
|
|
@@ -1057,6 +1054,11 @@ function checkboxDef(config, tokens) {
|
|
|
1057
1054
|
id: "checkbox",
|
|
1058
1055
|
label: "Checkbox",
|
|
1059
1056
|
description: "Binary toggle for boolean values. Supports indeterminate state for partial selections.",
|
|
1057
|
+
usageExample: `<Checkbox
|
|
1058
|
+
label="Accept terms"
|
|
1059
|
+
checked={accepted}
|
|
1060
|
+
onChange={(e) => setAccepted(e.target.checked)}
|
|
1061
|
+
/>`,
|
|
1060
1062
|
overviewHtml: `
|
|
1061
1063
|
<div class="comp-overview-section">
|
|
1062
1064
|
<div class="comp-overview-label">States</div>
|
|
@@ -1239,6 +1241,8 @@ function radioDef(config, tokens) {
|
|
|
1239
1241
|
id: "radio",
|
|
1240
1242
|
label: "Radio",
|
|
1241
1243
|
description: "Single selection within a mutually exclusive group. Always pair Radio with RadioGroup.",
|
|
1244
|
+
usageExample: `<Radio label="Option A" name="choice" value="a" checked={choice === 'a'} onChange={() => setChoice('a')} />
|
|
1245
|
+
<Radio label="Option B" name="choice" value="b" checked={choice === 'b'} onChange={() => setChoice('b')} />`,
|
|
1242
1246
|
overviewHtml: `
|
|
1243
1247
|
<div class="comp-overview-section">
|
|
1244
1248
|
<div class="comp-overview-label">RadioGroup (vertical)</div>
|
|
@@ -1425,6 +1429,12 @@ function selectDef(config, tokens) {
|
|
|
1425
1429
|
id: "select",
|
|
1426
1430
|
label: "Select",
|
|
1427
1431
|
description: "Dropdown picker for selecting from a list of options. Wraps native <select> for full accessibility.",
|
|
1432
|
+
usageExample: `<Select
|
|
1433
|
+
label="Country"
|
|
1434
|
+
options={[{ label: 'Norway', value: 'no' }, { label: 'Sweden', value: 'se' }]}
|
|
1435
|
+
value={country}
|
|
1436
|
+
onChange={(e) => setCountry(e.target.value)}
|
|
1437
|
+
/>`,
|
|
1428
1438
|
overviewHtml: `
|
|
1429
1439
|
<div class="comp-overview-section">
|
|
1430
1440
|
<div class="comp-overview-label">States</div>
|
|
@@ -1610,6 +1620,12 @@ function toastDef(config, tokens) {
|
|
|
1610
1620
|
id: "toast",
|
|
1611
1621
|
label: "Toast / Alert",
|
|
1612
1622
|
description: "Feedback for user actions. Alert is inline and static; Toast is an overlay with auto-dismiss and a useToast() hook.",
|
|
1623
|
+
usageExample: `<Toast
|
|
1624
|
+
message="Changes saved successfully"
|
|
1625
|
+
variant="success"
|
|
1626
|
+
duration={3000}
|
|
1627
|
+
onDismiss={() => setToast(null)}
|
|
1628
|
+
/>`,
|
|
1613
1629
|
overviewHtml: `
|
|
1614
1630
|
<div class="comp-overview-section">
|
|
1615
1631
|
<div class="comp-overview-label">Alert \u2014 inline variants</div>
|
|
@@ -1791,6 +1807,7 @@ function spinnerDef(config, tokens) {
|
|
|
1791
1807
|
id: "spinner",
|
|
1792
1808
|
label: "Spinner",
|
|
1793
1809
|
description: "Loading indicator for async operations. Includes a visually hidden status label for screen readers.",
|
|
1810
|
+
usageExample: `<Spinner size="lg" label="Saving your changes" />`,
|
|
1794
1811
|
overviewHtml: `
|
|
1795
1812
|
<div class="comp-overview-section">
|
|
1796
1813
|
<div class="comp-overview-label">Sizes</div>
|
|
@@ -2301,6 +2318,27 @@ ${themeCssDark}
|
|
|
2301
2318
|
.ds-card-body { padding: 12px 14px; }
|
|
2302
2319
|
.ds-card-footer { padding: 10px 14px; display: flex; justify-content: flex-end; }
|
|
2303
2320
|
|
|
2321
|
+
/* \u2500\u2500 Component docs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
2322
|
+
.component-docs { margin-top: 36px; }
|
|
2323
|
+
.component-description {
|
|
2324
|
+
font-size: 14px; color: var(--color-text-secondary, #64748b);
|
|
2325
|
+
line-height: 1.65; margin-bottom: 24px; max-width: 640px;
|
|
2326
|
+
}
|
|
2327
|
+
.component-docs h4 {
|
|
2328
|
+
font-size: 11px; font-weight: 600; text-transform: uppercase;
|
|
2329
|
+
letter-spacing: 0.07em; color: var(--color-text-secondary, #64748b);
|
|
2330
|
+
margin-bottom: 12px; padding-bottom: 8px;
|
|
2331
|
+
border-bottom: 1px solid var(--color-border-default, #e2e8f0);
|
|
2332
|
+
}
|
|
2333
|
+
.usage-example {
|
|
2334
|
+
margin: 0; padding: 16px 18px;
|
|
2335
|
+
background: var(--color-bg-default, #fff);
|
|
2336
|
+
color: var(--color-text-primary, #0f172a);
|
|
2337
|
+
border: 1px solid var(--color-border-default, #e2e8f0); border-radius: 8px;
|
|
2338
|
+
font-family: "SF Mono", "Fira Code", "Cascadia Code", monospace;
|
|
2339
|
+
font-size: 12.5px; line-height: 1.65; overflow-x: auto; white-space: pre;
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2304
2342
|
/* \u2500\u2500 Spinner animation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
2305
2343
|
@keyframes dsforge-spin { to { transform: rotate(360deg); } }
|
|
2306
2344
|
@media (prefers-reduced-motion: reduce) { @keyframes dsforge-spin { to { transform: none; } } }
|
package/dist/index.js
CHANGED
|
@@ -1143,6 +1143,10 @@ var rl = readline.createInterface({
|
|
|
1143
1143
|
output: process.stdout
|
|
1144
1144
|
});
|
|
1145
1145
|
|
|
1146
|
+
// src/lib/license.ts
|
|
1147
|
+
import { readFileSync } from "fs";
|
|
1148
|
+
import { join } from "path";
|
|
1149
|
+
|
|
1146
1150
|
// src/cli/commands/init.ts
|
|
1147
1151
|
var SPACING_PRESETS = {
|
|
1148
1152
|
compact: {
|
|
@@ -3062,7 +3066,7 @@ function generatePackageJson(config, componentNames) {
|
|
|
3062
3066
|
componentNames.map((c) => [`./metadata/${c}`, `./metadata/${c}.json`])
|
|
3063
3067
|
)
|
|
3064
3068
|
},
|
|
3065
|
-
files: ["dist", "tokens", "metadata", "
|
|
3069
|
+
files: ["dist", "tokens", "metadata", "CHANGELOG.md"],
|
|
3066
3070
|
scripts: {
|
|
3067
3071
|
build: "tsc",
|
|
3068
3072
|
prepublishOnly: "npm run build"
|