anubis-ui 1.2.15 → 1.2.18

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.
@@ -1,56 +1,184 @@
1
- import { getFiles } from "../fileStuff/file.tools"
2
- import { mapClassesIntoRules } from "../mapping/mapClassIntoRule"
3
- import { buildCssRuleFile } from "../fileStuff/cssFile"
4
- import { config } from "../config.tool"
1
+ import { getFiles } from '@tools/fileStuff/file.tools';
2
+ import { mapClassesIntoRules } from '@tools/mapping/mapClassIntoRule';
3
+ import { writeCssRuleFile } from '@tools/fileStuff/css.file';
4
+ import { config } from '@tools/config.tool';
5
+ import { mapColorsIntoMixinDeclaration } from '@tools/mapping/mapColorIntoDeclaration';
5
6
 
6
- const fs = require('fs')
7
+ import fs from 'fs';
8
+ import {
9
+ CLASS_COMMENT,
10
+ COLOR_COMMENT,
11
+ VARIANT_COMMENT,
12
+ } from '../output/css.output';
13
+ import { log } from '../logger';
14
+
15
+ // Cache for regex compilation
16
+ let cachedRegex: RegExp | null = null;
17
+ let cachedConfigHash: string | null = null;
18
+
19
+ // Performance optimization: limit concurrent file reads to avoid overwhelming the system
20
+ const MAX_CONCURRENT_FILE_READS = 10;
21
+
22
+ /**
23
+ * Execute promises with concurrency limit
24
+ * @param items - Items to process
25
+ * @param fn - Async function to execute for each item
26
+ * @param limit - Maximum number of concurrent operations
27
+ */
28
+ const pLimit = async <T, R>(
29
+ items: T[],
30
+ fn: (item: T) => Promise<R>,
31
+ limit: number
32
+ ): Promise<R[]> => {
33
+ const results: R[] = [];
34
+ let index = 0;
35
+
36
+ const executeNext = async (): Promise<void> => {
37
+ if (index >= items.length) return;
38
+
39
+ const currentIndex = index++;
40
+ const item = items[currentIndex];
41
+ const result = await fn(item);
42
+ results[currentIndex] = result;
43
+ };
44
+
45
+ const workers = Array(Math.min(limit, items.length))
46
+ .fill(null)
47
+ .map(async () => {
48
+ while (index < items.length) {
49
+ await executeNext();
50
+ }
51
+ });
52
+
53
+ await Promise.all(workers);
54
+ return results;
55
+ };
7
56
 
8
57
  /** Fetch vue file based on config target patterns */
9
58
  const init = async () => {
10
- const files = await getFiles(config.files)
59
+ // console.log({ config })
60
+ const files = await getFiles(config.files);
61
+
62
+ const uniqueClasses = await getUniqueClasses(files);
63
+ const { rules, variationsFromRules } = mapClassesIntoRules(uniqueClasses);
64
+
65
+ // Generate all colors from config (no filtering)
66
+ const mappedColors = `${COLOR_COMMENT}\n${mapColorsIntoMixinDeclaration(
67
+ config.colors
68
+ )}`;
69
+
70
+ // Get all variations that should be exported (export-variations: true)
71
+ const allExportVariations = getAllExportVariations();
72
+
73
+ // Merge used variations with all export variations (all export variations take priority)
74
+ const finalVariations = { ...variationsFromRules, ...allExportVariations };
75
+
76
+ // Generate CSS variables for variations
77
+ const variationsCss = Object.entries(finalVariations)
78
+ .map(([varName, varValue]) => ` --${varName}: ${varValue};`)
79
+ .join('\n');
11
80
 
12
- const uniqueClasses = await getUniqueClasses(files)
13
- const mappedRules = mapClassesIntoRules(uniqueClasses)
81
+ const wrappedVariations = variationsCss
82
+ ? `${VARIANT_COMMENT}\n:root {\n${variationsCss}\n}`
83
+ : '';
14
84
 
15
- const file = buildCssRuleFile(mappedRules)
16
- return file
17
- }
85
+ const wrappedRules = rules ? `${CLASS_COMMENT}\n${rules}` : '';
86
+
87
+ const file = writeCssRuleFile(mappedColors, wrappedVariations, wrappedRules);
88
+ return file;
89
+ };
18
90
 
19
91
  /** Extract detected class and map into a flat set */
