emily-css 1.0.21 → 1.0.22

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/CHANGELOG.md CHANGED
@@ -4,6 +4,11 @@ All notable changes to `emily-css` are documented here.
4
4
 
5
5
  ---
6
6
 
7
+ ## v1.0.22 — May 2026
8
+
9
+ **· Improve purge extraction and package robustness tests**
10
+
11
+ ---
7
12
  ## v1.0.21 — May 2026
8
13
 
9
14
  **"Include bundled showcase template**
package/bin/emilyui.js CHANGED
@@ -1,6 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ const path = require("path");
4
+
3
5
  const command = process.argv[2];
6
+ const packageJson = require(path.join(__dirname, "..", "package.json"));
4
7
 
5
8
  if (command === "init") {
6
9
  require("../src/init.js");
@@ -11,6 +14,8 @@ if (command === "init") {
11
14
  require("../src/watch.js");
12
15
  } else if (command === "showcase") {
13
16
  require("../src/showcase.js");
17
+ } else if (command === "version" || command === "--version" || command === "-v") {
18
+ console.log(packageJson.version);
14
19
  } else if (command === "help") {
15
20
  console.log(`
16
21
  emily-css — Config-driven CSS framework generator
@@ -20,6 +25,7 @@ if (command === "init") {
20
25
  emily-css build Generate production CSS to the configured output path
21
26
  emily-css watch Dev mode: watch for changes and rebuild
22
27
  emily-css showcase Launch the component showcase in your browser
28
+ emily-css version Show installed version
23
29
  emily-css help Show this help text
24
30
 
25
31
  npm scripts (added by init):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emily-css",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
4
4
  "description": "A config-driven utility CSS framework. Define your brand once, generate the CSS.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/purge.js CHANGED
@@ -57,7 +57,7 @@ function getAllFiles(dir, extensions = DEFAULT_EXTENSIONS) {
57
57
 
58
58
  function extractClassNames(content) {
59
59
  const classNames = new Set();
60
- const classRegex = /class\s*=\s*["']([^"']+)["']/g;
60
+ const classRegex = /(?:class|className)\s*=\s*["']([^"']+)["']/g;
61
61
  let match;
62
62
 
63
63
  while ((match = classRegex.exec(content)) !== null) {
@@ -76,6 +76,24 @@ function extractClassNames(content) {
76
76
  });
77
77
  }
78
78
 
79
+ const templateStringRegex = /`([^`]+)`/g;
80
+
81
+ while ((match = templateStringRegex.exec(content)) !== null) {
82
+ const possibleClasses = match[1].split(/\s+/);
83
+
84
+ possibleClasses.forEach((cls) => {
85
+ const cleaned = cls.trim();
86
+
87
+ if (
88
+ cleaned &&
89
+ /^[a-zA-Z0-9:_./-]+$/.test(cleaned) &&
90
+ /[-:]/.test(cleaned)
91
+ ) {
92
+ classNames.add(cleaned);
93
+ }
94
+ });
95
+ }
96
+
79
97
  return classNames;
80
98
  }
81
99
 
package/src/watch.js CHANGED
@@ -21,7 +21,9 @@ function readConfig() {
21
21
  const configPath = path.join(process.cwd(), "emily.config.json");
22
22
 
23
23
  if (!fs.existsSync(configPath)) {
24
- console.error('\n emily-css: No config found. Run "emily-css init" first.\n');
24
+ console.error(
25
+ '\n emily-css: No config found. Run "emily-css init" first.\n',
26
+ );
25
27
  process.exit(1);
26
28
  }
27
29
 
@@ -46,7 +48,9 @@ function shouldIgnore(filePath) {
46
48
  "coverage/",
47
49
  ".cache/",
48
50
  ".vite/",
49
- ].some((part) => normalised.includes("/" + part) || normalised.startsWith(part));
51
+ ].some(
52
+ (part) => normalised.includes("/" + part) || normalised.startsWith(part),
53
+ );
50
54
  }
51
55
 
52
56
  function runQuietly(fn) {
@@ -83,7 +87,9 @@ function getScanFiles(config) {
83
87
  ".njk",
84
88
  ".liquid",
85
89
  ".hbs",
90
+ ".js",
86
91
  ".jsx",
92
+ ".ts",
87
93
  ".tsx",
88
94
  ".vue",
89
95
  ".php",
@@ -124,7 +130,9 @@ function collectUsedClasses(config) {
124
130
 
125
131
  function getClassDiff(currentClasses) {
126
132
  const added = [...currentClasses].filter((cls) => !previousClasses.has(cls));
127
- const removed = [...previousClasses].filter((cls) => !currentClasses.has(cls));
133
+ const removed = [...previousClasses].filter(
134
+ (cls) => !currentClasses.has(cls),
135
+ );
128
136
 
129
137
  previousClasses = new Set(currentClasses);
130
138
 
@@ -141,35 +149,24 @@ function formatClassList(classes) {
141
149
  }
142
150
 
143
151
  function printSummary({ currentClasses, result, added, removed }) {
144
- const reduction = (
145
- ((result.originalSize - result.outputSize) / result.originalSize) *
146
- 100
147
- ).toFixed(1);
152
+ const reduction =
153
+ currentClasses.size === 0
154
+ ? "100.0"
155
+ : (
156
+ ((result.originalSize - result.outputSize) / result.originalSize) *
157
+ 100
158
+ ).toFixed(1);
159
+
160
+ const sizeKb =
161
+ currentClasses.size === 0 ? "0.0" : (result.outputSize / 1024).toFixed(1);
148
162
 
149
- const sizeKb = (result.outputSize / 1024).toFixed(1);
150
163
  const outputPath = result.outputPath
151
164
  ? path.relative(process.cwd(), result.outputPath)
152
165
  : "emily.min.css";
153
166
 
154
167
  const time = new Date().toLocaleTimeString();
155
168
 
156
- console.log(
157
- chalk.green("✓ " + time + " updated") +
158
- chalk.gray(
159
- " | " +
160
- currentClasses.size +
161
- " classes | " +
162
- sizeKb +
163
- " KB | " +
164
- reduction +
165
- "% reduced | " +
166
- outputPath,
167
- ),
168
- );
169
-
170
- if (!hasRunOnce) return;
171
-
172
- if (removed.length > 0) {
169
+ if (hasRunOnce && removed.length > 0) {
173
170
  console.log(
174
171
  chalk.red(
175
172
  "− removed " +
@@ -180,16 +177,27 @@ function printSummary({ currentClasses, result, added, removed }) {
180
177
  );
181
178
  }
182
179
 
183
- if (added.length > 0) {
180
+ if (hasRunOnce && added.length > 0) {
184
181
  console.log(
185
182
  chalk.green(
186
- "+ added " +
187
- added.length +
188
- " class" +
189
- (added.length === 1 ? "" : "es"),
183
+ "+ added " + added.length + " class" + (added.length === 1 ? "" : "es"),
190
184
  ) + chalk.gray(" (" + formatClassList(added) + ")"),
191
185
  );
192
186
  }
187
+
188
+ console.log(
189
+ chalk.green("✓ " + time + " updated") +
190
+ chalk.gray(
191
+ " | " +
192
+ currentClasses.size +
193
+ " classes | " +
194
+ sizeKb +
195
+ " KB | " +
196
+ reduction +
197
+ "% reduced | " +
198
+ outputPath,
199
+ ),
200
+ );
193
201
  }
194
202
 
195
203
  function runProductionUpdate(filePath) {
@@ -232,10 +240,7 @@ function runProductionUpdate(filePath) {
232
240
  }
233
241
 
234
242
  function getWatchPaths(config) {
235
- return [
236
- config.purge?.sourceDir || ".",
237
- "emily.config.json",
238
- ];
243
+ return [config.purge?.sourceDir || ".", "emily.config.json"];
239
244
  }
240
245
 
241
246
  function queueUpdate(filePath) {
@@ -247,14 +252,19 @@ function runWatch() {
247
252
  const config = readConfig();
248
253
  const watchPaths = getWatchPaths(config);
249
254
 
250
- console.log("\n👀 EmilyUI is watching...");
251
- console.log(chalk.gray(" Project: " + (config.purge?.projectType || "Unknown")));
252
- console.log(chalk.gray(" Output: " + (config.output?.css || "dist/emily.min.css")));
253
- console.log(chalk.gray(" Watching:"));
255
+ console.log("");
256
+ console.log(chalk.cyan("👀 EmilyUI is watching..."));
257
+ console.log(
258
+ chalk.gray(" Project: " + (config.purge?.projectType || "Unknown")),
259
+ );
260
+ console.log(
261
+ chalk.gray(" Output: " + (config.output?.css || "dist/emily.min.css")),
262
+ );
263
+ console.log(chalk.gray(" Watching:"));
254
264
 
255
- watchPaths.forEach((item) => {
256
- console.log(chalk.gray(" - " + item));
257
- });
265
+ watchPaths.forEach((item) => {
266
+ console.log(chalk.gray(" - " + item));
267
+ });
258
268
 
259
269
  runQuietly(() => ensureFullFramework());
260
270
  runProductionUpdate();