emily-css 1.2.2 → 1.2.4

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
@@ -1,29 +1,63 @@
1
- # Changelog
2
-
3
- All notable changes to `emily-css` are documented here.
4
-
1
+ # Changelog
2
+
3
+ All notable changes to `emily-css` are documented here.
4
+
5
5
  ---
6
6
 
7
- ## v1.2.2 — May 2026
7
+ ## v1.2.4 — May 2026
8
8
 
9
- ### Added
10
- - Added IntelliSense JSON generation via `intellisense` config output (`dist/emily.intellisense.json` by default).
11
- - Added build profiling via `emily-css build --profile` with coarse timing buckets.
12
- - Added initial accessibility warnings to `emily-css doctor` (focus removal, same token text/background, and `cursor-pointer` on non-interactive elements).
13
- - Added documentation stubs in `docs/` for installation, configuration, variants, accessibility, doctor, migrate, manifest, and IntelliSense.
9
+ **chore: release v1.2.4**
14
10
 
15
11
  ### Changed
16
- - Stabilised manifest schema metadata with explicit `schemaVersion`, package name, and package version fields.
17
- - Improved purge class extraction for complex variant patterns and safer junk filtering.
18
- - Updated README to reflect current product direction and command surface.
19
-
20
- ### Notes
21
- - EmilyCSS remains CommonJS-compatible and continues to support Node 16+.
22
- - ESM-only dependency major upgrades remain intentionally deferred for compatibility.
12
+ - chore: release v1.2.4
23
13
 
24
14
  ---
25
-
26
- ## v1.2.1 — May 2026
15
+ # Changelog
16
+
17
+ All notable changes to `emily-css` are documented here.
18
+
19
+ ---
20
+
21
+ ## v1.2.4 — May 2026
22
+
23
+ ### Changed
24
+ - Extracted shared config/path helpers (`getConfig`, `getFullCssPath`, `getManifestSettings`, etc.) into `src/config.js` to eliminate duplication between `src/index.js` and `src/doctor.js`. No behaviour change.
25
+ - Updated `purge.js` file discovery to use `fast-glob` (already a dependency) instead of manual recursive `fs.readdirSync`, and to respect `DEFAULT_PURGE_IGNORE` from `src/constants.js` rather than hardcoded ignores.
26
+ - Updated Node engine requirement to `>=22.0.0`. Node 16 and 18 are EOL.
27
+
28
+ ### Added
29
+ - `emily-css manifest` CLI command. Generates the utility/token manifest JSON to the configured output path (default: `dist/emily.manifest.json`). The manifest feature existed internally — this wires it as a standalone command.
30
+
31
+ ### Notes
32
+ - Current runtime support is Node 22+.
33
+
34
+ ---
35
+
36
+ ## v1.2.3 — May 2026
37
+
38
+ ****
39
+
40
+ ---
41
+ ## v1.2.2 — May 2026
42
+
43
+ ### Added
44
+ - Added IntelliSense JSON generation via `intellisense` config output (`dist/emily.intellisense.json` by default).
45
+ - Added build profiling via `emily-css build --profile` with coarse timing buckets.
46
+ - Added initial accessibility warnings to `emily-css doctor` (focus removal, same token text/background, and `cursor-pointer` on non-interactive elements).
47
+ - Added documentation stubs in `docs/` for installation, configuration, variants, accessibility, doctor, migrate, manifest, and IntelliSense.
48
+
49
+ ### Changed
50
+ - Stabilised manifest schema metadata with explicit `schemaVersion`, package name, and package version fields.
51
+ - Improved purge class extraction for complex variant patterns and safer junk filtering.
52
+ - Updated README to reflect current product direction and command surface.
53
+
54
+ ### Notes
55
+ - EmilyCSS remains CommonJS-compatible. Node engine requirement updated to >=22 in v1.2.4.
56
+ - ESM-only dependency major upgrades remain intentionally deferred for compatibility.
57
+
58
+ ---
59
+
60
+ ## v1.2.1 — May 2026
27
61
 
28
62
  ### Changed
29
63
  - Refactored utility generators into smaller internal modules.
