@salty-css/core 0.0.1-alpha.300 → 0.0.1-alpha.301

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.
Files changed (79) hide show
  1. package/.saltyrc.schema.json +1 -1
  2. package/bin/index.cjs +3 -1
  3. package/bin/index.js +2 -2
  4. package/bin/main.cjs +445 -11
  5. package/bin/main.js +405 -224
  6. package/cache/resolve-dynamic-config-cache.cjs +13 -1
  7. package/cache/resolve-dynamic-config-cache.js +10 -8
  8. package/compiler/index.cjs +774 -1
  9. package/compiler/index.d.ts +3 -0
  10. package/compiler/index.js +754 -20
  11. package/config/index.cjs +16 -1
  12. package/config/index.js +14 -12
  13. package/css/index.cjs +12 -1
  14. package/css/index.js +10 -10
  15. package/css/keyframes.cjs +49 -1
  16. package/css/keyframes.js +44 -34
  17. package/css/media.cjs +93 -1
  18. package/css/media.js +54 -49
  19. package/css/merge.cjs +15 -1
  20. package/css/merge.js +13 -3
  21. package/css/token.cjs +4 -1
  22. package/css/token.js +2 -2
  23. package/dash-case-Cz8wwE9a.cjs +32 -0
  24. package/dash-case-NMk0mXyT.js +33 -0
  25. package/define-templates-CVhhgPnd.js +60 -0
  26. package/define-templates-Deq1aCbN.cjs +59 -0
  27. package/factories/index.cjs +37 -1
  28. package/factories/index.js +27 -20
  29. package/generators/index.cjs +121 -1
  30. package/generators/index.js +82 -49
  31. package/helpers/index.cjs +53 -1
  32. package/helpers/index.js +40 -1170
  33. package/helpers-DM2fbDDz.js +18 -0
  34. package/helpers-wv74jTRI.cjs +18 -0
  35. package/index-ByR0nfaf.cjs +4 -0
  36. package/index-DKz1QXqs.js +4 -0
  37. package/package.json +1 -1
  38. package/parse-styles-CqBQc3eQ.js +232 -0
  39. package/parse-styles-D-p_guRO.cjs +231 -0
  40. package/parsers/index.cjs +57 -2
  41. package/parsers/index.js +55 -30
  42. package/pascal-case-By_l58S-.cjs +7 -0
  43. package/pascal-case-F3Usi5Wf.js +8 -0
  44. package/{react-styled-file-CGVf5n1B.js → react-styled-file-B99mwk0w.js} +2 -2
  45. package/react-styled-file-U02jek-B.cjs +11 -0
  46. package/react-vanilla-file-Bj6XC8GS.cjs +18 -0
  47. package/{react-vanilla-file-CCXbsjIb.js → react-vanilla-file-D9px70iK.js} +2 -2
  48. package/salty.config-DjosWdPw.js +4 -0
  49. package/salty.config-cqavVm2t.cjs +4 -0
  50. package/server/index.cjs +4 -1
  51. package/server/index.js +2 -2
  52. package/should-restart-5jI-bzz0.js +18 -0
  53. package/should-restart-DoaGoD5T.cjs +17 -0
  54. package/util/index.cjs +13 -1
  55. package/util/index.js +10 -8
  56. package/viewport-clamp-CEmzmcSj.cjs +10 -0
  57. package/viewport-clamp-K553uXu3.js +11 -0
  58. package/dash-case-BJEkFEGQ.cjs +0 -1
  59. package/dash-case-DBThphLm.js +0 -19
  60. package/define-templates-4A2yHcMF.js +0 -52
  61. package/define-templates-Cunsb_Tr.cjs +0 -1
  62. package/helpers-CC5pFyba.cjs +0 -1
  63. package/helpers-nHqH4L9L.js +0 -11
  64. package/index-84Wroia-.cjs +0 -1
  65. package/index-CituHO0U.js +0 -524
  66. package/index-D_732b92.js +0 -4
  67. package/index-ol1Q_xul.cjs +0 -41
  68. package/parse-styles-B1E0JeC7.cjs +0 -5
  69. package/parse-styles-y_-drahL.js +0 -161
  70. package/pascal-case-BQpR5PdN.js +0 -6
  71. package/pascal-case-iWoaJWwT.cjs +0 -1
  72. package/react-styled-file-Dkubsz-U.cjs +0 -8
  73. package/react-vanilla-file-CG_WJLam.cjs +0 -15
  74. package/salty.config-BhBY_oOk.js +0 -10
  75. package/salty.config-Dk6ZcCxI.cjs +0 -7
  76. package/should-restart-C6VJ-qaY.js +0 -12
  77. package/should-restart-DAhvRrtu.cjs +0 -1
  78. package/viewport-clamp-CaYwREKc.js +0 -7
  79. package/viewport-clamp-mq_DFtRR.cjs +0 -1