20
92
  const getUniqueClasses = async (files: string[]): Promise<string[]> => {
21
- const extractedClasses = (await Promise.all(
22
- files.map(async file => extractClasses(file))
23
- ))
24
- ?.flat()
93
+ // Use concurrency limit to avoid overwhelming the system on large codebases
94
+ const extractedClasses = (
95
+ await pLimit(files, extractClasses, MAX_CONCURRENT_FILE_READS)
96
+ ).flat();
97
+
98
+ const classes = [...extractedClasses, ...config.force].sort();
99
+
100
+ const uniqueClasses = Array.from(new Set(classes));
101
+ return uniqueClasses;
102
+ };
103
+
104
+ /** Build regex pattern from config */
105
+ const buildClassDetectionRegex = (): RegExp => {
106
+ const { states, utilities } = config;
107
+
108
+ const partialUtilities = utilities?.map(u => {
109
+ const { prefix, variations: variationEntries, declaration } = u
110
+
111
+ if (!prefix && !variationEntries) {
112
+ log(`Something doesn't look good -> ${u}`)
113
+ }
114
+ const variations = Array.isArray(variationEntries) ? variationEntries : Object.keys(variationEntries || {})
115
+ const hasVariations = !!variations?.length
116
+ const hasDefaultVariation = hasVariations && variations.includes('default')
117
+ const needColor = declaration.includes('${color}')
118
+
119
+ /** If variation has default key, it's considered as a standalone - can be used solo */
120
+ if (hasVariations && hasDefaultVariation && !needColor) {
121
+ return `${prefix}`
122
+ }
123
+
124
+ return `${prefix}-`
125
+ })
126
+
127
+ const mappedUtilities = [...partialUtilities]?.join('|')
128
+ const mappedStates = `(${states?.map(s => `${s}:`)?.join('|')})`;
129
+
130
+ const regexp = new RegExp(
131
+ `${mappedStates}?(${mappedUtilities})(-?(\\w+(-+)?)+)?`,
132
+ 'g'
133
+ );
134
+
135
+ return regexp
136
+ };
137
+
138
+ /** Get cached regex or build a new one if config changed */
139
+ const getClassDetectionRegex = (): RegExp => {
140
+ const { states, qol, utilitys } = config;
141
+ const configHash = JSON.stringify({ states, qol, utilitys });
25
142
 
26
- const classes = [...extractedClasses, ...config.force]?.sort()
143
+ if (cachedRegex && cachedConfigHash === configHash) {
144
+ return cachedRegex;
145
+ }
27
146
 
28
- const uniqueClasses = Array.from(new Set(classes))
29
- return uniqueClasses
30
- }
147
+ cachedRegex = buildClassDetectionRegex();
148
+ cachedConfigHash = configHash;
149
+ return cachedRegex;
150
+ };
31
151
 
32
152
  /** Find matching classes from a given file based on config states and prefixes */
33
153
  const extractClasses = async (filePath: string): Promise<string[]> => {
34
- const file = await fs.promises.readFile(filePath, 'utf-8')
35
- if (!file) { return [] }
154
+ const file = await fs.promises.readFile(filePath, 'utf-8');
155
+ if (!file) {
156
+ return [];
157
+ }
36
158
 
37
- const { states, qol, presets } = config
159
+ const classDetectionRegex = getClassDetectionRegex();
160
+ const matches = file.match(classDetectionRegex) || [];
38
161
 
39
- const partialPrefixes = presets?.map(p => `${p.prefix}-`)
40
- const partialQol = qol?.map(q => q.standalone ? `${q.prefix}` : `${q.prefix}-`)
162
+ return matches;
163
+ };
41
164
 
42
- const mappedPrefixes = [
43
- ...partialPrefixes,
44
- ...partialQol
45
- ]?.join('|')
46
- const mappedStates = `(${states?.map(s => `${s}:`)?.join('|')})`
165
+ /** Get all variations from utilitys with export-variations: true */
166
+ const getAllExportVariations = (): Record<string, string> => {
167
+ const allExportVariations: Record<string, string> = {};
168
+ const allUtilities = [...config.utilities];
47
169
 
48
- const classDetectionRegex = new RegExp(`${mappedStates}?(${mappedPrefixes})(-?(\\w+(-+)?)+)?`, 'g')
170
+ for (const utility of allUtilities) {
171
+ if (utility['export-variations'] === true && utility.variations) {
172
+ for (const [variantName, variantValue] of Object.entries(
173
+ utility.variations
174
+ )) {
175
+ const variableName = `${utility.prefix}-${variantName}`;
176
+ allExportVariations[variableName] = variantValue as string;
177
+ }
178
+ }
179
+ }
49
180
 
50
- const matches = file.match(classDetectionRegex) || []
51
- return matches
52
- }
181
+ return allExportVariations;
182
+ };
53
183
 