package/README.md CHANGED
@@ -12,7 +12,7 @@ emilyCSS lets you define design tokens in `emily.config.json` and generate stati
12
12
  - Framework-agnostic output (`dist/emily.css` and `dist/emily.min.css`)
13
13
  - Accessibility-focused utility coverage (focus rings, visually-hidden helpers, motion-aware variants)
14
14
  - Tooling support with manifest and IntelliSense JSON generation
15
- - CommonJS package with Node 16+ compatibility
15
+ - CommonJS package with Node 22+ compatibility
16
16
 
17
17
  ## Install and basic workflow
18
18
 
@@ -95,7 +95,7 @@ These files are intended for tooling, audits, and editor integrations. A VSCode
95
95
  ## Notes on compatibility
96
96
 
97
97
  - Package format: CommonJS
98
- - Runtime support: Node 16+
98
+ - Runtime support: Node 22+
99
99
  - ESM-only major upgrades are intentionally avoided where they would break compatibility
100
100
 
101
101
  ## Documentation stubs
@@ -104,4 +104,4 @@ Starter docs are available in [`docs/`](./docs) for installation, configuration,
104
104
 
105
105
  ## License
106
106
 
107
- MIT
107
+ MIT
package/bin/emilyui.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ const fs = require("fs");
3
4
  const path = require("path");
4
5
 
5
6
  const command = process.argv[2];
