@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
package/bin/main.js CHANGED
@@ -1,263 +1,444 @@
1
- import { Command as ot } from "commander";
2
- import { existsSync as Q, watch as rt } from "fs";
3
- import { mkdir as q, readFile as S, writeFile as C } from "fs/promises";
4
- import { join as a, relative as z, parse as ct, format as et } from "path";
5
- import { render as lt } from "ejs";
6
- import { l as e, a as h, g as K, i as dt, b as ft } from "../index-CituHO0U.js";
7
- import { p as pt } from "../pascal-case-BQpR5PdN.js";
8
- import { exec as gt } from "child_process";
9
- import ut from "ora";
10
- import { c as yt } from "../should-restart-C6VJ-qaY.js";
11
- const st = (u) => new Promise((v, k) => {
12
- gt(u, ($) => {
13
- if ($) return k($);
14
- v();
1
+ import { Command } from "commander";
2
+ import { existsSync, watch } from "fs";
3
+ import { mkdir, readFile, writeFile } from "fs/promises";
4
+ import { join, relative, parse, format } from "path";
5
+ import { render } from "ejs";
6
+ import { l as logger, a as logError, generateCss, isSaltyFile, generateFile } from "../compiler/index.js";
7
+ import { p as pascalCase } from "../pascal-case-F3Usi5Wf.js";
8
+ import { exec } from "child_process";
9
+ import ora from "ora";
10
+ import { c as checkShouldRestart } from "../should-restart-5jI-bzz0.js";
11
+ const execAsync = (command) => {
12
+ return new Promise((resolve, reject) => {
13
+ exec(command, (error) => {
14
+ if (error) return reject(error);
15
+ resolve();
16
+ });
15
17
  });
16
- }), E = async (...u) => {
17
- const v = u.map((J) => J.replace("-D", "").split("@").slice(0, -1).join("@").trim()).join(", "), k = ut(`Installing packages: ${v}`).start(), $ = u.join(" ");
18
- await st(`npm install ${$}`), k.succeed(`Installed packages: ${v}`);
19
- }, mt = () => Q(a(process.cwd(), "node_modules", ".bin", "prettier"));
20
- async function j(u) {
18
+ };
19
+ const npmInstall = async (...packages) => {
20
+ const packageNames = packages.map((p) => p.replace("-D", "").split("@").slice(0, -1).join("@").trim()).join(", ");
21
+ const spinner = ora(`Installing packages: ${packageNames}`).start();
22
+ const asString = packages.join(" ");
23
+ await execAsync(`npm install ${asString}`);
24
+ spinner.succeed(`Installed packages: ${packageNames}`);
25
+ };
26
+ const hasPrettierInstalled = () => {
27
+ return existsSync(join(process.cwd(), "node_modules", ".bin", "prettier"));
28
+ };
29
+ async function formatWithPrettier(filePath) {
21
30
  try {
22
- if (!mt()) return;
23
- await st(`./node_modules/.bin/prettier --write "${u}"`), e.info(`Formatted ${u} with Prettier`);
24
- } catch (v) {
25
- e.error(`Error formatting ${u} with Prettier:`, v);
31
+ const hasPrettier = hasPrettierInstalled();
32
+ if (!hasPrettier) return;
33
+ await execAsync(`./node_modules/.bin/prettier --write "${filePath}"`);
34
+ logger.info(`Formatted ${filePath} with Prettier`);
35
+ } catch (error) {
36
+ logger.error(`Error formatting ${filePath} with Prettier:`, error);
26
37
  }
27
38
  }
28
- async function Jt() {
29
- const u = new ot();
30
- u.name("salty-css").description("Salty-CSS CLI tool to help with annoying configuration tasks.");
31
- const v = {
39
+ async function main() {
40
+ const program = new Command();
41
+ program.name("salty-css").description("Salty-CSS CLI tool to help with annoying configuration tasks.");
42
+ const files = {
32
43
  // Core files
33
- "salty.config.ts": import("../salty.config-BhBY_oOk.js"),
34
- "saltygen/index.css": import("../index-D_732b92.js"),
44
+ "salty.config.ts": import("../salty.config-DjosWdPw.js"),
45
+ "saltygen/index.css": import("../index-DKz1QXqs.js"),
35
46
  // React
36
- "react/react-styled-file.ts": import("../react-styled-file-CGVf5n1B.js"),
37
- "react/react-vanilla-file.ts": import("../react-vanilla-file-CCXbsjIb.js")
38
- }, k = async (s, i) => {
39
- const { default: d } = await v[s], l = lt(d, i);
40
- return { fileName: s, content: l };
41
- }, $ = async () => {
42
- const s = a(process.cwd(), ".saltyrc.json");
43
- return await S(s, "utf-8").then(JSON.parse).catch(() => ({}));
44
- }, J = a(process.cwd(), "package.json"), O = async (s = J) => {
45
- const i = await S(s, "utf-8").then(JSON.parse).catch(() => {
46
- });
47
- if (!i) throw "Could not read package.json file!";
48
- return i;
49
- }, nt = async (s, i = J) => {
50
- typeof s == "object" && (s = JSON.stringify(s, null, 2)), await C(i, s);
51
- }, X = async () => {
52
- const s = new URL("../package.json", import.meta.url);
53
- return O(s);
54
- }, Y = await (async () => (await $()).defaultProject)(), N = await X(), A = {
55
- core: `@salty-css/core@${N.version}`,
56
- react: `@salty-css/react@${N.version}`,
57
- eslintConfigCore: `@salty-css/eslint-config-core@${N.version}`,
58
- vite: `@salty-css/vite@${N.version}`,
59
- next: `@salty-css/next@${N.version}`
60
- }, G = (s) => {
61
- const i = s === "." ? "" : s, d = process.cwd();
62
- return a(d, i);
47
+ "react/react-styled-file.ts": import("../react-styled-file-B99mwk0w.js"),
48
+ "react/react-vanilla-file.ts": import("../react-vanilla-file-D9px70iK.js")
49
+ };
50
+ const readTemplate = async (fileName, options) => {
51
+ const { default: file } = await files[fileName];
52
+ const content = render(file, options);
53
+ return { fileName, content };
54
+ };
55
+ const readRCFile = async () => {
56
+ const rcPath = join(process.cwd(), ".saltyrc.json");
57
+ const rcContent = await readFile(rcPath, "utf-8").then(JSON.parse).catch(() => ({}));
58
+ return rcContent;
63
59
  };
64
- u.command("init [directory]").description("Initialize a new Salty-CSS project.").option("-d, --dir <dir>", "Project directory to initialize the project in.").option("--css-file <css-file>", "Existing CSS file where to import the generated CSS. Path must be relative to the given project directory.").option("--skip-install", "Skip installing dependencies.").action(async function(s = ".") {
65
- if (!await O().catch(() => {
66
- })) return h("Salty CSS project must be initialized in a directory with a package.json file.");
67
- e.info("Initializing a new Salty-CSS project!");
68
- const { dir: d = s, cssFile: l, skipInstall: p } = this.opts();
69
- if (!d) return h("Project directory must be provided. Add it as the first argument after init command or use the --dir option.");
70
- p || await E(A.core, A.react);
71
- const r = process.cwd(), o = G(d), T = await Promise.all([k("salty.config.ts"), k("saltygen/index.css")]);
72
- await q(o, { recursive: !0 });
73
- const y = T.map(async ({ fileName: t, content: g }) => {
74
- const c = a(o, t);
75
- if (await S(c, "utf-8").catch(() => {
76
- }) !== void 0) {
77
- e.debug("File already exists: " + c);
60
+ const defaultPackageJsonPath = join(process.cwd(), "package.json");
61
+ const readPackageJson = async (filePath = defaultPackageJsonPath) => {
62
+ const packageJsonContent = await readFile(filePath, "utf-8").then(JSON.parse).catch(() => void 0);
63
+ if (!packageJsonContent) throw "Could not read package.json file!";
64
+ return packageJsonContent;
65
+ };
66
+ const updatePackageJson = async (content, filePath = defaultPackageJsonPath) => {
67
+ if (typeof content === "object") content = JSON.stringify(content, null, 2);
68
+ await writeFile(filePath, content);
69
+ };
70
+ const readThisPackageJson = async () => {
71
+ const packageJsonPath = new URL("../package.json", import.meta.url);
72
+ return readPackageJson(packageJsonPath);
73
+ };
74
+ const getDefaultProject = async () => {
75
+ const rcContent = await readRCFile();
76
+ return rcContent.defaultProject;
77
+ };
78
+ const defaultProject = await getDefaultProject();
79
+ const currentPackageJson = await readThisPackageJson();
80
+ const packages = {
81
+ core: `@salty-css/core@${currentPackageJson.version}`,
82
+ react: `@salty-css/react@${currentPackageJson.version}`,
83
+ eslintConfigCore: `@salty-css/eslint-config-core@${currentPackageJson.version}`,
84
+ vite: `@salty-css/vite@${currentPackageJson.version}`,
85
+ next: `@salty-css/next@${currentPackageJson.version}`
86
+ };
87
+ const resolveProjectDir = (dir) => {
88
+ const dirName = dir === "." ? "" : dir;
89
+ const rootDir = process.cwd();
90
+ const projectDir = join(rootDir, dirName);
91
+ return projectDir;
92
+ };
93
+ program.command("init [directory]").description("Initialize a new Salty-CSS project.").option("-d, --dir <dir>", "Project directory to initialize the project in.").option("--css-file <css-file>", "Existing CSS file where to import the generated CSS. Path must be relative to the given project directory.").option("--skip-install", "Skip installing dependencies.").action(async function(_dir = ".") {
94
+ const packageJson = await readPackageJson().catch(() => void 0);
95
+ if (!packageJson) return logError("Salty CSS project must be initialized in a directory with a package.json file.");
96
+ logger.info("Initializing a new Salty-CSS project!");
97
+ const { dir = _dir, cssFile, skipInstall } = this.opts();
98
+ if (!dir) return logError("Project directory must be provided. Add it as the first argument after init command or use the --dir option.");
99
+ if (!skipInstall) await npmInstall(packages.core, packages.react);
100
+ const rootDir = process.cwd();
101
+ const projectDir = resolveProjectDir(dir);
102
+ const projectFiles = await Promise.all([readTemplate("salty.config.ts"), readTemplate("saltygen/index.css")]);
103
+ await mkdir(projectDir, { recursive: true });
104
+ const writeFiles = projectFiles.map(async ({ fileName, content }) => {
105
+ const filePath = join(projectDir, fileName);
106
+ const existingContent = await readFile(filePath, "utf-8").catch(() => void 0);
107
+ if (existingContent !== void 0) {
108
+ logger.debug("File already exists: " + filePath);
78
109
  return;
79
110
  }
80
- const b = t.split("/").slice(0, -1).join("/");
81
- b && await q(a(o, b), { recursive: !0 }), e.info("Creating file: " + c), await C(c, g), await j(c);
82
- });
83
- await Promise.all(y);
84
- const w = z(r, o) || ".", m = a(r, ".saltyrc.json"), f = await S(m, "utf-8").catch(() => {
111
+ const additionalFolders = fileName.split("/").slice(0, -1).join("/");
112
+ if (additionalFolders) await mkdir(join(projectDir, additionalFolders), { recursive: true });
113
+ logger.info("Creating file: " + filePath);
114
+ await writeFile(filePath, content);
115
+ await formatWithPrettier(filePath);
85
116
  });
86
- if (f === void 0) {
87
- e.info("Creating file: " + m);
88
- const g = JSON.stringify({
117
+ await Promise.all(writeFiles);
118
+ const relativeProjectPath = relative(rootDir, projectDir) || ".";
119
+ const saltyrcPath = join(rootDir, ".saltyrc.json");
120
+ const existingSaltyrc = await readFile(saltyrcPath, "utf-8").catch(() => void 0);
121
+ if (existingSaltyrc === void 0) {
122
+ logger.info("Creating file: " + saltyrcPath);
123
+ const rcContent = {
89
124
  $schema: "./node_modules/@salty-css/core/.saltyrc.schema.json",
90
125
  info: "This file is used to define projects and their configurations for Salty CSS cli. Do not delete, modify or add this file to .gitignore.",
91
- defaultProject: w,
126
+ defaultProject: relativeProjectPath,
92
127
  projects: [
93
128
  {
94
- dir: w,
129
+ dir: relativeProjectPath,
95
130
  framework: "react"
96
131
  }
97
132
  ]
98
- }, null, 2);
99
- await C(m, g), await j(m);
133
+ };
134
+ const content = JSON.stringify(rcContent, null, 2);
135
+ await writeFile(saltyrcPath, content);
136
+ await formatWithPrettier(saltyrcPath);
100
137
  } else {
101
- const t = JSON.parse(f), g = (t == null ? void 0 : t.projects) || [];
102
- if (g.findIndex((n) => n.dir === w) === -1) {
103
- g.push({ dir: w, framework: "react" }), t.projects = [...g];
104
- const n = JSON.stringify(t, null, 2);
105
- n !== f && (e.info("Edit file: " + m), await C(m, n), await j(m));
138
+ const rcContent = JSON.parse(existingSaltyrc);
139
+ const projects = (rcContent == null ? void 0 : rcContent.projects) || [];
140
+ const projectIndex = projects.findIndex((p) => p.dir === relativeProjectPath);
141
+ if (projectIndex === -1) {
142
+ projects.push({ dir: relativeProjectPath, framework: "react" });
143
+ rcContent.projects = [...projects];
144
+ const content = JSON.stringify(rcContent, null, 2);
145
+ if (content !== existingSaltyrc) {
146
+ logger.info("Edit file: " + saltyrcPath);
147
+ await writeFile(saltyrcPath, content);
148
+ await formatWithPrettier(saltyrcPath);
149
+ }
106
150
  }
107
151
  }
108
- const P = a(r, ".gitignore"), H = await S(P, "utf-8").catch(() => {
109
- });
110
- H !== void 0 && (H.includes("saltygen") || (e.info("Edit file: " + P), await C(P, H + `
111
-
112
- # Salty-CSS
113
- saltygen
114
- `)));
115
- const F = ["src", "public", "assets", "styles", "css", "app"], M = ["styles", "css", "app", "pages"], B = ["index", "styles", "main", "app", "global", "globals"], U = [".css", ".scss", ".sass"], D = await (async () => {
116
- if (l) return l;
117
- for (const t of F)
118
- for (const g of B)
119
- for (const c of U) {
120
- const n = a(o, t, g + c);
121
- if (await S(n, "utf-8").catch(() => {
122
- }) !== void 0) return z(o, n);
123
- for (const L of M) {
124
- const R = a(o, t, L, g + c);
125
- if (await S(R, "utf-8").catch(() => {
126
- }) !== void 0) return z(o, R);
152
+ const gitIgnorePath = join(rootDir, ".gitignore");
153
+ const gitIgnoreContent = await readFile(gitIgnorePath, "utf-8").catch(() => void 0);
154
+ if (gitIgnoreContent !== void 0) {
155
+ const alreadyIgnoresSaltygen = gitIgnoreContent.includes("saltygen");
156
+ if (!alreadyIgnoresSaltygen) {
157
+ logger.info("Edit file: " + gitIgnorePath);
158
+ await writeFile(gitIgnorePath, gitIgnoreContent + "\n\n# Salty-CSS\nsaltygen\n");
159
+ }
160
+ }
161
+ const cssFileFoldersToLookFor = ["src", "public", "assets", "styles", "css", "app"];
162
+ const secondLevelFolders = ["styles", "css", "app", "pages"];
163
+ const cssFilesToLookFor = ["index", "styles", "main", "app", "global", "globals"];
164
+ const cssFileExtensions = [".css", ".scss", ".sass"];
165
+ const getTargetCssFile = async () => {
166
+ if (cssFile) return cssFile;
167
+ for (const folder of cssFileFoldersToLookFor) {
168
+ for (const file of cssFilesToLookFor) {
169
+ for (const ext of cssFileExtensions) {
170
+ const filePath = join(projectDir, folder, file + ext);
171
+ const fileContent = await readFile(filePath, "utf-8").catch(() => void 0);
172
+ if (fileContent !== void 0) return relative(projectDir, filePath);
173
+ for (const secondLevelFolder of secondLevelFolders) {
174
+ const filePath2 = join(projectDir, folder, secondLevelFolder, file + ext);
175
+ const fileContent2 = await readFile(filePath2, "utf-8").catch(() => void 0);
176
+ if (fileContent2 !== void 0) return relative(projectDir, filePath2);
127
177
  }
128
178
  }
129
- })();
130
- if (D) {
131
- const t = a(o, D), g = await S(t, "utf-8").catch(() => {
132
- });
133
- if (g !== void 0 && !g.includes("saltygen")) {
134
- const n = a(t, ".."), L = `@import '${z(n, a(o, "saltygen/index.css"))}';`;
135
- e.info("Adding global import statement to CSS file: " + t), await C(t, L + `
136
- ` + g), await j(t);
179
+ }
137
180
  }
138
- } else
139
- e.warn("Could not find a CSS file to import the generated CSS. Please add it manually.");
140
- const at = {
141
- projectJs: a(o, "eslint.config.js"),
142
- rootJs: a(r, "eslint.config.js"),
143
- projectMjs: a(o, "eslint.config.mjs"),
144
- rootMjs: a(r, "eslint.config.mjs"),
145
- projectJson: a(o, ".eslintrc.json"),
146
- rootJson: a(r, ".eslintrc.json")
147
- }, x = Object.values(at).find((t) => Q(t));
148
- if (x) {
149
- p || await E(A.eslintConfigCore);
150
- const t = await S(x, "utf-8").catch(() => {
151
- });
152
- if (!t) return h("Could not read ESLint config file.");
153
- if (!t.includes("salty-css"))
154
- if (e.info("Edit file: " + x), x.endsWith("js")) {
155
- let n = `import saltyCss from "@salty-css/eslint-config-core/flat";
156
- ${t}`;
157
- t.includes("typescript-eslint") ? n.includes(".config(") ? n = n.replace(".config(", ".config(saltyCss,") : e.warn("Could not find the correct place to add the Salty-CSS config for ESLint. Please add it manually.") : n.includes("export default [") ? n = n.replace("export default [", "export default [ saltyCss,") : n.includes("eslintConfig = [") ? n = n.replace("eslintConfig = [", "eslintConfig = [ saltyCss,") : e.warn("Could not find the correct place to add the Salty-CSS config for ESLint. Please add it manually."), await C(x, n), await j(x);
181
+ return void 0;
182
+ };
183
+ const targetCSSFile = await getTargetCssFile();
184
+ if (targetCSSFile) {
185
+ const cssFilePath = join(projectDir, targetCSSFile);
186
+ const cssFileContent = await readFile(cssFilePath, "utf-8").catch(() => void 0);
187
+ if (cssFileContent !== void 0) {
188
+ const alreadyImportsSaltygen = cssFileContent.includes("saltygen");
189
+ if (!alreadyImportsSaltygen) {
190
+ const cssFileFolder = join(cssFilePath, "..");
191
+ const relativePath = relative(cssFileFolder, join(projectDir, "saltygen/index.css"));
192
+ const importStatement = `@import '${relativePath}';`;
193
+ logger.info("Adding global import statement to CSS file: " + cssFilePath);
194
+ await writeFile(cssFilePath, importStatement + "\n" + cssFileContent);
195
+ await formatWithPrettier(cssFilePath);
196
+ }
197
+ }
198
+ } else {
199
+ logger.warn("Could not find a CSS file to import the generated CSS. Please add it manually.");
200
+ }
201
+ const eslintConfigs = {
202
+ projectJs: join(projectDir, "eslint.config.js"),
203
+ rootJs: join(rootDir, "eslint.config.js"),
204
+ projectMjs: join(projectDir, "eslint.config.mjs"),
205
+ rootMjs: join(rootDir, "eslint.config.mjs"),
206
+ projectJson: join(projectDir, ".eslintrc.json"),
207
+ rootJson: join(rootDir, ".eslintrc.json")
208
+ };
209
+ const eslintConfigToUse = Object.values(eslintConfigs).find((path) => existsSync(path));
210
+ if (eslintConfigToUse) {
211
+ if (!skipInstall) await npmInstall(packages.eslintConfigCore);
212
+ const eslintConfigContent = await readFile(eslintConfigToUse, "utf-8").catch(() => void 0);
213
+ if (!eslintConfigContent) return logError("Could not read ESLint config file.");
214
+ const alreadyHasSaltyConfig = eslintConfigContent.includes("salty-css");
215
+ if (!alreadyHasSaltyConfig) {
216
+ logger.info("Edit file: " + eslintConfigToUse);
217
+ if (eslintConfigToUse.endsWith("js")) {
218
+ const importStatement = 'import saltyCss from "@salty-css/eslint-config-core/flat";';
219
+ let newContent = `${importStatement}
220
+ ${eslintConfigContent}`;
221
+ const isTsEslint = eslintConfigContent.includes("typescript-eslint");
222
+ if (isTsEslint) {
223
+ if (newContent.includes(".config(")) newContent = newContent.replace(".config(", ".config(saltyCss,");
224
+ else logger.warn("Could not find the correct place to add the Salty-CSS config for ESLint. Please add it manually.");
225
+ } else {
226
+ if (newContent.includes("export default [")) newContent = newContent.replace("export default [", "export default [ saltyCss,");
227
+ else if (newContent.includes("eslintConfig = [")) newContent = newContent.replace("eslintConfig = [", "eslintConfig = [ saltyCss,");
228
+ else logger.warn("Could not find the correct place to add the Salty-CSS config for ESLint. Please add it manually.");
229
+ }
230
+ await writeFile(eslintConfigToUse, newContent);
231
+ await formatWithPrettier(eslintConfigToUse);
158
232
  } else {
159
- const c = JSON.parse(t);
160
- c.extends || (c.extends = []), c.extends.push("@salty-css/core");
161
- const n = JSON.stringify(c, null, 2);
162
- await C(x, n), await j(x);
233
+ const eslintConfigJson = JSON.parse(eslintConfigContent);
234
+ if (!eslintConfigJson.extends) eslintConfigJson.extends = [];
235
+ eslintConfigJson.extends.push("@salty-css/core");
236
+ const modifiedEslintConfigContent = JSON.stringify(eslintConfigJson, null, 2);
237
+ await writeFile(eslintConfigToUse, modifiedEslintConfigContent);
238
+ await formatWithPrettier(eslintConfigToUse);
163
239
  }
240
+ }
164
241
  }
165
- const W = a(o, "vite.config.ts"), V = await S(W, "utf-8").catch(() => {
166
- });
167
- if (V !== void 0 && !V.includes("saltyPlugin")) {
168
- e.info("Edit file: " + W);
169
- const g = `import { saltyPlugin } from '@salty-css/vite';
170
- `, n = V.replace(/(plugins: \[)/, `$1
171
- saltyPlugin(__dirname),`);
172
- p || await E(`-D ${A.vite}`), e.info("Adding Salty-CSS plugin to Vite config..."), await C(W, g + n), await j(W);
242
+ const viteConfigPath = join(projectDir, "vite.config.ts");
243
+ const viteConfigContent = await readFile(viteConfigPath, "utf-8").catch(() => void 0);
244
+ if (viteConfigContent !== void 0) {
245
+ const alreadyHasPlugin = viteConfigContent.includes("saltyPlugin");
246
+ if (!alreadyHasPlugin) {
247
+ logger.info("Edit file: " + viteConfigPath);
248
+ const pluginImport = "import { saltyPlugin } from '@salty-css/vite';\n";
249
+ const pluginConfig = "saltyPlugin(__dirname),";
250
+ const newContent = viteConfigContent.replace(/(plugins: \[)/, `$1
251
+ ${pluginConfig}`);
252
+ if (!skipInstall) await npmInstall(`-D ${packages.vite}`);
253
+ logger.info("Adding Salty-CSS plugin to Vite config...");
254
+ await writeFile(viteConfigPath, pluginImport + newContent);
255
+ await formatWithPrettier(viteConfigPath);
256
+ }
173
257
  }
174
- const _ = ["next.config.js", "next.config.cjs", "next.config.ts", "next.config.mjs"].map((t) => a(o, t)).find((t) => Q(t));
175
- if (_) {
176
- let t = await S(_, "utf-8").catch(() => {
177
- });
178
- if (t !== void 0 && !t.includes("withSaltyCss")) {
179
- let c = !1;
180
- /\splugins([^=]*)=[^[]\[/.test(t) && !c && (t = t.replace(/\splugins([^=]*)=[^[]\[/, (R, I) => ` plugins${I}= [withSaltyCss,`), c = !0);
181
- const b = t.includes("module.exports"), L = b ? `const { withSaltyCss } = require('@salty-css/next');
182
- ` : `import { withSaltyCss } from '@salty-css/next';
183
- `;
184
- b && !c ? (t = t.replace(/module.exports = ([^;]+)/, (R, I) => `module.exports = withSaltyCss(${I})`), c = !0) : c || (t = t.replace(/export default ([^;]+)/, (R, I) => `export default withSaltyCss(${I})`)), p || await E(`-D ${A.next}`), e.info("Adding Salty-CSS plugin to Next.js config..."), await C(_, L + t), await j(_);
258
+ const nextConfigFiles = ["next.config.js", "next.config.cjs", "next.config.ts", "next.config.mjs"];
259
+ const nextConfigPath = nextConfigFiles.map((file) => join(projectDir, file)).find((path) => existsSync(path));
260
+ if (nextConfigPath) {
261
+ let nextConfigContent = await readFile(nextConfigPath, "utf-8").catch(() => void 0);
262
+ if (nextConfigContent !== void 0) {
263
+ const alreadyHasPlugin = nextConfigContent.includes("withSaltyCss");
264
+ if (!alreadyHasPlugin) {
265
+ let saltyCssAppended = false;
266
+ const hasPluginsArray = /\splugins([^=]*)=[^[]\[/.test(nextConfigContent);
267
+ if (hasPluginsArray && !saltyCssAppended) {
268
+ nextConfigContent = nextConfigContent.replace(/\splugins([^=]*)=[^[]\[/, (_, config) => {
269
+ return ` plugins${config}= [withSaltyCss,`;
270
+ });
271
+ saltyCssAppended = true;
272
+ }
273
+ const useRequire = nextConfigContent.includes("module.exports");
274
+ const pluginImport = useRequire ? "const { withSaltyCss } = require('@salty-css/next');\n" : "import { withSaltyCss } from '@salty-css/next';\n";
275
+ if (useRequire && !saltyCssAppended) {
276
+ nextConfigContent = nextConfigContent.replace(/module.exports = ([^;]+)/, (_, config) => {
277
+ return `module.exports = withSaltyCss(${config})`;
278
+ });
279
+ saltyCssAppended = true;
280
+ } else if (!saltyCssAppended) {
281
+ nextConfigContent = nextConfigContent.replace(/export default ([^;]+)/, (_, config) => {
282
+ return `export default withSaltyCss(${config})`;
283
+ });
284
+ }
285
+ if (!skipInstall) await npmInstall(`-D ${packages.next}`);
286
+ logger.info("Adding Salty-CSS plugin to Next.js config...");
287
+ await writeFile(nextConfigPath, pluginImport + nextConfigContent);
288
+ await formatWithPrettier(nextConfigPath);
289
+ }
290
+ }
291
+ }
292
+ const packageJsonContent = await readPackageJson().catch(() => logError("Could not read package.json file.")).then((content) => {
293
+ if (!content.scripts) content.scripts = {};
294
+ if (content.scripts.prepare) {
295
+ const alreadyHasSaltyCss = content.scripts.prepare.includes("salty-css");
296
+ if (!alreadyHasSaltyCss) {
297
+ logger.info("Edit file: " + defaultPackageJsonPath);
298
+ content.scripts.prepare = content.scripts.prepare + " && npx salty-css build";
299
+ }
300
+ } else {
301
+ logger.info("Edit file: " + defaultPackageJsonPath);
302
+ content.scripts.prepare = "npx salty-css build";
185
303
  }
304
+ return content;
305
+ });
306
+ await updatePackageJson(packageJsonContent);
307
+ logger.info("Running the build to generate initial CSS...");
308
+ await generateCss(projectDir);
309
+ logger.info("🎉 Salty CSS project initialized successfully!");
310
+ logger.info("Next steps:");
311
+ logger.info("1. Configure variables and templates in `salty.config.ts`");
312
+ logger.info("2. Create a new component with `npx salty-css generate [component-name]`");
313
+ logger.info("3. Run `npx salty-css build` to generate the CSS");
314
+ logger.info("4. Read about the features in the documentation: https://salty-css.dev");
315
+ logger.info("5. Star the project on GitHub: https://github.com/margarita-form/salty-css ⭐");
316
+ });
317
+ program.command("build [directory]").alias("b").description("Build the Salty-CSS project.").option("-d, --dir <dir>", "Project directory to build the project in.").option("--watch", "Watch for changes and rebuild the project.").action(async function(_dir = defaultProject) {
318
+ logger.info("Building the Salty-CSS project...");
319
+ const { dir = _dir, watch: watch$1 } = this.opts();
320
+ if (!dir) return logError("Project directory must be provided. Add it as the first argument after build command or use the --dir option.");
321
+ const projectDir = resolveProjectDir(dir);
322
+ await generateCss(projectDir);
323
+ if (watch$1) {
324
+ logger.info("Watching for changes in the project directory...");
325
+ watch(projectDir, { recursive: true }, async (event, filePath) => {
326
+ const shouldRestart = await checkShouldRestart(filePath);
327
+ if (shouldRestart) {
328
+ await generateCss(projectDir, false, false);
329
+ } else {
330
+ const saltyFile = isSaltyFile(filePath);
331
+ if (saltyFile) await generateFile(projectDir, filePath);
332
+ }
333
+ });
186
334
  }
187
- const it = await O().catch(() => h("Could not read package.json file.")).then((t) => (t.scripts || (t.scripts = {}), t.scripts.prepare ? t.scripts.prepare.includes("salty-css") || (e.info("Edit file: " + J), t.scripts.prepare = t.scripts.prepare + " && npx salty-css build") : (e.info("Edit file: " + J), t.scripts.prepare = "npx salty-css build"), t));
188
- await nt(it), e.info("Running the build to generate initial CSS..."), await K(o), e.info("🎉 Salty CSS project initialized successfully!"), e.info("Next steps:"), e.info("1. Configure variables and templates in `salty.config.ts`"), e.info("2. Create a new component with `npx salty-css generate [component-name]`"), e.info("3. Run `npx salty-css build` to generate the CSS"), e.info("4. Read about the features in the documentation: https://salty-css.dev"), e.info("5. Star the project on GitHub: https://github.com/margarita-form/salty-css ⭐");
189
- }), u.command("build [directory]").alias("b").description("Build the Salty-CSS project.").option("-d, --dir <dir>", "Project directory to build the project in.").option("--watch", "Watch for changes and rebuild the project.").action(async function(s = Y) {
190
- e.info("Building the Salty-CSS project...");
191
- const { dir: i = s, watch: d } = this.opts();
192
- if (!i) return h("Project directory must be provided. Add it as the first argument after build command or use the --dir option.");
193
- const l = G(i);
194
- await K(l), d && (e.info("Watching for changes in the project directory..."), rt(l, { recursive: !0 }, async (p, r) => {
195
- await yt(r) ? await K(l, !1, !1) : dt(r) && await ft(l, r);
196
- }));
197
- }), u.command("generate [file] [directory]").alias("g").description("Generate a new component file.").option("-f, --file <file>", "File to generate.").option("-d, --dir <dir>", "Project directory to generate the file in.").option("-t, --tag <tag>", "HTML tag of the component.", "div").option("-n, --name <name>", "Name of the component.").option("-c, --className <className>", "CSS class of the component.").option("-r, --reactComponent", "Generate a React component as well.").action(async function(s, i = Y) {
198
- const { file: d = s, dir: l = i, tag: p, name: r, className: o, reactComponent: T = !1 } = this.opts();
199
- if (!d) return h("File to generate must be provided. Add it as the first argument after generate command or use the --file option.");
200
- if (!l) return h("Project directory must be provided. Add it as the second argument after generate command or use the --dir option.");
201
- const y = G(l), w = d.split("/").slice(0, -1).join("/");
202
- w && await q(a(y, w), { recursive: !0 });
203
- const m = a(y, d), f = ct(m);
204
- f.ext || (f.ext = ".ts"), f.name.endsWith(".css") || (f.name = f.name + ".css"), f.base = f.name + f.ext;
205
- const P = et(f);
206
- if (await S(P, "utf-8").catch(() => {
207
- }) !== void 0) {
208
- e.error("File already exists:", P);
335
+ });
336
+ program.command("generate [file] [directory]").alias("g").description("Generate a new component file.").option("-f, --file <file>", "File to generate.").option("-d, --dir <dir>", "Project directory to generate the file in.").option("-t, --tag <tag>", "HTML tag of the component.", "div").option("-n, --name <name>", "Name of the component.").option("-c, --className <className>", "CSS class of the component.").option("-r, --reactComponent", "Generate a React component as well.").action(async function(_file, _dir = defaultProject) {
337
+ const { file = _file, dir = _dir, tag, name, className, reactComponent = false } = this.opts();
338
+ if (!file) return logError("File to generate must be provided. Add it as the first argument after generate command or use the --file option.");
339
+ if (!dir) return logError("Project directory must be provided. Add it as the second argument after generate command or use the --dir option.");
340
+ const projectDir = resolveProjectDir(dir);
341
+ const additionalFolders = file.split("/").slice(0, -1).join("/");
342
+ if (additionalFolders) await mkdir(join(projectDir, additionalFolders), { recursive: true });
343
+ const filePath = join(projectDir, file);
344
+ const parsedFilePath = parse(filePath);
345
+ if (!parsedFilePath.ext) {
346
+ parsedFilePath.ext = ".ts";
347
+ }
348
+ if (!parsedFilePath.name.endsWith(".css")) {
349
+ parsedFilePath.name = parsedFilePath.name + ".css";
350
+ }
351
+ parsedFilePath.base = parsedFilePath.name + parsedFilePath.ext;
352
+ const formattedStyledFilePath = format(parsedFilePath);
353
+ const alreadyExists = await readFile(formattedStyledFilePath, "utf-8").catch(() => void 0);
354
+ if (alreadyExists !== void 0) {
355
+ logger.error("File already exists:", formattedStyledFilePath);
209
356
  return;
210
357
  }
211
- let F = pt(r || f.base.replace(/\.css\.\w+$/, ""));
212
- if (T) {
213
- const B = F + "Component";
214
- F = F + "Wrapper";
215
- const U = f.base.replace(/\.css\.\w+$/, ""), { content: tt } = await k("react/react-vanilla-file.ts", { tag: p, componentName: B, styledComponentName: F, className: o, fileName: U });
216
- f.name = U.replace(/\.css$/, ""), f.ext = ".tsx", f.base = f.name + f.ext;
217
- const D = et(f);
218
- e.info("Generating a new file: " + D), await C(D, tt), await j(D);
358
+ let styledComponentName = pascalCase(name || parsedFilePath.base.replace(/\.css\.\w+$/, ""));
359
+ if (reactComponent) {
360
+ const componentName = styledComponentName + "Component";
361
+ styledComponentName = styledComponentName + "Wrapper";
362
+ const fileName = parsedFilePath.base.replace(/\.css\.\w+$/, "");
363
+ const { content: reactContent } = await readTemplate("react/react-vanilla-file.ts", { tag, componentName, styledComponentName, className, fileName });
364
+ parsedFilePath.name = fileName.replace(/\.css$/, "");
365
+ parsedFilePath.ext = ".tsx";
366
+ parsedFilePath.base = parsedFilePath.name + parsedFilePath.ext;
367
+ const formattedReactFilePath = format(parsedFilePath);
368
+ logger.info("Generating a new file: " + formattedReactFilePath);
369
+ await writeFile(formattedReactFilePath, reactContent);
370
+ await formatWithPrettier(formattedReactFilePath);
219
371
  }
220
- const { content: M } = await k("react/react-styled-file.ts", { tag: p, name: F, className: o });
221
- e.info("Generating a new file: " + P), await C(P, M), await j(P);
372
+ const { content } = await readTemplate("react/react-styled-file.ts", { tag, name: styledComponentName, className });
373
+ logger.info("Generating a new file: " + formattedStyledFilePath);
374
+ await writeFile(formattedStyledFilePath, content);
375
+ await formatWithPrettier(formattedStyledFilePath);
222
376
  });
223
- const Z = async () => {
224
- const s = a(process.cwd(), "package.json"), i = await O(s).catch((p) => h(p));
225
- if (!i) return h("Could not read package.json file.");
226
- const d = { ...i.dependencies, ...i.devDependencies }, l = Object.entries(d).filter(([p]) => p === "salty-css" || p.startsWith("@salty-css/"));
227
- return l.length ? l : h(
228
- "No Salty-CSS packages found in package.json. Make sure you are running update command in the same directory! Used package.json path: " + s
229
- );
377
+ const getSaltyCssPackages = async () => {
378
+ const packageJSONPath = join(process.cwd(), "package.json");
379
+ const packageJson = await readPackageJson(packageJSONPath).catch((err) => logError(err));
380
+ if (!packageJson) return logError("Could not read package.json file.");
381
+ const allDependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
382
+ const saltyCssPackages = Object.entries(allDependencies).filter(([name]) => name === "salty-css" || name.startsWith("@salty-css/"));
383
+ if (!saltyCssPackages.length) {
384
+ return logError(
385
+ "No Salty-CSS packages found in package.json. Make sure you are running update command in the same directory! Used package.json path: " + packageJSONPath
386
+ );
387
+ }
388
+ return saltyCssPackages;
230
389
  };
231
- u.command("update [version]").alias("up").description("Update Salty-CSS packages to the latest or specified version.").option("-v, --version <version>", "Version to update to.").option("--legacy-peer-deps <legacyPeerDeps>", "Use legacy peer dependencies (not recommended).", !1).action(async function(s = "latest") {
232
- const { legacyPeerDeps: i, version: d = s } = this.opts(), l = await Z();
233
- if (!l) return h("Could not update Salty-CSS packages as any were found in package.json.");
234
- const p = l.map(([y]) => d === "@" ? `${y}@${N.version}` : `${y}@${d.replace(/^@/, "")}`);
235
- i ? (e.warn("Using legacy peer dependencies to update packages."), await E(...p, "--legacy-peer-deps")) : await E(...p);
236
- const r = await Z();
237
- if (!r) return h("Something went wrong while reading the updated packages.");
238
- const o = r.reduce((y, [w, m]) => (y[m] || (y[m] = []), y[m].push(w), y), {});
239
- if (Object.keys(o).length === 1) {
240
- const w = Object.keys(o)[0].replace(/^\^/, "");
241
- e.info(`Updated to all Salty CSS packages successfully to ${w}`);
242
- } else
243
- for (const [y, w] of Object.entries(o)) {
244
- const m = y.replace(/^\^/, "");
245
- e.info(`Updated to ${m}: ${w.join(", ")}`);
390
+ program.command("update [version]").alias("up").description("Update Salty-CSS packages to the latest or specified version.").option("-v, --version <version>", "Version to update to.").option("--legacy-peer-deps <legacyPeerDeps>", "Use legacy peer dependencies (not recommended).", false).action(async function(_version = "latest") {
391
+ const { legacyPeerDeps, version = _version } = this.opts();
392
+ const saltyCssPackages = await getSaltyCssPackages();
393
+ if (!saltyCssPackages) return logError("Could not update Salty-CSS packages as any were found in package.json.");
394
+ const packagesToUpdate = saltyCssPackages.map(([name]) => {
395
+ if (version === "@") return `${name}@${currentPackageJson.version}`;
396
+ return `${name}@${version.replace(/^@/, "")}`;
397
+ });
398
+ if (legacyPeerDeps) {
399
+ logger.warn("Using legacy peer dependencies to update packages.");
400
+ await npmInstall(...packagesToUpdate, "--legacy-peer-deps");
401
+ } else {
402
+ await npmInstall(...packagesToUpdate);
403
+ }
404
+ const updatedPackages = await getSaltyCssPackages();
405
+ if (!updatedPackages) return logError("Something went wrong while reading the updated packages.");
406
+ const mappedByVersions = updatedPackages.reduce((acc, [name, version2]) => {
407
+ if (!acc[version2]) acc[version2] = [];
408
+ acc[version2].push(name);
409
+ return acc;
410
+ }, {});
411
+ const versionsCount = Object.keys(mappedByVersions).length;
412
+ if (versionsCount === 1) {
413
+ const version2 = Object.keys(mappedByVersions)[0];
414
+ const versionString = version2.replace(/^\^/, "");
415
+ logger.info(`Updated to all Salty CSS packages successfully to ${versionString}`);
416
+ } else {
417
+ for (const [version2, names] of Object.entries(mappedByVersions)) {
418
+ const versionString = version2.replace(/^\^/, "");
419
+ logger.info(`Updated to ${versionString}: ${names.join(", ")}`);
246
420
  }
247
- }), u.option("-v, --version", "Show the current version of Salty-CSS.").action(async function() {
248
- const s = await X();
249
- e.info("CLI is running: " + s.version);
250
- const i = a(process.cwd(), "package.json"), d = await O(i).catch((r) => h(r));
251
- if (!d) return;
252
- const l = { ...d.dependencies, ...d.devDependencies }, p = Object.keys(l).filter((r) => r === "salty-css" || r.startsWith("@salty-css/"));
253
- if (!p.length)
254
- return h(
255
- "No Salty-CSS packages found in package.json. Make sure you are running update command in the same directory! Used package.json path: " + i
421
+ }
422
+ });
423
+ program.option("-v, --version", "Show the current version of Salty-CSS.").action(async function() {
424
+ const currentPackageJson2 = await readThisPackageJson();
425
+ logger.info("CLI is running: " + currentPackageJson2.version);
426
+ const packageJSONPath = join(process.cwd(), "package.json");
427
+ const packageJson = await readPackageJson(packageJSONPath).catch((err) => logError(err));
428
+ if (!packageJson) return;
429
+ const allDependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
430
+ const saltyCssPackages = Object.keys(allDependencies).filter((dep) => dep === "salty-css" || dep.startsWith("@salty-css/"));
431
+ if (!saltyCssPackages.length) {
432
+ return logError(
433
+ "No Salty-CSS packages found in package.json. Make sure you are running update command in the same directory! Used package.json path: " + packageJSONPath
256
434
  );
257
- for (const r of p)
258
- e.info(`${r}: ${l[r]}`);
259
- }), u.parseAsync(process.argv);
435
+ }
436
+ for (const dep of saltyCssPackages) {
437
+ logger.info(`${dep}: ${allDependencies[dep]}`);
438
+ }
439
+ });
440
+ program.parseAsync(process.argv);
260
441
  }
261
442
  export {
262
- Jt as main
443
+ main
263
444
  };