@knighted/css 1.0.0-rc.0 → 1.0.0-rc.1

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/dist/cjs/css.cjs CHANGED
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.DEFAULT_EXTENSIONS = void 0;
7
7
  exports.css = css;
8
8
  exports.cssWithMeta = cssWithMeta;
9
+ exports.compileVanillaModule = compileVanillaModule;
9
10
  const node_path_1 = __importDefault(require("node:path"));
10
11
  const node_fs_1 = require("node:fs");
11
12
  const dependency_tree_1 = __importDefault(require("dependency-tree"));
@@ -114,7 +115,7 @@ async function compileStyleModule(file, { cwd, peerResolver }) {
114
115
  case '.less':
115
116
  return compileLess(file.path, peerResolver);
116
117
  case '.css.ts':
117
- return compileVanillaExtract(file.path, cwd, peerResolver);
118
+ return (await compileVanillaModule(file.path, cwd, peerResolver)).css;
118
119
  default:
119
120
  return '';
120
121
  }
@@ -134,7 +135,7 @@ async function compileLess(filePath, peerResolver) {
134
135
  const result = await less.render(source, { filename: filePath });
135
136
  return result.css;
136
137
  }
137
- async function compileVanillaExtract(filePath, cwd, peerResolver) {
138
+ async function compileVanillaModule(filePath, cwd, peerResolver) {
138
139
  const mod = await optionalPeer('@vanilla-extract/integration', 'Vanilla Extract', peerResolver);
139
140
  const namespace = unwrapModuleNamespace(mod);
140
141
  const compileFn = namespace.compile;
@@ -174,7 +175,10 @@ async function compileVanillaExtract(filePath, cwd, peerResolver) {
174
175
  imports.push(virtualFile.source);
175
176
  }
176
177
  }
177
- return imports.join('\n');
178
+ return {
179
+ source,
180
+ css: imports.join('\n'),
181
+ };
178
182
  }
179
183
  const defaultPeerLoader = name => import(name);
