emily-css 1.0.18 → 1.0.20

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/src/init.js CHANGED
@@ -76,7 +76,9 @@ const PURGE_EXTENSIONS = [
76
76
  ".njk",
77
77
  ".liquid",
78
78
  ".hbs",
79
+ ".js",
79
80
  ".jsx",
81
+ ".ts",
80
82
  ".tsx",
81
83
  ".vue",
82
84
  ".php",
@@ -107,59 +109,37 @@ async function askHex(promptName, message, initial) {
107
109
  message,
108
110
  initial: initial || "#000000",
109
111
  validate(value) {
110
- return isValidHex(value) ? true : "Enter a valid hex colour, e.g. #0077B6";
112
+ return isValidHex(value)
113
+ ? true
114
+ : "Enter a valid hex colour, e.g. #0077B6";
111
115
  },
112
116
  }).run();
117
+
113
118
  return value.toUpperCase();
114
119
  }
115
120
 
116
121
  async function askColourFromPresets(label, presets, defaultHex) {
117
- const choices = presets.map(function(opt) {
122
+ const choices = presets.map(function (opt) {
118
123
  if (opt.value === "custom") {
119
124
  return { name: "custom", message: "Enter your own hex" };
120
125
  }
126
+
121
127
  return {
122
128
  name: opt.value,
123
- message: colourSwatch(opt.value) + " " + opt.label + " " + chalk.gray(opt.value),
129
+ message:
130
+ colourSwatch(opt.value) + " " + opt.label + " " + chalk.gray(opt.value),
124
131
  };
125
132
  });
126
133
 
127
134
  const selected = await new Select({
128
135
  name: label,
129
136
  message: label + " colour",
130
- choices: choices,
137
+ choices,
131
138
  }).run();
132
139
 
133
140
  if (selected !== "custom") return selected.toUpperCase();
134
- return askHex(label + "Custom", "Enter " + label + " hex", defaultHex);
135
- }
136
-
137
- async function askBtnColour(label, matchLabel, matchHex, presets) {
138
- const sameChoice = {
139
- name: matchHex,
140
- message: colourSwatch(matchHex) + " Same as " + matchLabel + " " + chalk.gray(matchHex),
141
- };
142
-
143
- const otherChoices = presets
144
- .filter(function(opt) { return opt.value !== matchHex; })
145
- .map(function(opt) {
146
- if (opt.value === "custom") {
147
- return { name: "custom", message: "Enter your own hex" };
148
- }
149
- return {
150
- name: opt.value,
151
- message: colourSwatch(opt.value) + " " + opt.label + " " + chalk.gray(opt.value),
152
- };
153
- });
154
141
 
155
- const selected = await new Select({
156
- name: label,
157
- message: label + " colour",
158
- choices: [sameChoice].concat(otherChoices),
159
- }).run();
160
-
161
- if (selected !== "custom") return selected.toUpperCase();
162
- return askHex(label + "Custom", "Enter " + label + " hex", matchHex);
142
+ return askHex(label + "Custom", "Enter " + label + " hex", defaultHex);
163
143
  }
164
144
 
165
145
  function hasFile(fileName) {
@@ -168,7 +148,9 @@ function hasFile(fileName) {
168
148
 
169
149
  function readPackageJson() {
170
150
  const packagePath = path.join(process.cwd(), "package.json");
151
+
171
152
  if (!fs.existsSync(packagePath)) return null;
153
+
172
154
  try {
173
155
  return JSON.parse(fs.readFileSync(packagePath, "utf8"));
174
156
  } catch {
@@ -178,34 +160,52 @@ function readPackageJson() {
178
160
 
179
161
  function hasDependency(packageJson, dependencyName) {
180
162
  if (!packageJson) return false;
163
+
181
164
  return Boolean(
182
165
  packageJson.dependencies?.[dependencyName] ||
183
166
  packageJson.devDependencies?.[dependencyName],
184
167
  );
185
168
  }
186
169
 
170
+ function titleCasePackageName(name) {
171
+ return name.replace(/-/g, " ").replace(/\b\w/g, function (c) {
172
+ return c.toUpperCase();
173
+ });
174
+ }
175
+
187
176
  function addEmilyScriptsToPackageJson() {
188
177
  const packagePath = path.join(process.cwd(), "package.json");
178
+
189
179
  if (!fs.existsSync(packagePath)) return false;
180
+
190
181
  try {
191
182
  const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
183
+
192
184
  packageJson.scripts = packageJson.scripts || {};
185
+
193
186
  let changed = false;
187
+
194
188
  const scripts = {
195
189
  "emily:build": "emily-css build",
196
190
  "emily:watch": "emily-css watch",
197
191
  "emily:help": "emily-css help",
198
192
  "emily:showcase": "emily-css showcase",
199
193
  };
200
- for (const [key, val] of Object.entries(scripts)) {
194
+
195
+ for (const [key, value] of Object.entries(scripts)) {
201
196
  if (!packageJson.scripts[key]) {
202
- packageJson.scripts[key] = val;
197
+ packageJson.scripts[key] = value;
203
198
  changed = true;
204
199
  }
205
200
  }
201
+
206
202
  if (changed) {
207
- fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + "\n");
203
+ fs.writeFileSync(
204
+ packagePath,
205
+ JSON.stringify(packageJson, null, 2) + "\n",
206
+ );
208
207
  }
208
+
209
209
  return true;
210
210
  } catch {
211
211
  return false;
@@ -227,12 +227,14 @@ function detectProject() {
227
227
  return {
228
228
  name: "Nuxt",
229
229
  sourceDir: ".",
230
+ outputPath: "public/emily.min.css",
230
231
  sourceGlobs: [
231
232
  "./components/**/*.{vue,js,ts}",
232
233
  "./pages/**/*.vue",
233
234
  "./layouts/**/*.vue",
234
235
  "./app.vue",
235
236
  ],
237
+ linkHint: '<link rel="stylesheet" href="/emily.min.css">',
236
238
  };
237
239
  }
238
240
 
@@ -240,12 +242,14 @@ function detectProject() {
240
242
  return {
241
243
  name: "Next.js",
242
244
  sourceDir: ".",
245
+ outputPath: "public/emily.min.css",
243
246
  sourceGlobs: [
244
247
  "./app/**/*.{js,jsx,ts,tsx}",
245
248
  "./pages/**/*.{js,jsx,ts,tsx}",
246
249
  "./components/**/*.{js,jsx,ts,tsx}",
247
250
  "./src/**/*.{js,jsx,ts,tsx}",
248
251
  ],
252
+ linkHint: '<link rel="stylesheet" href="/emily.min.css">',
249
253
  };
250
254
  }
251
255
 
@@ -253,10 +257,16 @@ function detectProject() {
253
257
  return {
254
258
  name: "React",
255
259
  sourceDir: "./src",
260
+ outputPath: hasFile("public")
261
+ ? "public/emily.min.css"
262
+ : "dist/emily.min.css",
256
263
  sourceGlobs: [
257
264
  "./src/**/*.{js,jsx,ts,tsx}",
258
265
  "./components/**/*.{js,jsx,ts,tsx}",
259
266
  ],
267
+ linkHint: hasFile("public")
268
+ ? '<link rel="stylesheet" href="/emily.min.css">'
269
+ : '<link rel="stylesheet" href="./dist/emily.min.css">',
260
270
  };
261
271
  }
262
272
 
@@ -268,7 +278,9 @@ function detectProject() {
268
278
  return {
269
279
  name: "Vue/Vite",
270
280
  sourceDir: "./src",
281
+ outputPath: "public/emily.min.css",
271
282
  sourceGlobs: ["./src/**/*.{vue,js,ts}"],
283
+ linkHint: '<link rel="stylesheet" href="/emily.min.css">',
272
284
  };
273
285
  }
274
286
 
@@ -276,14 +288,16 @@ function detectProject() {
276
288
  return {
277
289
  name: "Astro",
278
290
  sourceDir: "./src",
291
+ outputPath: "public/emily.min.css",
279
292
  sourceGlobs: ["./src/**/*.{astro,html,js,ts,vue,jsx,tsx,svelte}"],
293
+ linkHint: '<link rel="stylesheet" href="/emily.min.css">',
280
294
  };
281
295
  }
282
296
 
283
297
  const rootFiles = fs.readdirSync(process.cwd());
284
- const hasDrupalInfoFile = rootFiles.some((file) =>
285
- file.endsWith(".info.yml"),
286
- );
298
+ const hasDrupalInfoFile = rootFiles.some(function (file) {
299
+ return file.endsWith(".info.yml");
300
+ });
287
301
 
288
302
  if (
289
303
  hasDrupalInfoFile ||
@@ -292,21 +306,25 @@ function detectProject() {
292
306
  return {
293
307
  name: "Drupal",
294
308
  sourceDir: ".",
309
+ outputPath: "dist/emily.min.css",
295
310
  sourceGlobs: [
296
311
  "./web/themes/custom/**/*.{twig,js,ts}",
297
312
  "./templates/**/*.html.twig",
298
313
  "./components/**/*.twig",
299
314
  "./**/*.theme",
300
315
  ],
316
+ linkHint: "Attach dist/emily.min.css through your theme library YAML.",
301
317
  };
302
318
  }
303
319
 
304
320
  return {
305
321
  name: "Static/Generic",
306
322
  sourceDir: ".",
323
+ outputPath: "dist/emily.min.css",
307
324
  sourceGlobs: [
308
325
  "./**/*.{html,htm,twig,njk,liquid,hbs,php,astro,svelte,vue,js,ts}",
309
326
  ],
327
+ linkHint: '<link rel="stylesheet" href="./dist/emily.min.css">',
310
328
  };
311
329
  }
312
330
 
@@ -321,7 +339,6 @@ function createDefaultConfig({
321
339
  bodyFont,
322
340
  baseUnit,
323
341
  detectedProject,
324
- sourceDir,
325
342
  }) {
326
343
  return {
327
344
  name,
@@ -337,11 +354,16 @@ function createDefaultConfig({
337
354
 
338
355
  customFonts: [],
339
356
 
357
+ output: {
358
+ css: detectedProject.outputPath,
359
+ fullCss: "dist/emily.css",
360
+ },
361
+
340
362
  colours,
341
363
 
342
364
  purge: {
343
365
  projectType: detectedProject.name,
344
- sourceDir,
366
+ sourceDir: detectedProject.sourceDir,
345
367
  sourceGlobs: detectedProject.sourceGlobs,
346
368
  ignore: DEFAULT_PURGE_IGNORE,
347
369
  extensions: PURGE_EXTENSIONS,
@@ -469,26 +491,32 @@ function createDefaultConfig({
469
491
  // ============================================================================
470
492
 
471
493
  async function init() {
472
- console.log(chalk.bold.magenta("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"));
494
+ console.log(
495
+ chalk.bold.magenta("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"),
496
+ );
473
497
  console.log(chalk.bold.magenta(" EmilyUI Setup"));
474
- console.log(chalk.bold.magenta("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"));
498
+ console.log(
499
+ chalk.bold.magenta("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"),
500
+ );
475
501
 
476
502
  try {
477
503
  const spinner = ora("Analysing project structure...").start();
478
504
  const detectedProject = detectProject();
479
505
  spinner.succeed("Detected project: " + chalk.cyan(detectedProject.name));
480
506
 
481
- // Derive a sensible default name from package.json if available
482
507
  const packageJsonData = readPackageJson();
483
- const pkgName = packageJsonData && packageJsonData.name
484
- ? packageJsonData.name.replace(/-/g, " ").replace(/\b\w/g, function(c) { return c.toUpperCase(); })
485
- : "My Design System";
508
+ const pkgName =
509
+ packageJsonData && packageJsonData.name
510
+ ? titleCasePackageName(packageJsonData.name)
511
+ : "My Design System";
486
512
 
487
513
  const projectName = await new Input({
488
514
  name: "projectName",
489
515
  message: "Project name",
490
516
  initial: pkgName,
491
- validate: function(v) { return v.trim() ? true : "Project name is required"; },
517
+ validate: function (value) {
518
+ return value.trim() ? true : "Project name is required";
519
+ },
492
520
  }).run();
493
521
 
494
522
  if (!projectName || !projectName.trim()) {
@@ -502,31 +530,61 @@ async function init() {
502
530
 
503
531
  console.log(chalk.bold("\n" + chalk.magenta("→") + " Brand colours"));
504
532
 
505
- const primary = await askColourFromPresets("primary", COLOUR_PRESETS.primary, "#DB2777");
506
- const secondary = await askColourFromPresets("secondary", COLOUR_PRESETS.secondary, "#2563EB");
507
- const btnPrimary = await askBtnColour("btn-primary", "primary", primary, COLOUR_PRESETS.primary);
508
- const btnSecondary = await askBtnColour("btn-secondary", "secondary", secondary, COLOUR_PRESETS.secondary);
533
+ const primary = await askColourFromPresets(
534
+ "primary",
535
+ COLOUR_PRESETS.primary,
536
+ "#DB2777",
537
+ );
538
+ const secondary = await askColourFromPresets(
539
+ "secondary",
540
+ COLOUR_PRESETS.secondary,
541
+ "#2563EB",
542
+ );
543
+
544
+ console.log(
545
+ chalk.gray(
546
+ "\n Button colour tokens will use your brand colours by default:",
547
+ ),
548
+ );
549
+ console.log(chalk.gray(" - btn-primary = primary"));
550
+ console.log(chalk.gray(" - btn-secondary = secondary"));
509
551
 
510
552
  console.log(chalk.bold("\n" + chalk.magenta("→") + " Utility colours"));
511
- console.log(chalk.gray(" Defaults shown. Press enter to accept or pick an alternative.\n"));
512
-
513
- const success = await askColourFromPresets("success", COLOUR_PRESETS.success, "#017F65");
514
- const warning = await askColourFromPresets("warning", COLOUR_PRESETS.warning, "#FFC107");
515
- const error = await askColourFromPresets("error", COLOUR_PRESETS.error, "#B20000");
553
+ console.log(
554
+ chalk.gray(
555
+ " Defaults shown. Press enter to accept or pick an alternative.\n",
556
+ ),
557
+ );
558
+
559
+ const success = await askColourFromPresets(
560
+ "success",
561
+ COLOUR_PRESETS.success,
562
+ "#017F65",
563
+ );
564
+ const warning = await askColourFromPresets(
565
+ "warning",
566
+ COLOUR_PRESETS.warning,
567
+ "#FFC107",
568
+ );
569
+ const error = await askColourFromPresets(
570
+ "error",
571
+ COLOUR_PRESETS.error,
572
+ "#B20000",
573
+ );
516
574
 
517
575
  const colours = {
518
- primary: primary,
519
- secondary: secondary,
520
- "btn-primary": btnPrimary,
521
- "btn-secondary": btnSecondary,
522
- success: success,
523
- warning: warning,
524
- error: error,
576
+ primary,
577
+ secondary,
578
+ "btn-primary": primary,
579
+ "btn-secondary": secondary,
580
+ success,
581
+ warning,
582
+ error,
525
583
  neutral: "#57534E",
526
584
  };
527
585
 
528
- // Additional utility colours
529
586
  let addingMore = true;
587
+
530
588
  while (addingMore) {
531
589
  const wantsMore = await new Confirm({
532
590
  name: "addMore",
@@ -542,16 +600,24 @@ async function init() {
542
600
  const customName = await new Input({
543
601
  name: "customName",
544
602
  message: "Colour name (e.g. accent, highlight, brand-dark)",
545
- validate: function(value) {
603
+ validate: function (value) {
546
604
  const trimmed = value.trim();
605
+
547
606
  if (!trimmed) return "Name is required";
548
- if (!/^[a-z][a-z0-9-]*$/.test(trimmed)) return "Use lowercase letters, numbers, and hyphens only";
607
+ if (!/^[a-z][a-z0-9-]*$/.test(trimmed)) {
608
+ return "Use lowercase letters, numbers, and hyphens only";
609
+ }
549
610
  if (colours[trimmed]) return '"' + trimmed + '" is already defined';
611
+
550
612
  return true;
551
613
  },
552
614
  }).run();
553
615
 
554
- colours[customName.trim()] = await askHex("hex-" + customName, "Hex for " + customName, "#000000");
616
+ colours[customName.trim()] = await askHex(
617
+ "hex-" + customName,
618
+ "Hex for " + customName,
619
+ "#000000",
620
+ );
555
621
  }
556
622
 
557
623
  // =========================================================================
@@ -582,9 +648,13 @@ async function init() {
582
648
  name: "baseUnit",
583
649
  message: "Base spacing unit in px (18px = 1.125rem)",
584
650
  initial: "18",
585
- validate: function(value) {
651
+ validate: function (value) {
586
652
  const parsed = Number.parseInt(value, 10);
587
- if (Number.isNaN(parsed) || parsed <= 0) return "Must be a positive number.";
653
+
654
+ if (Number.isNaN(parsed) || parsed <= 0) {
655
+ return "Must be a positive number.";
656
+ }
657
+
588
658
  return true;
589
659
  },
590
660
  }).run();
@@ -592,16 +662,25 @@ async function init() {
592
662
  const baseUnit = Number.parseInt(baseUnitRaw, 10);
593
663
 
594
664
  // =========================================================================
595
- // PURGE
665
+ // PURGE / OUTPUT
596
666
  // =========================================================================
597
667
 
598
- console.log(chalk.bold("\n" + chalk.magenta("→") + " Purge settings"));
668
+ console.log(chalk.bold("\n" + chalk.magenta("→") + " Project files"));
599
669
 
600
- const sourceDirRaw = await new Input({
601
- name: "sourceDir",
602
- message: "Detected " + detectedProject.name + " — scan directory",
603
- initial: detectedProject.sourceDir,
604
- }).run();
670
+ console.log(
671
+ chalk.gray(
672
+ " Detected " +
673
+ detectedProject.name +
674
+ ". EmilyCSS will scan the recommended files automatically.",
675
+ ),
676
+ );
677
+
678
+ detectedProject.sourceGlobs.forEach(function (glob) {
679
+ console.log(chalk.gray(" - " + glob));
680
+ });
681
+
682
+ console.log(chalk.bold("\n" + chalk.magenta("→") + " CSS output"));
683
+ console.log(chalk.gray(" Output: " + detectedProject.outputPath));
605
684
 
606
685
  // =========================================================================
607
686
  // BUILD
@@ -609,18 +688,18 @@ async function init() {
609
688
 
610
689
  const config = createDefaultConfig({
611
690
  name: projectName.trim(),
612
- colours: colours,
613
- headingFont: headingFont,
614
- bodyFont: bodyFont,
615
- baseUnit: baseUnit,
616
- detectedProject: detectedProject,
617
- sourceDir: sourceDirRaw.trim() || detectedProject.sourceDir,
691
+ colours,
692
+ headingFont,
693
+ bodyFont,
694
+ baseUnit,
695
+ detectedProject,
618
696
  });
619
697
 
620
698
  const configPath = path.join(process.cwd(), "emily.config.json");
621
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
699
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
622
700
 
623
701
  console.log("");
702
+
624
703
  const buildSpinner = ora("Building EmilyUI CSS...").start();
625
704
 
626
705
  const build = crossSpawn("npx", ["emily-css", "build"], {
@@ -630,9 +709,12 @@ async function init() {
630
709
  });
631
710
 
632
711
  let stderr = "";
633
- build.stderr.on("data", function(data) { stderr += data.toString(); });
634
712
 
635
- build.on("close", async function(code) {
713
+ build.stderr.on("data", function (data) {
714
+ stderr += data.toString();
715
+ });
716
+
717
+ build.on("close", async function (code) {
636
718
  if (code === 0) {
637
719
  buildSpinner.succeed("EmilyUI CSS built successfully.");
638
720
 
@@ -640,22 +722,33 @@ async function init() {
640
722
 
641
723
  console.log(
642
724
  "\n" +
643
- boxen(
644
- chalk.green.bold("Setup complete") +
645
- "\n\nConfig: " + chalk.cyan("emily.config.json") +
646
- "\nOutput: " + chalk.cyan("dist/emily.min.css") +
647
- "\nProject: " + chalk.cyan(detectedProject.name) +
648
- "\nScan: " + chalk.cyan(config.purge.sourceDir) +
649
- "\n\nNext: link " + chalk.yellow("dist/emily.min.css") + " in your project." +
650
- (scriptsAdded
651
- ? "\n\nScripts added:\n" +
652
- chalk.cyan(" npm run emily:build\n") +
653
- chalk.cyan(" npm run emily:watch\n") +
654
- chalk.cyan(" npm run emily:showcase\n") +
655
- chalk.cyan(" npm run emily:help")
656
- : ""),
657
- { padding: 1, margin: 1, borderStyle: "round", borderColor: "magenta" },
658
- ),
725
+ boxen(
726
+ chalk.green.bold("Setup complete") +
727
+ "\n\nConfig: " +
728
+ chalk.cyan("emily.config.json") +
729
+ "\nOutput: " +
730
+ chalk.cyan(config.output.css) +
731
+ "\nProject: " +
732
+ chalk.cyan(detectedProject.name) +
733
+ "\nScan:\n " +
734
+ chalk.cyan(config.purge.sourceGlobs.join("\n ")) +
735
+ "\n\nNext: add this stylesheet to your project:" +
736
+ "\n" +
737
+ chalk.yellow(" " + detectedProject.linkHint) +
738
+ (scriptsAdded
739
+ ? "\n\nScripts added:\n" +
740
+ chalk.cyan(" npm run emily:build\n") +
741
+ chalk.cyan(" npm run emily:watch\n") +
742
+ chalk.cyan(" npm run emily:showcase\n") +
743
+ chalk.cyan(" npm run emily:help")
744
+ : ""),
745
+ {
746
+ padding: 1,
747
+ margin: 1,
748
+ borderStyle: "round",
749
+ borderColor: "magenta",
750
+ },
751
+ ),
659
752
  );
660
753
 
661
754
  const startWatch = await new Confirm({
@@ -665,31 +758,45 @@ async function init() {
665
758
  }).run();
666
759
 
667
760
  if (startWatch) {
668
- console.log(chalk.cyan("\nStarting watcher — press Ctrl+C to stop.\n"));
761
+ console.log(
762
+ chalk.cyan("\nStarting watcher. Press Ctrl+C to stop.\n"),
763
+ );
764
+
669
765
  const watcher = crossSpawn("npx", ["emily-css", "watch"], {
670
766
  cwd: process.cwd(),
671
767
  stdio: "inherit",
672
768
  shell: process.platform === "win32",
673
769
  });
674
- watcher.on("close", function(c) { process.exit(c || 0); });
770
+
771
+ watcher.on("close", function (c) {
772
+ process.exit(c || 0);
773
+ });
675
774
  } else {
676
- console.log(chalk.gray("\nRun the watcher any time with: npm run emily:watch\n"));
775
+ console.log(
776
+ chalk.gray(
777
+ "\nRun the watcher any time with: npm run emily:watch\n",
778
+ ),
779
+ );
677
780
  process.exit(0);
678
781
  }
679
- } else {
680
- buildSpinner.fail("Automatic build failed.");
681
- console.log("\nYour config was created, but CSS was not built.");
682
- console.log("\nRun manually:\n");
683
- console.log(chalk.cyan(" npx emily-css build"));
684
- if (stderr.trim()) {
685
- console.log(chalk.gray("\nBuild error:\n"));
686
- console.log(stderr.trim());
687
- }
688
- process.exit(1);
782
+
783
+ return;
784
+ }
785
+
786
+ buildSpinner.fail("Automatic build failed.");
787
+ console.log("\nYour config was created, but CSS was not built.");
788
+ console.log("\nRun manually:\n");
789
+ console.log(chalk.cyan(" npx emily-css build"));
790
+
791
+ if (stderr.trim()) {
792
+ console.log(chalk.gray("\nBuild error:\n"));
793
+ console.log(stderr.trim());
689
794
  }
795
+
796
+ process.exit(1);
690
797
  });
691
798
 
692
- build.on("error", function(error) {
799
+ build.on("error", function (error) {
693
800
  buildSpinner.fail("Automatic build failed.");
694
801
  console.log("\nYour config was created, but CSS was not built.");
695
802
  console.log("Reason: " + error.message);
@@ -697,12 +804,13 @@ async function init() {
697
804
  console.log(chalk.cyan(" npx emily-css build\n"));
698
805
  process.exit(1);
699
806
  });
700
-
701
807
  } catch (error) {
702
808
  console.log(chalk.red("\nSetup cancelled or failed."));
809
+
703
810
  if (error && error.message) {
704
811
  console.log(chalk.gray(error.message));
705
812
  }
813
+
706
814
  process.exit(1);
707
815
  }
708
816
  }