@salty-css/core 0.1.0-alpha.9 → 0.1.0-feat-define-import.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.
- package/README.md +44 -0
- package/bin/confirm-install.d.ts +34 -0
- package/bin/context.d.ts +3 -0
- package/bin/integrations/index.d.ts +11 -3
- package/bin/integrations/types.d.ts +14 -2
- package/bin/main.cjs +149 -48
- package/bin/main.js +149 -48
- package/{class-name-generator-YeSQe_Ik.js → class-name-generator-CMWY5KTJ.js} +1 -1
- package/{class-name-generator-B2Pb2obX.cjs → class-name-generator-DB5aQwC_.cjs} +1 -1
- package/compiler/resolve-import.d.ts +17 -0
- package/compiler/salty-compiler.cjs +85 -26
- package/compiler/salty-compiler.d.ts +7 -1
- package/compiler/salty-compiler.js +86 -26
- package/config/index.cjs +2 -0
- package/config/index.js +3 -1
- package/css/dynamic-styles.cjs +1 -1
- package/css/dynamic-styles.js +1 -1
- package/css/keyframes.cjs +1 -1
- package/css/keyframes.js +1 -1
- package/factories/define-import.d.ts +14 -0
- package/factories/index.cjs +19 -0
- package/factories/index.d.ts +1 -0
- package/factories/index.js +19 -0
- package/generators/index.cjs +1 -1
- package/generators/index.js +2 -2
- package/instances/classname-instance.cjs +1 -1
- package/instances/classname-instance.js +1 -1
- package/package.json +1 -1
- package/{parse-styles-CA3TP5n1.cjs → parse-styles-C54MOrPg.cjs} +106 -7
- package/{parse-styles-BTIoYnBr.js → parse-styles-CLMTHo2H.js} +107 -8
- package/parsers/index.cjs +2 -1
- package/parsers/index.d.ts +1 -0
- package/parsers/index.js +4 -3
- package/parsers/parser-regexes.d.ts +3 -0
- package/parsers/strict.d.ts +2 -0
- package/runtime/index.cjs +1 -1
- package/runtime/index.js +1 -1
- package/{salty.config-cqavVm2t.cjs → salty.config-DogY_sSQ.cjs} +1 -1
- package/salty.config-GV37Q-D2.js +4 -0
- package/types/config-types.d.ts +9 -0
- 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-
|
|
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
|
-
|
|
390
|
+
plan: async (ctx, configPath) => {
|
|
340
391
|
const existing = await readFile(configPath, "utf-8").catch(() => void 0);
|
|
341
|
-
if (existing === void 0) return
|
|
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
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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
|
-
|
|
512
|
+
plan: async (ctx, configPath) => {
|
|
452
513
|
const existing = await readFile(configPath, "utf-8").catch(() => void 0);
|
|
453
|
-
if (existing === void 0) return
|
|
514
|
+
if (existing === void 0) return null;
|
|
454
515
|
const { content } = editNextConfig(existing);
|
|
455
|
-
if (content === null) return
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
-
|
|
543
|
+
plan: async (ctx, configPath) => {
|
|
479
544
|
const existing = await readFile(configPath, "utf-8").catch(() => void 0);
|
|
480
|
-
if (existing === void 0) return
|
|
545
|
+
if (existing === void 0) return null;
|
|
481
546
|
const { content } = editViteConfig(existing);
|
|
482
|
-
if (content === null) return
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
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
|
|
493
|
-
const
|
|
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
|
|
498
|
-
|
|
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
|
-
|
|
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
|
|
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-
|
|
4
|
+
import { p as parseAndJoinStyles } from "./parse-styles-CLMTHo2H.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-
|
|
5
|
+
const parseStyles = require("./parse-styles-C54MOrPg.cjs");
|
|
6
6
|
const dashCase = require("./dash-case-DIwKaYgE.cjs");
|
|
7
7
|
const toHash = require("./to-hash-C05Y906F.cjs");
|
|
8
8
|
class StylesGenerator {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ImportSpec } from '../factories/define-import';
|
|
2
|
+
export interface ResolveImportOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Override for node_modules resolution. Receives the bare specifier (with any leading `~` already
|
|
5
|
+
* stripped) and the source file path of the salty file that called `defineImport`. Must return the
|
|
6
|
+
* absolute filesystem path of the resolved CSS file. Defaults to `createRequire(sourceFile).resolve`.
|
|
7
|
+
*/
|
|
8
|
+
resolveModule?: (specifier: string, sourceFile: string) => string;
|
|
9
|
+
/**
|
|
10
|
+
* Override for copying resolved node_modules CSS into `<destDir>/imports/`. Receives the absolute
|
|
11
|
+
* source and destination paths. Defaults to `copyFileSync`.
|
|
12
|
+
*/
|
|
13
|
+
copyAsset?: (from: string, to: string) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare const resolveImport: (spec: ImportSpec, sourceFile: string, destDir: string, options?: ResolveImportOptions) => {
|
|
16
|
+
rule: string;
|
|
17
|
+
};
|
|
@@ -11,14 +11,14 @@ const fs = require("fs");
|
|
|
11
11
|
const child_process = require("child_process");
|
|
12
12
|
const compiler_helpers = require("./helpers.cjs");
|
|
13
13
|
const defineTemplates = require("../define-templates-Deq1aCbN.cjs");
|
|
14
|
-
const
|
|
14
|
+
const module$1 = require("module");
|
|
15
15
|
const toHash = require("../to-hash-C05Y906F.cjs");
|
|
16
|
-
const
|
|
16
|
+
const dashCase = require("../dash-case-DIwKaYgE.cjs");
|
|
17
|
+
const parseStyles = require("../parse-styles-C54MOrPg.cjs");
|
|
17
18
|
const css_merge = require("../css/merge.cjs");
|
|
18
19
|
const parsers_index = require("../parsers/index.cjs");
|
|
19
|
-
const
|
|
20
|
+
const moduleType = require("../util/module-type");
|
|
20
21
|
const console = require("console");
|
|
21
|
-
var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
|
|
22
22
|
function _interopNamespaceDefault(e) {
|
|
23
23
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
24
24
|
if (e) {
|
|
@@ -44,19 +44,53 @@ const logger = winston.createLogger({
|
|
|
44
44
|
const logError = (message) => {
|
|
45
45
|
logger.error(message);
|
|
46
46
|
};
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
return
|
|
47
|
+
const EXTERNAL_URL = /^(?:[a-z][a-z0-9+.-]*:)?\/\//i;
|
|
48
|
+
const normaliseSpec = (spec) => {
|
|
49
|
+
if (typeof spec === "string") return { url: spec };
|
|
50
|
+
return spec;
|
|
51
|
+
};
|
|
52
|
+
const ensureRelativePrefix = (path2) => {
|
|
53
|
+
if (path2.startsWith(".") || path2.startsWith("/")) return path2;
|
|
54
|
+
return `./${path2}`;
|
|
55
|
+
};
|
|
56
|
+
const toPosix = (path2) => path2.split("\\").join("/");
|
|
57
|
+
const defaultResolveModule = (specifier, sourceFile) => {
|
|
58
|
+
return module$1.createRequire(sourceFile).resolve(specifier);
|
|
51
59
|
};
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
const defaultCopyAsset = (from, to) => {
|
|
61
|
+
const dir = path.dirname(to);
|
|
62
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
63
|
+
fs.copyFileSync(from, to);
|
|
64
|
+
};
|
|
65
|
+
const buildRule = (url, { media, supports }) => {
|
|
66
|
+
let rule = `@import url('${url}')`;
|
|
67
|
+
if (supports) rule += ` supports(${supports})`;
|
|
68
|
+
if (media) rule += ` ${media}`;
|
|
69
|
+
return `${rule};`;
|
|
70
|
+
};
|
|
71
|
+
const resolveImport = (spec, sourceFile, destDir, options = {}) => {
|
|
72
|
+
const opts = normaliseSpec(spec);
|
|
73
|
+
const { url } = opts;
|
|
74
|
+
const resolveModule = options.resolveModule ?? defaultResolveModule;
|
|
75
|
+
const copyAsset = options.copyAsset ?? defaultCopyAsset;
|
|
76
|
+
if (EXTERNAL_URL.test(url)) {
|
|
77
|
+
return { rule: buildRule(url, opts) };
|
|
78
|
+
}
|
|
79
|
+
if (url.startsWith("/")) {
|
|
80
|
+
return { rule: buildRule(url, opts) };
|
|
81
|
+
}
|
|
82
|
+
if (url.startsWith("./") || url.startsWith("../")) {
|
|
83
|
+
const absolute2 = path.resolve(path.dirname(sourceFile), url);
|
|
84
|
+
const fromImportsFile = path.relative(path.join(destDir, "css"), absolute2);
|
|
85
|
+
return { rule: buildRule(ensureRelativePrefix(toPosix(fromImportsFile)), opts) };
|
|
86
|
+
}
|
|
87
|
+
const specifier = url.startsWith("~") ? url.slice(1) : url;
|
|
88
|
+
const absolute = resolveModule(specifier, sourceFile);
|
|
89
|
+
const hash = toHash.toHash(absolute, 6);
|
|
90
|
+
const fileName = `${hash}-${path.basename(absolute)}`;
|
|
91
|
+
const destPath = path.join(destDir, "imports", fileName);
|
|
92
|
+
copyAsset(absolute, destPath);
|
|
93
|
+
return { rule: buildRule(`../imports/${fileName}`, opts) };
|
|
60
94
|
};
|
|
61
95
|
function dotCase(str) {
|
|
62
96
|
if (!str) return "";
|
|
@@ -111,7 +145,7 @@ const saltyReset = {
|
|
|
111
145
|
}
|
|
112
146
|
};
|
|
113
147
|
class SaltyCompiler {
|
|
114
|
-
constructor(projectRootDir) {
|
|
148
|
+
constructor(projectRootDir, options = {}) {
|
|
115
149
|
__publicField(this, "importFile", (path2) => {
|
|
116
150
|
const now = Date.now();
|
|
117
151
|
return import(
|
|
@@ -173,7 +207,7 @@ class SaltyCompiler {
|
|
|
173
207
|
const destDir = await this.getDestDir();
|
|
174
208
|
const coreConfigPath = path.join(this.projectRootDir, (rcProject == null ? void 0 : rcProject.configDir) || "", "salty.config.ts");
|
|
175
209
|
const coreConfigDest = path.join(destDir, "salty.config.js");
|
|
176
|
-
const moduleType = await detectCurrentModuleType(this.projectRootDir);
|
|
210
|
+
const moduleType$1 = await moduleType.detectCurrentModuleType(this.projectRootDir);
|
|
177
211
|
const externalModules = this.getExternalModules(coreConfigPath);
|
|
178
212
|
await esbuild__namespace.build({
|
|
179
213
|
entryPoints: [coreConfigPath],
|
|
@@ -181,7 +215,7 @@ class SaltyCompiler {
|
|
|
181
215
|
treeShaking: true,
|
|
182
216
|
bundle: true,
|
|
183
217
|
outfile: coreConfigDest,
|
|
184
|
-
format: moduleType,
|
|
218
|
+
format: moduleType$1,
|
|
185
219
|
external: externalModules
|
|
186
220
|
});
|
|
187
221
|
const { config } = await this.importFile(coreConfigDest);
|
|
@@ -233,6 +267,7 @@ ${currentFile}`;
|
|
|
233
267
|
fs.mkdirSync(path.join(destDir, "types"));
|
|
234
268
|
fs.mkdirSync(path.join(destDir, "js"));
|
|
235
269
|
fs.mkdirSync(path.join(destDir, "cache"));
|
|
270
|
+
fs.mkdirSync(path.join(destDir, "imports"));
|
|
236
271
|
};
|
|
237
272
|
if (clean) clearDistDir();
|
|
238
273
|
const files = /* @__PURE__ */ new Set();
|
|
@@ -348,7 +383,7 @@ ${currentFile}`;
|
|
|
348
383
|
});
|
|
349
384
|
}
|
|
350
385
|
const otherGlobalCssFiles = globalCssFiles.map((file) => `@import url('./css/${file}');`).join("\n");
|
|
351
|
-
const globalCssFilenames = ["_variables.css", "_reset.css", "_global.css", "_templates.css"];
|
|
386
|
+
const globalCssFilenames = ["_imports.css", "_variables.css", "_reset.css", "_global.css", "_templates.css"];
|
|
352
387
|
const importsWithData = globalCssFilenames.filter((file) => {
|
|
353
388
|
try {
|
|
354
389
|
const data = fs.readFileSync(path.join(destDir, "css", file), "utf8");
|
|
@@ -357,9 +392,12 @@ ${currentFile}`;
|
|
|
357
392
|
return false;
|
|
358
393
|
}
|
|
359
394
|
});
|
|
360
|
-
const globalImports = importsWithData.map((file) =>
|
|
395
|
+
const globalImports = importsWithData.map((file) => {
|
|
396
|
+
const layerSuffix = file === "_imports.css" ? " layer(imports)" : "";
|
|
397
|
+
return `@import url('./css/${file}')${layerSuffix};`;
|
|
398
|
+
});
|
|
361
399
|
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;
|
|
400
|
+
let cssContent = `${generatorText}@layer imports, reset, global, templates, l0, l1, l2, l3, l4, l5, l6, l7, l8;
|
|
363
401
|
|
|
364
402
|
${globalImports.join(
|
|
365
403
|
"\n"
|
|
@@ -405,7 +443,8 @@ ${css}
|
|
|
405
443
|
mediaQueries: [],
|
|
406
444
|
globalStyles: [],
|
|
407
445
|
variables: [],
|
|
408
|
-
templates: []
|
|
446
|
+
templates: [],
|
|
447
|
+
imports: []
|
|
409
448
|
};
|
|
410
449
|
await Promise.all(
|
|
411
450
|
[...configFiles].map(async (src) => {
|
|
@@ -415,6 +454,7 @@ ${css}
|
|
|
415
454
|
else if (value.isGlobalDefine) generationResults.globalStyles.push(value);
|
|
416
455
|
else if (value.isDefineVariables) generationResults.variables.push(value);
|
|
417
456
|
else if (value.isDefineTemplates) generationResults.templates.push(value._setPath(`${name};;${outputFilePath}`));
|
|
457
|
+
else if (value.isDefineImport) generationResults.imports.push(value._setPath(src));
|
|
418
458
|
});
|
|
419
459
|
})
|
|
420
460
|
);
|
|
@@ -513,6 +553,22 @@ ${css}
|
|
|
513
553
|
const templateTokens = parsers_index.getTemplateTypes(templates);
|
|
514
554
|
fs.writeFileSync(templateStylesPath, `@layer templates { ${templateStylesString} }`);
|
|
515
555
|
configCacheContent.templates = templates;
|
|
556
|
+
const importsPath = path.join(destDir, "css/_imports.css");
|
|
557
|
+
const importRules = [];
|
|
558
|
+
for (const factory of generationResults.imports) {
|
|
559
|
+
const sourceFile = factory._path;
|
|
560
|
+
if (!sourceFile) continue;
|
|
561
|
+
for (const spec of factory._current) {
|
|
562
|
+
try {
|
|
563
|
+
const { rule } = resolveImport(spec, sourceFile, destDir);
|
|
564
|
+
importRules.push(rule);
|
|
565
|
+
} catch (e) {
|
|
566
|
+
const url = typeof spec === "string" ? spec : spec.url;
|
|
567
|
+
logger.error(`Failed to resolve defineImport(${JSON.stringify(url)}) from ${sourceFile}: ${e.message}`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
fs.writeFileSync(importsPath, importRules.join("\n"));
|
|
516
572
|
const configTemplateFactories = config.templates ? [defineTemplates.defineTemplates(config.templates)._setPath(`config;;${configPath}`)] : [];
|
|
517
573
|
const templateFactories = css_merge.mergeFactories(generationResults.templates, configTemplateFactories);
|
|
518
574
|
configCacheContent.templatePaths = Object.fromEntries(Object.entries(templateFactories).map(([key, faktory]) => [key, faktory._path]));
|
|
@@ -546,11 +602,12 @@ ${css}
|
|
|
546
602
|
let currentFile = fs.readFileSync(sourceFilePath, "utf8");
|
|
547
603
|
currentFile = this.replaceStyledTag(currentFile);
|
|
548
604
|
currentFile = this.addConfigCache(currentFile);
|
|
549
|
-
const
|
|
605
|
+
const currentFileHash = toHash.toHash(currentFile);
|
|
606
|
+
const outputFilePath = path.join(outputDirectory, "js", `${hashedName}-${currentFileHash}.js`);
|
|
550
607
|
const rcProject = await this.getRCProjectConfig(this.projectRootDir);
|
|
551
608
|
const coreConfigPath = path.join(this.projectRootDir, (rcProject == null ? void 0 : rcProject.configDir) || "", "salty.config.ts");
|
|
552
609
|
const externalModules = this.getExternalModules(coreConfigPath);
|
|
553
|
-
const moduleType = await detectCurrentModuleType(this.projectRootDir);
|
|
610
|
+
const moduleType$1 = await moduleType.detectCurrentModuleType(this.projectRootDir);
|
|
554
611
|
await esbuild__namespace.build({
|
|
555
612
|
stdin: {
|
|
556
613
|
contents: currentFile,
|
|
@@ -562,7 +619,7 @@ ${css}
|
|
|
562
619
|
treeShaking: true,
|
|
563
620
|
bundle: true,
|
|
564
621
|
outfile: outputFilePath,
|
|
565
|
-
format: moduleType,
|
|
622
|
+
format: moduleType$1,
|
|
566
623
|
target: ["node20"],
|
|
567
624
|
keepNames: true,
|
|
568
625
|
external: externalModules,
|
|
@@ -690,11 +747,13 @@ ${newContent}
|
|
|
690
747
|
});
|
|
691
748
|
});
|
|
692
749
|
this.projectRootDir = projectRootDir;
|
|
750
|
+
this.options = options;
|
|
693
751
|
if (typeof process === "undefined") {
|
|
694
752
|
throw new Error("SaltyServer can only be used in a Node.js environment.");
|
|
695
753
|
}
|
|
696
754
|
}
|
|
697
755
|
get isProduction() {
|
|
756
|
+
if (this.options.mode) return this.options.mode === "production";
|
|
698
757
|
try {
|
|
699
758
|
return process.env["NODE_ENV"] !== "development";
|
|
700
759
|
} 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
|
+
isDefineImport?: boolean;
|
|
42
48
|
isKeyframes?: boolean;
|
|
43
49
|
animationName?: string;
|
|
44
50
|
css?: Promise<string>;
|