@salty-css/core 0.1.0-alpha.26 → 0.1.0-alpha.27

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 CHANGED
@@ -58,6 +58,7 @@ To get help with problems, [Join Salty CSS Discord server](https://discord.gg/R6
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
60
  - [defineFont](#custom-fonts) - register custom fonts via `@font-face` (or a remote stylesheet) and expose them as a CSS variable
61
+ - [defineImport](#importing-additional-css) - pull in external CSS files (relative, public, node_modules, or URL)
61
62
  - [keyframes](#keyframes-animations) - create CSS keyframes animation that can be used and imported in any styling function
62
63
 
63
64
  ### Styling helpers & utility
@@ -402,6 +403,49 @@ export const Body = styled('p', {
402
403
  });
403
404
  ```
404
405
 
406
+ ## Importing additional CSS
407
+
408
+ Use `defineImport` to pull in CSS that lives outside of Salty's authoring API — a reset stylesheet from npm, a Google Fonts URL, an asset in your app's `public/` folder, or a sibling `.css` file. The compiler turns each spec into an `@import` rule in the generated `saltygen/index.css`, so the imported stylesheets travel with the rest of your build.
409
+
410
+ ```ts
411
+ // /styles/imports.css.ts
412
+ import { defineImport } from '@salty-css/core/factories';
413
+
414
+ export default defineImport(
415
+ // Relative to this file
416
+ './reset.css',
417
+ // From node_modules (bare specifier — same as Vite / native CSS @import)
418
+ 'modern-normalize/modern-normalize.css',
419
+ // From node_modules (~ prefix — same resolver, webpack-style)
420
+ '~normalize.css/normalize.css',
421
+ // From your app's public/ folder (served at the host root)
422
+ '/fonts/inter.css',
423
+ // External URL
424
+ 'https://fonts.googleapis.com/css2?family=Inter&display=swap',
425
+ // Object form — attach media or supports() conditions
426
+ { url: './print.css', media: 'print' },
427
+ { url: './p3.css', supports: 'color(display-p3 1 1 1)' }
428
+ );
429
+ ```
430
+
431
+ Path resolution:
432
+
433
+ | Pattern | Behaviour |
434
+ | --------------------------- | ---------------------------------------------------------------------------------------- |
435
+ | `http://`, `https://`, `//` | Emitted verbatim |
436
+ | Starts with `/` | Public-folder URL — emitted verbatim, the browser resolves it against your host |
437
+ | Starts with `./` or `../` | Resolved at build time relative to the file that called `defineImport` |
438
+ | `~package/file.css` | Stripped of the leading `~`, then resolved from `node_modules` and copied into the build |
439
+ | `package/file.css` (bare) | Same `node_modules` resolution as the `~` form |
440
+
441
+ All imports are placed inside a new `imports` cascade layer that sits **before** `reset`, `global`, `templates`, and your component styles. This means your own styles always win over third-party CSS you pull in — which is what most teams expect when they drop in something like `modern-normalize`.
442
+
443
+ The full layer order in the generated `index.css` is:
444
+
445
+ ```css
446
+ @layer imports, reset, global, templates, l0, l1, l2, l3, l4, l5, l6, l7, l8;
447
+ ```
448
+
405
449
  ## Keyframes animations
406
450
 
407
451
  ```ts
@@ -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
+ };
@@ -13,12 +13,12 @@ const compiler_helpers = require("./helpers.cjs");
13
13
  const dashCase = require("../dash-case-DIwKaYgE.cjs");
14
14
  const toHash = require("../to-hash-C05Y906F.cjs");
15
15
  const defineTemplates = require("../define-templates-Deq1aCbN.cjs");
16
+ const module$1 = require("module");
16
17
  const parseStyles = require("../parse-styles-jPtMfgXH.cjs");
17
18
  const css_merge = require("../css/merge.cjs");
18
19
  const parsers_index = require("../parsers/index.cjs");
19
- const compiler_getFiles = require("./get-files.cjs");
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 readPackageJsonModule = async (dirname) => {
48
- const packageJsonContent = await compiler_getFiles.getPackageJson(dirname);
49
- if (!packageJsonContent) return void 0;
50
- return packageJsonContent.type;
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
51
  };
52
- let cachedModuleType;
53
- const detectCurrentModuleType = async (dirname) => {
54
- if (cachedModuleType) return cachedModuleType;
55
- const packageJsonModule = await readPackageJsonModule(dirname);
56
- if (packageJsonModule === "module") cachedModuleType = "esm";
57
- else if (packageJsonModule === "commonjs") cachedModuleType = "cjs";
58
- else if ((typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("compiler/salty-compiler.cjs", document.baseURI).href).endsWith(".cjs")) cachedModuleType = "cjs";
59
- return cachedModuleType || "esm";
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);
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 "";
@@ -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", "_fonts.css"];
386
+ const globalCssFilenames = ["_imports.css", "_variables.css", "_reset.css", "_global.css", "_templates.css", "_fonts.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) => `@import url('./css/${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, fonts, l0, l1, l2, l3, l4, l5, l6, l7, l8;
400
+ let cssContent = `${generatorText}@layer imports, reset, global, templates, fonts, l0, l1, l2, l3, l4, l5, l6, l7, l8;
363
401
 
364
402
  ${globalImports.join(
365
403
  "\n"
@@ -406,6 +444,7 @@ ${css}
406
444
  globalStyles: [],
407
445
  variables: [],
408
446
  templates: [],
447
+ imports: [],
409
448
  fonts: []
410
449
  };
411
450
  await Promise.all(
@@ -416,6 +455,7 @@ ${css}
416
455
  else if (value.isGlobalDefine) generationResults.globalStyles.push(value);
417
456
  else if (value.isDefineVariables) generationResults.variables.push(value);
418
457
  else if (value.isDefineTemplates) generationResults.templates.push(value._setPath(`${name};;${outputFilePath}`));
458
+ else if (value.isDefineImport) generationResults.imports.push(value._setPath(src));
419
459
  else if (value.isDefineFont) generationResults.fonts.push(value);
420
460
  });
421
461
  })
@@ -515,6 +555,22 @@ ${css}
515
555
  const templateTokens = parsers_index.getTemplateTypes(templates);
516
556
  fs.writeFileSync(templateStylesPath, `@layer templates { ${templateStylesString} }`);
517
557
  configCacheContent.templates = templates;
558
+ const importsPath = path.join(destDir, "css/_imports.css");
559
+ const importRules = [];
560
+ for (const factory of generationResults.imports) {
561
+ const sourceFile = factory._path;
562
+ if (!sourceFile) continue;
563
+ for (const spec of factory._current) {
564
+ try {
565
+ const { rule } = resolveImport(spec, sourceFile, destDir);
566
+ importRules.push(rule);
567
+ } catch (e) {
568
+ const url = typeof spec === "string" ? spec : spec.url;
569
+ logger.error(`Failed to resolve defineImport(${JSON.stringify(url)}) from ${sourceFile}: ${e.message}`);
570
+ }
571
+ }
572
+ }
573
+ fs.writeFileSync(importsPath, importRules.join("\n"));
518
574
  const configTemplateFactories = config.templates ? [defineTemplates.defineTemplates(config.templates)._setPath(`config;;${configPath}`)] : [];
519
575
  const templateFactories = css_merge.mergeFactories(generationResults.templates, configTemplateFactories);
520
576
  configCacheContent.templatePaths = Object.fromEntries(Object.entries(templateFactories).map(([key, faktory]) => [key, faktory._path]));
@@ -569,7 +625,7 @@ ${css}
569
625
  const rcProject = await this.getRCProjectConfig(this.projectRootDir);
570
626
  const coreConfigPath = path.join(this.projectRootDir, (rcProject == null ? void 0 : rcProject.configDir) || "", "salty.config.ts");
571
627
  const externalModules = this.getExternalModules(coreConfigPath);
572
- const moduleType = await detectCurrentModuleType(this.projectRootDir);
628
+ const moduleType$1 = await moduleType.detectCurrentModuleType(this.projectRootDir);
573
629
  await esbuild__namespace.build({
574
630
  stdin: {
575
631
  contents: currentFile,
@@ -581,7 +637,7 @@ ${css}
581
637
  treeShaking: true,
582
638
  bundle: true,
583
639
  outfile: outputFilePath,
584
- format: moduleType,
640
+ format: moduleType$1,
585
641
  target: ["node20"],
586
642
  keepNames: true,
587
643
  external: externalModules,
@@ -44,6 +44,7 @@ export declare class SaltyCompiler {
44
44
  isGlobalDefine?: boolean;
45
45
  isDefineVariables?: boolean;
46
46
  isDefineTemplates?: boolean;
47
+ isDefineImport?: boolean;
47
48
  isDefineFont?: boolean;
48
49
  isKeyframes?: boolean;
49
50
  animationName?: string;
@@ -2,19 +2,20 @@ 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
4
  import * as esbuild from "esbuild";
5
- import { join, parse } from "path";
5
+ import { resolve, dirname, relative, join, basename, parse } from "path";
6
6
  import { createLogger, transports, format } from "winston";
7
7
  import { readFile } from "fs/promises";
8
- import { readFileSync, existsSync, mkdirSync, statSync, readdirSync, writeFileSync } from "fs";
8
+ import { existsSync, mkdirSync, copyFileSync, readFileSync, statSync, readdirSync, writeFileSync } from "fs";
9
9
  import { execSync } from "child_process";
10
10
  import { isSaltyFile, resolveExportValue, getCorePackageRoot, saltyFileExtensions } from "./helpers.js";
11
11
  import { d as dashCase } from "../dash-case-DblXvymC.js";
12
12
  import { t as toHash } from "../to-hash-DAN2LcHK.js";
13
13
  import { d as defineTemplates } from "../define-templates-CVhhgPnd.js";
14
+ import { createRequire } from "module";
14
15
  import { p as parseAndJoinStyles, b as parseVariableTokens } from "../parse-styles--vHKY6Mw.js";
15
16
  import { mergeObjects, mergeFactories } from "../css/merge.js";
16
17
  import { parseTemplates, getTemplateTypes } from "../parsers/index.js";
17
- import { getPackageJson } from "./get-files.js";
18
+ import { detectCurrentModuleType } from "../util/module-type";
18
19
  import console from "console";
19
20
  const logger = createLogger({
20
21
  level: "debug",
@@ -24,19 +25,53 @@ const logger = createLogger({
24
25
  const logError = (message) => {
25
26
  logger.error(message);
26
27
  };
27
- const readPackageJsonModule = async (dirname) => {
28
- const packageJsonContent = await getPackageJson(dirname);
29
- if (!packageJsonContent) return void 0;
30
- return packageJsonContent.type;
28
+ const EXTERNAL_URL = /^(?:[a-z][a-z0-9+.-]*:)?\/\//i;
29
+ const normaliseSpec = (spec) => {
30
+ if (typeof spec === "string") return { url: spec };
31
+ return spec;
31
32
  };
32
- let cachedModuleType;
33
- const detectCurrentModuleType = async (dirname) => {
34
- if (cachedModuleType) return cachedModuleType;
35
- const packageJsonModule = await readPackageJsonModule(dirname);
36
- if (packageJsonModule === "module") cachedModuleType = "esm";
37
- else if (packageJsonModule === "commonjs") cachedModuleType = "cjs";
38
- else if (import.meta.url.endsWith(".cjs")) cachedModuleType = "cjs";
39
- return cachedModuleType || "esm";
33
+ const ensureRelativePrefix = (path) => {
34
+ if (path.startsWith(".") || path.startsWith("/")) return path;
35
+ return `./${path}`;
36
+ };
37
+ const toPosix = (path) => path.split("\\").join("/");
38
+ const defaultResolveModule = (specifier, sourceFile) => {
39
+ return createRequire(sourceFile).resolve(specifier);
40
+ };
41
+ const defaultCopyAsset = (from, to) => {
42
+ const dir = dirname(to);
43
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
44
+ copyFileSync(from, to);
45
+ };
46
+ const buildRule = (url, { media, supports }) => {
47
+ let rule = `@import url('${url}')`;
48
+ if (supports) rule += ` supports(${supports})`;
49
+ if (media) rule += ` ${media}`;
50
+ return `${rule};`;
51
+ };
52
+ const resolveImport = (spec, sourceFile, destDir, options = {}) => {
53
+ const opts = normaliseSpec(spec);
54
+ const { url } = opts;
55
+ const resolveModule = options.resolveModule ?? defaultResolveModule;
56
+ const copyAsset = options.copyAsset ?? defaultCopyAsset;
57
+ if (EXTERNAL_URL.test(url)) {
58
+ return { rule: buildRule(url, opts) };
59
+ }
60
+ if (url.startsWith("/")) {
61
+ return { rule: buildRule(url, opts) };
62
+ }
63
+ if (url.startsWith("./") || url.startsWith("../")) {
64
+ const absolute2 = resolve(dirname(sourceFile), url);
65
+ const fromImportsFile = relative(join(destDir, "css"), absolute2);
66
+ return { rule: buildRule(ensureRelativePrefix(toPosix(fromImportsFile)), opts) };
67
+ }
68
+ const specifier = url.startsWith("~") ? url.slice(1) : url;
69
+ const absolute = resolveModule(specifier, sourceFile);
70
+ const hash = toHash(absolute, 6);
71
+ const fileName = `${hash}-${basename(absolute)}`;
72
+ const destPath = join(destDir, "imports", fileName);
73
+ copyAsset(absolute, destPath);
74
+ return { rule: buildRule(`../imports/${fileName}`, opts) };
40
75
  };
41
76
  function dotCase(str) {
42
77
  if (!str) return "";
@@ -121,10 +156,10 @@ class SaltyCompiler {
121
156
  * Get the project configuration from the .saltyrc.json file based on the current directory.
122
157
  * If no specific project configuration is found, it falls back to the default project.
123
158
  */
124
- __publicField(this, "getRCProjectConfig", async (dirname) => {
159
+ __publicField(this, "getRCProjectConfig", async (dirname2) => {
125
160
  var _a, _b;
126
- const rcFile = await this.readRCFile(dirname);
127
- const projectConfig = (_a = rcFile.projects) == null ? void 0 : _a.find((project) => dirname.endsWith(project.dir || ""));
161
+ const rcFile = await this.readRCFile(dirname2);
162
+ const projectConfig = (_a = rcFile.projects) == null ? void 0 : _a.find((project) => dirname2.endsWith(project.dir || ""));
128
163
  if (!projectConfig) return (_b = rcFile.projects) == null ? void 0 : _b.find((project) => project.dir === rcFile.defaultProject);
129
164
  return projectConfig;
130
165
  });
@@ -213,6 +248,7 @@ ${currentFile}`;
213
248
  mkdirSync(join(destDir, "types"));
214
249
  mkdirSync(join(destDir, "js"));
215
250
  mkdirSync(join(destDir, "cache"));
251
+ mkdirSync(join(destDir, "imports"));
216
252
  };
217
253
  if (clean) clearDistDir();
218
254
  const files = /* @__PURE__ */ new Set();
@@ -328,7 +364,7 @@ ${currentFile}`;
328
364
  });
329
365
  }
330
366
  const otherGlobalCssFiles = globalCssFiles.map((file) => `@import url('./css/${file}');`).join("\n");
331
- const globalCssFilenames = ["_variables.css", "_reset.css", "_global.css", "_templates.css", "_fonts.css"];
367
+ const globalCssFilenames = ["_imports.css", "_variables.css", "_reset.css", "_global.css", "_templates.css", "_fonts.css"];
332
368
  const importsWithData = globalCssFilenames.filter((file) => {
333
369
  try {
334
370
  const data = readFileSync(join(destDir, "css", file), "utf8");
@@ -337,9 +373,12 @@ ${currentFile}`;
337
373
  return false;
338
374
  }
339
375
  });
340
- const globalImports = importsWithData.map((file) => `@import url('./css/${file}');`);
376
+ const globalImports = importsWithData.map((file) => {
377
+ const layerSuffix = file === "_imports.css" ? " layer(imports)" : "";
378
+ return `@import url('./css/${file}')${layerSuffix};`;
379
+ });
341
380
  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, fonts, l0, l1, l2, l3, l4, l5, l6, l7, l8;
381
+ let cssContent = `${generatorText}@layer imports, reset, global, templates, fonts, l0, l1, l2, l3, l4, l5, l6, l7, l8;
343
382
 
344
383
  ${globalImports.join(
345
384
  "\n"
@@ -386,6 +425,7 @@ ${css}
386
425
  globalStyles: [],
387
426
  variables: [],
388
427
  templates: [],
428
+ imports: [],
389
429
  fonts: []
390
430
  };
391
431
  await Promise.all(
@@ -396,6 +436,7 @@ ${css}
396
436
  else if (value.isGlobalDefine) generationResults.globalStyles.push(value);
397
437
  else if (value.isDefineVariables) generationResults.variables.push(value);
398
438
  else if (value.isDefineTemplates) generationResults.templates.push(value._setPath(`${name};;${outputFilePath}`));
439
+ else if (value.isDefineImport) generationResults.imports.push(value._setPath(src));
399
440
  else if (value.isDefineFont) generationResults.fonts.push(value);
400
441
  });
401
442
  })
@@ -495,6 +536,22 @@ ${css}
495
536
  const templateTokens = getTemplateTypes(templates);
496
537
  writeFileSync(templateStylesPath, `@layer templates { ${templateStylesString} }`);
497
538
  configCacheContent.templates = templates;
539
+ const importsPath = join(destDir, "css/_imports.css");
540
+ const importRules = [];
541
+ for (const factory of generationResults.imports) {
542
+ const sourceFile = factory._path;
543
+ if (!sourceFile) continue;
544
+ for (const spec of factory._current) {
545
+ try {
546
+ const { rule } = resolveImport(spec, sourceFile, destDir);
547
+ importRules.push(rule);
548
+ } catch (e) {
549
+ const url = typeof spec === "string" ? spec : spec.url;
550
+ logger.error(`Failed to resolve defineImport(${JSON.stringify(url)}) from ${sourceFile}: ${e.message}`);
551
+ }
552
+ }
553
+ }
554
+ writeFileSync(importsPath, importRules.join("\n"));
498
555
  const configTemplateFactories = config.templates ? [defineTemplates(config.templates)._setPath(`config;;${configPath}`)] : [];
499
556
  const templateFactories = mergeFactories(generationResults.templates, configTemplateFactories);
500
557
  configCacheContent.templatePaths = Object.fromEntries(Object.entries(templateFactories).map(([key, faktory]) => [key, faktory._path]));
package/config/index.cjs CHANGED
@@ -7,9 +7,11 @@ const defineConfig = (config) => {
7
7
  };
8
8
  exports.FontFactory = factories_index.FontFactory;
9
9
  exports.GlobalStylesFactory = factories_index.GlobalStylesFactory;
10
+ exports.ImportFactory = factories_index.ImportFactory;
10
11
  exports.VariablesFactory = factories_index.VariablesFactory;
11
12
  exports.defineFont = factories_index.defineFont;
12
13
  exports.defineGlobalStyles = factories_index.defineGlobalStyles;
14
+ exports.defineImport = factories_index.defineImport;
13
15
  exports.defineMediaQuery = factories_index.defineMediaQuery;
14
16
  exports.defineVariables = factories_index.defineVariables;
15
17
  exports.TemplateFactory = defineTemplates.TemplateFactory;
package/config/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { FontFactory, GlobalStylesFactory, VariablesFactory, defineFont, defineGlobalStyles, defineMediaQuery, defineVariables } from "../factories/index.js";
1
+ import { FontFactory, GlobalStylesFactory, ImportFactory, VariablesFactory, defineFont, defineGlobalStyles, defineImport, 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;
@@ -6,12 +6,14 @@ const defineConfig = (config) => {
6
6
  export {
7
7
  FontFactory,
8
8
  GlobalStylesFactory,
9
+ ImportFactory,
9
10
  T as TemplateFactory,
10
11
  a as TemplatesFactory,
11
12
  VariablesFactory,
12
13
  defineConfig,
13
14
  defineFont,
14
15
  defineGlobalStyles,
16
+ defineImport,
15
17
  defineMediaQuery,
16
18
  d as defineTemplates,
17
19
  defineVariables
@@ -0,0 +1,14 @@
1
+ export interface ImportSpecOptions {
2
+ url: string;
3
+ media?: string;
4
+ supports?: string;
5
+ }
6
+ export type ImportSpec = string | ImportSpecOptions;
7
+ export declare class ImportFactory {
8
+ _current: ImportSpec[];
9
+ _path?: string;
10
+ constructor(_current: ImportSpec[]);
11
+ get isDefineImport(): boolean;
12
+ _setPath(path: string): this;
13
+ }
14
+ export declare const defineImport: (...specs: ImportSpec[]) => ImportFactory;
@@ -136,6 +136,20 @@ class GlobalStylesFactory {
136
136
  const defineGlobalStyles = (styles) => {
137
137
  return new GlobalStylesFactory(styles);
138
138
  };
139
+ class ImportFactory {
140
+ constructor(_current) {
141
+ __publicField(this, "_path");
142
+ this._current = _current;
143
+ }
144
+ get isDefineImport() {
145
+ return true;
146
+ }
147
+ _setPath(path) {
148
+ this._path = path;
149
+ return this;
150
+ }
151
+ }
152
+ const defineImport = (...specs) => new ImportFactory(specs);
139
153
  const defineMediaQuery = (mediaFactory) => {
140
154
  return mediaFactory(css_media.media);
141
155
  };
@@ -155,8 +169,10 @@ exports.TemplatesFactory = defineTemplates.TemplatesFactory;
155
169
  exports.defineTemplates = defineTemplates.defineTemplates;
156
170
  exports.FontFactory = FontFactory;
157
171
  exports.GlobalStylesFactory = GlobalStylesFactory;
172
+ exports.ImportFactory = ImportFactory;
158
173
  exports.VariablesFactory = VariablesFactory;
159
174
  exports.defineFont = defineFont;
160
175
  exports.defineGlobalStyles = defineGlobalStyles;
176
+ exports.defineImport = defineImport;
161
177
  exports.defineMediaQuery = defineMediaQuery;
162
178
  exports.defineVariables = defineVariables;
@@ -1,5 +1,6 @@
1
1
  export * from './define-font';
2
2
  export * from './define-global-styles';
3
+ export * from './define-import';
3
4
  export * from './define-media-query';
4
5
  export * from './define-variables';
5
6
  export * from './define-templates';
@@ -134,6 +134,20 @@ class GlobalStylesFactory {
134
134
  const defineGlobalStyles = (styles) => {
135
135
  return new GlobalStylesFactory(styles);
136
136
  };
137
+ class ImportFactory {
138
+ constructor(_current) {
139
+ __publicField(this, "_path");
140
+ this._current = _current;
141
+ }
142
+ get isDefineImport() {
143
+ return true;
144
+ }
145
+ _setPath(path) {
146
+ this._path = path;
147
+ return this;
148
+ }
149
+ }
150
+ const defineImport = (...specs) => new ImportFactory(specs);
137
151
  const defineMediaQuery = (mediaFactory) => {
138
152
  return mediaFactory(media);
139
153
  };
@@ -151,11 +165,13 @@ const defineVariables = (variables) => {
151
165
  export {
152
166
  FontFactory,
153
167
  GlobalStylesFactory,
168
+ ImportFactory,
154
169
  T as TemplateFactory,
155
170
  a as TemplatesFactory,
156
171
  VariablesFactory,
157
172
  defineFont,
158
173
  defineGlobalStyles,
174
+ defineImport,
159
175
  defineMediaQuery,
160
176
  d as defineTemplates,
161
177
  defineVariables
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salty-css/core",
3
- "version": "0.1.0-alpha.26",
3
+ "version": "0.1.0-alpha.27",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "typings": "./dist/index.d.ts",