@salty-css/core 0.1.0-alpha.8 → 0.1.0-feat-define-font.0

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 (41) hide show
  1. package/README.md +83 -0
  2. package/bin/confirm-install.d.ts +34 -0
  3. package/bin/context.d.ts +3 -0
  4. package/bin/integrations/index.d.ts +11 -3
  5. package/bin/integrations/types.d.ts +14 -2
  6. package/bin/main.cjs +149 -48
  7. package/bin/main.js +149 -48
  8. package/{class-name-generator-YeSQe_Ik.js → class-name-generator-B2LriwKm.js} +1 -1
  9. package/{class-name-generator-B2Pb2obX.cjs → class-name-generator-BIYysuhW.cjs} +1 -1
  10. package/compiler/salty-compiler.cjs +28 -7
  11. package/compiler/salty-compiler.d.ts +7 -1
  12. package/compiler/salty-compiler.js +28 -7
  13. package/config/index.cjs +2 -0
  14. package/config/index.js +3 -1
  15. package/css/dynamic-styles.cjs +1 -1
  16. package/css/dynamic-styles.js +1 -1
  17. package/css/keyframes.cjs +1 -1
  18. package/css/keyframes.js +1 -1
  19. package/factories/define-font.d.ts +28 -0
  20. package/factories/index.cjs +125 -0
  21. package/factories/index.d.ts +1 -0
  22. package/factories/index.js +125 -0
  23. package/generators/index.cjs +1 -1
  24. package/generators/index.js +2 -2
  25. package/instances/classname-instance.cjs +1 -1
  26. package/instances/classname-instance.js +1 -1
  27. package/package.json +1 -1
  28. package/{parse-styles-BTIoYnBr.js → parse-styles--vHKY6Mw.js} +108 -8
  29. package/{parse-styles-CA3TP5n1.cjs → parse-styles-jPtMfgXH.cjs} +107 -7
  30. package/parsers/index.cjs +2 -1
  31. package/parsers/index.d.ts +1 -0
  32. package/parsers/index.js +4 -3
  33. package/parsers/parser-regexes.d.ts +3 -0
  34. package/parsers/strict.d.ts +2 -0
  35. package/runtime/index.cjs +1 -1
  36. package/runtime/index.js +1 -1
  37. package/{salty.config-cqavVm2t.cjs → salty.config-DogY_sSQ.cjs} +1 -1
  38. package/salty.config-GV37Q-D2.js +4 -0
  39. package/types/config-types.d.ts +10 -1
  40. package/types/font-types.d.ts +53 -0
  41. package/salty.config-DjosWdPw.js +0 -4
package/bin/main.js CHANGED
@@ -9,6 +9,7 @@ import { exec } from "child_process";
9
9
  import ora from "ora";
10
10
  import { p as pascalCase } from "../pascal-case-F3Usi5Wf.js";
11
11
  import ejs from "ejs";
12
+ import { createInterface } from "readline/promises";
12
13
  const defaultPackageJsonPath = join(process.cwd(), "package.json");
13
14
  const readPackageJson = async (filePath = defaultPackageJsonPath) => {
14
15
  const content = await readFile(filePath, "utf-8").then(JSON.parse).catch(() => void 0);
@@ -138,17 +139,21 @@ const buildContext = async (opts) => {
138
139
  packageJson,
139
140
  rcFile,
140
141
  cliVersion: cliPackageJson.version || "0.0.0",
141
- skipInstall: !!opts.skipInstall
142
+ skipInstall: !!opts.skipInstall,
143
+ yes: !!opts.yes
142
144
  };
143
145
  };