@@ -15,6 +16,7 @@ const usageText = `
15
16
  emily-css doctor Scan project files for unknown EmilyCSS classes
16
17
  emily-css migrate Generate a Tailwind-to-EmilyCSS migration report
17
18
  --import-colours Detect Tailwind colour palettes and suggest importedPalettes config
19
+ emily-css manifest Generate the utility/token manifest JSON
18
20
  emily-css showcase Browse components in your browser
19
21
  emily-css help Full command reference
20
22
 
@@ -43,6 +45,19 @@ if (command === "init") {
43
45
  const importColours = process.argv.includes("--import-colours");
44
46
  const report = generateMigrationReport({ importColours });
45
47
  console.log(formatMigrationReport(report, { importColours }));
48
+ } else if (command === "manifest") {
49
+ const { getConfig, getFullCssPath, getManifestOutputPath, ensureDirectoryForFile } = require("../src/config.js");
50
+ const { ensureFullFramework } = require("../src/index.js");
51
+ const { generateManifest } = require("../src/manifest.js");
52
+ const config = getConfig();
53
+ ensureFullFramework();
54
+ const fullCssPath = getFullCssPath(config);
55
+ const css = fs.readFileSync(fullCssPath, "utf8");
56
+ const manifestData = generateManifest(css, config);
57
+ const manifestPath = getManifestOutputPath(config);
58
+ ensureDirectoryForFile(manifestPath);
59
+ fs.writeFileSync(manifestPath, JSON.stringify(manifestData, null, 2));
60
+ console.log(`✓ Generated manifest: ${manifestPath}`);
46
61
  } else if (command === "version" || command === "--version" || command === "-v") {
47
62
  console.log(packageJson.version);
48
63
  } else if (command === "help") {
@@ -57,6 +72,7 @@ if (command === "init") {
57
72
  emily-css doctor Scan project files for unknown EmilyCSS classes
58
73
  emily-css migrate Generate a Tailwind-to-EmilyCSS migration report
59
74
  --import-colours Detect Tailwind colour palettes and suggest importedPalettes config
75
+ emily-css manifest Generate the utility/token manifest JSON
60
76
  emily-css showcase Launch the component showcase in your browser
61
77
  emily-css version Show installed version
62
78
  emily-css help Show this help text
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emily-css",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
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": {
@@ -42,7 +42,7 @@
42
42
  "author": "Andy Terry",
43
43
  "license": "MIT",
44
44
  "engines": {
45
- "node": ">=16.0.0"
45
+ "node": ">=22.0.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "nodemon": "^3.1.14"
package/src/config.js ADDED
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ function getConfigPath() {
7
+ return path.join(process.cwd(), 'emily.config.json');
8
+ }
9
+
10
+ function getConfig() {
11
+ const configPath = getConfigPath();
12
+
13
+ if (!fs.existsSync(configPath)) {
14
+ console.error('\n emily-css: No config found. Run "emily-css init" first.\n');
15
+ process.exit(1);
16
+ }
17
+
18
+ return JSON.parse(fs.readFileSync(configPath, 'utf8'));
19
+ }
20
+
21
+ function getFullCssPath(config) {
22
+ return path.join(process.cwd(), config.output?.fullCss || 'dist/emily.css');
23
+ }
24
+
25
+ function getProductionCssPath(config) {
26
+ return path.join(process.cwd(), config.output?.css || 'dist/emily.min.css');
27
+ }
28
+
29
+ function getManifestSettings(config) {
30
+ const manifestConfig = config.manifest;
31
+
32
+ if (manifestConfig === true) {
33
+ return { enabled: true, output: 'dist/emily.manifest.json' };
34
+ }
35
+
36
+ if (manifestConfig && typeof manifestConfig === 'object') {
37
+ return {
38
+ enabled: manifestConfig.enabled === true,
39
+ output: manifestConfig.output || 'dist/emily.manifest.json',
40
+ };
41
+ }
42
+
43
+ return { enabled: false, output: 'dist/emily.manifest.json' };
44
+ }
45
+
46
+ function getManifestOutputPath(config) {
47
+ const manifestSettings = getManifestSettings(config);
48
+ const outputPath = manifestSettings.output || 'dist/emily.manifest.json';
49
+
50
+ return path.isAbsolute(outputPath)
51
+ ? outputPath
52
+ : path.join(process.cwd(), outputPath);
53
+ }
54
+
55
+ function getIntellisenseSettings(config) {
56
+ const intellisenseConfig = config.intellisense;
57
+
58
+ if (intellisenseConfig === true) {
59
+ return { enabled: true, output: 'dist/emily.intellisense.json' };
60
+ }
61
+
62
+ if (intellisenseConfig && typeof intellisenseConfig === 'object') {
63
+ return {
64
+ enabled: intellisenseConfig.enabled === true,
65
+ output: intellisenseConfig.output || 'dist/emily.intellisense.json',
66
+ };
67
+ }
68
+
69
+ return { enabled: false, output: 'dist/emily.intellisense.json' };
70
+ }
71
+
72
+ function getIntellisenseOutputPath(config) {
73
+ const intellisenseSettings = getIntellisenseSettings(config);
74
+ const outputPath = intellisenseSettings.output || 'dist/emily.intellisense.json';
75
+
76
+ return path.isAbsolute(outputPath)
77
+ ? outputPath
78
+ : path.join(process.cwd(), outputPath);
79
+ }
80
+
81
+ function ensureDirectoryForFile(filePath) {
82
+ const dir = path.dirname(filePath);
83
+
84
+ if (!fs.existsSync(dir)) {
85
+ fs.mkdirSync(dir, { recursive: true });
86
+ }
87
+ }
88
+
89
+ function getSourceDir(config) {
90
+ return config.purge?.sourceDir || '.';
91
+ }
92
+
93
+ module.exports = {
94
+ getConfigPath,
95
+ getConfig,
96
+ getFullCssPath,
97
+ getProductionCssPath,
98
+ getManifestSettings,
99
+ getManifestOutputPath,
100
+ getIntellisenseSettings,
101
+ getIntellisenseOutputPath,
102
+ ensureDirectoryForFile,
103
+ getSourceDir,
104
+ };
package/src/doctor.js CHANGED
@@ -1,54 +1,17 @@
1
+ 'use strict';
2
+
1
3
  const fs = require("fs");
2
4
  const path = require("path");
3
5
  const fg = require("fast-glob");
4
6
  const { extractClassNames } = require("./purge.js");
5
7
  const { ensureFullFramework, generateManifest } = require("./index.js");
6
8
  const { DEFAULT_EXTENSIONS } = require("./constants.js");
7
-
8
- function getConfigPath() {
9
- return path.join(process.cwd(), "emily.config.json");
10
- }
11
-
12
- function getConfig() {
13
- const configPath = getConfigPath();
14
-
15
- if (!fs.existsSync(configPath)) {
16
- console.error('\n emily-css: No config found. Run "emily-css init" first.\n');
17
- process.exit(1);
18
- }
19
-
20
- return JSON.parse(fs.readFileSync(configPath, "utf8"));
21
- }
22
-
23
- function getFullCssPath(config) {
24
- return path.join(process.cwd(), config.output?.fullCss || "dist/emily.css");
25
- }
26
-
27
- function getManifestSettings(config) {
28
- const manifestConfig = config.manifest;
29
-
30
- if (manifestConfig === true) {
31
- return { enabled: true, output: "dist/emily.manifest.json" };
32
- }
33
-
34
- if (manifestConfig && typeof manifestConfig === "object") {
35
- return {
36
- enabled: manifestConfig.enabled === true,
37
- output: manifestConfig.output || "dist/emily.manifest.json",
38
- };
39
- }
40
-
41
- return { enabled: false, output: "dist/emily.manifest.json" };
42
- }
43
-
44
- function getManifestOutputPath(config) {
45
- const manifestSettings = getManifestSettings(config);
46
- const outputPath = manifestSettings.output || "dist/emily.manifest.json";
47
-
48
- return path.isAbsolute(outputPath)
49
- ? outputPath
50
- : path.join(process.cwd(), outputPath);
51
- }
9
+ const {
10
+ getConfig,
11
+ getFullCssPath,
12
+ getManifestSettings,
13
+ getManifestOutputPath,
14
+ } = require("./config.js");
52
15
 
53
16
  function normaliseClassForManifest(className) {
54
17
  if (!className || typeof className !== "string") {
package/src/index.js CHANGED
@@ -1,10 +1,21 @@
1
- // new version
2
-
1
+ 'use strict';
3
2
 
4
3
  const fs = require('fs');
5
4
  const path = require('path');
6
5
  const { generateManifest } = require('./manifest');
7
6
  const { generateIntellisense } = require('./intellisense');
7
+ const {
8
+ getConfigPath,
9
+ getConfig,
10
+ getFullCssPath,
11
+ getProductionCssPath,
12
+ getManifestSettings,
13
+ getManifestOutputPath,
14
+ getIntellisenseSettings,
15
+ getIntellisenseOutputPath,
16
+ ensureDirectoryForFile,
17
+ getSourceDir,
18
+ } = require('./config');
8
19
 
9
20
 
10
21
  // ============================================================================
@@ -1455,97 +1466,6 @@ function generatePatternComponents() {
1455
1466
  // BUILD FUNCTION
1456
1467
  // ============================================================================
1457
1468
 
1458
- // ============================================================================
1459
- // BUILD FUNCTION
1460
- // ============================================================================
1461
-
1462
- function getConfigPath() {
1463
- return path.join(process.cwd(), 'emily.config.json');
1464
- }
1465
-
1466
- function getConfig() {
1467
- const configPath = getConfigPath();
1468
-
1469
- if (!fs.existsSync(configPath)) {
1470
- console.error('\n emily-css: No config found. Run "emily-css init" first.\n');
1471
- process.exit(1);
1472
- }
1473
-
1474
- return JSON.parse(fs.readFileSync(configPath, 'utf8'));
1475
- }
1476
-
1477
- function getFullCssPath(config) {
1478
- return path.join(process.cwd(), config.output?.fullCss || 'dist/emily.css');
1479
- }
1480
-
1481
- function getProductionCssPath(config) {
1482
- return path.join(process.cwd(), config.output?.css || 'dist/emily.min.css');
1483
- }
1484
-
1485
- function getManifestSettings(config) {
1486
- const manifestConfig = config.manifest;
1487
-
1488
- if (manifestConfig === true) {
1489
- return { enabled: true, output: 'dist/emily.manifest.json' };
1490
- }
1491
-
1492
- if (manifestConfig && typeof manifestConfig === 'object') {
1493
- return {
1494
- enabled: manifestConfig.enabled === true,
1495
- output: manifestConfig.output || 'dist/emily.manifest.json',
1496
- };
1497
- }
1498
-
1499
- return { enabled: false, output: 'dist/emily.manifest.json' };
1500
- }
1501
-
1502
- function getManifestOutputPath(config) {
1503
- const manifestSettings = getManifestSettings(config);
1504
- const outputPath = manifestSettings.output || 'dist/emily.manifest.json';
1505
-
1506
- return path.isAbsolute(outputPath)
1507
- ? outputPath
1508
- : path.join(process.cwd(), outputPath);
1509
- }
1510
-
1511
- function getIntellisenseSettings(config) {
1512
- const intellisenseConfig = config.intellisense;
1513
-
1514
- if (intellisenseConfig === true) {
1515
- return { enabled: true, output: 'dist/emily.intellisense.json' };
1516
- }
1517
-
1518
- if (intellisenseConfig && typeof intellisenseConfig === 'object') {
1519
- return {
1520
- enabled: intellisenseConfig.enabled === true,
1521
- output: intellisenseConfig.output || 'dist/emily.intellisense.json',
1522
- };
1523
- }
1524
-
1525
- return { enabled: false, output: 'dist/emily.intellisense.json' };
1526
- }
1527
-
1528
- function getIntellisenseOutputPath(config) {
1529
- const intellisenseSettings = getIntellisenseSettings(config);
1530
- const outputPath = intellisenseSettings.output || 'dist/emily.intellisense.json';
1531
-
1532
- return path.isAbsolute(outputPath)
1533
- ? outputPath
1534
- : path.join(process.cwd(), outputPath);
1535
- }
1536
-
1537
- function ensureDirectoryForFile(filePath) {
1538
- const dir = path.dirname(filePath);
1539
-
1540
- if (!fs.existsSync(dir)) {
1541
- fs.mkdirSync(dir, { recursive: true });
1542
- }
1543
- }
1544
-
1545
- function getSourceDir(config) {
1546
- return config.purge?.sourceDir || '.';
1547
- }
1548
-
1549
1469
  function buildFullFramework() {
1550
1470
  const config = getConfig();
1551
1471
 
package/src/purge.js CHANGED
@@ -1,37 +1,27 @@
1
- // new version
1
+ 'use strict';
2
2
 
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
- const { DEFAULT_EXTENSIONS } = require("./constants.js");
5
+ const fg = require("fast-glob");
6
+ const { DEFAULT_EXTENSIONS, DEFAULT_PURGE_IGNORE } = require("./constants.js");
6
7
 
7
8
  function getAllFiles(dir, extensions = DEFAULT_EXTENSIONS) {
8
- let files = [];
9
+ const absoluteDir = path.isAbsolute(dir) ? dir : path.resolve(dir);
10
+ const patterns = extensions.map((ext) => `**/*${ext}`);
11
+ const ignore = DEFAULT_PURGE_IGNORE.map((d) => `**/${d}/**`);
9
12
 
10
13
  try {
11
- const entries = fs.readdirSync(dir, { withFileTypes: true });
12
-
13
- for (const entry of entries) {
14
- const fullPath = path.join(dir, entry.name);
15
-
16
- if (
17
- entry.name.startsWith(".") ||
18
- entry.name === "node_modules" ||
19
- entry.name === "dist"
20
- ) {
21
- continue;
22
- }
23
-
24
- if (entry.isDirectory()) {
25
- files = files.concat(getAllFiles(fullPath, extensions));
26
- } else if (extensions.some((ext) => entry.name.endsWith(ext))) {
27
- files.push(fullPath);
28
- }
29
- }
14
+ return fg.sync(patterns, {
15
+ cwd: absoluteDir,
16
+ ignore,
17
+ onlyFiles: true,
18
+ unique: true,
19
+ absolute: true,
20
+ });
30
21
  } catch (err) {
31
- console.warn(`Warning: Could not read directory ${dir}: ${err.message}`);
22
+ console.warn(`Warning: Could not scan directory ${absoluteDir}: ${err.message}`);
23
+ return [];
32
24
  }
33
-
34
- return files;
35
25
  }
36
26
 
37
27
  function extractClassNames(content) {
@@ -186,8 +176,6 @@ function purgeBlock(block, usedClasses) {
186
176
 
187
177
  function getFilesForPurge(scanDir, config, extensions) {
188
178
  if (config?.purge?.sourceGlobs && config.purge.sourceGlobs.length) {
189
- const fg = require("fast-glob");
190
-
191
179
  console.log(`\n🔍 Scanning using sourceGlobs`);
192
180
  config.purge.sourceGlobs.forEach((glob) => console.log(` - ${glob}`));
193
181
  console.log(` Extensions: ${extensions.join(", ")}`);