180
184
  async function optionalPeer(name, label, loader) {
@@ -21,6 +21,10 @@ export interface CssOptions {
21
21
  resolver?: CssResolver;
22
22
  peerResolver?: PeerLoader;
23
23
  }
24
+ export interface VanillaCompileResult {
25
+ source: string;
26
+ css: string;
27
+ }
24
28
  /**
25
29
  * Extract and compile all CSS-like dependencies for a given module.
26
30
  */
@@ -30,4 +34,5 @@ export interface CssResult {
30
34
  }
31
35
  export declare function css(entry: string, options?: CssOptions): Promise<string>;
32
36
  export declare function cssWithMeta(entry: string, options?: CssOptions): Promise<CssResult>;
37
+ export declare function compileVanillaModule(filePath: string, cwd: string, peerResolver?: PeerLoader): Promise<VanillaCompileResult>;
33
38
  export {};
@@ -5,29 +5,63 @@ const css_js_1 = require("./css.cjs");
5
5
  const DEFAULT_EXPORT_NAME = 'knightedCss';
6
6
  const COMBINED_QUERY_FLAG = 'combined';
7
7
  const loader = async function loader(source) {
8
- const cssOptions = resolveCssOptions(this);
8
+ const { cssOptions, vanillaOptions } = resolveLoaderOptions(this);
9
9
  const css = await extractCss(this, cssOptions);
10
10
  const injection = buildInjection(css);
11
- const input = toSourceString(source);
12
11
  const isStyleModule = this.resourcePath.endsWith('.css.ts');
13
- return isStyleModule ? `${injection}export default {};\n` : `${input}${injection}`;
12
+ if (isStyleModule) {
13
+ const { source: compiledSource } = await (0, css_js_1.compileVanillaModule)(this.resourcePath, cssOptions.cwd ?? this.rootContext ?? process.cwd(), cssOptions.peerResolver);
14
+ const vanillaSource = maybeTransformVanillaModule(compiledSource, vanillaOptions);
15
+ return `${vanillaSource}${injection}`;
16
+ }
17
+ const input = toSourceString(source);
18
+ return `${input}${injection}`;
14
19
  };
20
+ function transformVanillaModuleToEsm(source) {
21
+ const exportBlock = /__export\([^,]+,\s*{([\s\S]*?)}\);/m.exec(source);
22
+ if (!exportBlock) {
23
+ return source;
24
+ }
25
+ const names = exportBlock[1]
26
+ .split(',')
27
+ .map(part => part.trim())
28
+ .filter(Boolean)
29
+ .map(entry => entry.split(':')[0]?.trim())
30
+ .filter(Boolean);
31
+ let transformed = source.replace(/module\.exports\s*=\s*__toCommonJS\([^;]+;\n?/m, '');
32
+ transformed = transformed.replace(/0 && \(module\.exports = {[^}]+}\);?\n?/m, '');
33
+ if (names.length > 0) {
34
+ transformed = `${transformed}\nexport { ${names.join(', ')} };\n`;
35
+ }
36
+ return transformed;
37
+ }
38
+ function maybeTransformVanillaModule(source, options) {
39
+ if (!options?.transformToEsm) {
40
+ return source;
41
+ }
42
+ return transformVanillaModuleToEsm(source);
43
+ }
15
44
  const pitch = function pitch() {
16
45
  if (!hasCombinedQuery(this.resourceQuery)) {
17
46
  return;
18
47
  }
19
48
  const request = buildProxyRequest(this);
20
- const cssOptions = resolveCssOptions(this);
49
+ const { cssOptions } = resolveLoaderOptions(this);
21
50
  return extractCss(this, cssOptions).then(css => createCombinedModule(request, css));
22
51
  };
23
52
  exports.pitch = pitch;
24
53
  loader.pitch = exports.pitch;
25
54
  exports.default = loader;
26
- function resolveCssOptions(ctx) {
55
+ function resolveLoaderOptions(ctx) {
27
56
  const rawOptions = (typeof ctx.getOptions === 'function' ? ctx.getOptions() : {});
57
+ const { vanilla, ...rest } = rawOptions;
58
+ const cssOptions = {
59
+ ...rest,
60
+ cwd: rest.cwd ?? ctx.rootContext ?? process.cwd(),
61
+ };
28
62
  return {
29
- ...rawOptions,
30
- cwd: rawOptions.cwd ?? ctx.rootContext ?? process.cwd(),
63
+ cssOptions,
64
+ vanillaOptions: vanilla,
31
65
  };
32
66
  }
33
67
  async function extractCss(ctx, options) {
@@ -57,6 +91,11 @@ function hasCombinedQuery(query) {
57
91
  }
58
92
  function buildProxyRequest(ctx) {
59
93
  const sanitizedQuery = buildSanitizedQuery(ctx.resourceQuery);
94
+ const rawRequest = getRawRequest(ctx);
95
+ if (rawRequest) {
96
+ const stripped = stripResourceQuery(rawRequest);
97
+ return `${stripped}${sanitizedQuery}`;
98
+ }
60
99
  const request = `${ctx.resourcePath}${sanitizedQuery}`;
61
100
  const context = ctx.context ?? ctx.rootContext ?? process.cwd();
62
101
  if (ctx.utils && typeof ctx.utils.contextify === 'function') {
@@ -64,6 +103,18 @@ function buildProxyRequest(ctx) {
64
103
  }
65
104
  return request;
66
105
  }
106
+ function getRawRequest(ctx) {
107
+ const mod = ctx._module;
108
+ const request = mod?.rawRequest;
109
+ if (typeof request === 'string' && request.length > 0) {
110
+ return request;
111
+ }
112
+ return undefined;
113
+ }
114
+ function stripResourceQuery(request) {
115
+ const idx = request.indexOf('?');
116
+ return idx >= 0 ? request.slice(0, idx) : request;
117
+ }
67
118
  function buildSanitizedQuery(query) {
68
119
  if (!query)
69
120
  return '';
@@ -89,15 +140,26 @@ function isQueryFlag(entry, flag) {
89
140
  }
90
141
  function createCombinedModule(request, css) {
91
142
  const requestLiteral = JSON.stringify(request);
92
- const defaultExport = `const __knightedDefault =
93
- typeof __knightedModule.default !== 'undefined'
94
- ? __knightedModule.default
95
- : __knightedModule;`;
96
- return [
143
+ const lines = [
97
144
  `import * as __knightedModule from ${requestLiteral};`,
98
145
  `export * from ${requestLiteral};`,
99
- defaultExport,
100
- 'export default __knightedDefault;',
101
- buildInjection(css),
102
- ].join('\n');
146
+ ];
147
+ if (shouldForwardDefaultExport(request)) {
148
+ lines.push(`const __knightedDefault =
149
+ typeof __knightedModule.default !== 'undefined'
150
+ ? __knightedModule.default
151
+ : __knightedModule;`, 'export default __knightedDefault;');
152
+ }
153
+ lines.push(buildInjection(css));
154
+ return lines.join('\n');
155
+ }
156
+ function shouldForwardDefaultExport(request) {
157
+ const [pathPart] = request.split('?');
158
+ if (!pathPart)
159
+ return true;
160
+ const lower = pathPart.toLowerCase();
161
+ if (lower.endsWith('.css.ts') || lower.endsWith('.css.js')) {
162
+ return false;
163
+ }
164
+ return true;
103
165
  }
@@ -3,7 +3,11 @@ import { type CssOptions } from './css.cjs';
3
3
  export type KnightedCssCombinedModule<TModule> = TModule & {
4
4
  knightedCss: string;
5
5
  };
6
+ export interface KnightedCssVanillaOptions {
7
+ transformToEsm?: boolean;
8
+ }
6
9
  export interface KnightedCssLoaderOptions extends CssOptions {
10
+ vanilla?: KnightedCssVanillaOptions;
7
11
  }
8
12
  declare const loader: LoaderDefinitionFunction<KnightedCssLoaderOptions>;
9
13
  export declare const pitch: PitchLoaderDefinitionFunction<KnightedCssLoaderOptions>;
package/dist/css.d.ts CHANGED
@@ -21,6 +21,10 @@ export interface CssOptions {
21
21
  resolver?: CssResolver;
22
22
  peerResolver?: PeerLoader;
23
23
  }
24
+ export interface VanillaCompileResult {
25
+ source: string;
26
+ css: string;
27
+ }
24
28
  /**
25
29
  * Extract and compile all CSS-like dependencies for a given module.
26
30
  */
@@ -30,4 +34,5 @@ export interface CssResult {
30
34
  }
31
35
  export declare function css(entry: string, options?: CssOptions): Promise<string>;
32
36
  export declare function cssWithMeta(entry: string, options?: CssOptions): Promise<CssResult>;
37
+ export declare function compileVanillaModule(filePath: string, cwd: string, peerResolver?: PeerLoader): Promise<VanillaCompileResult>;
33
38
  export {};
package/dist/css.js CHANGED
@@ -106,7 +106,7 @@ async function compileStyleModule(file, { cwd, peerResolver }) {
106
106
  case '.less':
107
107
  return compileLess(file.path, peerResolver);
108
108
  case '.css.ts':
109
- return compileVanillaExtract(file.path, cwd, peerResolver);
109
+ return (await compileVanillaModule(file.path, cwd, peerResolver)).css;
110
110
  default:
111
111
  return '';
112
112
  }
@@ -126,7 +126,7 @@ async function compileLess(filePath, peerResolver) {
126
126
  const result = await less.render(source, { filename: filePath });
127
127
  return result.css;
128
128
  }
129
- async function compileVanillaExtract(filePath, cwd, peerResolver) {
129
+ export async function compileVanillaModule(filePath, cwd, peerResolver) {
130
130
  const mod = await optionalPeer('@vanilla-extract/integration', 'Vanilla Extract', peerResolver);
131
131
  const namespace = unwrapModuleNamespace(mod);
132
132
  const compileFn = namespace.compile;
@@ -166,7 +166,10 @@ async function compileVanillaExtract(filePath, cwd, peerResolver) {
166
166
  imports.push(virtualFile.source);
167
167
  }
168
168
  }
169
- return imports.join('\n');
169
+ return {
170
+ source,
171
+ css: imports.join('\n'),
172
+ };
170
173
  }
171
174
  const defaultPeerLoader = name => import(name);
172
175
  async function optionalPeer(name, label, loader) {
package/dist/loader.d.ts CHANGED
@@ -3,7 +3,11 @@ import { type CssOptions } from './css.js';
3
3
  export type KnightedCssCombinedModule<TModule> = TModule & {
4
4
  knightedCss: string;
5
5
  };
6
+ export interface KnightedCssVanillaOptions {
7
+ transformToEsm?: boolean;
8
+ }
6
9
  export interface KnightedCssLoaderOptions extends CssOptions {
10
+ vanilla?: KnightedCssVanillaOptions;
7
11
  }
8
12
  declare const loader: LoaderDefinitionFunction<KnightedCssLoaderOptions>;
9
13
  export declare const pitch: PitchLoaderDefinitionFunction<KnightedCssLoaderOptions>;
package/dist/loader.js CHANGED
@@ -1,29 +1,63 @@
1
- import { cssWithMeta } from './css.js';
1
+ import { cssWithMeta, compileVanillaModule } from './css.js';
2
2
  const DEFAULT_EXPORT_NAME = 'knightedCss';
3
3
  const COMBINED_QUERY_FLAG = 'combined';
4
4
  const loader = async function loader(source) {
5
- const cssOptions = resolveCssOptions(this);
5
+ const { cssOptions, vanillaOptions } = resolveLoaderOptions(this);
6
6
  const css = await extractCss(this, cssOptions);
7
7
  const injection = buildInjection(css);
8
- const input = toSourceString(source);
9
8
  const isStyleModule = this.resourcePath.endsWith('.css.ts');
10
- return isStyleModule ? `${injection}export default {};\n` : `${input}${injection}`;
9
+ if (isStyleModule) {
10
+ const { source: compiledSource } = await compileVanillaModule(this.resourcePath, cssOptions.cwd ?? this.rootContext ?? process.cwd(), cssOptions.peerResolver);
11
+ const vanillaSource = maybeTransformVanillaModule(compiledSource, vanillaOptions);
12
+ return `${vanillaSource}${injection}`;
13
+ }
14
+ const input = toSourceString(source);
15
+ return `${input}${injection}`;
11
16
  };
17
+ function transformVanillaModuleToEsm(source) {
18
+ const exportBlock = /__export\([^,]+,\s*{([\s\S]*?)}\);/m.exec(source);
19
+ if (!exportBlock) {
20
+ return source;
21
+ }
22
+ const names = exportBlock[1]
23
+ .split(',')
24
+ .map(part => part.trim())
25
+ .filter(Boolean)
26
+ .map(entry => entry.split(':')[0]?.trim())
27
+ .filter(Boolean);
28
+ let transformed = source.replace(/module\.exports\s*=\s*__toCommonJS\([^;]+;\n?/m, '');
29
+ transformed = transformed.replace(/0 && \(module\.exports = {[^}]+}\);?\n?/m, '');
30
+ if (names.length > 0) {
31
+ transformed = `${transformed}\nexport { ${names.join(', ')} };\n`;
32
+ }
33
+ return transformed;
34
+ }
35
+ function maybeTransformVanillaModule(source, options) {
36
+ if (!options?.transformToEsm) {
37
+ return source;
38
+ }
39
+ return transformVanillaModuleToEsm(source);
40
+ }
12
41
  export const pitch = function pitch() {
13
42
  if (!hasCombinedQuery(this.resourceQuery)) {
14
43
  return;
15
44
  }
16
45
  const request = buildProxyRequest(this);
17
- const cssOptions = resolveCssOptions(this);
46
+ const { cssOptions } = resolveLoaderOptions(this);
18
47
  return extractCss(this, cssOptions).then(css => createCombinedModule(request, css));
19
48
  };
20
49
  loader.pitch = pitch;
21
50
  export default loader;
22
- function resolveCssOptions(ctx) {
51
+ function resolveLoaderOptions(ctx) {
23
52
  const rawOptions = (typeof ctx.getOptions === 'function' ? ctx.getOptions() : {});
53
+ const { vanilla, ...rest } = rawOptions;
54
+ const cssOptions = {
55
+ ...rest,
56
+ cwd: rest.cwd ?? ctx.rootContext ?? process.cwd(),
57
+ };
24
58
  return {
25
- ...rawOptions,
26
- cwd: rawOptions.cwd ?? ctx.rootContext ?? process.cwd(),
59
+ cssOptions,
60
+ vanillaOptions: vanilla,
27
61
  };
28
62
  }
29
63
  async function extractCss(ctx, options) {
@@ -53,6 +87,11 @@ function hasCombinedQuery(query) {
53
87
  }
54
88
  function buildProxyRequest(ctx) {
55
89
  const sanitizedQuery = buildSanitizedQuery(ctx.resourceQuery);
90
+ const rawRequest = getRawRequest(ctx);
91
+ if (rawRequest) {
92
+ const stripped = stripResourceQuery(rawRequest);
93
+ return `${stripped}${sanitizedQuery}`;
94
+ }
56
95
  const request = `${ctx.resourcePath}${sanitizedQuery}`;
57
96
  const context = ctx.context ?? ctx.rootContext ?? process.cwd();
58
97
  if (ctx.utils && typeof ctx.utils.contextify === 'function') {
@@ -60,6 +99,18 @@ function buildProxyRequest(ctx) {
60
99
  }
61
100
  return request;
62
101
  }
102
+ function getRawRequest(ctx) {
103
+ const mod = ctx._module;
104
+ const request = mod?.rawRequest;
105
+ if (typeof request === 'string' && request.length > 0) {
106
+ return request;
107
+ }
108
+ return undefined;
109
+ }
110
+ function stripResourceQuery(request) {
111
+ const idx = request.indexOf('?');
112
+ return idx >= 0 ? request.slice(0, idx) : request;
113
+ }
63
114
  function buildSanitizedQuery(query) {
64
115
  if (!query)
65
116
  return '';
@@ -85,15 +136,26 @@ function isQueryFlag(entry, flag) {
85
136
  }
86
137
  function createCombinedModule(request, css) {
87
138
  const requestLiteral = JSON.stringify(request);
88
- const defaultExport = `const __knightedDefault =
89
- typeof __knightedModule.default !== 'undefined'
90
- ? __knightedModule.default
91
- : __knightedModule;`;
92
- return [
139
+ const lines = [
93
140
  `import * as __knightedModule from ${requestLiteral};`,
94
141
  `export * from ${requestLiteral};`,
95
- defaultExport,
96
- 'export default __knightedDefault;',
97
- buildInjection(css),
98
- ].join('\n');
142
+ ];
143
+ if (shouldForwardDefaultExport(request)) {
144
+ lines.push(`const __knightedDefault =
145
+ typeof __knightedModule.default !== 'undefined'
146
+ ? __knightedModule.default
147
+ : __knightedModule;`, 'export default __knightedDefault;');
148
+ }
149
+ lines.push(buildInjection(css));
150
+ return lines.join('\n');
151
+ }
152
+ function shouldForwardDefaultExport(request) {
153
+ const [pathPart] = request.split('?');
154
+ if (!pathPart)
155
+ return true;
156
+ const lower = pathPart.toLowerCase();
157
+ if (lower.endsWith('.css.ts') || lower.endsWith('.css.js')) {
158
+ return false;
159
+ }
160
+ return true;
99
161
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knighted/css",
3
- "version": "1.0.0-rc.0",
3
+ "version": "1.0.0-rc.1",
4
4
  "description": "A build-time utility that traverses JavaScript/TypeScript module dependency graphs to extract, compile, and optimize all imported CSS into a single, in-memory string.",
5
5
  "type": "module",
6
6
  "main": "./dist/css.js",