54
- export {
55
- init
56
- }
184
+ export { init };
@@ -0,0 +1,44 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { log } from '@tools/logger';
4
+
5
+ const userConfigPath = path.join(process.cwd(), 'anubis.config.json');
6
+ let userConfig = null;
7
+
8
+ const readUserConfigFile = () => {
9
+ const userConfigExists = fs.existsSync(userConfigPath);
10
+
11
+ if (!userConfigExists) {
12
+ log('No user config file found, using default configuration.');
13
+ return;
14
+ }
15
+
16
+ const config = fs.readFileSync(userConfigPath, { encoding: 'utf-8' });
17
+ userConfig = JSON.parse(config);
18
+
19
+ return userConfig;
20
+ };
21
+
22
+ /** Print a warning if the config file has unknow keys */
23
+ const checkUserConfigFile = (configFile: string[]): void => {
24
+ if (!userConfig) {
25
+ return;
26
+ }
27
+
28
+ // todo - also check values
29
+ const userConfigKeys = Object.keys(userConfig);
30
+
31
+ const unknownKeys = userConfigKeys?.filter(
32
+ key => !configFile.includes(key) && key !== 'force'
33
+ );
34
+ if (!unknownKeys?.length) {
35
+ return;
36
+ }
37
+
38
+ log(`${unknownKeys?.length} unknown config keys found in user config file`);
39
+ for (const key of unknownKeys) {
40
+ log(`- ${key}`);
41
+ }
42
+ };
43
+
44
+ export { userConfig, readUserConfigFile, checkUserConfigFile };
@@ -0,0 +1,47 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ import { log } from '@tools/logger';
5
+ import { getHeader } from '@tools/output/css.output';
6
+
7
+ const srcDir = path.join(process.cwd(), 'src', 'css');
8
+ const outputPath = path.join(srcDir, '_anubis.scss');
9
+
10
+ const checkCssRuleFilePresence = () => {
11
+ try {
12
+ fs.mkdirSync(srcDir, { recursive: true });
13
+
14
+ if (fs.existsSync(outputPath)) {
15
+ return;
16
+ }
17
+
18
+ log('Output file missing, generating..');
19
+ fs.writeFileSync(outputPath, '');
20
+ } catch (err: any) {
21
+ throw new Error(
22
+ `Erreur lors de la vérification du fichier CSS: ${err.message}`
23
+ );
24
+ }
25
+ };
26
+
27
+ const writeCssRuleFile = (
28
+ colors: string = '',
29
+ variants: string = '',
30
+ classes: string = ''
31
+ ) => {
32
+ try {
33
+ checkCssRuleFilePresence();
34
+
35
+ const content = `${getHeader()}\n${colors}\n\n${variants}\n\n${classes}`;
36
+
37
+ fs.writeFileSync(outputPath, content);
38
+
39
+ return outputPath;
40
+ } catch (err: any) {
41
+ throw new Error(
42
+ `Erreur lors de l'écriture du fichier CSS: ${err.message}`
43
+ );
44
+ }
45
+ };
46
+
47
+ export { writeCssRuleFile };
@@ -1,15 +1,12 @@
1
- const fg = require('fast-glob')
2
-
3
- import { IFileConfig } from '../../interfaces/files.interface'
1
+ import fg from 'fast-glob';
2
+ import { IFileConfig } from '@interfaces/files.interface';
4
3
 
5
4
  const getFiles = async (routeConfig: IFileConfig) => {
6
- return await fg(routeConfig.targets || '*.vue', {
7
- absolute: true,
8
- onlyFiles: true,
9
- ignore: routeConfig.ignore || [],
10
- })
11
- }
5
+ return await fg(routeConfig.targets || '*.vue', {
6
+ absolute: true,
7
+ onlyFiles: true,
8
+ ignore: routeConfig.ignore || [],
9
+ });
10
+ };
12
11
 
13
- export {
14
- getFiles
15
- }
12
+ export { getFiles };
@@ -1,8 +1,8 @@
1
+ import packageJson from '../../package.json';
2
+
1
3
  const logPrefix = '☯︎ [ANUBIS]'
2
4
  const log = (str: string) => console.log(`${logPrefix} ${str}`)
3
5
 
4
- const { version } = require('./../../package.json')
5
-
6
6
  const logo = () => {
7
7
  log(' ___ _ ____ ______ _________')
8
8
  log(' / | / | / / / / / __ )/ _/ ___/')
@@ -10,21 +10,14 @@ const logo = () => {
10
10
  log(' / ___ |/ /| / /_/ / /_/ // / ___/ /')
11
11
  log('/_/ |_/_/ |_/\\____/_____/___//____/')
12
12
  log('')
13
- log('Welcome to Anubis 1.0')
13
+ log(`Welcome to Anubis v${packageJson.version}`)
14
14
  log('Autonomous Nominative Utility Based Intuitive Styler')
15
15
  log('---')
16
16
  }
17
17
 
18
- const cssHeader = `/*!
19
- * * Anubis v.${version}
20
- * * Improba
21
- * * Released under the MIT License.
22
- * */`
23
-
24
18
  export {
25
19
  logo,
26
- cssHeader,
27
20
 
28
21
  log,
29
22
  logPrefix
30
- }
23
+ }