@knighted/css 1.0.0-rc.0 → 1.0.0-rc.10
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/bin/generate-types.js +31 -0
- package/dist/cjs/css.cjs +107 -25
- package/dist/cjs/css.d.cts +10 -6
- package/dist/cjs/generateTypes.cjs +636 -0
- package/dist/cjs/generateTypes.d.cts +104 -0
- package/dist/cjs/loader.cjs +128 -56
- package/dist/cjs/loader.d.cts +5 -0
- package/dist/cjs/loaderInternals.cjs +108 -0
- package/dist/cjs/loaderInternals.d.cts +23 -0
- package/dist/cjs/moduleGraph.cjs +431 -0
- package/dist/cjs/moduleGraph.d.cts +15 -0
- package/dist/cjs/moduleInfo.cjs +62 -0
- package/dist/cjs/moduleInfo.d.cts +10 -0
- package/dist/cjs/sassInternals.cjs +135 -0
- package/dist/cjs/sassInternals.d.cts +25 -0
- package/dist/cjs/stableNamespace.cjs +12 -0
- package/dist/cjs/stableNamespace.d.cts +3 -0
- package/dist/cjs/stableSelectors.cjs +44 -0
- package/dist/cjs/stableSelectors.d.cts +13 -0
- package/dist/cjs/stableSelectorsLiteral.cjs +104 -0
- package/dist/cjs/stableSelectorsLiteral.d.cts +19 -0
- package/dist/cjs/types.cjs +2 -0
- package/dist/cjs/types.d.cts +4 -0
- package/dist/css.d.ts +10 -6
- package/dist/css.js +107 -26
- package/dist/generateTypes.d.ts +104 -0
- package/dist/generateTypes.js +628 -0
- package/dist/loader.d.ts +5 -0
- package/dist/loader.js +127 -55
- package/dist/loaderInternals.d.ts +23 -0
- package/dist/loaderInternals.js +96 -0
- package/dist/moduleGraph.d.ts +15 -0
- package/dist/moduleGraph.js +425 -0
- package/dist/moduleInfo.d.ts +10 -0
- package/dist/moduleInfo.js +55 -0
- package/dist/sassInternals.d.ts +25 -0
- package/dist/sassInternals.js +124 -0
- package/dist/stableNamespace.d.ts +3 -0
- package/dist/stableNamespace.js +8 -0
- package/dist/stableSelectors.d.ts +13 -0
- package/dist/stableSelectors.js +36 -0
- package/dist/stableSelectorsLiteral.d.ts +19 -0
- package/dist/stableSelectorsLiteral.js +98 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.js +1 -0
- package/loader-queries.d.ts +61 -0
- package/package.json +58 -8
- package/stable/_index.scss +57 -0
- package/stable/stable.css +15 -0
- package/types-stub/index.d.ts +5 -0
- package/types.d.ts +4 -0
package/dist/loader.js
CHANGED
|
@@ -1,29 +1,103 @@
|
|
|
1
|
-
import { cssWithMeta } from './css.js';
|
|
1
|
+
import { cssWithMeta, compileVanillaModule } from './css.js';
|
|
2
|
+
import { detectModuleDefaultExport } from './moduleInfo.js';
|
|
3
|
+
import { buildSanitizedQuery, hasCombinedQuery, hasNamedOnlyQueryFlag, hasQueryFlag, shouldEmitCombinedDefault, shouldForwardDefaultExport, TYPES_QUERY_FLAG, } from './loaderInternals.js';
|
|
4
|
+
import { buildStableSelectorsLiteral } from './stableSelectorsLiteral.js';
|
|
5
|
+
import { resolveStableNamespace } from './stableNamespace.js';
|
|
2
6
|
const DEFAULT_EXPORT_NAME = 'knightedCss';
|
|
3
|
-
const COMBINED_QUERY_FLAG = 'combined';
|
|
4
7
|
const loader = async function loader(source) {
|
|
5
|
-
const cssOptions =
|
|
8
|
+
const { cssOptions, vanillaOptions, stableNamespace: optionNamespace, } = resolveLoaderOptions(this);
|
|
9
|
+
const resolvedNamespace = resolveStableNamespace(optionNamespace);
|
|
10
|
+
const typesRequested = hasQueryFlag(this.resourceQuery, TYPES_QUERY_FLAG);
|
|
6
11
|
const css = await extractCss(this, cssOptions);
|
|
7
|
-
const
|
|
8
|
-
|
|
12
|
+
const stableSelectorsLiteral = typesRequested
|
|
13
|
+
? buildStableSelectorsLiteral({
|
|
14
|
+
css,
|
|
15
|
+
namespace: resolvedNamespace,
|
|
16
|
+
resourcePath: this.resourcePath,
|
|
17
|
+
emitWarning: message => emitKnightedWarning(this, message),
|
|
18
|
+
})
|
|
19
|
+
: undefined;
|
|
20
|
+
const injection = buildInjection(css, {
|
|
21
|
+
stableSelectorsLiteral: stableSelectorsLiteral?.literal,
|
|
22
|
+
});
|
|
9
23
|
const isStyleModule = this.resourcePath.endsWith('.css.ts');
|
|
10
|
-
|
|
24
|
+
if (isStyleModule) {
|
|
25
|
+
const { source: compiledSource } = await compileVanillaModule(this.resourcePath, cssOptions.cwd ?? this.rootContext ?? process.cwd(), cssOptions.peerResolver);
|
|
26
|
+
const vanillaSource = maybeTransformVanillaModule(compiledSource, vanillaOptions);
|
|
27
|
+
return `${vanillaSource}${injection}`;
|
|
28
|
+
}
|
|
29
|
+
const input = toSourceString(source);
|
|
30
|
+
return `${input}${injection}`;
|
|
11
31
|
};
|
|
32
|
+
function transformVanillaModuleToEsm(source) {
|
|
33
|
+
const exportBlock = /__export\([^,]+,\s*{([\s\S]*?)}\);/m.exec(source);
|
|
34
|
+
if (!exportBlock) {
|
|
35
|
+
return source;
|
|
36
|
+
}
|
|
37
|
+
const names = exportBlock[1]
|
|
38
|
+
.split(',')
|
|
39
|
+
.map(part => part.trim())
|
|
40
|
+
.filter(Boolean)
|
|
41
|
+
.map(entry => entry.split(':')[0]?.trim())
|
|
42
|
+
.filter(Boolean);
|
|
43
|
+
let transformed = source.replace(/module\.exports\s*=\s*__toCommonJS\([^;]+;\n?/m, '');
|
|
44
|
+
transformed = transformed.replace(/0 && \(module\.exports = {[^}]+}\);?\n?/m, '');
|
|
45
|
+
if (names.length > 0) {
|
|
46
|
+
transformed = `${transformed}\nexport { ${names.join(', ')} };\n`;
|
|
47
|
+
}
|
|
48
|
+
return transformed;
|
|
49
|
+
}
|
|
50
|
+
function maybeTransformVanillaModule(source, options) {
|
|
51
|
+
if (!options?.transformToEsm) {
|
|
52
|
+
return source;
|
|
53
|
+
}
|
|
54
|
+
return transformVanillaModuleToEsm(source);
|
|
55
|
+
}
|
|
12
56
|
export const pitch = function pitch() {
|
|
13
57
|
if (!hasCombinedQuery(this.resourceQuery)) {
|
|
14
58
|
return;
|
|
15
59
|
}
|
|
16
60
|
const request = buildProxyRequest(this);
|
|
17
|
-
const cssOptions =
|
|
18
|
-
|
|
61
|
+
const { cssOptions, stableNamespace: optionNamespace } = resolveLoaderOptions(this);
|
|
62
|
+
const typesRequested = hasQueryFlag(this.resourceQuery, TYPES_QUERY_FLAG);
|
|
63
|
+
const resolvedNamespace = resolveStableNamespace(optionNamespace);
|
|
64
|
+
const skipSyntheticDefault = hasNamedOnlyQueryFlag(this.resourceQuery);
|
|
65
|
+
const defaultSignalPromise = skipSyntheticDefault
|
|
66
|
+
? Promise.resolve('unknown')
|
|
67
|
+
: detectModuleDefaultExport(this.resourcePath);
|
|
68
|
+
return Promise.all([extractCss(this, cssOptions), defaultSignalPromise]).then(([css, defaultSignal]) => {
|
|
69
|
+
const emitDefault = shouldEmitCombinedDefault({
|
|
70
|
+
request,
|
|
71
|
+
skipSyntheticDefault,
|
|
72
|
+
detection: defaultSignal,
|
|
73
|
+
});
|
|
74
|
+
const stableSelectorsLiteral = typesRequested
|
|
75
|
+
? buildStableSelectorsLiteral({
|
|
76
|
+
css,
|
|
77
|
+
namespace: resolvedNamespace,
|
|
78
|
+
resourcePath: this.resourcePath,
|
|
79
|
+
emitWarning: message => emitKnightedWarning(this, message),
|
|
80
|
+
})
|
|
81
|
+
: undefined;
|
|
82
|
+
return createCombinedModule(request, css, {
|
|
83
|
+
emitDefault,
|
|
84
|
+
stableSelectorsLiteral: stableSelectorsLiteral?.literal,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
19
87
|
};
|
|
20
88
|
loader.pitch = pitch;
|
|
21
89
|
export default loader;
|
|
22
|
-
function
|
|
90
|
+
function resolveLoaderOptions(ctx) {
|
|
23
91
|
const rawOptions = (typeof ctx.getOptions === 'function' ? ctx.getOptions() : {});
|
|
92
|
+
const { vanilla, stableNamespace, ...rest } = rawOptions;
|
|
93
|
+
const cssOptions = {
|
|
94
|
+
...rest,
|
|
95
|
+
cwd: rest.cwd ?? ctx.rootContext ?? process.cwd(),
|
|
96
|
+
};
|
|
24
97
|
return {
|
|
25
|
-
|
|
26
|
-
|
|
98
|
+
cssOptions,
|
|
99
|
+
vanillaOptions: vanilla,
|
|
100
|
+
stableNamespace,
|
|
27
101
|
};
|
|
28
102
|
}
|
|
29
103
|
async function extractCss(ctx, options) {
|
|
@@ -37,22 +111,20 @@ async function extractCss(ctx, options) {
|
|
|
37
111
|
function toSourceString(source) {
|
|
38
112
|
return typeof source === 'string' ? source : source.toString('utf8');
|
|
39
113
|
}
|
|
40
|
-
function buildInjection(css) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const trimmed = query.startsWith('?') ? query.slice(1) : query;
|
|
47
|
-
if (!trimmed)
|
|
48
|
-
return false;
|
|
49
|
-
return trimmed
|
|
50
|
-
.split('&')
|
|
51
|
-
.filter(Boolean)
|
|
52
|
-
.some(part => isQueryFlag(part, COMBINED_QUERY_FLAG));
|
|
114
|
+
function buildInjection(css, extras) {
|
|
115
|
+
const lines = [`\n\nexport const ${DEFAULT_EXPORT_NAME} = ${JSON.stringify(css)};\n`];
|
|
116
|
+
if (extras?.stableSelectorsLiteral) {
|
|
117
|
+
lines.push(extras.stableSelectorsLiteral);
|
|
118
|
+
}
|
|
119
|
+
return lines.join('');
|
|
53
120
|
}
|
|
54
121
|
function buildProxyRequest(ctx) {
|
|
55
122
|
const sanitizedQuery = buildSanitizedQuery(ctx.resourceQuery);
|
|
123
|
+
const rawRequest = getRawRequest(ctx);
|
|
124
|
+
if (rawRequest) {
|
|
125
|
+
const stripped = stripResourceQuery(rawRequest);
|
|
126
|
+
return `${stripped}${sanitizedQuery}`;
|
|
127
|
+
}
|
|
56
128
|
const request = `${ctx.resourcePath}${sanitizedQuery}`;
|
|
57
129
|
const context = ctx.context ?? ctx.rootContext ?? process.cwd();
|
|
58
130
|
if (ctx.utils && typeof ctx.utils.contextify === 'function') {
|
|
@@ -60,40 +132,40 @@ function buildProxyRequest(ctx) {
|
|
|
60
132
|
}
|
|
61
133
|
return request;
|
|
62
134
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return
|
|
68
|
-
});
|
|
69
|
-
return entries.length > 0 ? `?${entries.join('&')}` : '';
|
|
70
|
-
}
|
|
71
|
-
function splitQuery(query) {
|
|
72
|
-
const trimmed = query.startsWith('?') ? query.slice(1) : query;
|
|
73
|
-
if (!trimmed)
|
|
74
|
-
return [];
|
|
75
|
-
return trimmed.split('&').filter(Boolean);
|
|
76
|
-
}
|
|
77
|
-
function isQueryFlag(entry, flag) {
|
|
78
|
-
const [rawKey] = entry.split('=');
|
|
79
|
-
try {
|
|
80
|
-
return decodeURIComponent(rawKey) === flag;
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
return rawKey === flag;
|
|
135
|
+
function getRawRequest(ctx) {
|
|
136
|
+
const mod = ctx._module;
|
|
137
|
+
const request = mod?.rawRequest;
|
|
138
|
+
if (typeof request === 'string' && request.length > 0) {
|
|
139
|
+
return request;
|
|
84
140
|
}
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
function stripResourceQuery(request) {
|
|
144
|
+
const idx = request.indexOf('?');
|
|
145
|
+
return idx >= 0 ? request.slice(0, idx) : request;
|
|
85
146
|
}
|
|
86
|
-
function createCombinedModule(request, css) {
|
|
147
|
+
function createCombinedModule(request, css, options) {
|
|
148
|
+
const shouldEmitDefault = options?.emitDefault ?? shouldForwardDefaultExport(request);
|
|
87
149
|
const requestLiteral = JSON.stringify(request);
|
|
88
|
-
const
|
|
89
|
-
typeof __knightedModule.default !== 'undefined'
|
|
90
|
-
? __knightedModule.default
|
|
91
|
-
: __knightedModule;`;
|
|
92
|
-
return [
|
|
150
|
+
const lines = [
|
|
93
151
|
`import * as __knightedModule from ${requestLiteral};`,
|
|
94
152
|
`export * from ${requestLiteral};`,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
153
|
+
];
|
|
154
|
+
if (shouldEmitDefault) {
|
|
155
|
+
lines.push(`const __knightedDefault =
|
|
156
|
+
typeof __knightedModule.default !== 'undefined'
|
|
157
|
+
? __knightedModule.default
|
|
158
|
+
: __knightedModule;`, 'export default __knightedDefault;');
|
|
159
|
+
}
|
|
160
|
+
lines.push(buildInjection(css, { stableSelectorsLiteral: options?.stableSelectorsLiteral }));
|
|
161
|
+
return lines.join('\n');
|
|
162
|
+
}
|
|
163
|
+
function emitKnightedWarning(ctx, message) {
|
|
164
|
+
const formatted = `\x1b[33m@knighted/css warning\x1b[0m ${message}`;
|
|
165
|
+
if (typeof ctx.emitWarning === 'function') {
|
|
166
|
+
ctx.emitWarning(new Error(formatted));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
// eslint-disable-next-line no-console
|
|
170
|
+
console.warn(formatted);
|
|
99
171
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ModuleDefaultSignal } from './moduleInfo.js';
|
|
2
|
+
export declare const COMBINED_QUERY_FLAG = "combined";
|
|
3
|
+
export declare const TYPES_QUERY_FLAG = "types";
|
|
4
|
+
export declare const NAMED_ONLY_QUERY_FLAGS: readonly ["named-only", "no-default"];
|
|
5
|
+
export type SelectorTypeVariant = 'types' | 'combined' | 'combinedWithoutDefault';
|
|
6
|
+
export declare function splitQuery(query: string): string[];
|
|
7
|
+
export declare function isQueryFlag(entry: string, flag: string): boolean;
|
|
8
|
+
export declare function buildSanitizedQuery(query?: string | null): string;
|
|
9
|
+
export declare function hasQueryFlag(query: string | null | undefined, flag: string): boolean;
|
|
10
|
+
export declare function shouldForwardDefaultExport(request: string): boolean;
|
|
11
|
+
export declare function hasCombinedQuery(query?: string | null): boolean;
|
|
12
|
+
export declare function hasNamedOnlyQueryFlag(query?: string | null): boolean;
|
|
13
|
+
export declare function determineSelectorVariant(query?: string | null): SelectorTypeVariant;
|
|
14
|
+
export declare function shouldEmitCombinedDefault(options: {
|
|
15
|
+
detection: ModuleDefaultSignal;
|
|
16
|
+
request: string;
|
|
17
|
+
skipSyntheticDefault: boolean;
|
|
18
|
+
}): boolean;
|
|
19
|
+
export declare const __loaderInternals: {
|
|
20
|
+
buildSanitizedQuery: typeof buildSanitizedQuery;
|
|
21
|
+
shouldEmitCombinedDefault: typeof shouldEmitCombinedDefault;
|
|
22
|
+
determineSelectorVariant: typeof determineSelectorVariant;
|
|
23
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export const COMBINED_QUERY_FLAG = 'combined';
|
|
2
|
+
export const TYPES_QUERY_FLAG = 'types';
|
|
3
|
+
export const NAMED_ONLY_QUERY_FLAGS = ['named-only', 'no-default'];
|
|
4
|
+
export function splitQuery(query) {
|
|
5
|
+
const trimmed = query.startsWith('?') ? query.slice(1) : query;
|
|
6
|
+
if (!trimmed)
|
|
7
|
+
return [];
|
|
8
|
+
return trimmed.split('&').filter(Boolean);
|
|
9
|
+
}
|
|
10
|
+
export function isQueryFlag(entry, flag) {
|
|
11
|
+
const [rawKey] = entry.split('=');
|
|
12
|
+
try {
|
|
13
|
+
return decodeURIComponent(rawKey) === flag;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return rawKey === flag;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function buildSanitizedQuery(query) {
|
|
20
|
+
if (!query)
|
|
21
|
+
return '';
|
|
22
|
+
const entries = splitQuery(query).filter(part => {
|
|
23
|
+
if (isQueryFlag(part, COMBINED_QUERY_FLAG)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (isQueryFlag(part, 'knighted-css')) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
if (isQueryFlag(part, TYPES_QUERY_FLAG)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (NAMED_ONLY_QUERY_FLAGS.some(flag => isQueryFlag(part, flag))) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
});
|
|
37
|
+
return entries.length > 0 ? `?${entries.join('&')}` : '';
|
|
38
|
+
}
|
|
39
|
+
export function hasQueryFlag(query, flag) {
|
|
40
|
+
if (!query)
|
|
41
|
+
return false;
|
|
42
|
+
const entries = splitQuery(query);
|
|
43
|
+
if (entries.length === 0)
|
|
44
|
+
return false;
|
|
45
|
+
return entries.some(part => isQueryFlag(part, flag));
|
|
46
|
+
}
|
|
47
|
+
function safeDecode(value) {
|
|
48
|
+
try {
|
|
49
|
+
return decodeURIComponent(value);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function shouldForwardDefaultExport(request) {
|
|
56
|
+
const [pathPart] = request.split('?');
|
|
57
|
+
if (!pathPart)
|
|
58
|
+
return true;
|
|
59
|
+
const lower = pathPart.toLowerCase();
|
|
60
|
+
if (lower.endsWith('.css.ts') || lower.endsWith('.css.js')) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
export function hasCombinedQuery(query) {
|
|
66
|
+
return hasQueryFlag(query, COMBINED_QUERY_FLAG);
|
|
67
|
+
}
|
|
68
|
+
export function hasNamedOnlyQueryFlag(query) {
|
|
69
|
+
return NAMED_ONLY_QUERY_FLAGS.some(flag => hasQueryFlag(query, flag));
|
|
70
|
+
}
|
|
71
|
+
export function determineSelectorVariant(query) {
|
|
72
|
+
if (hasCombinedQuery(query)) {
|
|
73
|
+
return hasNamedOnlyQueryFlag(query) ? 'combinedWithoutDefault' : 'combined';
|
|
74
|
+
}
|
|
75
|
+
return 'types';
|
|
76
|
+
}
|
|
77
|
+
export function shouldEmitCombinedDefault(options) {
|
|
78
|
+
if (options.skipSyntheticDefault) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (!shouldForwardDefaultExport(options.request)) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
if (options.detection === 'has-default') {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
if (options.detection === 'no-default') {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
export const __loaderInternals = {
|
|
93
|
+
buildSanitizedQuery,
|
|
94
|
+
shouldEmitCombinedDefault,
|
|
95
|
+
determineSelectorVariant,
|
|
96
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CssResolver } from './types.js';
|
|
2
|
+
export interface ModuleGraphOptions {
|
|
3
|
+
tsConfig?: string | Record<string, unknown>;
|
|
4
|
+
extensions?: string[];
|
|
5
|
+
conditions?: string[];
|
|
6
|
+
}
|
|
7
|
+
interface CollectOptions {
|
|
8
|
+
cwd: string;
|
|
9
|
+
styleExtensions: string[];
|
|
10
|
+
filter: (filePath: string) => boolean;
|
|
11
|
+
resolver?: CssResolver;
|
|
12
|
+
graphOptions?: ModuleGraphOptions;
|
|
13
|
+
}
|
|
14
|
+
export declare function collectStyleImports(entryPath: string, options: CollectOptions): Promise<string[]>;
|
|
15
|
+
export {};
|