@knighted/css 1.0.9 → 1.1.0-rc.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.
@@ -28,6 +28,7 @@ export interface GenerateTypesOptions {
28
28
  include?: string[];
29
29
  outDir?: string;
30
30
  stableNamespace?: string;
31
+ autoStable?: boolean;
31
32
  }
32
33
  type ModuleTypeDetector = () => ReturnType<typeof moduleType>;
33
34
  declare function resolvePackageRoot(): string;
@@ -62,6 +63,7 @@ export interface ParsedCliArgs {
62
63
  include?: string[];
63
64
  outDir?: string;
64
65
  stableNamespace?: string;
66
+ autoStable?: boolean;
65
67
  help?: boolean;
66
68
  }
67
69
  declare function parseCliArgs(argv: string[]): ParsedCliArgs;
@@ -7,15 +7,30 @@ exports.pitch = void 0;
7
7
  const node_path_1 = __importDefault(require("node:path"));
8
8
  const css_js_1 = require("./css.cjs");
9
9
  const moduleInfo_js_1 = require("./moduleInfo.cjs");
10
+ const autoStableSelectors_js_1 = require("./autoStableSelectors.cjs");
10
11
  const loaderInternals_js_1 = require("./loaderInternals.cjs");
11
12
  const stableSelectorsLiteral_js_1 = require("./stableSelectorsLiteral.cjs");
12
13
  const stableNamespace_js_1 = require("./stableNamespace.cjs");
14
+ const stableSelectors_js_1 = require("./stableSelectors.cjs");
13
15
  const DEFAULT_EXPORT_NAME = 'knightedCss';
