@salty-css/core 0.1.0-feat-define-font.0 → 0.1.0-refactor-add-additional-paths-to-config-cache.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 +0 -83
- package/bin/main.cjs +58 -57
- package/bin/main.js +2 -1
- package/cache/resolve-dynamic-config-cache.cjs +64 -16
- package/cache/resolve-dynamic-config-cache.d.ts +20 -1
- package/cache/resolve-dynamic-config-cache.js +65 -17
- package/{class-name-generator-B2LriwKm.js → class-name-generator-CMWY5KTJ.js} +1 -1
- package/{class-name-generator-BIYysuhW.cjs → class-name-generator-DB5aQwC_.cjs} +1 -1
- package/compiler/copy-config-cache.cjs +39 -0
- package/compiler/copy-config-cache.d.ts +17 -0
- package/compiler/copy-config-cache.js +39 -0
- package/compiler/salty-compiler.cjs +21 -41
- package/compiler/salty-compiler.d.ts +5 -1
- package/compiler/salty-compiler.js +19 -39
- package/config/index.cjs +0 -2
- package/config/index.js +1 -3
- package/css/dynamic-styles.cjs +21 -8
- package/css/dynamic-styles.d.ts +39 -0
- package/css/dynamic-styles.js +22 -9
- package/css/index.cjs +1 -0
- package/css/index.js +2 -1
- package/css/keyframes.cjs +1 -1
- package/css/keyframes.js +1 -1
- package/factories/index.cjs +0 -125
- package/factories/index.d.ts +0 -1
- package/factories/index.js +0 -125
- 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/logger-7xz0pyAz.cjs +12 -0
- package/logger-hHmCwThj.js +13 -0
- package/package.json +5 -1
- package/{parse-styles-jPtMfgXH.cjs → parse-styles-C54MOrPg.cjs} +0 -1
- package/{parse-styles--vHKY6Mw.js → parse-styles-CLMTHo2H.js} +0 -1
- package/parsers/index.cjs +1 -1
- package/parsers/index.js +2 -2
- package/runtime/index.cjs +1 -1
- package/runtime/index.js +1 -1
- package/types/config-types.d.ts +1 -1
- package/factories/define-font.d.ts +0 -28
- package/types/font-types.d.ts +0 -53
package/README.md
CHANGED
|
@@ -57,7 +57,6 @@ To get help with problems, [Join Salty CSS Discord server](https://discord.gg/R6
|
|
|
57
57
|
- [defineVariables](#variables) - create CSS variables (tokens) that can be used in any styling function
|
|
58
58
|
- [defineMediaQuery](#media-queries) - create CSS media queries and use them in any styling function
|
|
59
59
|
- [defineTemplates](#templates) - create reusable templates that can be applied when same styles are used over and over again
|
|
60
|
-
- [defineFont](#custom-fonts) - register custom fonts via `@font-face` (or a remote stylesheet) and expose them as a CSS variable
|
|
61
60
|
- [keyframes](#keyframes-animations) - create CSS keyframes animation that can be used and imported in any styling function
|
|
62
61
|
|
|
63
62
|
### Styling helpers & utility
|
|
@@ -320,88 +319,6 @@ Example usage:
|
|
|
320
319
|
styled('div', { base: { textStyle: 'headline.large', card: '20px' } });
|
|
321
320
|
```
|
|
322
321
|
|
|
323
|
-
## Custom fonts
|
|
324
|
-
|
|
325
|
-
Register custom fonts that will be emitted as `@font-face` declarations and exposed as a CSS variable. Mirrors the developer experience of Next.js / Astro font loaders, but generated at build time alongside the rest of your Salty CSS output.
|
|
326
|
-
|
|
327
|
-
The returned object stringifies to its `font-family` value and exposes helpers for explicit usage:
|
|
328
|
-
|
|
329
|
-
- `Font.variable` → CSS variable name (e.g. `--font-inter`)
|
|
330
|
-
- `Font.fontFamily` → final `font-family` string with fallbacks
|
|
331
|
-
- `Font.className` → class that sets the variable + applies the font on a subtree
|
|
332
|
-
- `Font.style` → object you can spread on a React `style` prop
|
|
333
|
-
|
|
334
|
-
```ts
|
|
335
|
-
// /styles/fonts.css.ts
|
|
336
|
-
import { defineFont } from '@salty-css/core/factories';
|
|
337
|
-
|
|
338
|
-
// 1. Local or self-hosted @font-face sources.
|
|
339
|
-
// URLs are passed through as-is (use a public-folder path or a CDN URL).
|
|
340
|
-
export const Inter = defineFont({
|
|
341
|
-
name: 'Inter', // CSS font-family value
|
|
342
|
-
variable: '--font-inter', // Optional — accepts 'font-inter' too; if omitted we derive `--font-<name>-<hash>` from the inputs
|
|
343
|
-
display: 'swap', // Optional default applied to variants without their own `display`
|
|
344
|
-
fallback: ['system-ui', 'sans-serif'], // Optional family fallbacks appended after `name`
|
|
345
|
-
variants: [
|
|
346
|
-
{
|
|
347
|
-
weight: 400,
|
|
348
|
-
style: 'normal',
|
|
349
|
-
// Shorthand: pass a string and the `format()` descriptor is auto-detected
|
|
350
|
-
// from the file extension (woff2, woff, ttf, otf, eot, svg, ttc).
|
|
351
|
-
src: '/fonts/inter-400.woff2',
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
weight: 700,
|
|
355
|
-
style: 'normal',
|
|
356
|
-
// Multiple sources can be a string array — first entry is preferred;
|
|
357
|
-
// the browser picks the first format it supports.
|
|
358
|
-
src: ['/fonts/inter-700.woff2', '/fonts/inter-700.ttf'],
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
weight: 400,
|
|
362
|
-
style: 'italic',
|
|
363
|
-
// Use the `{ url, format }` object form when the URL has no recognisable
|
|
364
|
-
// extension (signed CDN URLs, query-only endpoints, etc.). You can also
|
|
365
|
-
// mix strings and objects in the same array.
|
|
366
|
-
src: ['/fonts/inter-400-italic.woff2', { url: 'https://cdn.example.com/inter-italic', format: 'woff' }],
|
|
367
|
-
},
|
|
368
|
-
],
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
// 2. Remote stylesheet (Google Fonts, etc.). Emits `@import url(...)` and still
|
|
372
|
-
// registers the CSS variable so usage stays the same as the @font-face flow.
|
|
373
|
-
export const InterCdn = defineFont({
|
|
374
|
-
name: 'Inter',
|
|
375
|
-
variable: '--font-inter',
|
|
376
|
-
import: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap',
|
|
377
|
-
});
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
Example usage:
|
|
381
|
-
|
|
382
|
-
```tsx
|
|
383
|
-
import { Inter } from './fonts.css';
|
|
384
|
-
import { styled } from '@salty-css/react/styled';
|
|
385
|
-
|
|
386
|
-
// Apply the font globally by attaching its className high up in the tree.
|
|
387
|
-
// This sets `--font-inter` on the subtree and applies `font-family: var(--font-inter)`.
|
|
388
|
-
export const App = ({ children }) => <div className={Inter.className}>{children}</div>;
|
|
389
|
-
|
|
390
|
-
// `Inter` stringifies to its font-family value (with fallbacks), so it can be used directly.
|
|
391
|
-
export const Heading = styled('h1', {
|
|
392
|
-
base: {
|
|
393
|
-
fontFamily: `${Inter}`,
|
|
394
|
-
},
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
// Or reference the CSS variable explicitly.
|
|
398
|
-
export const Body = styled('p', {
|
|
399
|
-
base: {
|
|
400
|
-
fontFamily: `var(${Inter.variable})`,
|
|
401
|
-
},
|
|
402
|
-
});
|
|
403
|
-
```
|
|
404
|
-
|
|
405
322
|
## Keyframes animations
|
|
406
323
|
|
|
407
324
|
```ts
|
package/bin/main.cjs
CHANGED
|
@@ -9,6 +9,7 @@ const path = require("path");
|
|
|
9
9
|
const promises = require("fs/promises");
|
|
10
10
|
const child_process = require("child_process");
|
|
11
11
|
const ora = require("ora");
|
|
12
|
+
const logger = require("../logger-7xz0pyAz.cjs");
|
|
12
13
|
const pascalCase = require("../pascal-case-By_l58S-.cjs");
|
|
13
14
|
const ejs = require("ejs");
|
|
14
15
|
const promises$1 = require("readline/promises");
|
|
@@ -65,9 +66,9 @@ async function formatWithPrettier(filePath) {
|
|
|
65
66
|
const hasPrettier = hasPrettierInstalled();
|
|
66
67
|
if (!hasPrettier) return;
|
|
67
68
|
await execAsync(`./node_modules/.bin/prettier --write "${filePath}"`);
|
|
68
|
-
|
|
69
|
+
logger.logger.info(`Formatted ${filePath} with Prettier`);
|
|
69
70
|
} catch (error) {
|
|
70
|
-
|
|
71
|
+
logger.logger.error(`Error formatting ${filePath} with Prettier:`, error);
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
const SALTYRC_FILENAME = ".saltyrc.json";
|
|
@@ -110,8 +111,8 @@ const writeProjectToRc = async (cwd, relativeProjectPath, framework) => {
|
|
|
110
111
|
const existing = await readRawRc(cwd);
|
|
111
112
|
const { content, changed, created } = upsertProjectInRc(existing, relativeProjectPath, framework);
|
|
112
113
|
if (!changed) return false;
|
|
113
|
-
if (created)
|
|
114
|
-
else
|
|
114
|
+
if (created) logger.logger.info("Creating file: " + path2);
|
|
115
|
+
else logger.logger.info("Edit file: " + path2);
|
|
115
116
|
await promises.writeFile(path2, content);
|
|
116
117
|
await formatWithPrettier(path2);
|
|
117
118
|
return true;
|
|
@@ -148,18 +149,18 @@ const buildContext = async (opts) => {
|
|
|
148
149
|
};
|
|
149
150
|
const registerBuildCommand = (program, defaultProject) => {
|
|
150
151
|
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) {
|
|
151
|
-
|
|
152
|
+
logger.logger.info("Building the Salty-CSS project...");
|
|
152
153
|
const { dir = _dir, watch, mode } = this.opts();
|
|
153
154
|
if (mode !== void 0 && mode !== "production" && mode !== "development") {
|
|
154
|
-
return
|
|
155
|
+
return logger.logError(`Invalid --mode "${mode}". Expected "production" or "development".`);
|
|
155
156
|
}
|
|
156
157
|
const resolved = dir ?? await getDefaultProject();
|
|
157
|
-
if (!resolved) return
|
|
158
|
+
if (!resolved) return logger.logError("Project directory must be provided. Add it as the first argument after build command or use the --dir option.");
|
|
158
159
|
const projectDir = resolveProjectDir(resolved);
|
|
159
160
|
const compiler = new compiler_saltyCompiler.SaltyCompiler(projectDir, { mode });
|
|
160
161
|
await compiler.generateCss();
|
|
161
162
|
if (watch) {
|
|
162
|
-
|
|
163
|
+
logger.logger.info("Watching for changes in the project directory...");
|
|
163
164
|
fs.watch(projectDir, { recursive: true }, async (_event, filePath) => {
|
|
164
165
|
const shouldRestart$1 = await shouldRestart.checkShouldRestart(filePath);
|
|
165
166
|
if (shouldRestart$1) {
|
|
@@ -245,13 +246,13 @@ const readTemplate = async (key, options) => {
|
|
|
245
246
|
const registerGenerateCommand = (program, defaultProject) => {
|
|
246
247
|
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 wrapper component file alongside the styled definition.").action(async function(_file, _dir = defaultProject) {
|
|
247
248
|
const { file = _file, dir = _dir, tag, name, className, reactComponent = false } = this.opts();
|
|
248
|
-
if (!file) return
|
|
249
|
-
if (!dir) return
|
|
249
|
+
if (!file) return logger.logError("File to generate must be provided. Add it as the first argument after generate command or use the --file option.");
|
|
250
|
+
if (!dir) return logger.logError("Project directory must be provided. Add it as the second argument after generate command or use the --dir option.");
|
|
250
251
|
let ctx;
|
|
251
252
|
try {
|
|
252
253
|
ctx = await buildContext({ dir, requirePackageJson: false });
|
|
253
254
|
} catch (err) {
|
|
254
|
-
return
|
|
255
|
+
return logger.logError(err instanceof Error ? err.message : String(err));
|
|
255
256
|
}
|
|
256
257
|
const rcFramework = getFramework(getProjectFramework(ctx.rcFile, ctx.relativeProjectPath));
|
|
257
258
|
const framework = rcFramework ?? await detectFramework(ctx);
|
|
@@ -265,13 +266,13 @@ const registerGenerateCommand = (program, defaultProject) => {
|
|
|
265
266
|
const formattedStyledFilePath = path.format(parsedFilePath);
|
|
266
267
|
const alreadyExists = await promises.readFile(formattedStyledFilePath, "utf-8").catch(() => void 0);
|
|
267
268
|
if (alreadyExists !== void 0) {
|
|
268
|
-
|
|
269
|
+
logger.logger.error("File already exists: " + formattedStyledFilePath);
|
|
269
270
|
return;
|
|
270
271
|
}
|
|
271
272
|
let styledComponentName = pascalCase.pascalCase(name || parsedFilePath.base.replace(/\.css\.\w+$/, ""));
|
|
272
273
|
if (reactComponent) {
|
|
273
274
|
if (!framework.templates.component) {
|
|
274
|
-
return
|
|
275
|
+
return logger.logError(`--reactComponent is not supported for the ${framework.name} framework.`);
|
|
275
276
|
}
|
|
276
277
|
const componentName = styledComponentName + "Component";
|
|
277
278
|
styledComponentName = styledComponentName + "Wrapper";
|
|
@@ -287,13 +288,13 @@ const registerGenerateCommand = (program, defaultProject) => {
|
|
|
287
288
|
parsedFilePath.ext = framework.templates.component.wrapperExt;
|
|
288
289
|
parsedFilePath.base = parsedFilePath.name + parsedFilePath.ext;
|
|
289
290
|
const formattedWrapperPath = path.format(parsedFilePath);
|
|
290
|
-
|
|
291
|
+
logger.logger.info("Generating a new file: " + formattedWrapperPath);
|
|
291
292
|
await promises.writeFile(formattedWrapperPath, wrapperContent);
|
|
292
293
|
await formatWithPrettier(formattedWrapperPath);
|
|
293
294
|
}
|
|
294
295
|
const styledKey = reactComponent && framework.templates.component ? framework.templates.component.styled : framework.templates.styled;
|
|
295
296
|
const { content } = await readTemplate(styledKey, { tag, name: styledComponentName, className });
|
|
296
|
-
|
|
297
|
+
logger.logger.info("Generating a new file: " + formattedStyledFilePath);
|
|
297
298
|
await promises.writeFile(formattedStyledFilePath, content);
|
|
298
299
|
await formatWithPrettier(formattedStyledFilePath);
|
|
299
300
|
});
|
|
@@ -394,13 +395,13 @@ const astroIntegration = {
|
|
|
394
395
|
const existing = await promises.readFile(configPath, "utf-8").catch(() => void 0);
|
|
395
396
|
if (existing === void 0) return null;
|
|
396
397
|
const result = editAstroConfig(existing);
|
|
397
|
-
if (result.warning)
|
|
398
|
+
if (result.warning) logger.logger.warn(result.warning);
|
|
398
399
|
if (result.content === null) return null;
|
|
399
400
|
const newContent = result.content;
|
|
400
401
|
return {
|
|
401
402
|
packages: [`-D ${astroPackage(ctx.cliVersion)}`],
|
|
402
403
|
execute: async () => {
|
|
403
|
-
|
|
404
|
+
logger.logger.info("Adding Salty-CSS integration to Astro config: " + configPath);
|
|
404
405
|
await promises.writeFile(configPath, newContent);
|
|
405
406
|
await formatWithPrettier(configPath);
|
|
406
407
|
return { changed: true };
|
|
@@ -467,17 +468,17 @@ const eslintIntegration = {
|
|
|
467
468
|
plan: async (ctx, configPath) => {
|
|
468
469
|
const existing = await promises.readFile(configPath, "utf-8").catch(() => void 0);
|
|
469
470
|
if (existing === void 0) {
|
|
470
|
-
|
|
471
|
+
logger.logger.error("Could not read ESLint config file.");
|
|
471
472
|
return null;
|
|
472
473
|
}
|
|
473
474
|
const result = editEslintConfig(existing, configPath.endsWith("js"));
|
|
474
|
-
if (result.warning)
|
|
475
|
+
if (result.warning) logger.logger.warn(result.warning);
|
|
475
476
|
if (result.content === null) return null;
|
|
476
477
|
const newContent = result.content;
|
|
477
478
|
return {
|
|
478
479
|
packages: [corePackages.eslintConfigCore(ctx.cliVersion)],
|
|
479
480
|
execute: async () => {
|
|
480
|
-
|
|
481
|
+
logger.logger.info("Edit file: " + configPath);
|
|
481
482
|
await promises.writeFile(configPath, newContent);
|
|
482
483
|
await formatWithPrettier(configPath);
|
|
483
484
|
return { changed: true };
|
|
@@ -520,7 +521,7 @@ const nextIntegration = {
|
|
|
520
521
|
return {
|
|
521
522
|
packages: [`-D ${nextPackage(ctx.cliVersion)}`],
|
|
522
523
|
execute: async () => {
|
|
523
|
-
|
|
524
|
+
logger.logger.info("Adding Salty-CSS plugin to Next.js config...");
|
|
524
525
|
await promises.writeFile(configPath, content);
|
|
525
526
|
await formatWithPrettier(configPath);
|
|
526
527
|
return { changed: true };
|
|
@@ -551,8 +552,8 @@ const viteIntegration = {
|
|
|
551
552
|
return {
|
|
552
553
|
packages: [`-D ${vitePackage(ctx.cliVersion)}`],
|
|
553
554
|
execute: async () => {
|
|
554
|
-
|
|
555
|
-
|
|
555
|
+
logger.logger.info("Edit file: " + configPath);
|
|
556
|
+
logger.logger.info("Adding Salty-CSS plugin to Vite config...");
|
|
556
557
|
await promises.writeFile(configPath, content);
|
|
557
558
|
await formatWithPrettier(configPath);
|
|
558
559
|
return { changed: true };
|
|
@@ -583,12 +584,12 @@ const applyIntegrationPlans = async (planned) => {
|
|
|
583
584
|
const writeProjectFile = async (projectDir, fileName, content) => {
|
|
584
585
|
const filePath = path.join(projectDir, fileName);
|
|
585
586
|
if (fs.existsSync(filePath)) {
|
|
586
|
-
|
|
587
|
+
logger.logger.debug("File already exists: " + filePath);
|
|
587
588
|
return;
|
|
588
589
|
}
|
|
589
590
|
const additionalFolders = fileName.split("/").slice(0, -1).join("/");
|
|
590
591
|
if (additionalFolders) await promises.mkdir(path.join(projectDir, additionalFolders), { recursive: true });
|
|
591
|
-
|
|
592
|
+
logger.logger.info("Creating file: " + filePath);
|
|
592
593
|
await promises.writeFile(filePath, content);
|
|
593
594
|
await formatWithPrettier(filePath);
|
|
594
595
|
};
|
|
@@ -597,13 +598,13 @@ const ensureGitignoreSaltygen = async (rootDir) => {
|
|
|
597
598
|
const existing = await promises.readFile(path$1, "utf-8").catch(() => void 0);
|
|
598
599
|
if (existing === void 0) return;
|
|
599
600
|
if (existing.includes("saltygen")) return;
|
|
600
|
-
|
|
601
|
+
logger.logger.info("Edit file: " + path$1);
|
|
601
602
|
await promises.writeFile(path$1, existing + "\n\n# Salty-CSS\nsaltygen\n");
|
|
602
603
|
};
|
|
603
604
|
const importSaltygenIntoCss = async (projectDir, explicitCssFile) => {
|
|
604
605
|
const target = explicitCssFile ?? await findGlobalCssFile(projectDir);
|
|
605
606
|
if (!target) {
|
|
606
|
-
|
|
607
|
+
logger.logger.warn("Could not find a CSS file to import the generated CSS. Please add it manually.");
|
|
607
608
|
return;
|
|
608
609
|
}
|
|
609
610
|
const cssFilePath = path.join(projectDir, target);
|
|
@@ -612,14 +613,14 @@ const importSaltygenIntoCss = async (projectDir, explicitCssFile) => {
|
|
|
612
613
|
if (cssFileContent.includes("saltygen")) return;
|
|
613
614
|
const cssFileFolder = path.join(cssFilePath, "..");
|
|
614
615
|
const relPath = path.relative(cssFileFolder, path.join(projectDir, "saltygen/index.css"));
|
|
615
|
-
|
|
616
|
+
logger.logger.info("Adding global import statement to CSS file: " + cssFilePath);
|
|
616
617
|
await promises.writeFile(cssFilePath, `@import '${relPath}';
|
|
617
618
|
` + cssFileContent);
|
|
618
619
|
await formatWithPrettier(cssFilePath);
|
|
619
620
|
};
|
|
620
621
|
const wirePrepareScript = async () => {
|
|
621
622
|
const pkg = await readPackageJson().catch(() => {
|
|
622
|
-
|
|
623
|
+
logger.logError("Could not read package.json file.");
|
|
623
624
|
return void 0;
|
|
624
625
|
});
|
|
625
626
|
if (!pkg) return;
|
|
@@ -631,11 +632,11 @@ const registerInitCommand = (program) => {
|
|
|
631
632
|
try {
|
|
632
633
|
const opts = this.opts();
|
|
633
634
|
const dir = opts.dir ?? _dir;
|
|
634
|
-
if (!dir) return
|
|
635
|
+
if (!dir) return logger.logError("Project directory must be provided. Add it as the first argument after init command or use the --dir option.");
|
|
635
636
|
const ctx = await buildContext({ dir, skipInstall: opts.skipInstall, yes: opts.yes });
|
|
636
|
-
|
|
637
|
+
logger.logger.info("Initializing a new Salty-CSS project!");
|
|
637
638
|
const framework = await detectFramework(ctx);
|
|
638
|
-
|
|
639
|
+
logger.logger.info(`Detected framework: ${framework.name}`);
|
|
639
640
|
const plannedIntegrations = await planIntegrations(ctx);
|
|
640
641
|
if (!ctx.skipInstall) {
|
|
641
642
|
const packages = [
|
|
@@ -654,29 +655,29 @@ const registerInitCommand = (program) => {
|
|
|
654
655
|
await importSaltygenIntoCss(ctx.projectDir, opts.cssFile);
|
|
655
656
|
await applyIntegrationPlans(plannedIntegrations);
|
|
656
657
|
await wirePrepareScript();
|
|
657
|
-
|
|
658
|
+
logger.logger.info("Running the build to generate initial CSS...");
|
|
658
659
|
const compiler = new compiler_saltyCompiler.SaltyCompiler(ctx.projectDir);
|
|
659
660
|
await compiler.generateCss();
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
661
|
+
logger.logger.info("🎉 Salty CSS project initialized successfully!");
|
|
662
|
+
logger.logger.info("Next steps:");
|
|
663
|
+
logger.logger.info("1. Configure variables and templates in `salty.config.ts`");
|
|
664
|
+
logger.logger.info("2. Create a new component with `npx salty-css generate [component-name]`");
|
|
665
|
+
logger.logger.info("3. Run `npx salty-css build` to generate the CSS");
|
|
666
|
+
logger.logger.info("4. Read about the features in the documentation: https://salty-css.dev");
|
|
667
|
+
logger.logger.info("5. Star the project on GitHub: https://github.com/margarita-form/salty-css ⭐");
|
|
667
668
|
} catch (err) {
|
|
668
|
-
return
|
|
669
|
+
return logger.logError(err instanceof Error ? err.message : String(err));
|
|
669
670
|
}
|
|
670
671
|
});
|
|
671
672
|
};
|
|
672
673
|
const getSaltyCssPackages = async () => {
|
|
673
674
|
const packageJSONPath = path.join(process.cwd(), "package.json");
|
|
674
|
-
const packageJson = await readPackageJson(packageJSONPath).catch((err) =>
|
|
675
|
-
if (!packageJson) return
|
|
675
|
+
const packageJson = await readPackageJson(packageJSONPath).catch((err) => logger.logError(err));
|
|
676
|
+
if (!packageJson) return logger.logError("Could not read package.json file.");
|
|
676
677
|
const allDependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
677
678
|
const saltyCssPackages = Object.entries(allDependencies).filter(([name]) => name === "salty-css" || name.startsWith("@salty-css/"));
|
|
678
679
|
if (!saltyCssPackages.length) {
|
|
679
|
-
return
|
|
680
|
+
return logger.logError(
|
|
680
681
|
"No Salty-CSS packages found in package.json. Make sure you are running update command in the same directory! Used package.json path: " + packageJSONPath
|
|
681
682
|
);
|
|
682
683
|
}
|
|
@@ -686,7 +687,7 @@ const registerUpdateCommand = (program) => {
|
|
|
686
687
|
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") {
|
|
687
688
|
const { legacyPeerDeps, version = _version, yes = false, dir } = this.opts();
|
|
688
689
|
const saltyCssPackages = await getSaltyCssPackages();
|
|
689
|
-
if (!saltyCssPackages) return
|
|
690
|
+
if (!saltyCssPackages) return logger.logError("Could not update Salty-CSS packages as any were found in package.json.");
|
|
690
691
|
const cli = await readThisPackageJson();
|
|
691
692
|
const packagesToUpdate = saltyCssPackages.map(([name]) => {
|
|
692
693
|
if (version === "@") return `${name}@${cli.version}`;
|
|
@@ -695,16 +696,16 @@ const registerUpdateCommand = (program) => {
|
|
|
695
696
|
try {
|
|
696
697
|
await confirmInstall(packagesToUpdate, yes);
|
|
697
698
|
} catch (err) {
|
|
698
|
-
return
|
|
699
|
+
return logger.logError(err instanceof Error ? err.message : String(err));
|
|
699
700
|
}
|
|
700
701
|
if (legacyPeerDeps) {
|
|
701
|
-
|
|
702
|
+
logger.logger.warn("Using legacy peer dependencies to update packages.");
|
|
702
703
|
await npmInstall(...packagesToUpdate, "--legacy-peer-deps");
|
|
703
704
|
} else {
|
|
704
705
|
await npmInstall(...packagesToUpdate);
|
|
705
706
|
}
|
|
706
707
|
const updatedPackages = await getSaltyCssPackages();
|
|
707
|
-
if (!updatedPackages) return
|
|
708
|
+
if (!updatedPackages) return logger.logError("Something went wrong while reading the updated packages.");
|
|
708
709
|
const mappedByVersions = updatedPackages.reduce((acc, [name, version2]) => {
|
|
709
710
|
if (!acc[version2]) acc[version2] = [];
|
|
710
711
|
acc[version2].push(name);
|
|
@@ -713,41 +714,41 @@ const registerUpdateCommand = (program) => {
|
|
|
713
714
|
const versionsCount = Object.keys(mappedByVersions).length;
|
|
714
715
|
if (versionsCount === 1) {
|
|
715
716
|
const v = Object.keys(mappedByVersions)[0];
|
|
716
|
-
|
|
717
|
+
logger.logger.info(`Updated to all Salty CSS packages successfully to ${v.replace(/^\^/, "")}`);
|
|
717
718
|
} else {
|
|
718
719
|
for (const [v, names] of Object.entries(mappedByVersions)) {
|
|
719
|
-
|
|
720
|
+
logger.logger.info(`Updated to ${v.replace(/^\^/, "")}: ${names.join(", ")}`);
|
|
720
721
|
}
|
|
721
722
|
}
|
|
722
723
|
const project = dir ?? await getDefaultProject();
|
|
723
724
|
if (!project) {
|
|
724
|
-
|
|
725
|
+
logger.logger.warn("Skipping rebuild: no project directory configured. Run `salty-css build [dir]` manually.");
|
|
725
726
|
return;
|
|
726
727
|
}
|
|
727
728
|
const shouldRebuild = await confirmYesNo("Rebuild Salty CSS now?", { yes });
|
|
728
729
|
if (!shouldRebuild) return;
|
|
729
730
|
const projectDir = resolveProjectDir(project);
|
|
730
|
-
|
|
731
|
+
logger.logger.info("Rebuilding Salty-CSS project...");
|
|
731
732
|
await new compiler_saltyCompiler.SaltyCompiler(projectDir).generateCss();
|
|
732
|
-
|
|
733
|
+
logger.logger.info("Rebuild complete.");
|
|
733
734
|
});
|
|
734
735
|
};
|
|
735
736
|
const registerVersionOption = (program) => {
|
|
736
737
|
program.option("-v, --version", "Show the current version of Salty-CSS.").action(async function() {
|
|
737
738
|
const cli = await readThisPackageJson();
|
|
738
|
-
|
|
739
|
+
logger.logger.info("CLI is running: " + cli.version);
|
|
739
740
|
const packageJSONPath = path.join(process.cwd(), "package.json");
|
|
740
|
-
const packageJson = await readPackageJson(packageJSONPath).catch((err) =>
|
|
741
|
+
const packageJson = await readPackageJson(packageJSONPath).catch((err) => logger.logError(err));
|
|
741
742
|
if (!packageJson) return;
|
|
742
743
|
const allDependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
743
744
|
const saltyCssPackages = Object.keys(allDependencies).filter((dep) => dep === "salty-css" || dep.startsWith("@salty-css/"));
|
|
744
745
|
if (!saltyCssPackages.length) {
|
|
745
|
-
return
|
|
746
|
+
return logger.logError(
|
|
746
747
|
"No Salty-CSS packages found in package.json. Make sure you are running update command in the same directory! Used package.json path: " + packageJSONPath
|
|
747
748
|
);
|
|
748
749
|
}
|
|
749
750
|
for (const dep of saltyCssPackages) {
|
|
750
|
-
|
|
751
|
+
logger.logger.info(`${dep}: ${allDependencies[dep]}`);
|
|
751
752
|
}
|
|
752
753
|
});
|
|
753
754
|
};
|
package/bin/main.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { existsSync, watch } from "fs";
|
|
3
|
-
import {
|
|
3
|
+
import { SaltyCompiler } from "../compiler/salty-compiler.js";
|
|
4
4
|
import { isSaltyFile } from "../compiler/helpers.js";
|
|
5
5
|
import { c as checkShouldRestart } from "../should-restart-CXIO0jxY.js";
|
|
6
6
|
import { join, relative, parse, format } from "path";
|
|
7
7
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
8
8
|
import { exec } from "child_process";
|
|
9
9
|
import ora from "ora";
|
|
10
|
+
import { l as logger, a as logError } from "../logger-hHmCwThj.js";
|
|
10
11
|
import { p as pascalCase } from "../pascal-case-F3Usi5Wf.js";
|
|
11
12
|
import ejs from "ejs";
|
|
12
13
|
import { createInterface } from "readline/promises";
|
|
@@ -2,23 +2,71 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const promises = require("fs/promises");
|
|
4
4
|
const path = require("path");
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
const CACHE_FILENAME = "config-cache.json";
|
|
6
|
+
const ENV_VAR = "SALTY_CONFIG_CACHE_PATH";
|
|
7
|
+
const defaultPatterns = [
|
|
8
|
+
"",
|
|
9
|
+
"saltygen",
|
|
10
|
+
"src",
|
|
11
|
+
"src/saltygen",
|
|
12
|
+
"cache",
|
|
13
|
+
"src/cache",
|
|
14
|
+
"saltygen/cache",
|
|
15
|
+
"src/saltygen/cache",
|
|
16
|
+
"dist",
|
|
17
|
+
"dist/cache",
|
|
18
|
+
"dist/saltygen/cache",
|
|
19
|
+
"build",
|
|
20
|
+
"build/cache",
|
|
21
|
+
"build/saltygen/cache",
|
|
22
|
+
"public/saltygen/cache",
|
|
23
|
+
".next",
|
|
24
|
+
".next/server",
|
|
25
|
+
".next/server/cache",
|
|
26
|
+
".vercel/output/functions"
|
|
27
|
+
];
|
|
28
|
+
const memo = /* @__PURE__ */ new Map();
|
|
29
|
+
let warned = false;
|
|
30
|
+
const toAbsolute = (p, cwd) => path.isAbsolute(p) ? p : path.join(cwd, p);
|
|
31
|
+
const candidatePathsFrom = (entry, cwd) => {
|
|
32
|
+
const abs = toAbsolute(entry, cwd);
|
|
33
|
+
if (abs.endsWith(".json")) return [abs];
|
|
34
|
+
return [path.join(abs, CACHE_FILENAME), path.join(abs, "cache", CACHE_FILENAME), path.join(abs, "saltygen", "cache", CACHE_FILENAME)];
|
|
35
|
+
};
|
|
36
|
+
const tryRead = async (path2) => {
|
|
37
|
+
if (memo.has(path2)) return memo.get(path2);
|
|
38
|
+
try {
|
|
39
|
+
const contents = await promises.readFile(path2, "utf8");
|
|
40
|
+
if (!contents) return void 0;
|
|
41
|
+
const parsed = JSON.parse(contents);
|
|
42
|
+
memo.set(path2, parsed);
|
|
43
|
+
return parsed;
|
|
44
|
+
} catch {
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const resolveDynamicConfigCache = async (options = {}) => {
|
|
49
|
+
var _a;
|
|
50
|
+
const cwd = options.cwd ?? process.cwd();
|
|
51
|
+
const envPath = typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a[ENV_VAR] : void 0;
|
|
52
|
+
const ordered = [];
|
|
53
|
+
if (options.primaryPath) ordered.push(...candidatePathsFrom(options.primaryPath, cwd));
|
|
54
|
+
if (envPath) ordered.push(...candidatePathsFrom(envPath, cwd));
|
|
55
|
+
if (options.extraPaths) for (const p of options.extraPaths) ordered.push(...candidatePathsFrom(p, cwd));
|
|
56
|
+
for (const pattern of defaultPatterns) ordered.push(path.join(cwd, pattern, CACHE_FILENAME));
|
|
57
|
+
for (const candidate of ordered) {
|
|
58
|
+
const result = await tryRead(candidate);
|
|
59
|
+
if (result) return result;
|
|
17
60
|
}
|
|
18
|
-
if (!
|
|
19
|
-
|
|
20
|
-
|
|
61
|
+
if (!warned) {
|
|
62
|
+
warned = true;
|
|
63
|
+
console.warn(`Could not find config cache file (${CACHE_FILENAME}) in any of the expected locations.`);
|
|
21
64
|
}
|
|
22
|
-
return
|
|
65
|
+
return {};
|
|
66
|
+
};
|
|
67
|
+
const _resetDynamicConfigCacheMemo = () => {
|
|
68
|
+
memo.clear();
|
|
69
|
+
warned = false;
|
|
23
70
|
};
|
|
71
|
+
exports._resetDynamicConfigCacheMemo = _resetDynamicConfigCacheMemo;
|
|
24
72
|
exports.resolveDynamicConfigCache = resolveDynamicConfigCache;
|
|
@@ -1 +1,20 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface ResolveDynamicConfigCacheOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Highest-priority path checked first. If it resolves, no other paths are tried.
|
|
4
|
+
* Absolute, or relative to `cwd`.
|
|
5
|
+
*/
|
|
6
|
+
primaryPath?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Extra paths checked before the built-in defaults. Absolute, or relative to `cwd`.
|
|
9
|
+
*/
|
|
10
|
+
extraPaths?: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Base directory for resolving relative paths. Defaults to `process.cwd()`.
|
|
13
|
+
*/
|
|
14
|
+
cwd?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const resolveDynamicConfigCache: (options?: ResolveDynamicConfigCacheOptions) => Promise<Record<string, unknown>>;
|
|
17
|
+
/**
|
|
18
|
+
* Clear the in-memory cache of parsed config-cache.json files. Test-only.
|
|
19
|
+
*/
|
|
20
|
+
export declare const _resetDynamicConfigCacheMemo: () => void;
|