144
146
  const registerBuildCommand = (program, defaultProject) => {
145
- 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) {
147
+ 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.").option("--mode <mode>", 'Build mode: "production" or "development". Defaults to NODE_ENV-based detection.').action(async function(_dir = defaultProject) {
146
148
  logger.info("Building the Salty-CSS project...");
147
- const { dir = _dir, watch: watch$1 } = this.opts();
149
+ const { dir = _dir, watch: watch$1, mode } = this.opts();
150
+ if (mode !== void 0 && mode !== "production" && mode !== "development") {
151
+ return logError(`Invalid --mode "${mode}". Expected "production" or "development".`);
152
+ }
148
153
  const resolved = dir ?? await getDefaultProject();
149
154
  if (!resolved) return logError("Project directory must be provided. Add it as the first argument after build command or use the --dir option.");
150
155
  const projectDir = resolveProjectDir(resolved);
151
- const compiler = new SaltyCompiler(projectDir);
156
+ const compiler = new SaltyCompiler(projectDir, { mode });
152
157
  await compiler.generateCss();
153
158
  if (watch$1) {
154
159
  logger.info("Watching for changes in the project directory...");
@@ -222,7 +227,7 @@ const getFramework = (name) => {
222
227
  return frameworksByName[name];
223
228
  };
224
229
  const templateLoaders = {
225
- "salty.config.ts": () => import("../salty.config-DjosWdPw.js"),
230
+ "salty.config.ts": () => import("../salty.config-GV37Q-D2.js"),
226
231
  "saltygen/index.css": () => import("../index-DKz1QXqs.js"),
227
232
  "react/styled-file.ts": () => import("../styled-file-Cda3EeR6.js"),
228
233
  "react/vanilla-file.ts": () => import("../vanilla-file-1kOqbCIM.js"),
@@ -290,6 +295,52 @@ const registerGenerateCommand = (program, defaultProject) => {
290
295
  await formatWithPrettier(formattedStyledFilePath);
291
296
  });
292
297
  };
298
+ const formatPackageForDisplay = (spec) => {
299
+ const trimmed = spec.trim();
300
+ if (trimmed.startsWith("-D ")) return `${trimmed.slice(3).trim()} (dev)`;
301
+ return trimmed;
302
+ };
303
+ const renderPackageList = (packages) => {
304
+ return packages.map((p) => ` + ${formatPackageForDisplay(p)}`).join("\n");
305
+ };
306
+ const confirmInstall = async (packages, yes, options = {}) => {
307
+ if (yes) return;
308
+ if (packages.length === 0) return;
309
+ const input = options.input ?? process.stdin;
310
+ const output = options.output ?? process.stdout;
311
+ const isTTY = options.isTTY ?? process.stdin.isTTY ?? false;
312
+ if (!isTTY) {
313
+ throw new Error("Cannot prompt for install confirmation: stdin is not a TTY. Re-run with --yes to install the listed packages without prompting.");
314
+ }
315
+ output.write(`The following packages will be installed:
316
+ ${renderPackageList(packages)}
317
+ `);
318
+ const rl = createInterface({ input, output, terminal: false });
319
+ try {
320
+ const answer = (await rl.question("Proceed? (y/N) ")).trim().toLowerCase();
321
+ if (answer !== "y" && answer !== "yes") {
322
+ throw new Error("Install cancelled by user.");
323
+ }
324
+ } finally {
325
+ rl.close();
326
+ }
327
+ };
328
+ const confirmYesNo = async (question, options = {}) => {
329
+ if (options.yes) return true;
330
+ const input = options.input ?? process.stdin;
331
+ const output = options.output ?? process.stdout;
332
+ const isTTY = options.isTTY ?? process.stdin.isTTY ?? false;
333
+ if (!isTTY) return false;
334
+ const suffix = options.defaultYes ? "(Y/n)" : "(y/N)";
335
+ const rl = createInterface({ input, output, terminal: false });
336
+ try {
337
+ const answer = (await rl.question(`${question} ${suffix} `)).trim().toLowerCase();
338
+ if (answer === "") return !!options.defaultYes;
339
+ return answer === "y" || answer === "yes";
340
+ } finally {
341
+ rl.close();
342
+ }
343
+ };
293
344
  const CSS_FILE_FOLDERS = ["src", "public", "assets", "styles", "css", "app"];
294
345
  const CSS_SECOND_LEVEL_FOLDERS = ["styles", "css", "app", "pages"];
295
346
  const CSS_FILE_NAMES = ["index", "styles", "main", "app", "global", "globals"];
@@ -336,17 +387,22 @@ const editAstroConfig = (existing) => {
336
387
  const astroIntegration = {
337
388
  name: "astro",
338
389
  detect: (ctx) => findAstroConfig(ctx.projectDir),
339
- apply: async (ctx, configPath) => {
390
+ plan: async (ctx, configPath) => {
340
391
  const existing = await readFile(configPath, "utf-8").catch(() => void 0);
341
- if (existing === void 0) return { changed: false };
392
+ if (existing === void 0) return null;
342
393
  const result = editAstroConfig(existing);
343
394
  if (result.warning) logger.warn(result.warning);
344
- if (result.content === null) return { changed: false };
345
- if (!ctx.skipInstall) await npmInstall(`-D ${astroPackage(ctx.cliVersion)}`);
346
- logger.info("Adding Salty-CSS integration to Astro config: " + configPath);
347
- await writeFile(configPath, result.content);
348
- await formatWithPrettier(configPath);
349
- return { changed: true };
395
+ if (result.content === null) return null;
396
+ const newContent = result.content;
397
+ return {
398
+ packages: [`-D ${astroPackage(ctx.cliVersion)}`],
399
+ execute: async () => {
400
+ logger.info("Adding Salty-CSS integration to Astro config: " + configPath);
401
+ await writeFile(configPath, newContent);
402
+ await formatWithPrettier(configPath);
403
+ return { changed: true };
404
+ }
405
+ };
350
406
  }
351
407
  };
352
408
  const ESLINT_CONFIG_CANDIDATES = [
@@ -405,20 +461,25 @@ const eslintIntegration = {
405
461
  const candidates = eslintConfigCandidates(ctx.projectDir, ctx.cwd);
406
462
  return candidates.find((p) => existsSync(p)) ?? null;
407
463
  },
408
- apply: async (ctx, configPath) => {
464
+ plan: async (ctx, configPath) => {
409
465
  const existing = await readFile(configPath, "utf-8").catch(() => void 0);
410
466
  if (existing === void 0) {
411
467
  logger.error("Could not read ESLint config file.");
412
- return { changed: false };
468
+ return null;
413
469
  }
414
- if (!ctx.skipInstall) await npmInstall(corePackages.eslintConfigCore(ctx.cliVersion));
415
470
  const result = editEslintConfig(existing, configPath.endsWith("js"));
416
471
  if (result.warning) logger.warn(result.warning);
417
- if (result.content === null) return { changed: false };
418
- logger.info("Edit file: " + configPath);
419
- await writeFile(configPath, result.content);
420
- await formatWithPrettier(configPath);
421
- return { changed: true };
472
+ if (result.content === null) return null;
473
+ const newContent = result.content;
474
+ return {
475
+ packages: [corePackages.eslintConfigCore(ctx.cliVersion)],
476
+ execute: async () => {
477
+ logger.info("Edit file: " + configPath);
478
+ await writeFile(configPath, newContent);
479
+ await formatWithPrettier(configPath);
480
+ return { changed: true };
481
+ }
482
+ };
422
483
  }
423
484
  };
424
485
  const nextConfigFiles = ["next.config.js", "next.config.cjs", "next.config.ts", "next.config.mjs"];
@@ -448,16 +509,20 @@ const nextIntegration = {
448
509
  const found = nextConfigFiles.map((file) => join(ctx.projectDir, file)).find((p) => existsSync(p));
449
510
  return found ?? null;
450
511
  },
451
- apply: async (ctx, configPath) => {
512
+ plan: async (ctx, configPath) => {
452
513
  const existing = await readFile(configPath, "utf-8").catch(() => void 0);
453
- if (existing === void 0) return { changed: false };
514
+ if (existing === void 0) return null;
454
515
  const { content } = editNextConfig(existing);
455
- if (content === null) return { changed: false };
456
- if (!ctx.skipInstall) await npmInstall(`-D ${nextPackage(ctx.cliVersion)}`);
457
- logger.info("Adding Salty-CSS plugin to Next.js config...");
458
- await writeFile(configPath, content);
459
- await formatWithPrettier(configPath);
460
- return { changed: true };
516
+ if (content === null) return null;
517
+ return {
518
+ packages: [`-D ${nextPackage(ctx.cliVersion)}`],
519
+ execute: async () => {
520
+ logger.info("Adding Salty-CSS plugin to Next.js config...");
521
+ await writeFile(configPath, content);
522
+ await formatWithPrettier(configPath);
523
+ return { changed: true };
524
+ }
525
+ };
461
526
  }
462
527
  };
463
528
  const vitePackage = (version) => `@salty-css/vite@${version}`;
@@ -475,27 +540,40 @@ const viteIntegration = {
475
540
  const path = join(ctx.projectDir, "vite.config.ts");
476
541
  return existsSync(path) ? path : null;
477
542
  },
478
- apply: async (ctx, configPath) => {
543
+ plan: async (ctx, configPath) => {
479
544
  const existing = await readFile(configPath, "utf-8").catch(() => void 0);
480
- if (existing === void 0) return { changed: false };
545
+ if (existing === void 0) return null;
481
546
  const { content } = editViteConfig(existing);
482
- if (content === null) return { changed: false };
483
- logger.info("Edit file: " + configPath);
484
- if (!ctx.skipInstall) await npmInstall(`-D ${vitePackage(ctx.cliVersion)}`);
485
- logger.info("Adding Salty-CSS plugin to Vite config...");
486
- await writeFile(configPath, content);
487
- await formatWithPrettier(configPath);
488
- return { changed: true };
547
+ if (content === null) return null;
548
+ return {
549
+ packages: [`-D ${vitePackage(ctx.cliVersion)}`],
550
+ execute: async () => {
551
+ logger.info("Edit file: " + configPath);
552
+ logger.info("Adding Salty-CSS plugin to Vite config...");
553
+ await writeFile(configPath, content);
554
+ await formatWithPrettier(configPath);
555
+ return { changed: true };
556
+ }
557
+ };
489
558
  }
490
559
  };
491
560
  const buildIntegrationRegistry = [eslintIntegration, viteIntegration, nextIntegration, astroIntegration];
492
- const detectAndApplyIntegrations = async (ctx) => {
493
- const results = [];
561
+ const planIntegrations = async (ctx) => {
562
+ const planned = [];
494
563
  for (const integration of buildIntegrationRegistry) {
495
564
  const configPath = await integration.detect(ctx);
496
565
  if (!configPath) continue;
497
- const result = await integration.apply(ctx, configPath);
498
- results.push({ name: integration.name, configPath, changed: result.changed });
566
+ const plan = await integration.plan(ctx, configPath);
567
+ if (!plan) continue;
568
+ planned.push({ name: integration.name, configPath, plan });
569
+ }
570
+ return planned;
571
+ };
572
+ const applyIntegrationPlans = async (planned) => {
573
+ const results = [];
574
+ for (const { name, configPath, plan } of planned) {
575
+ const result = await plan.execute();
576
+ results.push({ name, configPath, changed: result.changed });
499
577
  }
500
578
  return results;
501
579
  };
@@ -546,17 +624,24 @@ const wirePrepareScript = async () => {
546
624
  await updatePackageJson(next);
547
625
  };
548
626
  const registerInitCommand = (program) => {
549
- 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 = ".") {
627
+ 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.").option("-y, --yes", "Skip the install confirmation prompt.").action(async function(_dir = ".") {
550
628
  try {
551
629
  const opts = this.opts();
552
630
  const dir = opts.dir ?? _dir;
553
631
  if (!dir) return logError("Project directory must be provided. Add it as the first argument after init command or use the --dir option.");
554
- const ctx = await buildContext({ dir, skipInstall: opts.skipInstall });
632
+ const ctx = await buildContext({ dir, skipInstall: opts.skipInstall, yes: opts.yes });
555
633
  logger.info("Initializing a new Salty-CSS project!");
556
634
  const framework = await detectFramework(ctx);
557
635
  logger.info(`Detected framework: ${framework.name}`);
636
+ const plannedIntegrations = await planIntegrations(ctx);
558
637
  if (!ctx.skipInstall) {
559
- await npmInstall(corePackages.core(ctx.cliVersion), framework.runtimePackage(ctx.cliVersion));
638
+ const packages = [
639
+ corePackages.core(ctx.cliVersion),
640
+ framework.runtimePackage(ctx.cliVersion),
641
+ ...plannedIntegrations.flatMap((p) => p.plan.packages)
642
+ ];
643
+ await confirmInstall(packages, ctx.yes);
644
+ await npmInstall(...packages);
560
645
  }
561
646
  const projectFiles = await Promise.all([readTemplate("salty.config.ts"), readTemplate("saltygen/index.css")]);
562
647
  await mkdir(ctx.projectDir, { recursive: true });
@@ -564,7 +649,7 @@ const registerInitCommand = (program) => {
564
649
  await writeProjectToRc(ctx.cwd, ctx.relativeProjectPath, framework);
565
650
  await ensureGitignoreSaltygen(ctx.cwd);
566
651
  await importSaltygenIntoCss(ctx.projectDir, opts.cssFile);
567
- await detectAndApplyIntegrations(ctx);
652
+ await applyIntegrationPlans(plannedIntegrations);
568
653
  await wirePrepareScript();
569
654
  logger.info("Running the build to generate initial CSS...");
570
655
  const compiler = new SaltyCompiler(ctx.projectDir);
@@ -595,8 +680,8 @@ const getSaltyCssPackages = async () => {
595
680
  return saltyCssPackages;
596
681
  };
597
682
  const registerUpdateCommand = (program) => {
598
- 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") {
599
- const { legacyPeerDeps, version = _version } = this.opts();
683
+ 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).option("-y, --yes", "Skip confirmation prompts (install and rebuild).").option("-d, --dir <dir>", "Project directory to rebuild after updating.").action(async function(_version = "latest") {
684
+ const { legacyPeerDeps, version = _version, yes = false, dir } = this.opts();
600
685
  const saltyCssPackages = await getSaltyCssPackages();
601
686
  if (!saltyCssPackages) return logError("Could not update Salty-CSS packages as any were found in package.json.");
602
687
  const cli = await readThisPackageJson();
@@ -604,6 +689,11 @@ const registerUpdateCommand = (program) => {
604
689
  if (version === "@") return `${name}@${cli.version}`;
605
690
  return `${name}@${version.replace(/^@/, "")}`;
606
691
  });
692
+ try {
693
+ await confirmInstall(packagesToUpdate, yes);
694
+ } catch (err) {
695
+ return logError(err instanceof Error ? err.message : String(err));
696
+ }
607
697
  if (legacyPeerDeps) {
608
698
  logger.warn("Using legacy peer dependencies to update packages.");
609
699
  await npmInstall(...packagesToUpdate, "--legacy-peer-deps");
@@ -626,6 +716,17 @@ const registerUpdateCommand = (program) => {
626
716
  logger.info(`Updated to ${v.replace(/^\^/, "")}: ${names.join(", ")}`);
627
717
  }
628
718
  }
719
+ const project = dir ?? await getDefaultProject();
720
+ if (!project) {
721
+ logger.warn("Skipping rebuild: no project directory configured. Run `salty-css build [dir]` manually.");
722
+ return;
723
+ }
724
+ const shouldRebuild = await confirmYesNo("Rebuild Salty CSS now?", { yes });
725
+ if (!shouldRebuild) return;
726
+ const projectDir = resolveProjectDir(project);
727
+ logger.info("Rebuilding Salty-CSS project...");
728
+ await new SaltyCompiler(projectDir).generateCss();
729
+ logger.info("Rebuild complete.");
629
730
  });
630
731
  };
631
732
  const registerVersionOption = (program) => {
@@ -1,7 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { p as parseAndJoinStyles } from "./parse-styles-BTIoYnBr.js";
4
+ import { p as parseAndJoinStyles } from "./parse-styles--vHKY6Mw.js";
5
5
  import { d as dashCase } from "./dash-case-DblXvymC.js";
6
6
  import { t as toHash } from "./to-hash-DAN2LcHK.js";
7
7
  class StylesGenerator {
@@ -2,7 +2,7 @@
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
- const parseStyles = require("./parse-styles-CA3TP5n1.cjs");
5
+ const parseStyles = require("./parse-styles-jPtMfgXH.cjs");
6
6
  const dashCase = require("./dash-case-DIwKaYgE.cjs");
7
7
  const toHash = require("./to-hash-C05Y906F.cjs");
8
8
  class StylesGenerator {
@@ -10,10 +10,10 @@ const promises = require("fs/promises");
10
10
  const fs = require("fs");
11
11
  const child_process = require("child_process");
12
12
  const compiler_helpers = require("./helpers.cjs");
13
- const defineTemplates = require("../define-templates-Deq1aCbN.cjs");
14
13
  const dashCase = require("../dash-case-DIwKaYgE.cjs");
15
14
  const toHash = require("../to-hash-C05Y906F.cjs");
16
- const parseStyles = require("../parse-styles-CA3TP5n1.cjs");
15
+ const defineTemplates = require("../define-templates-Deq1aCbN.cjs");
16
+ const parseStyles = require("../parse-styles-jPtMfgXH.cjs");
17
17
  const css_merge = require("../css/merge.cjs");
18
18
  const parsers_index = require("../parsers/index.cjs");
19
19
  const compiler_getFiles = require("./get-files.cjs");
@@ -111,7 +111,7 @@ const saltyReset = {
111
111
  }
112
112
  };
113
113
  class SaltyCompiler {
114
- constructor(projectRootDir) {
114
+ constructor(projectRootDir, options = {}) {
115
115
  __publicField(this, "importFile", (path2) => {
116
116
  const now = Date.now();
117
117
  return import(
@@ -348,7 +348,7 @@ ${currentFile}`;
348
348
  });
349
349
  }
350
350
  const otherGlobalCssFiles = globalCssFiles.map((file) => `@import url('./css/${file}');`).join("\n");
351
- const globalCssFilenames = ["_variables.css", "_reset.css", "_global.css", "_templates.css"];
351
+ const globalCssFilenames = ["_variables.css", "_reset.css", "_global.css", "_templates.css", "_fonts.css"];
352
352
  const importsWithData = globalCssFilenames.filter((file) => {
353
353
  try {
354
354
  const data = fs.readFileSync(path.join(destDir, "css", file), "utf8");
@@ -359,7 +359,7 @@ ${currentFile}`;
359
359
  });
360
360
  const globalImports = importsWithData.map((file) => `@import url('./css/${file}');`);
361
361
  const generatorText = "/*!\n * Generated with Salty CSS (https://salty-css.dev)\n * Do not edit this file directly\n */\n";
362
- let cssContent = `${generatorText}@layer reset, global, templates, l0, l1, l2, l3, l4, l5, l6, l7, l8;
362
+ let cssContent = `${generatorText}@layer reset, global, templates, fonts, l0, l1, l2, l3, l4, l5, l6, l7, l8;
363
363
 
364
364
  ${globalImports.join(
365
365
  "\n"
@@ -405,7 +405,8 @@ ${css}
405
405
  mediaQueries: [],
406
406
  globalStyles: [],
407
407
  variables: [],
408
- templates: []
408
+ templates: [],
409
+ fonts: []
409
410
  };
410
411
  await Promise.all(
411
412
  [...configFiles].map(async (src) => {
@@ -415,6 +416,7 @@ ${css}
415
416
  else if (value.isGlobalDefine) generationResults.globalStyles.push(value);
416
417
  else if (value.isDefineVariables) generationResults.variables.push(value);
417
418
  else if (value.isDefineTemplates) generationResults.templates.push(value._setPath(`${name};;${outputFilePath}`));
419
+ else if (value.isDefineFont) generationResults.fonts.push(value);
418
420
  });
419
421
  })
420
422
  );
@@ -516,6 +518,22 @@ ${css}
516
518
  const configTemplateFactories = config.templates ? [defineTemplates.defineTemplates(config.templates)._setPath(`config;;${configPath}`)] : [];
517
519
  const templateFactories = css_merge.mergeFactories(generationResults.templates, configTemplateFactories);
518
520
  configCacheContent.templatePaths = Object.fromEntries(Object.entries(templateFactories).map(([key, faktory]) => [key, faktory._path]));
521
+ const fontsStylesPath = path.join(destDir, "css/_fonts.css");
522
+ if (generationResults.fonts.length === 0) {
523
+ fs.writeFileSync(fontsStylesPath, "");
524
+ } else {
525
+ const fontImports = [];
526
+ const fontBodies = [];
527
+ for (const font of generationResults.fonts) {
528
+ const { imports, body } = font._toCss();
529
+ fontImports.push(...imports);
530
+ fontBodies.push(body);
531
+ }
532
+ const importBlock = fontImports.length ? `${fontImports.join("\n")}
533
+
534
+ ` : "";
535
+ fs.writeFileSync(fontsStylesPath, `${importBlock}@layer fonts { ${fontBodies.join(" ")} }`);
536
+ }
519
537
  const tsTokensPath = path.join(destDir, "types/css-tokens.d.ts");
520
538
  const tsVariableTokens = [...variableTokens].join("|");
521
539
  const tsTokensTypes = `
@@ -546,7 +564,8 @@ ${css}
546
564
  let currentFile = fs.readFileSync(sourceFilePath, "utf8");
547
565
  currentFile = this.replaceStyledTag(currentFile);
548
566
  currentFile = this.addConfigCache(currentFile);
549
- const outputFilePath = path.join(outputDirectory, "js", hashedName + ".js");
567
+ const currentFileHash = toHash.toHash(currentFile);
568
+ const outputFilePath = path.join(outputDirectory, "js", `${hashedName}-${currentFileHash}.js`);
550
569
  const rcProject = await this.getRCProjectConfig(this.projectRootDir);
551
570
  const coreConfigPath = path.join(this.projectRootDir, (rcProject == null ? void 0 : rcProject.configDir) || "", "salty.config.ts");
552
571
  const externalModules = this.getExternalModules(coreConfigPath);
@@ -690,11 +709,13 @@ ${newContent}
690
709
  });
691
710
  });
692
711
  this.projectRootDir = projectRootDir;
712
+ this.options = options;
693
713
  if (typeof process === "undefined") {
694
714
  throw new Error("SaltyServer can only be used in a Node.js environment.");
695
715
  }
696
716
  }
697
717
  get isProduction() {
718
+ if (this.options.mode) return this.options.mode === "production";
698
719
  try {
699
720
  return process.env["NODE_ENV"] !== "development";
700
721
  } catch {
@@ -1,9 +1,14 @@
1
1
  import { CachedConfig, SaltyConfig } from '../config';
2
+ export type SaltyCompilerMode = 'production' | 'development';
3
+ export interface SaltyCompilerOptions {
4
+ mode?: SaltyCompilerMode;
5
+ }
2
6
  export declare class SaltyCompiler {
3
7
  projectRootDir: string;
8
+ private options;
4
9
  importFile: (path: string) => Promise<any>;
5
10
  private cache;
6
- constructor(projectRootDir: string);
11
+ constructor(projectRootDir: string, options?: SaltyCompilerOptions);
7
12
  get isProduction(): boolean;
8
13
  /**
9
14
  * Locate and read the .saltyrc.json file starting from the current directory and moving up the directory tree.
@@ -39,6 +44,7 @@ export declare class SaltyCompiler {
39
44
  isGlobalDefine?: boolean;
40
45
  isDefineVariables?: boolean;
41
46
  isDefineTemplates?: boolean;
47
+ isDefineFont?: boolean;
42
48
  isKeyframes?: boolean;
43
49
  animationName?: string;
44
50
  css?: Promise<string>;
@@ -8,10 +8,10 @@ import { readFile } from "fs/promises";
8
8
  import { readFileSync, existsSync, mkdirSync, statSync, readdirSync, writeFileSync } from "fs";
9
9
  import { execSync } from "child_process";
10
10
  import { isSaltyFile, resolveExportValue, getCorePackageRoot, saltyFileExtensions } from "./helpers.js";
11
- import { d as defineTemplates } from "../define-templates-CVhhgPnd.js";
12
11
  import { d as dashCase } from "../dash-case-DblXvymC.js";
13
12
  import { t as toHash } from "../to-hash-DAN2LcHK.js";
14
- import { p as parseAndJoinStyles, b as parseVariableTokens } from "../parse-styles-BTIoYnBr.js";
13
+ import { d as defineTemplates } from "../define-templates-CVhhgPnd.js";
14
+ import { p as parseAndJoinStyles, b as parseVariableTokens } from "../parse-styles--vHKY6Mw.js";
15
15
  import { mergeObjects, mergeFactories } from "../css/merge.js";
16
16
  import { parseTemplates, getTemplateTypes } from "../parsers/index.js";
17
17
  import { getPackageJson } from "./get-files.js";
@@ -91,7 +91,7 @@ const saltyReset = {
91
91
  }
92
92
  };
93
93
  class SaltyCompiler {
94
- constructor(projectRootDir) {
94
+ constructor(projectRootDir, options = {}) {
95
95
  __publicField(this, "importFile", (path) => {
96
96
  const now = Date.now();
97
97
  return import(
@@ -328,7 +328,7 @@ ${currentFile}`;
328
328
  });
329
329
  }
330
330
  const otherGlobalCssFiles = globalCssFiles.map((file) => `@import url('./css/${file}');`).join("\n");
331
- const globalCssFilenames = ["_variables.css", "_reset.css", "_global.css", "_templates.css"];
331
+ const globalCssFilenames = ["_variables.css", "_reset.css", "_global.css", "_templates.css", "_fonts.css"];
332
332
  const importsWithData = globalCssFilenames.filter((file) => {
333
333
  try {
334
334
  const data = readFileSync(join(destDir, "css", file), "utf8");
@@ -339,7 +339,7 @@ ${currentFile}`;
339
339
  });
340
340
  const globalImports = importsWithData.map((file) => `@import url('./css/${file}');`);
341
341
  const generatorText = "/*!\n * Generated with Salty CSS (https://salty-css.dev)\n * Do not edit this file directly\n */\n";
342
- let cssContent = `${generatorText}@layer reset, global, templates, l0, l1, l2, l3, l4, l5, l6, l7, l8;
342
+ let cssContent = `${generatorText}@layer reset, global, templates, fonts, l0, l1, l2, l3, l4, l5, l6, l7, l8;
343
343
 
344
344
  ${globalImports.join(
345
345
  "\n"
@@ -385,7 +385,8 @@ ${css}
385
385
  mediaQueries: [],
386
386
  globalStyles: [],
387
387
  variables: [],
388
- templates: []
388
+ templates: [],
389
+ fonts: []
389
390
  };
390
391
  await Promise.all(
391
392
  [...configFiles].map(async (src) => {
@@ -395,6 +396,7 @@ ${css}
395
396
  else if (value.isGlobalDefine) generationResults.globalStyles.push(value);
396
397
  else if (value.isDefineVariables) generationResults.variables.push(value);
397
398
  else if (value.isDefineTemplates) generationResults.templates.push(value._setPath(`${name};;${outputFilePath}`));
399
+ else if (value.isDefineFont) generationResults.fonts.push(value);
398
400
  });
399
401
  })
400
402
  );
@@ -496,6 +498,22 @@ ${css}
496
498
  const configTemplateFactories = config.templates ? [defineTemplates(config.templates)._setPath(`config;;${configPath}`)] : [];
497
499
  const templateFactories = mergeFactories(generationResults.templates, configTemplateFactories);
498
500
  configCacheContent.templatePaths = Object.fromEntries(Object.entries(templateFactories).map(([key, faktory]) => [key, faktory._path]));
501
+ const fontsStylesPath = join(destDir, "css/_fonts.css");
502
+ if (generationResults.fonts.length === 0) {
503
+ writeFileSync(fontsStylesPath, "");
504
+ } else {
505
+ const fontImports = [];
506
+ const fontBodies = [];
507
+ for (const font of generationResults.fonts) {
508
+ const { imports, body } = font._toCss();
509
+ fontImports.push(...imports);
510
+ fontBodies.push(body);
511
+ }
512
+ const importBlock = fontImports.length ? `${fontImports.join("\n")}
513
+
514
+ ` : "";
515
+ writeFileSync(fontsStylesPath, `${importBlock}@layer fonts { ${fontBodies.join(" ")} }`);
516
+ }
499
517
  const tsTokensPath = join(destDir, "types/css-tokens.d.ts");
500
518
  const tsVariableTokens = [...variableTokens].join("|");
501
519
  const tsTokensTypes = `
@@ -526,7 +544,8 @@ ${css}
526
544
  let currentFile = readFileSync(sourceFilePath, "utf8");
527
545
  currentFile = this.replaceStyledTag(currentFile);
528
546
  currentFile = this.addConfigCache(currentFile);
529
- const outputFilePath = join(outputDirectory, "js", hashedName + ".js");
547
+ const currentFileHash = toHash(currentFile);
548
+ const outputFilePath = join(outputDirectory, "js", `${hashedName}-${currentFileHash}.js`);
530
549
  const rcProject = await this.getRCProjectConfig(this.projectRootDir);
531
550
  const coreConfigPath = join(this.projectRootDir, (rcProject == null ? void 0 : rcProject.configDir) || "", "salty.config.ts");
532
551
  const externalModules = this.getExternalModules(coreConfigPath);
@@ -670,11 +689,13 @@ ${newContent}
670
689
  });
671
690
  });
672
691
  this.projectRootDir = projectRootDir;
692
+ this.options = options;
673
693
  if (typeof process === "undefined") {
674
694
  throw new Error("SaltyServer can only be used in a Node.js environment.");
675
695
  }
676
696
  }
677
697
  get isProduction() {
698
+ if (this.options.mode) return this.options.mode === "production";
678
699
  try {
679
700
  return process.env["NODE_ENV"] !== "development";
680
701
  } catch {
package/config/index.cjs CHANGED
@@ -5,8 +5,10 @@ const defineTemplates = require("../define-templates-Deq1aCbN.cjs");
5
5
  const defineConfig = (config) => {
6
6
  return config;
7
7
  };
8
+ exports.FontFactory = factories_index.FontFactory;
8
9
  exports.GlobalStylesFactory = factories_index.GlobalStylesFactory;
9
10
  exports.VariablesFactory = factories_index.VariablesFactory;
11
+ exports.defineFont = factories_index.defineFont;
10
12
  exports.defineGlobalStyles = factories_index.defineGlobalStyles;
11
13
  exports.defineMediaQuery = factories_index.defineMediaQuery;
12
14
  exports.defineVariables = factories_index.defineVariables;
package/config/index.js CHANGED
@@ -1,14 +1,16 @@
1
- import { GlobalStylesFactory, VariablesFactory, defineGlobalStyles, defineMediaQuery, defineVariables } from "../factories/index.js";
1
+ import { FontFactory, GlobalStylesFactory, VariablesFactory, defineFont, defineGlobalStyles, defineMediaQuery, defineVariables } from "../factories/index.js";
2
2
  import { T, a, d } from "../define-templates-CVhhgPnd.js";
3
3
  const defineConfig = (config) => {
4
4
  return config;
5
5
  };
6
6
  export {
7
+ FontFactory,
7
8
  GlobalStylesFactory,
8
9
  T as TemplateFactory,
9
10
  a as TemplatesFactory,
10
11
  VariablesFactory,
11
12
  defineConfig,
13
+ defineFont,
12
14
  defineGlobalStyles,
13
15
  defineMediaQuery,
14
16
  d as defineTemplates,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const parseStyles = require("../parse-styles-CA3TP5n1.cjs");
3
+ const parseStyles = require("../parse-styles-jPtMfgXH.cjs");
4
4
  const toHash = require("../to-hash-C05Y906F.cjs");
5
5
  const cache_resolveDynamicConfigCache = require("../cache/resolve-dynamic-config-cache.cjs");
6
6
  const getDynamicStylesClassName = (styles) => {
@@ -1,4 +1,4 @@
1
- import { a as parseStyles } from "../parse-styles-BTIoYnBr.js";
1
+ import { a as parseStyles } from "../parse-styles--vHKY6Mw.js";
2
2
  import { t as toHash } from "../to-hash-DAN2LcHK.js";
3
3
  import { resolveDynamicConfigCache } from "../cache/resolve-dynamic-config-cache.js";
4
4
  const getDynamicStylesClassName = (styles) => {
package/css/keyframes.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const parseStyles = require("../parse-styles-CA3TP5n1.cjs");
3
+ const parseStyles = require("../parse-styles-jPtMfgXH.cjs");
4
4
  const toHash = require("../to-hash-C05Y906F.cjs");
5
5
  const keyframes = ({ animationName: _name, params: _params, appendInitialStyles, ...keyframes2 }) => {
6
6
  const modifyKeyframes = async (params = {}) => {
package/css/keyframes.js CHANGED
@@ -1,4 +1,4 @@
1
- import { p as parseAndJoinStyles } from "../parse-styles-BTIoYnBr.js";
1
+ import { p as parseAndJoinStyles } from "../parse-styles--vHKY6Mw.js";
2
2
  import { t as toHash } from "../to-hash-DAN2LcHK.js";
3
3
  const keyframes = ({ animationName: _name, params: _params, appendInitialStyles, ...keyframes2 }) => {
4
4
  const modifyKeyframes = async (params = {}) => {