14
16
  const loader = async function loader(source) {
15
17
  const { cssOptions, vanillaOptions, stableNamespace: optionNamespace, } = resolveLoaderOptions(this);
16
18
  const resolvedNamespace = (0, stableNamespace_js_1.resolveStableNamespace)(optionNamespace);
17
19
  const typesRequested = (0, loaderInternals_js_1.hasQueryFlag)(this.resourceQuery, loaderInternals_js_1.TYPES_QUERY_FLAG);
18
- const css = await extractCss(this, cssOptions);
20
+ const isStyleModule = this.resourcePath.endsWith('.css.ts');
21
+ const cssOptionsForExtract = isStyleModule
22
+ ? { ...cssOptions, autoStable: undefined }
23
+ : cssOptions;
24
+ const cssMeta = await extractCss(this, cssOptionsForExtract);
25
+ const activeAutoStable = (0, autoStableSelectors_js_1.normalizeAutoStableOption)(cssOptionsForExtract.autoStable);
26
+ const cssModuleExports = activeAutoStable
27
+ ? mergeCssModuleExports(cssMeta.exports, {
28
+ namespace: activeAutoStable.namespace ?? resolvedNamespace,
29
+ include: activeAutoStable.include,
30
+ exclude: activeAutoStable.exclude,
31
+ })
32
+ : undefined;
33
+ const css = cssMeta.css;
19
34
  const stableSelectorsLiteral = typesRequested
20
35
  ? (0, stableSelectorsLiteral_js_1.buildStableSelectorsLiteral)({
21
36
  css,
@@ -25,10 +40,12 @@ const loader = async function loader(source) {
25
40
  target: 'js',
26
41
  })
27
42
  : undefined;
43
+ const emitCssModuleDefault = isCssLikeResource(this.resourcePath) && Boolean(cssModuleExports);
28
44
  const injection = buildInjection(css, {
29
45
  stableSelectorsLiteral: stableSelectorsLiteral?.literal,
46
+ cssModuleExports,
47
+ emitCssModuleDefault,
30
48
  });
31
- const isStyleModule = this.resourcePath.endsWith('.css.ts');
32
49
  if (isStyleModule) {
33
50
  const { source: compiledSource } = await (0, css_js_1.compileVanillaModule)(this.resourcePath, cssOptions.cwd ?? this.rootContext ?? process.cwd(), cssOptions.peerResolver);
34
51
  const vanillaSource = maybeTransformVanillaModule(compiledSource, vanillaOptions);
@@ -73,24 +90,34 @@ const pitch = function pitch() {
73
90
  const defaultSignalPromise = skipSyntheticDefault
74
91
  ? Promise.resolve('unknown')
75
92
  : (0, moduleInfo_js_1.detectModuleDefaultExport)(this.resourcePath);
76
- return Promise.all([extractCss(this, cssOptions), defaultSignalPromise]).then(([css, defaultSignal]) => {
93
+ return Promise.all([extractCss(this, cssOptions), defaultSignalPromise]).then(([cssMeta, defaultSignal]) => {
77
94
  const emitDefault = (0, loaderInternals_js_1.shouldEmitCombinedDefault)({
78
95
  request,
79
96
  skipSyntheticDefault,
80
97
  detection: defaultSignal,
81
98
  });
99
+ const activeAutoStable = (0, autoStableSelectors_js_1.normalizeAutoStableOption)(cssOptions.autoStable);
100
+ const cssModuleExports = activeAutoStable
101
+ ? mergeCssModuleExports(cssMeta.exports, {
102
+ namespace: activeAutoStable.namespace ?? resolvedNamespace,
103
+ include: activeAutoStable.include,
104
+ exclude: activeAutoStable.exclude,
105
+ })
106
+ : undefined;
82
107
  const stableSelectorsLiteral = typesRequested
83
108
  ? (0, stableSelectorsLiteral_js_1.buildStableSelectorsLiteral)({
84
- css,
109
+ css: cssMeta.css,
85
110
  namespace: resolvedNamespace,
86
111
  resourcePath: this.resourcePath,
87
112
  emitWarning: message => emitKnightedWarning(this, message),
88
113
  target: 'js',
89
114
  })
90
115
  : undefined;
91
- return createCombinedModule(request, css, {
116
+ return createCombinedModule(request, cssMeta.css, {
92
117
  emitDefault,
93
118
  stableSelectorsLiteral: stableSelectorsLiteral?.literal,
119
+ cssModuleExports,
120
+ emitCssModuleDefault: false,
94
121
  });
95
122
  });
96
123
  };
@@ -111,12 +138,12 @@ function resolveLoaderOptions(ctx) {
111
138
  };
112
139
  }
113
140
  async function extractCss(ctx, options) {
114
- const { css, files } = await (0, css_js_1.cssWithMeta)(ctx.resourcePath, options);
115
- const uniqueFiles = new Set([ctx.resourcePath, ...files]);
141
+ const result = await (0, css_js_1.cssWithMeta)(ctx.resourcePath, options);
142
+ const uniqueFiles = new Set([ctx.resourcePath, ...result.files]);
116
143
  for (const file of uniqueFiles) {
117
144
  ctx.addDependency(file);
118
145
  }
119
- return css;
146
+ return result;
120
147
  }
121
148
  function toSourceString(source) {
122
149
  return typeof source === 'string' ? source : source.toString('utf8');
@@ -126,8 +153,57 @@ function buildInjection(css, extras) {
126
153
  if (extras?.stableSelectorsLiteral) {
127
154
  lines.push(extras.stableSelectorsLiteral);
128
155
  }
156
+ if (extras?.cssModuleExports) {
157
+ lines.push(`export const knightedCssModules = ${JSON.stringify(extras.cssModuleExports)};`);
158
+ if (extras.emitCssModuleDefault) {
159
+ lines.push('export default knightedCssModules;');
160
+ }
161
+ }
129
162
  return lines.join('');
130
163
  }
164
+ function isCssLikeResource(resourcePath) {
165
+ return (/\.(css|scss|sass|less)(\?.*)?$/i.test(resourcePath) &&
166
+ !resourcePath.endsWith('.css.ts'));
167
+ }
168
+ function mergeCssModuleExports(exportsMap, options) {
169
+ if (!exportsMap)
170
+ return undefined;
171
+ const output = {};
172
+ for (const [token, value] of Object.entries(exportsMap)) {
173
+ const hashedParts = toClassParts(value);
174
+ if (options.exclude && options.exclude.test(token)) {
175
+ output[token] = hashedParts.join(' ');
176
+ continue;
177
+ }
178
+ if (options.include && !options.include.test(token)) {
179
+ output[token] = hashedParts.join(' ');
180
+ continue;
181
+ }
182
+ const stable = (0, stableSelectors_js_1.stableClass)(token, { namespace: options.namespace });
183
+ if (stable && !hashedParts.includes(stable)) {
184
+ hashedParts.push(stable);
185
+ }
186
+ output[token] = hashedParts.join(' ');
187
+ }
188
+ return output;
189
+ }
190
+ function toClassParts(value) {
191
+ if (!value)
192
+ return [];
193
+ if (Array.isArray(value)) {
194
+ return value.flatMap(part => part.split(/\s+/).filter(Boolean));
195
+ }
196
+ if (typeof value === 'object') {
197
+ const parts = [
198
+ value.name,
199
+ ...(value.composes ?? []).map(entry => typeof entry === 'string' ? entry : entry?.name),
200
+ ]
201
+ .filter(Boolean)
202
+ .map(String);
203
+ return parts.flatMap(part => part.split(/\s+/).filter(Boolean));
204
+ }
205
+ return value.split(/\s+/).filter(Boolean);
206
+ }
131
207
  function buildProxyRequest(ctx) {
132
208
  const sanitizedQuery = (0, loaderInternals_js_1.buildSanitizedQuery)(ctx.resourceQuery);
133
209
  const rawRequest = getRawRequest(ctx);
@@ -208,7 +284,11 @@ typeof __knightedModule.default !== 'undefined'
208
284
  ? __knightedModule.default
209
285
  : __knightedModule;`, 'export default __knightedDefault;');
210
286
  }
211
- lines.push(buildInjection(css, { stableSelectorsLiteral: options?.stableSelectorsLiteral }));
287
+ lines.push(buildInjection(css, {
288
+ stableSelectorsLiteral: options?.stableSelectorsLiteral,
289
+ cssModuleExports: options?.cssModuleExports,
290
+ emitCssModuleDefault: options?.emitCssModuleDefault,
291
+ }));
212
292
  return lines.join('\n');
213
293
  }
214
294
  function emitKnightedWarning(ctx, message) {