@@ -1 +1,774 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require("esbuild");require("child_process");require("../dash-case-BJEkFEGQ.cjs");require("path");require("fs");require("fs/promises");require("../parse-styles-B1E0JeC7.cjs");require("../parsers/index.cjs");const e=require("../index-ol1Q_xul.cjs");require("../css/merge.cjs");require("../define-templates-Cunsb_Tr.cjs");require("../helpers-CC5pFyba.cjs");exports.compileSaltyFile=e.compileSaltyFile;exports.generateConfigStyles=e.generateConfigStyles;exports.generateCss=e.generateCss;exports.generateFile=e.generateFile;exports.isSaltyFile=e.isSaltyFile;exports.minimizeFile=e.minimizeFile;exports.saltyFileExtensions=e.saltyFileExtensions;exports.saltyFileRegExp=e.saltyFileRegExp;
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const esbuild = require("esbuild");
4
+ const child_process = require("child_process");
5
+ const vm = require("vm");
6
+ const dashCase = require("../dash-case-Cz8wwE9a.cjs");
7
+ const path = require("path");
8
+ const fs = require("fs");
9
+ const promises = require("fs/promises");
10
+ const parseStyles = require("../parse-styles-D-p_guRO.cjs");
11
+ const parsers_index = require("../parsers/index.cjs");
12
+ const winston = require("winston");
13
+ const css_merge = require("../css/merge.cjs");
14
+ const defineTemplates = require("../define-templates-Deq1aCbN.cjs");
15
+ const ts = require("typescript");
16
+ const helpers = require("../helpers-wv74jTRI.cjs");
17
+ var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
18
+ function _interopNamespaceDefault(e) {
19
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
20
+ if (e) {
21
+ for (const k in e) {
22
+ if (k !== "default") {
23
+ const d = Object.getOwnPropertyDescriptor(e, k);
24
+ Object.defineProperty(n, k, d.get ? d : {
25
+ enumerable: true,
26
+ get: () => e[k]
27
+ });
28
+ }
29
+ }
30
+ }
31
+ n.default = e;
32
+ return Object.freeze(n);
33
+ }
34
+ const esbuild__namespace = /* @__PURE__ */ _interopNamespaceDefault(esbuild);
35
+ const getPackageJsonPath = (dirname) => {
36
+ if (!dirname || dirname === "/") throw new Error("Could not find package.json file");
37
+ const packageJsonPath = path.join(dirname, "package.json");
38
+ if (!fs.existsSync(packageJsonPath)) return getPackageJsonPath(path.join(dirname, ".."));
39
+ return packageJsonPath;
40
+ };
41
+ const getPackageJson = async (dirname) => {
42
+ const packageJsonPath = getPackageJsonPath(dirname);
43
+ const packageJsonContent = await promises.readFile(packageJsonPath, "utf-8").then(JSON.parse).catch(() => void 0);
44
+ return packageJsonContent;
45
+ };
46
+ const readPackageJsonModule = async (dirname) => {
47
+ const packageJsonContent = await getPackageJson(dirname);
48
+ if (!packageJsonContent) return void 0;
49
+ return packageJsonContent.type;
50
+ };
51
+ let cachedModuleType;
52
+ const detectCurrentModuleType = async (dirname) => {
53
+ if (cachedModuleType) return cachedModuleType;
54
+ const packageJsonModule = await readPackageJsonModule(dirname);
55
+ if (packageJsonModule === "module") cachedModuleType = "esm";
56
+ else if (packageJsonModule === "commonjs") cachedModuleType = "cjs";
57
+ else if ((typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("compiler/index.cjs", document.baseURI).href).endsWith(".cjs")) cachedModuleType = "cjs";
58
+ return cachedModuleType || "esm";
59
+ };
60
+ const logger = winston.createLogger({
61
+ level: "debug",
62
+ format: winston.format.combine(winston.format.colorize(), winston.format.cli()),
63
+ transports: [new winston.transports.Console({})]
64
+ });
65
+ const logError = (message) => {
66
+ logger.error(message);
67
+ };
68
+ function dotCase(str) {
69
+ if (!str) return "";
70
+ if (typeof str !== "string") return dotCase(String(str));
71
+ return str.replace(/[^\d\w]/g, ".");
72
+ }
73
+ const saltyReset = {
74
+ /** Set box model to border-box */
75
+ "*, *::before, *::after": {
76
+ boxSizing: "border-box"
77
+ },
78
+ /** Remove default margin and padding */
79
+ "*": {
80
+ margin: 0
81
+ },
82
+ /** Remove adjust font properties */
83
+ html: {
84
+ lineHeight: 1.15,
85
+ textSizeAdjust: "100%",
86
+ WebkitFontSmoothing: "antialiased"
87
+ },
88
+ /** Make media elements responsive */
89
+ "img, picture, video, canvas, svg": {
90
+ display: "block",
91
+ maxWidth: "100%"
92
+ },
93
+ /** Avoid overflow of text */
94
+ "p, h1, h2, h3, h4, h5, h6": {
95
+ overflowWrap: "break-word"
96
+ },
97
+ /** Improve text wrapping */
98
+ p: {
99
+ textWrap: "pretty"
100
+ },
101
+ "h1, h2, h3, h4, h5, h6": {
102
+ textWrap: "balance"
103
+ },
104
+ /** Improve link color */
105
+ a: {
106
+ color: "currentColor"
107
+ },
108
+ /** Improve button line height */
109
+ button: {
110
+ lineHeight: "1em",
111
+ color: "currentColor"
112
+ },
113
+ /** Improve form elements */
114
+ "input, optgroup, select, textarea": {
115
+ fontFamily: "inherit",
116
+ fontSize: "100%",
117
+ lineHeight: "1.15em"
118
+ }
119
+ };
120
+ const getFunctionRange = (contents, name) => {
121
+ return new Promise((resolve, reject) => {
122
+ const timeout = setTimeout(() => {
123
+ reject(new Error("Timeout"));
124
+ }, 100);
125
+ const sourceFile = ts.createSourceFile("temp.ts", contents, ts.ScriptTarget.Latest, true);
126
+ function visit(node) {
127
+ if (ts.isVariableDeclaration(node) && node.name.getText() === name) {
128
+ const start = node.getStart();
129
+ const end = node.getEnd();
130
+ clearTimeout(timeout);
131
+ resolve([start, end]);
132
+ }
133
+ node.forEachChild(visit);
134
+ }
135
+ visit(sourceFile);
136
+ });
137
+ };
138
+ const cache = {
139
+ externalModules: [],
140
+ rcFile: void 0,
141
+ destDir: void 0
142
+ };
143
+ const getExternalModules = (coreConfigPath) => {
144
+ if (cache.externalModules.length > 0) return cache.externalModules;
145
+ const content = fs.readFileSync(coreConfigPath, "utf8");
146
+ const match = content.match(/externalModules:\s?\[(.*)\]/);
147
+ if (!match) return [];
148
+ const externalModules = match[1].split(",").map((d) => d.replace(/['"`]/g, "").trim());
149
+ cache.externalModules = externalModules;
150
+ return externalModules;
151
+ };
152
+ const getDestDir = async (dirname) => {
153
+ if (cache.destDir) return cache.destDir;
154
+ const projectConfig = await getRCProjectConfig(dirname);
155
+ const destDir = path.join(dirname, (projectConfig == null ? void 0 : projectConfig.saltygenDir) || "saltygen");
156
+ cache.destDir = destDir;
157
+ return destDir;
158
+ };
159
+ const saltyFileExtensions = ["salty", "css", "styles", "styled"];
160
+ const saltyFileRegExp = (additional = []) => new RegExp(`\\.(${[...saltyFileExtensions, ...additional].join("|")})\\.`);
161
+ const isSaltyFile = (file, additional = []) => saltyFileRegExp(additional).test(file);
162
+ const readRCFile = async (currentDir) => {
163
+ if (cache.rcFile) return cache.rcFile;
164
+ if (currentDir === "/") throw new Error("Could not find .saltyrc.json file");
165
+ const rcPath = path.join(currentDir, ".saltyrc.json");
166
+ const rcContent = await promises.readFile(rcPath, "utf-8").then(JSON.parse).catch(() => void 0);
167
+ if (!rcContent) return readRCFile(path.join(currentDir, ".."));
168
+ cache.rcFile = rcContent;
169
+ return rcContent;
170
+ };
171
+ const getRCProjectConfig = async (dirname) => {
172
+ var _a, _b;
173
+ const rcFile = await readRCFile(dirname);
174
+ const projectConfig = (_a = rcFile.projects) == null ? void 0 : _a.find((project) => dirname.endsWith(project.dir || ""));
175
+ if (!projectConfig) return (_b = rcFile.projects) == null ? void 0 : _b.find((project) => project.dir === rcFile.defaultProject);
176
+ return projectConfig;
177
+ };
178
+ const generateConfig = async (dirname) => {
179
+ const rcProject = await getRCProjectConfig(dirname);
180
+ const destDir = await getDestDir(dirname);
181
+ const coreConfigPath = path.join(dirname, (rcProject == null ? void 0 : rcProject.configDir) || "", "salty.config.ts");
182
+ const coreConfigDest = path.join(destDir, "salty.config.js");
183
+ await detectCurrentModuleType(dirname);
184
+ const externalModules = getExternalModules(coreConfigPath);
185
+ await esbuild__namespace.build({
186
+ entryPoints: [coreConfigPath],
187
+ minify: true,
188
+ treeShaking: true,
189
+ bundle: true,
190
+ outfile: coreConfigDest,
191
+ format: "cjs",
192
+ external: externalModules
193
+ });
194
+ const raw = await promises.readFile(coreConfigDest, "utf8");
195
+ const scriptReal = new vm.Script(raw);
196
+ const context = { module: { exports: {} } };
197
+ scriptReal.runInNewContext(context);
198
+ const { config } = context.module.exports;
199
+ return {
200
+ config,
201
+ path: coreConfigDest
202
+ };
203
+ };
204
+ const generateConfigStyles = async (dirname, configFiles) => {
205
+ var _a, _b;
206
+ const destDir = await getDestDir(dirname);
207
+ const generationResults = {
208
+ mediaQueries: [],
209
+ globalStyles: [],
210
+ variables: [],
211
+ templates: []
212
+ };
213
+ await Promise.all(
214
+ [...configFiles].map(async (src) => {
215
+ const { contents, outputFilePath } = await compileSaltyFile(dirname, src, destDir);
216
+ Object.entries(contents).forEach(([name, value]) => {
217
+ if (value.isMedia) generationResults.mediaQueries.push([name, value]);
218
+ else if (value.isGlobalDefine) generationResults.globalStyles.push(value);
219
+ else if (value.isDefineVariables) generationResults.variables.push(value);
220
+ else if (value.isDefineTemplates) generationResults.templates.push(value._setPath(`${name};;${outputFilePath}`));
221
+ });
222
+ })
223
+ );
224
+ const { config, path: configPath } = await generateConfig(dirname);
225
+ const configCacheContent = { ...config };
226
+ const { mediaQueries } = generationResults;
227
+ configCacheContent.mediaQueries = Object.fromEntries(mediaQueries.map(([name, value]) => [`@${name}`, value]));
228
+ const mediaQueryKeys = mediaQueries.map(([name]) => `'@${name}'`).join(" | ");
229
+ const variableTokens = /* @__PURE__ */ new Set();
230
+ const parseVariables = async (obj, path2 = []) => {
231
+ if (!obj) return [];
232
+ const promises2 = Object.entries(obj).map(async ([key, value]) => {
233
+ const parseVariable = async (value2) => {
234
+ if (!value2) return void 0;
235
+ if (value2 instanceof Promise) return await parseVariable(await value2);
236
+ if (typeof value2 === "function") return await parseVariable(await value2());
237
+ if (typeof value2 === "object") return await parseVariables(value2, [...path2, key]);
238
+ const dottedKey = dotCase(key);
239
+ const dashedKey = dashCase.dashCase(key);
240
+ const tsName = [...path2, dottedKey].join(".");
241
+ variableTokens.add(`"${tsName}"`);
242
+ const cssName = [...path2.map(dashCase.dashCase), dashedKey].join("-");
243
+ const result = parseStyles.parseVariableTokens(value2);
244
+ if (!result) return `--${cssName}: ${value2};`;
245
+ return `--${cssName}: ${result.transformed};`;
246
+ };
247
+ return await parseVariable(value);
248
+ });
249
+ const results = await Promise.all(promises2);
250
+ return results.flat();
251
+ };
252
+ const parseResponsiveVariables = async (obj) => {
253
+ if (!obj) return [];
254
+ const promises2 = Object.entries(obj).map(async ([mediaQuery, values]) => {
255
+ const variables = await parseVariables(values);
256
+ if (mediaQuery === "base") return variables.join("");
257
+ if (configCacheContent.mediaQueries[mediaQuery]) {
258
+ const mediaQueryValue = configCacheContent.mediaQueries[mediaQuery];
259
+ return `${mediaQueryValue} { ${variables.join("")} }`;
260
+ }
261
+ return `${mediaQuery} { ${variables.join("")} }`;
262
+ });
263
+ const results = await Promise.all(promises2);
264
+ return results.flat();
265
+ };
266
+ const parseConditionalVariables = async (obj) => {
267
+ if (!obj) return [];
268
+ const promises2 = Object.entries(obj).map(async ([property, conditions]) => {
269
+ const promises22 = Object.entries(conditions).map(async ([condition, values]) => {
270
+ const variables = await parseVariables(values, [property]);
271
+ const conditionScope = `.${property}-${condition}, [data-${property}="${condition}"]`;
272
+ const combined = variables.join("");
273
+ return `${conditionScope} { ${combined} }`;
274
+ });
275
+ const result = await Promise.all(promises22);
276
+ return result.flat();
277
+ });
278
+ const results = await Promise.all(promises2);
279
+ return results.flat();
280
+ };
281
+ const getStaticVariables = (variables = {}) => {
282
+ return { ...variables, responsive: void 0, conditional: void 0 };
283
+ };
284
+ const getGeneratedVariables = (type) => {
285
+ return generationResults.variables.map((factory) => {
286
+ if (type === "static") return getStaticVariables(factory._current);
287
+ return factory._current[type];
288
+ });
289
+ };
290
+ const _staticVariables = css_merge.mergeObjects(getStaticVariables(config.variables), getGeneratedVariables("static"));
291
+ const staticVariables = await parseVariables(_staticVariables);
292
+ const _responsiveVariables = css_merge.mergeObjects((_a = config.variables) == null ? void 0 : _a.responsive, getGeneratedVariables("responsive"));
293
+ const responsiveVariables = await parseResponsiveVariables(_responsiveVariables);
294
+ const _conditionalVariables = css_merge.mergeObjects((_b = config.variables) == null ? void 0 : _b.conditional, getGeneratedVariables("conditional"));
295
+ const conditionalVariables = await parseConditionalVariables(_conditionalVariables);
296
+ const variablesPath = path.join(destDir, "css/_variables.css");
297
+ const variablesCss = `:root { ${staticVariables.join("")} ${responsiveVariables.join("")} } ${conditionalVariables.join("")}`;
298
+ fs.writeFileSync(variablesPath, variablesCss);
299
+ configCacheContent.staticVariables = _staticVariables;
300
+ const globalStylesPath = path.join(destDir, "css/_global.css");
301
+ const mergedGlobalStyles = css_merge.mergeObjects(config.global, generationResults.globalStyles);
302
+ const globalStylesString = await parseStyles.parseAndJoinStyles(mergedGlobalStyles, "");
303
+ fs.writeFileSync(globalStylesPath, `@layer global { ${globalStylesString} }`);
304
+ const resetStylesPath = path.join(destDir, "css/_reset.css");
305
+ const getResetStyles = () => {
306
+ if (config.reset === "none") return {};
307
+ if (typeof config.reset === "object") return config.reset;
308
+ return saltyReset;
309
+ };
310
+ const resetStyles = getResetStyles();
311
+ const resetStylesString = await parseStyles.parseAndJoinStyles(resetStyles, "");
312
+ fs.writeFileSync(resetStylesPath, `@layer reset { ${resetStylesString} }`);
313
+ const templateStylesPath = path.join(destDir, "css/_templates.css");
314
+ const templates = css_merge.mergeObjects(config.templates, generationResults.templates);
315
+ const templateStylesString = await parsers_index.parseTemplates(templates);
316
+ const templateTokens = parsers_index.getTemplateTypes(templates);
317
+ fs.writeFileSync(templateStylesPath, `@layer templates { ${templateStylesString} }`);
318
+ configCacheContent.templates = templates;
319
+ const configTemplateFactories = config.templates ? [defineTemplates.defineTemplates(config.templates)._setPath(`config;;${configPath}`)] : [];
320
+ const templateFactories = css_merge.mergeFactories(generationResults.templates, configTemplateFactories);
321
+ configCacheContent.templatePaths = Object.fromEntries(Object.entries(templateFactories).map(([key, faktory]) => [key, faktory._path]));
322
+ const tsTokensPath = path.join(destDir, "types/css-tokens.d.ts");
323
+ const tsVariableTokens = [...variableTokens].join("|");
324
+ const tsTokensTypes = `
325
+ // Variable types
326
+ type VariableTokens = ${tsVariableTokens || `''`};
327
+ type PropertyValueToken = \`{\${VariableTokens}}\`;
328
+
329
+ // Template types
330
+ type TemplateTokens = {
331
+ ${Object.entries(templateTokens).map(([key, value]) => `${key}?: ${value}`).join("\n")}
332
+ }
333
+
334
+ // Media query types
335
+ type MediaQueryKeys = ${mediaQueryKeys || `''`};
336
+ `;
337
+ fs.writeFileSync(tsTokensPath, tsTokensTypes);
338
+ const configCachePath = path.join(destDir, "cache/config-cache.json");
339
+ fs.writeFileSync(configCachePath, JSON.stringify(configCacheContent, null, 2));
340
+ const corePackageRoot = helpers.getCorePackageRoot();
341
+ const configCacheSecondaryPath = path.join(corePackageRoot, "cache/config-cache.json");
342
+ fs.writeFileSync(configCacheSecondaryPath, JSON.stringify(configCacheContent, null, 2));
343
+ };
344
+ const replaceStyledTag = (currentFile) => {
345
+ return currentFile.replace(/styled\(([^"'`{,]+),/g, (match, tag) => {
346
+ const isString = /^['"`]/.test(tag);
347
+ if (isString) return match;
348
+ const isImportedRegExp = new RegExp(`import[^;]*${tag}[,\\s{][^;]*from\\s?([^{};]+);`);
349
+ const isImported = isImportedRegExp.test(currentFile);
350
+ if (!isImported) return match;
351
+ const importResult = isImportedRegExp.exec(currentFile);
352
+ if (importResult) {
353
+ const importPath = importResult.at(1);
354
+ const isSaltyImport = saltyFileExtensions.some((ext) => importPath == null ? void 0 : importPath.includes(ext));
355
+ if (isSaltyImport) return match;
356
+ }
357
+ return "styled('div',";
358
+ });
359
+ };
360
+ const addConfigCache = (currentFile, dirname) => {
361
+ try {
362
+ const saltyCachedConfig = fs.readFileSync(path.join(dirname, "saltygen/cache/config-cache.json"), "utf8");
363
+ if (!saltyCachedConfig) return `globalThis.saltyConfig = {};
364
+
365
+ ${currentFile}`;
366
+ return `globalThis.saltyConfig = ${saltyCachedConfig};
367
+
368
+ ${currentFile}`;
369
+ } catch {
370
+ return currentFile;
371
+ }
372
+ };
373
+ const compileSaltyFile = async (dirname, sourceFilePath, outputDirectory) => {
374
+ const hashedName = dashCase.toHash(sourceFilePath);
375
+ const tempDir = path.join(outputDirectory, "./temp");
376
+ if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir);
377
+ const parsed = path.parse(sourceFilePath);
378
+ let currentFile = fs.readFileSync(sourceFilePath, "utf8");
379
+ currentFile = replaceStyledTag(currentFile);
380
+ currentFile = addConfigCache(currentFile, dirname);
381
+ const outputFilePath = path.join(outputDirectory, "js", hashedName + ".js");
382
+ const rcProject = await getRCProjectConfig(dirname);
383
+ const coreConfigPath = path.join(dirname, (rcProject == null ? void 0 : rcProject.configDir) || "", "salty.config.ts");
384
+ const externalModules = getExternalModules(coreConfigPath);
385
+ await detectCurrentModuleType(dirname);
386
+ await esbuild__namespace.build({
387
+ stdin: {
388
+ contents: currentFile,
389
+ sourcefile: parsed.base,
390
+ resolveDir: parsed.dir,
391
+ loader: "tsx"
392
+ },
393
+ minify: false,
394
+ treeShaking: true,
395
+ bundle: true,
396
+ outfile: outputFilePath,
397
+ format: "cjs",
398
+ target: ["node20"],
399
+ keepNames: true,
400
+ external: externalModules,
401
+ packages: "external",
402
+ plugins: [
403
+ {
404
+ name: "test",
405
+ setup: (build) => {
406
+ build.onLoad({ filter: /.*\.css|salty|styles|styled\.ts/ }, (args) => {
407
+ const original = fs.readFileSync(args.path, "utf8");
408
+ const modified = replaceStyledTag(original);
409
+ return { contents: modified, loader: "ts" };
410
+ });
411
+ }
412
+ }
413
+ ]
414
+ });
415
+ const context = { module: { exports: {} } };
416
+ const raw = await promises.readFile(outputFilePath, "utf8");
417
+ new vm.Script(raw).runInNewContext(context);
418
+ return {
419
+ contents: context.module.exports,
420
+ outputFilePath
421
+ };
422
+ };
423
+ const getConfigCache = async (dirname) => {
424
+ const destDir = await getDestDir(dirname);
425
+ const coreConfigDest = path.join(destDir, "cache/config-cache.json");
426
+ const contents = fs.readFileSync(coreConfigDest, "utf8");
427
+ if (!contents) throw new Error("Could not find config cache file");
428
+ return JSON.parse(contents);
429
+ };
430
+ const getConfig = async (dirname) => {
431
+ const cached = await getConfigCache(dirname);
432
+ const destDir = await getDestDir(dirname);
433
+ const coreConfigDest = path.join(destDir, "salty.config.js");
434
+ const context = { module: { exports: {} } };
435
+ const raw = await promises.readFile(coreConfigDest, "utf8");
436
+ new vm.Script(raw).runInNewContext(context);
437
+ const { config } = context.module.exports;
438
+ return css_merge.mergeObjects(config, cached);
439
+ };
440
+ const isProduction = () => {
441
+ try {
442
+ return process.env["NODE_ENV"] === "production";
443
+ } catch {
444
+ return false;
445
+ }
446
+ };
447
+ const generateCss = async (dirname, prod = isProduction(), clean = true) => {
448
+ try {
449
+ const start = Date.now();
450
+ if (prod) logger.info("Generating CSS in production mode! 🔥");
451
+ else logger.info("Generating CSS in development mode! 🚀");
452
+ const globalCssFiles = [];
453
+ const cssFiles = [];
454
+ const destDir = await getDestDir(dirname);
455
+ const cssFile = path.join(destDir, "index.css");
456
+ const clearDistDir = () => {
457
+ if (fs.existsSync(destDir)) child_process.execSync("rm -rf " + destDir);
458
+ fs.mkdirSync(destDir, { recursive: true });
459
+ fs.mkdirSync(path.join(destDir, "css"));
460
+ fs.mkdirSync(path.join(destDir, "types"));
461
+ fs.mkdirSync(path.join(destDir, "js"));
462
+ fs.mkdirSync(path.join(destDir, "cache"));
463
+ };
464
+ if (clean) clearDistDir();
465
+ const files = /* @__PURE__ */ new Set();
466
+ const configFiles = /* @__PURE__ */ new Set();
467
+ async function collectFiles(src) {
468
+ const foldersToSkip = ["node_modules", "saltygen"];
469
+ const stats = fs.statSync(src);
470
+ if (stats.isDirectory()) {
471
+ const files2 = fs.readdirSync(src);
472
+ const shouldSkip = foldersToSkip.some((folder) => src.includes(folder));
473
+ if (shouldSkip) return;
474
+ await Promise.all(files2.map((file) => collectFiles(path.join(src, file))));
475
+ } else if (stats.isFile()) {
476
+ const validFile = isSaltyFile(src);
477
+ if (validFile) {
478
+ files.add(src);
479
+ const contents = fs.readFileSync(src, "utf8");
480
+ const hasDefineFunction = /define[\w\d]+\(/.test(contents);
481
+ if (hasDefineFunction) configFiles.add(src);
482
+ }
483
+ }
484
+ }
485
+ await collectFiles(dirname);
486
+ await generateConfigStyles(dirname, configFiles);
487
+ const generationResults = {
488
+ keyframes: [],
489
+ components: [],
490
+ classNames: []
491
+ };
492
+ await Promise.all(
493
+ [...files].map(async (src) => {
494
+ const { contents } = await compileSaltyFile(dirname, src, destDir);
495
+ for (let [name, value] of Object.entries(contents)) {
496
+ const resolved = await helpers.resolveExportValue(value, 1);
497
+ if (resolved.isKeyframes) {
498
+ generationResults.keyframes.push({
499
+ value: resolved,
500
+ src,
501
+ name
502
+ });
503
+ } else if (resolved.isClassName) {
504
+ generationResults.classNames.push({
505
+ ...value,
506
+ src,
507
+ name
508
+ });
509
+ } else if (resolved.generator) {
510
+ generationResults.components.push({
511
+ ...value,
512
+ src,
513
+ name
514
+ });
515
+ }
516
+ }
517
+ })
518
+ );
519
+ const config = await getConfig(dirname);
520
+ for (const keyframes of generationResults.keyframes) {
521
+ const { value } = keyframes;
522
+ const fileName = `a_${value.animationName}.css`;
523
+ const filePath = `css/${fileName}`;
524
+ const cssPath = path.join(destDir, filePath);
525
+ globalCssFiles.push(fileName);
526
+ fs.writeFileSync(cssPath, value.css);
527
+ }
528
+ const localCssFiles = {};
529
+ for (const componentResult of generationResults.components) {
530
+ const { src, name } = componentResult;
531
+ if (!localCssFiles[src]) localCssFiles[src] = [];
532
+ const generator = componentResult.generator._withBuildContext({
533
+ callerName: name,
534
+ isProduction: prod,
535
+ config
536
+ });
537
+ if (!cssFiles[generator.priority]) cssFiles[generator.priority] = [];
538
+ const styles = await generator.css;
539
+ if (!styles) continue;
540
+ cssFiles[generator.priority].push(generator.cssFileName);
541
+ const filePath = `css/${generator.cssFileName}`;
542
+ const cssPath = path.join(destDir, filePath);
543
+ fs.writeFileSync(cssPath, styles);
544
+ if (config.importStrategy === "component") {
545
+ localCssFiles[src].push(generator.cssFileName);
546
+ }
547
+ }
548
+ for (const classNameResult of generationResults.classNames) {
549
+ const { src, name } = classNameResult;
550
+ if (!localCssFiles[src]) localCssFiles[src] = [];
551
+ const generator = classNameResult.generator._withBuildContext({
552
+ callerName: name,
553
+ isProduction: prod,
554
+ config
555
+ });
556
+ const styles = await generator.css;
557
+ if (!styles) continue;
558
+ if (!cssFiles[generator.priority]) cssFiles[generator.priority] = [];
559
+ cssFiles[generator.priority].push(generator.cssFileName);
560
+ const filePath = `css/${generator.cssFileName}`;
561
+ const cssPath = path.join(destDir, filePath);
562
+ fs.writeFileSync(cssPath, styles);
563
+ if (config.importStrategy === "component") {
564
+ localCssFiles[src].push(generator.cssFileName);
565
+ }
566
+ }
567
+ if (config.importStrategy === "component") {
568
+ Object.entries(localCssFiles).forEach(([src, localCssFile]) => {
569
+ const cssContent2 = localCssFile.map((file) => `@import url('./${file}');`).join("\n");
570
+ const hashName = dashCase.toHash(src, 6);
571
+ const parsedPath = path.parse(src);
572
+ const dasherized = dashCase.dashCase(parsedPath.name);
573
+ const cssFile2 = path.join(destDir, `css/f_${dasherized}-${hashName}.css`);
574
+ fs.writeFileSync(cssFile2, cssContent2 || `/* Empty file */`);
575
+ });
576
+ }
577
+ const otherGlobalCssFiles = globalCssFiles.map((file) => `@import url('./css/${file}');`).join("\n");
578
+ const globalCssFilenames = ["_variables.css", "_reset.css", "_global.css", "_templates.css"];
579
+ const importsWithData = globalCssFilenames.filter((file) => {
580
+ try {
581
+ const data = fs.readFileSync(path.join(destDir, "css", file), "utf8");
582
+ return data.length > 0;
583
+ } catch {
584
+ return false;
585
+ }
586
+ });
587
+ const globalImports = importsWithData.map((file) => `@import url('./css/${file}');`);
588
+ const generatorText = "/*!\n * Generated with Salty CSS (https://salty-css.dev)\n * Do not edit this file directly\n */\n";
589
+ let cssContent = `${generatorText}@layer reset, global, templates, l0, l1, l2, l3, l4, l5, l6, l7, l8;
590
+
591
+ ${globalImports.join(
592
+ "\n"
593
+ )}
594
+ ${otherGlobalCssFiles}`;
595
+ if (config.importStrategy !== "component") {
596
+ const mergedContent = cssFiles.reduce((acc, val, layer) => {
597
+ const layerContent = val.reduce((layerAcc, file) => {
598
+ var _a;
599
+ const filepath = path.join(destDir, "css", file);
600
+ const css = fs.readFileSync(filepath, "utf8");
601
+ const filepathHash = ((_a = /.*-([^-]+)-\d+.css/.exec(file)) == null ? void 0 : _a.at(1)) || dashCase.toHash(filepath, 6);
602
+ if (layerAcc.includes(filepathHash)) return layerAcc;
603
+ return `${layerAcc}
604
+ /*start:${filepathHash}-${file}*/
605
+ ${css}
606
+ /*end:${filepathHash}*/
607
+ `;
608
+ }, "");
609
+ const layerFileName = `l_${layer}.css`;
610
+ const layerFilePath = path.join(destDir, "css", layerFileName);
611
+ const layerContentWithLayer = `@layer l${layer} { ${layerContent}
612
+ }`;
613
+ fs.writeFileSync(layerFilePath, layerContentWithLayer);
614
+ return `${acc}
615
+ @import url('./css/${layerFileName}');`;
616
+ }, "");
617
+ cssContent += mergedContent;
618
+ }
619
+ fs.writeFileSync(cssFile, cssContent);
620
+ const end = Date.now();
621
+ const time = end - start;
622
+ const emoji = time < 200 ? "🔥" : time < 500 ? "🚀" : time < 1e3 ? "🎉" : time < 2e3 ? "🚗" : time < 5e3 ? "🤔" : "🥴";
623
+ logger.info(`Generated CSS in ${time}ms! ${emoji}`);
624
+ } catch (e) {
625
+ console.error(e);
626
+ }
627
+ };
628
+ const generateFile = async (dirname, file, prod = isProduction()) => {
629
+ try {
630
+ const destDir = await getDestDir(dirname);
631
+ const validFile = isSaltyFile(file);
632
+ if (validFile) {
633
+ const cssFiles = [];
634
+ const config = await getConfig(dirname);
635
+ const { contents } = await compileSaltyFile(dirname, file, destDir);
636
+ for (const [name, value] of Object.entries(contents)) {
637
+ const resolved = await helpers.resolveExportValue(value, 1);
638
+ if (resolved.isKeyframes && resolved.css) {
639
+ const fileName = `a_${resolved.animationName}.css`;
640
+ const filePath2 = `css/${fileName}`;
641
+ const cssPath2 = path.join(destDir, filePath2);
642
+ fs.writeFileSync(cssPath2, await resolved.css);
643
+ continue;
644
+ }
645
+ if (resolved.isClassName) {
646
+ const generator2 = resolved.generator._withBuildContext({
647
+ callerName: name,
648
+ isProduction: prod,
649
+ config
650
+ });
651
+ const styles2 = await generator2.css;
652
+ if (!styles2) continue;
653
+ if (!cssFiles[generator2.priority]) cssFiles[generator2.priority] = [];
654
+ cssFiles[generator2.priority].push(generator2.cssFileName);
655
+ const filePath2 = `css/${generator2.cssFileName}`;
656
+ const cssPath2 = path.join(destDir, filePath2);
657
+ fs.writeFileSync(cssPath2, styles2);
658
+ continue;
659
+ }
660
+ if (!resolved.generator) continue;
661
+ const generator = resolved.generator._withBuildContext({
662
+ callerName: name,
663
+ isProduction: prod,
664
+ config
665
+ });
666
+ const styles = await generator.css;
667
+ if (!styles) continue;
668
+ const filePath = `css/${generator.cssFileName}`;
669
+ const cssPath = path.join(destDir, filePath);
670
+ fs.writeFileSync(cssPath, styles);
671
+ if (!cssFiles[generator.priority]) cssFiles[generator.priority] = [];
672
+ cssFiles[generator.priority].push(generator.cssFileName);
673
+ }
674
+ if (config.importStrategy !== "component") {
675
+ cssFiles.forEach((val, layer) => {
676
+ const layerFileName = `l_${layer}.css`;
677
+ const layerFilePath = path.join(destDir, "css", layerFileName);
678
+ let currentLayerFileContent = fs.readFileSync(layerFilePath, "utf8");
679
+ val.forEach((file2) => {
680
+ var _a;
681
+ const filepath = path.join(destDir, "css", file2);
682
+ const filepathHash = ((_a = /.*-([^-]+)-\d+.css/.exec(file2)) == null ? void 0 : _a.at(1)) || dashCase.toHash(filepath, 6);
683
+ const found = currentLayerFileContent.includes(filepathHash);
684
+ if (!found) {
685
+ const css = fs.readFileSync(filepath, "utf8");
686
+ const newContent = `/*start:${filepathHash}-${file2}*/
687
+ ${css}
688
+ /*end:${filepathHash}*/
689
+ `;
690
+ currentLayerFileContent = `${currentLayerFileContent.replace(/\}$/, "")}
691
+ ${newContent}
692
+ }`;
693
+ }
694
+ });
695
+ fs.writeFileSync(layerFilePath, currentLayerFileContent);
696
+ });
697
+ } else {
698
+ const cssContent = cssFiles.flat().map((file2) => `@import url('./${file2}');`).join("\n");
699
+ const hashName = dashCase.toHash(file, 6);
700
+ const parsedPath = path.parse(file);
701
+ const dasherized = dashCase.dashCase(parsedPath.name);
702
+ const cssFile = path.join(destDir, `css/f_${dasherized}-${hashName}.css`);
703
+ fs.writeFileSync(cssFile, cssContent || `/* Empty file */`);
704
+ }
705
+ }
706
+ } catch (e) {
707
+ console.error(e);
708
+ }
709
+ };
710
+ const minimizeFile = async (dirname, file, prod = isProduction()) => {
711
+ var _a, _b;
712
+ try {
713
+ const destDir = await getDestDir(dirname);
714
+ const validFile = isSaltyFile(file);
715
+ if (validFile) {
716
+ const original = fs.readFileSync(file, "utf8");
717
+ const config = await getConfig(dirname);
718
+ const { contents } = await compileSaltyFile(dirname, file, destDir);
719
+ let current = original;
720
+ for (const [name, value] of Object.entries(contents)) {
721
+ const resolved = await helpers.resolveExportValue(value, 1);
722
+ if (resolved.isKeyframes) continue;
723
+ if (!resolved.generator) continue;
724
+ const generator = resolved.generator._withBuildContext({
725
+ callerName: name,
726
+ isProduction: prod,
727
+ config
728
+ });
729
+ const [start, end] = await getFunctionRange(current, name);
730
+ const range = current.slice(start, end);
731
+ if (resolved.isClassName) {
732
+ const copy = current;
733
+ const clientVersion = ` ${name} = className("${generator.classNames}")`;
734
+ current = current.replace(range, clientVersion);
735
+ if (copy === current) console.error("Minimize file failed to change content", { name });
736
+ }
737
+ if (range.includes("styled")) {
738
+ const tagName = (_b = (_a = /styled\(([^,]+),/.exec(range)) == null ? void 0 : _a.at(1)) == null ? void 0 : _b.trim();
739
+ const copy = current;
740
+ const clientVersion = ` ${name} = styled(${tagName}, "${generator.classNames}", ${JSON.stringify(generator.clientProps)})`;
741
+ current = current.replace(range, clientVersion);
742
+ if (copy === current) console.error("Minimize file failed to change content", { name, tagName });
743
+ }
744
+ }
745
+ if (config.importStrategy === "component") {
746
+ const fileHash = dashCase.toHash(file, 6);
747
+ const parsed = path.parse(file);
748
+ const dasherized = dashCase.dashCase(parsed.name);
749
+ const cssFileName = `f_${dasherized}-${fileHash}.css`;
750
+ current = `import '../../saltygen/css/${cssFileName}';
751
+ ${current}`;
752
+ }
753
+ current = current.replace(`@salty-css/react/class-name`, `@salty-css/react/class-name-client`);
754
+ current = current.replace(`{ styled }`, `{ styledClient as styled }`);
755
+ current = current.replace(`@salty-css/react/styled`, `@salty-css/react/styled-client`);
756
+ return current;
757
+ }
758
+ } catch (e) {
759
+ console.error("Error in minimizeFile:", e);
760
+ }
761
+ return void 0;
762
+ };
763
+ exports.compileSaltyFile = compileSaltyFile;
764
+ exports.generateConfigStyles = generateConfigStyles;
765
+ exports.generateCss = generateCss;
766
+ exports.generateFile = generateFile;
767
+ exports.getConfig = getConfig;
768
+ exports.getDestDir = getDestDir;
769
+ exports.isSaltyFile = isSaltyFile;
770
+ exports.logError = logError;
771
+ exports.logger = logger;
772
+ exports.minimizeFile = minimizeFile;
773
+ exports.saltyFileExtensions = saltyFileExtensions;
774
+ exports.saltyFileRegExp = saltyFileRegExp;