xatriumcss 1.0.3 → 1.0.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/package.json +1 -1
- package/src/cli.js +1 -1
- package/src/collectClasses.js +73 -13
- package/src/parser.js +2 -211
- package/xatriumcss-oxide.win32-x64-msvc.node +0 -0
- package/xatriumcss.win32-x64-msvc.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
package/src/collectClasses.js
CHANGED
|
@@ -3,9 +3,11 @@ const { glob } = require('glob');
|
|
|
3
3
|
|
|
4
4
|
let nativeScanner;
|
|
5
5
|
try {
|
|
6
|
-
nativeScanner = require('../
|
|
6
|
+
nativeScanner = require('../index');
|
|
7
|
+
console.log("using native scanner")
|
|
7
8
|
} catch (e) {
|
|
8
|
-
console.
|
|
9
|
+
console.log("using fallback scanner")
|
|
10
|
+
console.log("ERROR:", e.message);
|
|
9
11
|
nativeScanner = null;
|
|
10
12
|
}
|
|
11
13
|
|
|
@@ -98,22 +100,68 @@ function collectClasses(contentPaths) {
|
|
|
98
100
|
// Use native scanner if available
|
|
99
101
|
if (nativeScanner) {
|
|
100
102
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// Add patterns
|
|
103
|
+
// Build paths array
|
|
104
104
|
let pathsArray = sourceConfig.disableAuto
|
|
105
105
|
? sourceConfig.explicitPaths
|
|
106
106
|
: [...(Array.isArray(contentPaths) ? contentPaths : [contentPaths]), ...sourceConfig.explicitPaths];
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
// Filter out any null/undefined values
|
|
109
|
+
pathsArray = pathsArray.filter(p => p != null);
|
|
110
|
+
|
|
111
|
+
if (pathsArray.length === 0) {
|
|
112
|
+
console.warn('⚠️ No valid patterns to scan, falling back to JS scanner');
|
|
113
|
+
throw new Error('No patterns provided');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Convert patterns to SourceEntry format
|
|
117
|
+
const sources = [];
|
|
118
|
+
|
|
119
|
+
// Add positive patterns
|
|
120
|
+
pathsArray.forEach(pattern => {
|
|
121
|
+
sources.push({
|
|
122
|
+
base: process.cwd(),
|
|
123
|
+
pattern: pattern,
|
|
124
|
+
negated: false
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Add negative patterns (ignore paths)
|
|
129
|
+
sourceConfig.ignorePaths.forEach(pattern => {
|
|
130
|
+
sources.push({
|
|
131
|
+
base: process.cwd(),
|
|
132
|
+
pattern: pattern,
|
|
133
|
+
negated: true
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
console.log('🚀 Using native scanner (Rust) for file discovery');
|
|
138
|
+
console.log('📋 Patterns:', pathsArray);
|
|
139
|
+
|
|
140
|
+
// Create scanner with options
|
|
141
|
+
let scanner;
|
|
142
|
+
try {
|
|
143
|
+
scanner = new nativeScanner.Scanner({ sources });
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.warn('⚠️ Native scanner failed, falling back to JS:', error.message);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Get the files that were matched by the scanner
|
|
149
|
+
const files = scanner.files;
|
|
150
|
+
|
|
151
|
+
if (!files || files.length === 0) {
|
|
152
|
+
console.warn('⚠️ Native scanner found no files');
|
|
153
|
+
throw new Error('No files found');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
console.log(`📄 Native scanner found ${files.length} files`);
|
|
110
157
|
|
|
111
|
-
|
|
112
|
-
const
|
|
158
|
+
// Read files and extract quoted strings manually to preserve grouping
|
|
159
|
+
const quotedStrings = scanner.scan(); // Rust does EVERYTHING!
|
|
113
160
|
|
|
114
|
-
|
|
161
|
+
console.log(`✅ Extracted ${quotedStrings.length} quoted strings from files`);
|
|
162
|
+
return processClasses(quotedStrings);
|
|
115
163
|
} catch (error) {
|
|
116
|
-
console.warn('⚠️ Native scanner failed, falling back:', error.message);
|
|
164
|
+
console.warn('⚠️ Native scanner failed, falling back to JS:', error.message);
|
|
117
165
|
}
|
|
118
166
|
}
|
|
119
167
|
|
|
@@ -122,9 +170,21 @@ function collectClasses(contentPaths) {
|
|
|
122
170
|
}
|
|
123
171
|
|
|
124
172
|
function processClasses(rawClasses) {
|
|
173
|
+
// Additional safety check
|
|
174
|
+
if (!rawClasses || !Array.isArray(rawClasses)) {
|
|
175
|
+
console.warn('⚠️ processClasses received invalid input:', typeof rawClasses);
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
|
|
125
179
|
const allClasses = new Set();
|
|
126
180
|
|
|
127
181
|
rawClasses.forEach(part => {
|
|
182
|
+
// Ensure part is a string
|
|
183
|
+
if (typeof part !== 'string') {
|
|
184
|
+
console.warn('⚠️ Skipping non-string class:', typeof part, part);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
128
188
|
let cls = part.trim();
|
|
129
189
|
if (!cls) return;
|
|
130
190
|
|
|
@@ -330,8 +390,8 @@ function collectClassesJS(contentPaths) {
|
|
|
330
390
|
files.forEach(filePath => {
|
|
331
391
|
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
332
392
|
|
|
333
|
-
// Grab only strings inside single
|
|
334
|
-
const parts = Array.from(fileContent.matchAll(/(['"])(.*?)\1/
|
|
393
|
+
// Grab only strings inside single quotes, double quotes, or backticks
|
|
394
|
+
const parts = Array.from(fileContent.matchAll(/(['"`])(.*?)\1/gs), m => m[2]);
|
|
335
395
|
|
|
336
396
|
parts.forEach(part => {
|
|
337
397
|
let cls = part.trim();
|
package/src/parser.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const { glob } = require('glob');
|
|
3
|
+
const collectClasses = require('./collectClasses.js');
|
|
3
4
|
|
|
4
5
|
// --- 1. Fill this array with all your CSS properties ---
|
|
5
6
|
const allCSSProperties = [
|
|
@@ -22876,216 +22877,6 @@ function parseXatriumCSSConfig(inputCssPath) {
|
|
|
22876
22877
|
xatriumSourceInlines.notInline = Array.from(new Set(xatriumSourceInlines.notInline));
|
|
22877
22878
|
}
|
|
22878
22879
|
|
|
22879
|
-
function collectClasses(contentPaths) {
|
|
22880
|
-
const allClasses = new Set();
|
|
22881
|
-
|
|
22882
|
-
// Get source configuration
|
|
22883
|
-
const sourceConfig = global.xatriumSourceConfig || {
|
|
22884
|
-
basePath: null,
|
|
22885
|
-
disableAuto: false,
|
|
22886
|
-
explicitPaths: [],
|
|
22887
|
-
ignorePaths: []
|
|
22888
|
-
};
|
|
22889
|
-
|
|
22890
|
-
let pathsArray = [];
|
|
22891
|
-
|
|
22892
|
-
// If source(none) is set, only use explicit paths
|
|
22893
|
-
if (sourceConfig.disableAuto) {
|
|
22894
|
-
pathsArray = sourceConfig.explicitPaths;
|
|
22895
|
-
console.log('🔒 Auto-detection disabled - using explicit paths only:', pathsArray);
|
|
22896
|
-
} else {
|
|
22897
|
-
// Use provided contentPaths or defaults
|
|
22898
|
-
pathsArray = Array.isArray(contentPaths) ? contentPaths : (contentPaths ? [contentPaths] : []);
|
|
22899
|
-
|
|
22900
|
-
// Add explicit paths from @source directives
|
|
22901
|
-
if (sourceConfig.explicitPaths.length > 0) {
|
|
22902
|
-
pathsArray = [...pathsArray, ...sourceConfig.explicitPaths];
|
|
22903
|
-
console.log('➕ Added explicit paths:', sourceConfig.explicitPaths);
|
|
22904
|
-
}
|
|
22905
|
-
}
|
|
22906
|
-
|
|
22907
|
-
// Apply base path if set
|
|
22908
|
-
if (sourceConfig.basePath) {
|
|
22909
|
-
const path = require('path');
|
|
22910
|
-
pathsArray = pathsArray.map(p => {
|
|
22911
|
-
const resolved = path.resolve(path.dirname(process.cwd()), sourceConfig.basePath, p);
|
|
22912
|
-
return resolved;
|
|
22913
|
-
});
|
|
22914
|
-
console.log('📂 Applied base path:', sourceConfig.basePath);
|
|
22915
|
-
}
|
|
22916
|
-
|
|
22917
|
-
console.log('🔍 Scanning paths:', pathsArray);
|
|
22918
|
-
|
|
22919
|
-
// Scan all files matching the patterns
|
|
22920
|
-
let files = [];
|
|
22921
|
-
pathsArray.forEach(pattern => {
|
|
22922
|
-
try {
|
|
22923
|
-
const matches = glob.sync(pattern, {
|
|
22924
|
-
ignore: sourceConfig.ignorePaths.length > 0 ? sourceConfig.ignorePaths : undefined
|
|
22925
|
-
});
|
|
22926
|
-
files.push(...matches);
|
|
22927
|
-
|
|
22928
|
-
if (sourceConfig.ignorePaths.length > 0) {
|
|
22929
|
-
console.log(`🚫 Ignoring paths:`, sourceConfig.ignorePaths);
|
|
22930
|
-
}
|
|
22931
|
-
} catch (err) {
|
|
22932
|
-
console.error(`❌ Error scanning pattern ${pattern}:`, err.message);
|
|
22933
|
-
}
|
|
22934
|
-
});
|
|
22935
|
-
|
|
22936
|
-
console.log(`📄 Found ${files.length} files to scan`);
|
|
22937
|
-
|
|
22938
|
-
if (files.length === 0) {
|
|
22939
|
-
return [];
|
|
22940
|
-
}
|
|
22941
|
-
|
|
22942
|
-
files.forEach(filePath => {
|
|
22943
|
-
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
22944
|
-
|
|
22945
|
-
// Grab only strings inside single or double quotes
|
|
22946
|
-
const parts = Array.from(fileContent.matchAll(/(['"])(.*?)\1/g), m => m[2]);
|
|
22947
|
-
|
|
22948
|
-
parts.forEach(part => {
|
|
22949
|
-
let cls = part.trim();
|
|
22950
|
-
if (!cls) return;
|
|
22951
|
-
|
|
22952
|
-
// Normalize whitespace to single spaces, but preserve inside ( [ { " '
|
|
22953
|
-
let normalizedCls = "";
|
|
22954
|
-
let parenDepth = 0;
|
|
22955
|
-
let bracketDepth = 0;
|
|
22956
|
-
let braceDepth = 0;
|
|
22957
|
-
let inSingleQuote = false;
|
|
22958
|
-
let inDoubleQuote = false;
|
|
22959
|
-
|
|
22960
|
-
for (let i = 0; i < cls.length; i++) {
|
|
22961
|
-
const char = cls[i];
|
|
22962
|
-
|
|
22963
|
-
// Track quote state
|
|
22964
|
-
if (char === "'" && !inDoubleQuote) inSingleQuote = !inSingleQuote;
|
|
22965
|
-
else if (char === '"' && !inSingleQuote) inDoubleQuote = !inDoubleQuote;
|
|
22966
|
-
|
|
22967
|
-
const inQuotes = inSingleQuote || inDoubleQuote;
|
|
22968
|
-
|
|
22969
|
-
// Track bracket depths (only if not in quotes)
|
|
22970
|
-
if (!inQuotes) {
|
|
22971
|
-
if (char === "(") parenDepth++;
|
|
22972
|
-
else if (char === ")") parenDepth--;
|
|
22973
|
-
else if (char === "[") bracketDepth++;
|
|
22974
|
-
else if (char === "]") bracketDepth--;
|
|
22975
|
-
else if (char === "{") braceDepth++;
|
|
22976
|
-
else if (char === "}") braceDepth--;
|
|
22977
|
-
}
|
|
22978
|
-
|
|
22979
|
-
const insideGroup = parenDepth > 0 || bracketDepth > 0 || braceDepth > 0 || inQuotes;
|
|
22980
|
-
|
|
22981
|
-
// Normalize whitespace only when NOT inside groups
|
|
22982
|
-
if (/\s/.test(char)) {
|
|
22983
|
-
if (insideGroup) {
|
|
22984
|
-
normalizedCls += char;
|
|
22985
|
-
} else {
|
|
22986
|
-
// Collapse consecutive whitespace to single space
|
|
22987
|
-
if (normalizedCls.length > 0 && !/\s/.test(normalizedCls[normalizedCls.length - 1])) {
|
|
22988
|
-
normalizedCls += " ";
|
|
22989
|
-
}
|
|
22990
|
-
}
|
|
22991
|
-
} else {
|
|
22992
|
-
normalizedCls += char;
|
|
22993
|
-
}
|
|
22994
|
-
}
|
|
22995
|
-
|
|
22996
|
-
normalizedCls = normalizedCls.trim();
|
|
22997
|
-
const innerParts = smartSplitNoBrace(normalizedCls, " ");
|
|
22998
|
-
|
|
22999
|
-
const spawnShorthandRegex = /^(.*?:)?spawn-((?:from|to|back|half|\[[^\]]+\])(?:\/(?:from|to|back|half|\[[^\]]+\]))*):(.+)$/;
|
|
23000
|
-
const scrollShorthandRegex = /^(.*?:)?scroll-((?:from|to|back|half|\[[^\]]+\])(?:\/(?:from|to|back|half|\[[^\]]+\]))*):(.+)$/;
|
|
23001
|
-
const scrollPrefixRegex = /^(.*?:)?scroll:(.+)$/;
|
|
23002
|
-
|
|
23003
|
-
// Group by prefix for spawn/scroll classes
|
|
23004
|
-
const spawnByPrefix = {};
|
|
23005
|
-
const scrollByPrefix = {};
|
|
23006
|
-
const nonShorthandParts = [];
|
|
23007
|
-
|
|
23008
|
-
innerParts.forEach(part => {
|
|
23009
|
-
if (spawnShorthandRegex.test(part)) {
|
|
23010
|
-
const match = part.match(spawnShorthandRegex);
|
|
23011
|
-
const prefix = match[1] || ''; // Empty string for no prefix
|
|
23012
|
-
|
|
23013
|
-
if (!spawnByPrefix[prefix]) {
|
|
23014
|
-
spawnByPrefix[prefix] = [];
|
|
23015
|
-
}
|
|
23016
|
-
spawnByPrefix[prefix].push(part);
|
|
23017
|
-
} else if (scrollShorthandRegex.test(part) || scrollPrefixRegex.test(part)) {
|
|
23018
|
-
const match = part.match(scrollShorthandRegex) || part.match(scrollPrefixRegex);
|
|
23019
|
-
const prefix = match[1] || ''; // Empty string for no prefix
|
|
23020
|
-
|
|
23021
|
-
if (!scrollByPrefix[prefix]) {
|
|
23022
|
-
scrollByPrefix[prefix] = [];
|
|
23023
|
-
}
|
|
23024
|
-
scrollByPrefix[prefix].push(part);
|
|
23025
|
-
} else {
|
|
23026
|
-
nonShorthandParts.push(part);
|
|
23027
|
-
}
|
|
23028
|
-
});
|
|
23029
|
-
|
|
23030
|
-
// Add non-shorthand classes normally
|
|
23031
|
-
nonShorthandParts.forEach(c => allClasses.add(c));
|
|
23032
|
-
|
|
23033
|
-
// Add spawn classes grouped by prefix
|
|
23034
|
-
Object.values(spawnByPrefix).forEach(group => {
|
|
23035
|
-
if (group.length > 0) {
|
|
23036
|
-
allClasses.add(group.join(' '));
|
|
23037
|
-
}
|
|
23038
|
-
});
|
|
23039
|
-
|
|
23040
|
-
// Add scroll classes grouped by prefix
|
|
23041
|
-
Object.values(scrollByPrefix).forEach(group => {
|
|
23042
|
-
if (group.length > 0) {
|
|
23043
|
-
allClasses.add(group.join(' '));
|
|
23044
|
-
}
|
|
23045
|
-
});
|
|
23046
|
-
});
|
|
23047
|
-
});
|
|
23048
|
-
|
|
23049
|
-
// Group and sort motion classes by prefix length
|
|
23050
|
-
const motionRegex = /^(.*?)motion-\[([^\]]+)\]:/;
|
|
23051
|
-
const motionByName = {};
|
|
23052
|
-
const nonMotionClasses = [];
|
|
23053
|
-
|
|
23054
|
-
Array.from(allClasses).forEach(cls => {
|
|
23055
|
-
const match = cls.match(motionRegex);
|
|
23056
|
-
if (match) {
|
|
23057
|
-
const prefix = match[1]; // Everything before "motion-["
|
|
23058
|
-
const animName = match[2];
|
|
23059
|
-
|
|
23060
|
-
if (!motionByName[animName]) {
|
|
23061
|
-
motionByName[animName] = [];
|
|
23062
|
-
}
|
|
23063
|
-
|
|
23064
|
-
motionByName[animName].push({
|
|
23065
|
-
cls: cls,
|
|
23066
|
-
prefix: prefix,
|
|
23067
|
-
prefixLength: prefix.length
|
|
23068
|
-
});
|
|
23069
|
-
} else {
|
|
23070
|
-
nonMotionClasses.push(cls);
|
|
23071
|
-
}
|
|
23072
|
-
});
|
|
23073
|
-
|
|
23074
|
-
// Sort each animation's classes by prefix length (shortest first)
|
|
23075
|
-
const sortedMotionClasses = [];
|
|
23076
|
-
Object.values(motionByName).forEach(group => {
|
|
23077
|
-
group.sort((a, b) => a.prefixLength - b.prefixLength);
|
|
23078
|
-
sortedMotionClasses.push(...group.map(item => item.cls));
|
|
23079
|
-
});
|
|
23080
|
-
|
|
23081
|
-
// Rebuild allClasses: non-motion first, then sorted motion
|
|
23082
|
-
allClasses.clear();
|
|
23083
|
-
nonMotionClasses.forEach(c => allClasses.add(c));
|
|
23084
|
-
sortedMotionClasses.forEach(c => allClasses.add(c));
|
|
23085
|
-
|
|
23086
|
-
return Array.from(allClasses);
|
|
23087
|
-
}
|
|
23088
|
-
|
|
23089
22880
|
const parseMediaConditions = (input, isContainer = false, isSupports = false) => {
|
|
23090
22881
|
// ✅ Detect custom: prefix at the start and return as-is
|
|
23091
22882
|
if (input.startsWith('custom:')) {
|
|
@@ -25952,7 +25743,7 @@ function runParser(config) {
|
|
|
25952
25743
|
isFirstRun = true;
|
|
25953
25744
|
previouslyParsedClasses = [];
|
|
25954
25745
|
previouslyGeneratedProps.clear();
|
|
25955
|
-
const fullResult = generateCSSString(collectClasses(), false, isFirstRun);
|
|
25746
|
+
const fullResult = generateCSSString(collectClasses(config.content), false, isFirstRun);
|
|
25956
25747
|
const finalCSS = removeNewlines(fullResult.css); // ← Use fullResult, not result
|
|
25957
25748
|
fs.writeFileSync(outputPath, finalCSS, 'utf8');
|
|
25958
25749
|
isFirstRun = false; // ← Reset the flag after rebuild
|
|
Binary file
|
|
Binary file
|
|
Binary file
|