xatriumcss 1.0.27 → 1.0.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xatriumcss",
3
- "version": "1.0.27",
3
+ "version": "1.0.28",
4
4
  "description": "Ultra-fast utility-first CSS framework",
5
5
  "main": "./src/index.js",
6
6
  "files": [
package/src/cli.js CHANGED
@@ -42,7 +42,7 @@ const config = {
42
42
  config.input = path.resolve(projectRoot, config.input);
43
43
  config.output = path.resolve(projectRoot, config.output);
44
44
 
45
- function build() {
45
+ async function build() {
46
46
  const startTime = process.hrtime.bigint();
47
47
 
48
48
  console.log('🔍 Checking for @import "xatriumcss"...');
@@ -64,7 +64,7 @@ function build() {
64
64
  return;
65
65
  }
66
66
 
67
- runParser(config);
67
+ await runParser(config);
68
68
 
69
69
  const endTime = process.hrtime.bigint();
70
70
  const duration = endTime - startTime;
@@ -82,10 +82,10 @@ function formatTime(nanoseconds) {
82
82
  // Initial build
83
83
  (async () => {
84
84
  try {
85
- build();
85
+ await build();
86
86
  } catch (error) {
87
- console.error('❌ Build failed:', error.message);
88
87
  console.error('Stack:', error.stack);
88
+ console.error('❌ Build failed:', error.message);
89
89
  process.exit(1);
90
90
  }
91
91
 
@@ -96,25 +96,21 @@ function formatTime(nanoseconds) {
96
96
 
97
97
  const changedFiles = new Set();
98
98
  let rebuildTimer = null;
99
- let isBuilding = false; // ← ADD THIS FLAG
100
99
 
101
100
  function scheduleRebuild() {
102
- if (rebuildTimer || isBuilding) return; // ← Check if building
101
+ if (rebuildTimer) return;
103
102
 
104
- rebuildTimer = setTimeout(() => {
103
+ rebuildTimer = setTimeout(async () => {
105
104
  const files = Array.from(changedFiles);
106
105
  changedFiles.clear();
107
106
  rebuildTimer = null;
108
107
 
109
- isBuilding = true; // ← Set flag
110
108
  try {
111
109
  build();
112
110
  } catch (error) {
113
111
  console.error('❌ Build error:', error.message);
114
- } finally {
115
- isBuilding = false; // ← Clear flag
116
112
  }
117
- }, 100); // ← Increase to 100ms
113
+ }, 10);
118
114
  }
119
115
 
120
116
  // Get directories to watch
@@ -47,25 +47,47 @@ export async function collectClasses(contentPaths) {
47
47
 
48
48
  const allClasses = await extractClassesFromFiles(files);
49
49
 
50
+ // Ensure allClasses is an array
51
+ if (!Array.isArray(allClasses)) {
52
+ console.warn('⚠️ extractClassesFromFiles did not return an array, got:', typeof allClasses);
53
+ console.warn('Value:', allClasses);
54
+ return [];
55
+ }
56
+
50
57
  console.log(`✅ Extracted ${allClasses.length} classes`);
51
58
  return allClasses;
52
59
  } catch (error) {
53
60
  console.error('❌ Error during class collection:', error.message);
61
+ console.error('Stack:', error.stack);
54
62
  return [];
55
63
  }
56
64
  }
57
65
 
58
66
  async function scanFiles(patterns, ignorePaths = []) {
59
67
  const files = new Set();
60
- const ignoreSet = new Set(ignorePaths.map(p => p.toLowerCase()));
68
+ const ignoreSet = new Set((ignorePaths || []).map(p => p.toLowerCase()));
61
69
 
62
70
  for (const pattern of patterns) {
63
71
  if (pattern.includes('*') || pattern.includes('?')) {
64
- const dir = path.dirname(pattern);
65
- const glob = path.basename(pattern);
66
-
72
+ // Normalize path separators to forward slashes for consistent splitting
73
+ const normalizedPattern = pattern.replace(/\\/g, '/');
74
+ const parts = normalizedPattern.split('/');
75
+ let baseDir = '.';
76
+ let globPattern = pattern;
77
+
78
+ // Find the first non-glob part to determine base directory
79
+ for (let i = 0; i < parts.length; i++) {
80
+ if (parts[i].includes('*') || parts[i].includes('?')) {
81
+ baseDir = parts.slice(0, i).join('/') || '.';
82
+ // Convert baseDir back to system-specific path
83
+ baseDir = path.resolve(baseDir);
84
+ globPattern = parts.slice(i).join('/');
85
+ break;
86
+ }
87
+ }
88
+
67
89
  try {
68
- const matched = await globWalk(dir, glob);
90
+ const matched = await globWalk(baseDir, globPattern);
69
91
  matched.forEach(f => {
70
92
  const lowerF = f.toLowerCase();
71
93
  if (!ignoreSet.has(lowerF)) {
@@ -88,9 +110,16 @@ async function scanFiles(patterns, ignorePaths = []) {
88
110
  return Array.from(files);
89
111
  }
90
112
 
91
- async function globWalk(dir, pattern) {
113
+ async function globWalk(baseDir, pattern) {
92
114
  const files = [];
93
- const regexPattern = globToRegex(pattern);
115
+
116
+ // Normalize the pattern to use forward slashes
117
+ const normalizedPattern = pattern.replace(/\\/g, '/');
118
+ const parts = normalizedPattern.split('/');
119
+
120
+ // Last part is the file pattern (e.g., "*.html")
121
+ const filePattern = parts[parts.length - 1];
122
+ const regexPattern = globToRegex(filePattern);
94
123
 
95
124
  function walk(currentPath) {
96
125
  try {
@@ -99,9 +128,13 @@ async function globWalk(dir, pattern) {
99
128
  for (const entry of entries) {
100
129
  const fullPath = path.join(currentPath, entry.name);
101
130
 
102
- if (entry.isFile() && regexPattern.test(entry.name)) {
103
- files.push(fullPath);
131
+ if (entry.isFile()) {
132
+ // Check if filename matches the pattern
133
+ if (regexPattern.test(entry.name)) {
134
+ files.push(fullPath);
135
+ }
104
136
  } else if (entry.isDirectory() && !entry.name.startsWith('.')) {
137
+ // Recursively walk all subdirectories
105
138
  walk(fullPath);
106
139
  }
107
140
  }
@@ -110,8 +143,8 @@ async function globWalk(dir, pattern) {
110
143
  }
111
144
  }
112
145
 
113
- if (fs.existsSync(dir)) {
114
- walk(dir);
146
+ if (fs.existsSync(baseDir)) {
147
+ walk(baseDir);
115
148
  }
116
149
 
117
150
  return files;
@@ -234,6 +267,12 @@ function smartSplit(str, delimiter = ' ') {
234
267
  }
235
268
 
236
269
  function sortMotionClasses(classes) {
270
+ // Ensure input is an array
271
+ if (!Array.isArray(classes)) {
272
+ console.warn('⚠️ sortMotionClasses received non-array input:', typeof classes);
273
+ return [];
274
+ }
275
+
237
276
  const motionRegex = /^(.*?)motion-\[([^\]]+)\]:/;
238
277
  const motionByName = {};
239
278
  const nonMotionClasses = [];
@@ -264,5 +303,13 @@ function sortMotionClasses(classes) {
264
303
  sortedMotion.push(...group.map(item => item.cls));
265
304
  });
266
305
 
267
- return [...nonMotionClasses, ...sortedMotion];
306
+ // Ensure we always return an array
307
+ const result = [...nonMotionClasses, ...sortedMotion];
308
+
309
+ if (!Array.isArray(result)) {
310
+ console.error('❌ sortMotionClasses failed to return array');
311
+ return [];
312
+ }
313
+
314
+ return result;
268
315
  }
package/src/parser.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import { glob } from 'glob';
3
- import { collectClasses } from './src/collectClasses.js';
3
+ import { collectClasses } from './collectClasses.js';
4
4
 
5
- // --- 1. Fill this array with all your CSS properties ---
6
5
  const allCSSProperties = [
7
6
  // Display & Visibility
8
7
  "display",
@@ -11667,7 +11666,7 @@ function _parseClassInternal(cls, isFromGrouped = false, needed, isGlobal) {
11667
11666
  }
11668
11667
  if (i < cls.length && cls[i] === closeBracket) i++; // skip ) or ]
11669
11668
  if (i < cls.length && (cls[i] === '-' || cls[i] === ':')) i++; // skip dash/colon before pct
11670
-
11669
+
11671
11670
  } else if (/\d/.test(nextChar)) {
11672
11671
  // Could be <num>-<pct> OR just malformed
11673
11672
  // Look ahead for dash
@@ -15071,7 +15070,7 @@ function _parseClassInternal(cls, isFromGrouped = false, needed, isGlobal) {
15071
15070
  ];
15072
15071
  }
15073
15072
 
15074
- return buildParsed(prop,value)
15073
+ return buildParsed(prop, value)
15075
15074
  }
15076
15075
  }
15077
15076
 
@@ -24266,14 +24265,14 @@ function expandBracePattern(pattern) {
24266
24265
  function expandRangePattern(pattern) {
24267
24266
  const rangeRegex = /^(-?\d+)\.\.(-?\d+)(?:\.\.(-?\d+))?$/;
24268
24267
  const P = [];
24269
-
24268
+
24270
24269
  function splitByDelimiter(str, delimiter) {
24271
24270
  let depth = 0,
24272
24271
  parts = [],
24273
24272
  startIndex = 0,
24274
24273
  length = str.length,
24275
24274
  delimiterCode = delimiter.charCodeAt(0);
24276
-
24275
+
24277
24276
  for (let i = 0; i < length; i++) {
24278
24277
  let charCode = str.charCodeAt(i);
24279
24278
  if (0 !== depth || charCode !== delimiterCode)
@@ -24308,16 +24307,16 @@ function expandRangePattern(pattern) {
24308
24307
  }
24309
24308
  return parts.push(str.slice(startIndex)), parts;
24310
24309
  }
24311
-
24310
+
24312
24311
  let openBraceIndex = pattern.indexOf("{");
24313
24312
  if (openBraceIndex === -1) return [pattern];
24314
-
24313
+
24315
24314
  let results = [],
24316
24315
  prefix = pattern.slice(0, openBraceIndex),
24317
24316
  remaining = pattern.slice(openBraceIndex),
24318
24317
  braceDepth = 0,
24319
24318
  closeBraceIndex = remaining.lastIndexOf("}");
24320
-
24319
+
24321
24320
  for (let i = 0; i < remaining.length; i++) {
24322
24321
  let char = remaining[i];
24323
24322
  if ("{" === char) braceDepth++;
@@ -24326,13 +24325,13 @@ function expandRangePattern(pattern) {
24326
24325
  break;
24327
24326
  }
24328
24327
  }
24329
-
24328
+
24330
24329
  if (-1 === closeBraceIndex) throw new Error(`The pattern \`${pattern}\` is not balanced.`);
24331
-
24330
+
24332
24331
  let expandedItems,
24333
24332
  braceContent = remaining.slice(1, closeBraceIndex),
24334
24333
  suffix = remaining.slice(closeBraceIndex + 1);
24335
-
24334
+
24336
24335
  (expandedItems = rangeRegex.test(braceContent)
24337
24336
  ? (function (rangeStr) {
24338
24337
  let match = rangeStr.match(rangeRegex);
@@ -24352,7 +24351,7 @@ function expandRangePattern(pattern) {
24352
24351
  })(braceContent)
24353
24352
  : splitByDelimiter(braceContent, ",")),
24354
24353
  (expandedItems = expandedItems.flatMap((item) => expandRangePattern(item)));
24355
-
24354
+
24356
24355
  let expandedSuffixes = expandRangePattern(suffix);
24357
24356
  for (let suffixPart of expandedSuffixes) for (let item of expandedItems) results.push(prefix + item + suffixPart);
24358
24357
  return results;
@@ -24468,35 +24467,31 @@ function extractLayersFromCSS(css) {
24468
24467
  }
24469
24468
 
24470
24469
  function generateCSSString(classes, generateWithoutSelector = false, isFirstRun = false) {
24471
- // Expand xatriumSourceInlines
24472
- const expandedInlineClasses = [];
24473
- const expandedNotInlineClasses = [];
24474
-
24475
- xatriumSourceInlines.inline.forEach(pattern => {
24476
- const expanded = expandBracePattern(pattern);
24477
- expandedInlineClasses.push(...expanded);
24478
- });
24470
+ // Cache expanded patterns to avoid re-expanding every run
24471
+ if (!global._expandedInlineCache) {
24472
+ global._expandedInlineCache = {
24473
+ inline: xatriumSourceInlines.inline.flatMap(expandBracePattern),
24474
+ notInline: xatriumSourceInlines.notInline.flatMap(expandBracePattern)
24475
+ };
24476
+ }
24477
+ const expandedInlineClasses = global._expandedInlineCache.inline;
24478
+ const expandedNotInlineClasses = global._expandedInlineCache.notInline;
24479
24479
 
24480
- xatriumSourceInlines.notInline.forEach(pattern => {
24481
- const expanded = expandBracePattern(pattern);
24482
- expandedNotInlineClasses.push(...expanded);
24483
- });
24484
-
24485
- classes = Array.from(new Set(classes));
24480
+ const notInlineSet = new Set(expandedNotInlineClasses);
24481
+ const classesSet = new Set(classes);
24486
24482
 
24487
24483
  const classesToParse = isFirstRun
24488
- ? Array.from(new Set(classes)).filter(cls => {
24489
- if (expandedNotInlineClasses.includes(cls)) return false;
24484
+ ? Array.from(classesSet).filter(cls => {
24485
+ if (notInlineSet.has(cls)) return false;
24490
24486
  // Check if ...allVariants:cls exists in notInline
24491
24487
  const baseClass = cls.includes(':') ? cls.split(':').pop() : cls;
24492
- if (expandedNotInlineClasses.includes(`...allVariants:${baseClass}`)) return false;
24488
+ if (notInlineSet.has(`...allVariants:${baseClass}`)) return false;
24493
24489
  return true;
24494
24490
  })
24495
- : Array.from(new Set(classes)).filter(cls => {
24496
- if (previouslyParsedClasses.includes(cls) || expandedNotInlineClasses.includes(cls)) return false;
24497
- // Check if ...allVariants:cls exists in notInline
24491
+ : Array.from(classesSet).filter(cls => {
24492
+ if (previouslyParsedClasses.includes(cls) || notInlineSet.has(cls)) return false;
24498
24493
  const baseClass = cls.includes(':') ? cls.split(':').pop() : cls;
24499
- if (expandedNotInlineClasses.includes(`...allVariants:${baseClass}`)) return false;
24494
+ if (notInlineSet.has(`...allVariants:${baseClass}`)) return false;
24500
24495
  return true;
24501
24496
  });
24502
24497
  // Update tracker
@@ -24537,6 +24532,10 @@ function generateCSSString(classes, generateWithoutSelector = false, isFirstRun
24537
24532
  previouslyParsedClasses.push(...inlineToAdd);
24538
24533
  }
24539
24534
 
24535
+ // Check if it's a spawn/scroll SHORTHAND (with from/to/back/half/[])
24536
+ const spawnShorthandRegex = /^(.*?:)?spawn-(from|to|back|half|\[[^\]]+\])(\/(?:from|to|back|half|\[[^\]]+\]))*:/;
24537
+ const scrollShorthandRegex = /^(.*?:)?scroll-(from|to|back|half|\[[^\]]+\])(\/(?:from|to|back|half|\[[^\]]+\]))*:/;
24538
+
24540
24539
  function mergeNestedStructures(bodies) {
24541
24540
  // Parse each body into a tree structure
24542
24541
  const parseBody = (body) => {
@@ -24688,10 +24687,6 @@ function generateCSSString(classes, generateWithoutSelector = false, isFirstRun
24688
24687
  const firstActual = firstSplit[0];
24689
24688
  const original = firstSplit[1] || '';
24690
24689
 
24691
- // Check if it's a spawn/scroll SHORTHAND (with from/to/back/half/[])
24692
- const spawnShorthandRegex = /^(.*?:)?spawn-(from|to|back|half|\[[^\]]+\])(\/(?:from|to|back|half|\[[^\]]+\]))*:/;
24693
- const scrollShorthandRegex = /^(.*?:)?scroll-(from|to|back|half|\[[^\]]+\])(\/(?:from|to|back|half|\[[^\]]+\]))*:/;
24694
-
24695
24690
  const isSpawnShorthand = checkIfOutside(firstActual, "spawn-") && spawnShorthandRegex.test(firstActual);
24696
24691
  const isScrollShorthand = checkIfOutside(firstActual, "scroll-") && scrollShorthandRegex.test(firstActual);
24697
24692
 
@@ -25688,7 +25683,7 @@ function formatCSS(raw) {
25688
25683
  .trim();
25689
25684
  }
25690
25685
 
25691
- export function runParser(config) {
25686
+ export async function runParser(config) {
25692
25687
  // Reset source config for each run
25693
25688
  global.xatriumSourceConfig = {
25694
25689
  basePath: null,
@@ -25699,10 +25694,32 @@ export function runParser(config) {
25699
25694
  parseXatriumCSSConfig(config.input || './src/input.css');
25700
25695
  useRangeSyntax = xatriumConfig.settings?.query !== "min-max";
25701
25696
 
25702
- const classes = collectClasses(config.content);
25703
25697
 
25704
- const result = generateCSSString(classes, false, isFirstRun);
25705
- // Skip if no changes in incremental mode
25698
+ // Ensure config.content is an array
25699
+ let contentPatterns = config.content;
25700
+ if (!Array.isArray(contentPatterns)) {
25701
+ if (typeof contentPatterns === 'string') {
25702
+ contentPatterns = [contentPatterns];
25703
+ } else if (contentPatterns && typeof contentPatterns === 'object') {
25704
+ contentPatterns = Object.values(contentPatterns);
25705
+ } else {
25706
+ contentPatterns = [];
25707
+ }
25708
+ }
25709
+
25710
+ console.log('📋 Content patterns:', contentPatterns);
25711
+
25712
+ let classes = await collectClasses(contentPatterns);
25713
+
25714
+ // Ensure classes is an array
25715
+ if (!Array.isArray(classes)) {
25716
+ console.warn('⚠️ collectClasses returned non-array:', typeof classes);
25717
+ classes = [];
25718
+ }
25719
+
25720
+ console.log('📊 Classes found:', classes.length);
25721
+
25722
+ const result = generateCSSString(classes, false, isFirstRun) // Skip if no changes in incremental mode
25706
25723
  if (result.type === 'incremental' && result.layers.length === 0) {
25707
25724
  return;
25708
25725
  }
@@ -25713,6 +25730,7 @@ export function runParser(config) {
25713
25730
  if (!fs.existsSync(outputDir)) {
25714
25731
  fs.mkdirSync(outputDir, { recursive: true });
25715
25732
  }
25733
+ console.log("classes",classes)
25716
25734
 
25717
25735
  if (result.type === 'first') {
25718
25736
  const finalCSS = removeNewlines(result.css);
@@ -25725,15 +25743,17 @@ export function runParser(config) {
25725
25743
 
25726
25744
  // If CSS is empty or missing critical structure, force full rebuild
25727
25745
  if (!currentCSS || !currentCSS.includes('@layer base') || !currentCSS.includes('@layer utilities')) {
25728
- // Force full rebuild
25729
25746
  isFirstRun = true;
25730
25747
  previouslyParsedClasses = [];
25731
25748
  previouslyGeneratedProps.clear();
25732
- const fullResult = generateCSSString(collectClasses(config.content), false, isFirstRun);
25733
- const finalCSS = removeNewlines(fullResult.css); // ← Use fullResult, not result
25749
+
25750
+ const rebuiltClasses = await collectClasses(config.content);
25751
+ const fullResult = generateCSSString(rebuiltClasses, false, isFirstRun);
25752
+
25753
+ const finalCSS = removeNewlines(fullResult.css);
25734
25754
  fs.writeFileSync(outputPath, finalCSS, 'utf8');
25735
- isFirstRun = false; // ← Reset the flag after rebuild
25736
- return finalCSS; // ← Return the CSS instead of undefined
25755
+ isFirstRun = false;
25756
+ return finalCSS;
25737
25757
  }
25738
25758
 
25739
25759
  result.layers.forEach(layer => {
@@ -25885,7 +25905,7 @@ export function runParser(config) {
25885
25905
  });
25886
25906
 
25887
25907
  fs.writeFileSync(outputPath, removeNewlines(currentCSS), 'utf8');
25888
- return removeNewlines(currentCSS); // ← ADD THIS
25908
+ return removeNewlines(currentCSS);
25889
25909
  }
25890
25910
  }
25891
25911
 
@@ -26608,9 +26628,9 @@ export function hasXatriumImport(inputCssPath) {
26608
26628
  }
26609
26629
 
26610
26630
  const content = fs.readFileSync(inputCssPath, 'utf8');
26611
-
26631
+
26612
26632
  // Match any @import "xatriumcss" with or without source()
26613
26633
  const importRegex = /@import\s+['"]xatriumcss['"]/gi;
26614
-
26634
+
26615
26635
  return importRegex.test(content);
26616
26636
  }