auklet 0.2.7 → 0.2.8
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 +7 -5
- package/dist/css/core/styleModuleEntryPlanner.js +1 -1
- package/dist/css/core/stylePackageContext.d.ts +6 -1
- package/dist/css/core/stylePackageContext.js +23 -1
- package/dist/css/core/styleProcessor.d.ts +10 -0
- package/dist/css/core/styleProcessor.js +148 -23
- package/dist/css/core/workspaceStyleResolver.d.ts +5 -0
- package/dist/css/core/workspaceStyleResolver.js +35 -3
- package/dist/css/production/builder.js +1 -0
- package/dist/css/production/format/moduleWriter.d.ts +1 -0
- package/dist/css/production/format/moduleWriter.js +7 -7
- package/dist/css/production/format/sourceWriter.d.ts +1 -1
- package/dist/css/production/format/sourceWriter.js +10 -4
- package/dist/css/production/moduleOutputWriter.js +1 -0
- package/dist/css/vite/moduleGraph/styleCodeFactory.d.ts +2 -0
- package/dist/css/vite/moduleGraph/styleCodeFactory.js +40 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -181,8 +181,10 @@ pattern syntax is a small glob subset: `*`, `**`, and `?`.
|
|
|
181
181
|
|
|
182
182
|
For example, `components/CodeBlock/index.css` may import
|
|
183
183
|
`../../internal/syntaxHighlight.css` when it matches `styles.shared`; component
|
|
184
|
-
CSS outputs
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
184
|
+
CSS outputs keep that `@import` relationship instead of expanding the shared
|
|
185
|
+
rules into every component output. The shared CSS file is still copied as its
|
|
186
|
+
own source-level CSS file. `dist/index.css` remains the full package CSS
|
|
187
|
+
aggregate, while format-level and component-level CSS entries preserve the
|
|
188
|
+
import graph as much as possible. Shared CSS cannot import component CSS or
|
|
189
|
+
theme CSS. Component-to-component CSS imports are still rejected; package CSS
|
|
190
|
+
dependencies should be expressed through `styles.dependencies`.
|
|
@@ -62,7 +62,7 @@ export class StyleModuleEntryPlanner {
|
|
|
62
62
|
throw new Error(`[css] cross-package CSS import detected: ${importer} imports ${imported}. ` +
|
|
63
63
|
'Use styles.dependencies to express package style dependencies.');
|
|
64
64
|
}
|
|
65
|
-
if (this.packageContext.
|
|
65
|
+
if (this.packageContext.shouldAllowSharedStyleImport(item))
|
|
66
66
|
continue;
|
|
67
67
|
if (this.packageContext.isSharedStyleFile(item.importer)) {
|
|
68
68
|
const importer = this.toRelativeSourceFile(item.importer);
|
|
@@ -22,14 +22,19 @@ export declare class StylePackageContext {
|
|
|
22
22
|
private readonly sourceModuleDirs;
|
|
23
23
|
private readonly themeStyleFileKeys;
|
|
24
24
|
private readonly sharedStyleFileKeys;
|
|
25
|
+
private hasValidatedSourceRootLocalStyleImports;
|
|
26
|
+
private hasValidatedPreservedLocalStyleImports;
|
|
25
27
|
private moduleStyleEntryPlanner?;
|
|
26
28
|
private moduleStyleImports?;
|
|
27
29
|
constructor(options: StylePackageContextOptions);
|
|
28
30
|
getStyleFiles(files: Array<string>): string[];
|
|
29
31
|
getModuleStyleImports(): Map<string, string[]>;
|
|
30
32
|
getModuleStyleEntryPlanner(): StyleModuleEntryPlanner;
|
|
33
|
+
getStyleEntryFiles(): string[];
|
|
31
34
|
isSharedStyleFile(file: string): boolean;
|
|
32
|
-
|
|
35
|
+
shouldAllowSharedStyleImport(reference: StyleFileImportReference): boolean;
|
|
36
|
+
assertPreservedLocalStyleImports(): void;
|
|
37
|
+
assertNoSourceRootEscapingLocalStyleImports(): void;
|
|
33
38
|
private isSharedHelperStyleFile;
|
|
34
39
|
private getSourceModuleDirs;
|
|
35
40
|
private isSourceModuleStyleFile;
|
|
@@ -23,6 +23,8 @@ export class StylePackageContext {
|
|
|
23
23
|
sourceModuleDirs;
|
|
24
24
|
themeStyleFileKeys;
|
|
25
25
|
sharedStyleFileKeys;
|
|
26
|
+
hasValidatedSourceRootLocalStyleImports = false;
|
|
27
|
+
hasValidatedPreservedLocalStyleImports = false;
|
|
26
28
|
moduleStyleEntryPlanner;
|
|
27
29
|
moduleStyleImports;
|
|
28
30
|
constructor(options) {
|
|
@@ -61,15 +63,35 @@ export class StylePackageContext {
|
|
|
61
63
|
this.moduleStyleEntryPlanner ??= new StyleModuleEntryPlanner(this);
|
|
62
64
|
return this.moduleStyleEntryPlanner;
|
|
63
65
|
}
|
|
66
|
+
getStyleEntryFiles() {
|
|
67
|
+
const importedStyleFiles = this.styleProcessor.collectImportedStyleFiles(this.styleFiles);
|
|
68
|
+
return this.styleFiles.filter((styleFile) => !importedStyleFiles.has(path.resolve(styleFile)));
|
|
69
|
+
}
|
|
64
70
|
isSharedStyleFile(file) {
|
|
65
71
|
return this.sharedStyleFileKeys.has(normalizeFileKey(file));
|
|
66
72
|
}
|
|
67
|
-
|
|
73
|
+
shouldAllowSharedStyleImport(reference) {
|
|
68
74
|
return ((this.isSharedStyleFile(reference.imported) &&
|
|
69
75
|
this.isSharedHelperStyleFile(reference.imported)) ||
|
|
70
76
|
(this.isSharedStyleFile(reference.importer) &&
|
|
71
77
|
this.isSharedHelperStyleFile(reference.imported)));
|
|
72
78
|
}
|
|
79
|
+
assertPreservedLocalStyleImports() {
|
|
80
|
+
if (this.hasValidatedPreservedLocalStyleImports)
|
|
81
|
+
return;
|
|
82
|
+
this.assertNoSourceRootEscapingLocalStyleImports();
|
|
83
|
+
this.styleProcessor.assertNoLocalStyleImportCycles(this.styleFiles);
|
|
84
|
+
this.hasValidatedPreservedLocalStyleImports = true;
|
|
85
|
+
}
|
|
86
|
+
assertNoSourceRootEscapingLocalStyleImports() {
|
|
87
|
+
if (this.hasValidatedSourceRootLocalStyleImports)
|
|
88
|
+
return;
|
|
89
|
+
this.styleProcessor.assertNoSourceRootEscapingLocalStyleImports([
|
|
90
|
+
...this.styleFiles,
|
|
91
|
+
...this.themeFiles.values(),
|
|
92
|
+
]);
|
|
93
|
+
this.hasValidatedSourceRootLocalStyleImports = true;
|
|
94
|
+
}
|
|
73
95
|
isSharedHelperStyleFile(file) {
|
|
74
96
|
return (this.isInsideSourceRoot(file) &&
|
|
75
97
|
!this.isThemeStyleFile(file) &&
|
|
@@ -4,8 +4,10 @@ import type { WorkspaceStyleResolver } from '#auklet/css/core/workspaceStyleReso
|
|
|
4
4
|
export type StyleFileImportReference = {
|
|
5
5
|
importer: string;
|
|
6
6
|
imported: string;
|
|
7
|
+
specifier: string;
|
|
7
8
|
};
|
|
8
9
|
export type StyleFileImportExpandOptions = {
|
|
10
|
+
mapImportSpecifier?: (reference: StyleFileImportReference) => string;
|
|
9
11
|
shouldExpandImport?: (reference: StyleFileImportReference) => boolean;
|
|
10
12
|
};
|
|
11
13
|
export declare class StyleProcessor {
|
|
@@ -17,9 +19,17 @@ export declare class StyleProcessor {
|
|
|
17
19
|
stringify(root: Root): string;
|
|
18
20
|
appendStyleContent(target: Root, content: string, from: string): void;
|
|
19
21
|
readStyleFile(stylePath: string, seen?: Set<string>, options?: StyleFileImportExpandOptions): string;
|
|
22
|
+
private isSourceStyleImportSpecifier;
|
|
23
|
+
private throwMissingLocalStyleImport;
|
|
20
24
|
collectImportedStyleFiles(styleFiles: Array<string>): Set<string>;
|
|
21
25
|
collectImportedStyleFileReferences(styleFiles: Array<string>): StyleFileImportReference[];
|
|
22
26
|
collectStyleImportSpecifiers(styleFiles: Array<string>): Set<string>;
|
|
27
|
+
assertNoLocalStyleImportCycles(styleFiles: Array<string>): void;
|
|
28
|
+
assertNoSourceRootEscapingLocalStyleImports(styleFiles: Array<string>): void;
|
|
23
29
|
private parse;
|
|
24
30
|
private parseImportSpecifier;
|
|
31
|
+
private resolveStyleImportReference;
|
|
32
|
+
private assertSourceRootLocalStyleImport;
|
|
33
|
+
private collectLocalStyleImportReferences;
|
|
34
|
+
private parseImportSpecifierReference;
|
|
25
35
|
}
|
|
@@ -44,29 +44,39 @@ export class StyleProcessor {
|
|
|
44
44
|
const root = this.parse(css, stylePath);
|
|
45
45
|
const imports = [];
|
|
46
46
|
root.walkAtRules('import', (rule) => {
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
imports.push({ rule,
|
|
47
|
+
const reference = this.parseImportSpecifierReference(rule.params);
|
|
48
|
+
if (reference)
|
|
49
|
+
imports.push({ rule, ...reference });
|
|
50
50
|
});
|
|
51
|
-
for (const { rule, specifier } of imports) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (options.shouldExpandImport?.(reference) === false)
|
|
51
|
+
for (const { rule, specifier, specifierStart, specifierEnd } of imports) {
|
|
52
|
+
const { reference, isLocalStyleImport } = this.resolveStyleImportReference(specifier, stylePath);
|
|
53
|
+
this.assertSourceRootLocalStyleImport(reference, isLocalStyleImport);
|
|
54
|
+
const mappedSpecifier = options.mapImportSpecifier?.(reference);
|
|
55
|
+
if (mappedSpecifier) {
|
|
56
|
+
rule.params = `${rule.params.slice(0, specifierStart)}${mappedSpecifier}${rule.params.slice(specifierEnd)}`;
|
|
57
|
+
}
|
|
58
|
+
if (options.shouldExpandImport?.(reference) === false) {
|
|
60
59
|
continue;
|
|
61
|
-
|
|
60
|
+
}
|
|
61
|
+
const content = this.readStyleFile(reference.imported, seen, options);
|
|
62
62
|
if (!content.trim()) {
|
|
63
63
|
rule.remove();
|
|
64
64
|
continue;
|
|
65
65
|
}
|
|
66
|
-
rule.replaceWith(...(this.parse(content,
|
|
66
|
+
rule.replaceWith(...(this.parse(content, reference.imported).nodes ?? []));
|
|
67
67
|
}
|
|
68
68
|
return root.toString();
|
|
69
69
|
}
|
|
70
|
+
isSourceStyleImportSpecifier(specifier, importedPath) {
|
|
71
|
+
if (specifier.startsWith('#'))
|
|
72
|
+
return true;
|
|
73
|
+
return (this.config.styleExtensions.includes(path.extname(importedPath ?? specifier)) &&
|
|
74
|
+
(specifier.startsWith('.') ||
|
|
75
|
+
(importedPath ? this.resolver.isInsideSourceRoot(importedPath) : false)));
|
|
76
|
+
}
|
|
77
|
+
throwMissingLocalStyleImport(specifier, stylePath) {
|
|
78
|
+
throw new Error(`[css] local CSS import not found: ${specifier} from ${stylePath}`);
|
|
79
|
+
}
|
|
70
80
|
collectImportedStyleFiles(styleFiles) {
|
|
71
81
|
return new Set(this.collectImportedStyleFileReferences(styleFiles).map((item) => item.imported));
|
|
72
82
|
}
|
|
@@ -77,14 +87,13 @@ export class StyleProcessor {
|
|
|
77
87
|
const root = this.parse(css, styleFile);
|
|
78
88
|
root.walkAtRules('import', (rule) => {
|
|
79
89
|
const specifier = this.parseImportSpecifier(rule.params);
|
|
80
|
-
if (!specifier
|
|
81
|
-
|
|
90
|
+
if (!specifier)
|
|
91
|
+
return;
|
|
92
|
+
const { reference, isLocalStyleImport } = this.resolveStyleImportReference(specifier, styleFile);
|
|
93
|
+
if (!isLocalStyleImport) {
|
|
82
94
|
return;
|
|
83
95
|
}
|
|
84
|
-
imports.push(
|
|
85
|
-
importer: path.resolve(styleFile),
|
|
86
|
-
imported: path.resolve(path.dirname(styleFile), specifier),
|
|
87
|
-
});
|
|
96
|
+
imports.push(reference);
|
|
88
97
|
});
|
|
89
98
|
}
|
|
90
99
|
return imports;
|
|
@@ -102,17 +111,117 @@ export class StyleProcessor {
|
|
|
102
111
|
}
|
|
103
112
|
return specifiers;
|
|
104
113
|
}
|
|
114
|
+
assertNoLocalStyleImportCycles(styleFiles) {
|
|
115
|
+
const visited = new Set();
|
|
116
|
+
const visiting = new Set();
|
|
117
|
+
const stack = [];
|
|
118
|
+
const visit = (styleFile) => {
|
|
119
|
+
const normalizedPath = path.resolve(styleFile);
|
|
120
|
+
if (visited.has(normalizedPath))
|
|
121
|
+
return;
|
|
122
|
+
if (visiting.has(normalizedPath)) {
|
|
123
|
+
const cycleStart = stack.indexOf(normalizedPath);
|
|
124
|
+
const cycle = cycleStart >= 0
|
|
125
|
+
? [...stack.slice(cycleStart), normalizedPath]
|
|
126
|
+
: [normalizedPath, normalizedPath];
|
|
127
|
+
throw new Error(`[css] circular CSS import detected: ${cycle.join(' -> ')}`);
|
|
128
|
+
}
|
|
129
|
+
if (!fs.existsSync(normalizedPath))
|
|
130
|
+
return;
|
|
131
|
+
visiting.add(normalizedPath);
|
|
132
|
+
stack.push(normalizedPath);
|
|
133
|
+
for (const reference of this.collectLocalStyleImportReferences(normalizedPath)) {
|
|
134
|
+
visit(reference.imported);
|
|
135
|
+
}
|
|
136
|
+
stack.pop();
|
|
137
|
+
visiting.delete(normalizedPath);
|
|
138
|
+
visited.add(normalizedPath);
|
|
139
|
+
};
|
|
140
|
+
for (const styleFile of styleFiles) {
|
|
141
|
+
visit(styleFile);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
assertNoSourceRootEscapingLocalStyleImports(styleFiles) {
|
|
145
|
+
for (const styleFile of styleFiles) {
|
|
146
|
+
if (!fs.existsSync(styleFile))
|
|
147
|
+
continue;
|
|
148
|
+
for (const reference of this.collectLocalStyleImportReferences(path.resolve(styleFile))) {
|
|
149
|
+
this.assertSourceRootLocalStyleImport(reference, true);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
105
153
|
parse(code, from) {
|
|
106
154
|
// Keep parsing behind one method so future style languages can transform
|
|
107
155
|
// to CSS before PostCSS reads the final stylesheet.
|
|
108
156
|
return postcss.parse(code, { from });
|
|
109
157
|
}
|
|
110
158
|
parseImportSpecifier(params) {
|
|
159
|
+
return this.parseImportSpecifierReference(params)?.specifier ?? null;
|
|
160
|
+
}
|
|
161
|
+
resolveStyleImportReference(specifier, stylePath) {
|
|
162
|
+
const fromDir = path.dirname(stylePath);
|
|
163
|
+
const sourceStylePath = this.resolver.resolveSourceStyleDependency(specifier, fromDir);
|
|
164
|
+
const isSourceStyleSpecifier = this.isSourceStyleImportSpecifier(specifier, sourceStylePath);
|
|
165
|
+
if (isSourceStyleSpecifier) {
|
|
166
|
+
if (!sourceStylePath || !fs.existsSync(sourceStylePath)) {
|
|
167
|
+
this.throwMissingLocalStyleImport(specifier, stylePath);
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
reference: {
|
|
171
|
+
importer: path.resolve(stylePath),
|
|
172
|
+
imported: path.resolve(sourceStylePath),
|
|
173
|
+
specifier,
|
|
174
|
+
},
|
|
175
|
+
isLocalStyleImport: true,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const importedPath = this.resolver.resolveStyleDependency(specifier, fromDir);
|
|
179
|
+
return {
|
|
180
|
+
reference: {
|
|
181
|
+
importer: path.resolve(stylePath),
|
|
182
|
+
imported: path.resolve(importedPath),
|
|
183
|
+
specifier,
|
|
184
|
+
},
|
|
185
|
+
isLocalStyleImport: false,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
assertSourceRootLocalStyleImport(reference, isLocalStyleImport) {
|
|
189
|
+
if (!isLocalStyleImport ||
|
|
190
|
+
!this.resolver.isInsideSourceRoot(reference.importer) ||
|
|
191
|
+
this.resolver.isInsideSourceRoot(reference.imported)) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
throw new Error(`[css] local CSS import escapes source root: ${reference.specifier} from ${reference.importer}`);
|
|
195
|
+
}
|
|
196
|
+
collectLocalStyleImportReferences(styleFile) {
|
|
197
|
+
const imports = [];
|
|
198
|
+
const css = fs.readFileSync(styleFile, 'utf8');
|
|
199
|
+
const root = this.parse(css, styleFile);
|
|
200
|
+
root.walkAtRules('import', (rule) => {
|
|
201
|
+
const specifier = this.parseImportSpecifier(rule.params);
|
|
202
|
+
if (!specifier)
|
|
203
|
+
return;
|
|
204
|
+
const { reference, isLocalStyleImport } = this.resolveStyleImportReference(specifier, styleFile);
|
|
205
|
+
if (!isLocalStyleImport) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
imports.push(reference);
|
|
209
|
+
});
|
|
210
|
+
return imports;
|
|
211
|
+
}
|
|
212
|
+
parseImportSpecifierReference(params) {
|
|
111
213
|
const value = params.trim();
|
|
214
|
+
const valueOffset = params.indexOf(value);
|
|
112
215
|
const first = value[0];
|
|
113
216
|
if (first === '"' || first === "'") {
|
|
114
217
|
const end = value.indexOf(first, 1);
|
|
115
|
-
return end > 0
|
|
218
|
+
return end > 0
|
|
219
|
+
? {
|
|
220
|
+
specifier: value.slice(1, end),
|
|
221
|
+
specifierStart: valueOffset + 1,
|
|
222
|
+
specifierEnd: valueOffset + end,
|
|
223
|
+
}
|
|
224
|
+
: null;
|
|
116
225
|
}
|
|
117
226
|
if (!value.startsWith('url(')) {
|
|
118
227
|
return null;
|
|
@@ -124,8 +233,24 @@ export class StyleProcessor {
|
|
|
124
233
|
const quote = url[0];
|
|
125
234
|
if (quote === '"' || quote === "'") {
|
|
126
235
|
const quoteEnd = url.indexOf(quote, 1);
|
|
127
|
-
|
|
236
|
+
const quotedValueStart = value.indexOf(quote, 4);
|
|
237
|
+
return quoteEnd > 0
|
|
238
|
+
? {
|
|
239
|
+
specifier: url.slice(1, quoteEnd),
|
|
240
|
+
specifierStart: valueOffset + quotedValueStart + 1,
|
|
241
|
+
specifierEnd: valueOffset + quotedValueStart + quoteEnd,
|
|
242
|
+
}
|
|
243
|
+
: null;
|
|
128
244
|
}
|
|
129
|
-
|
|
245
|
+
if (!url)
|
|
246
|
+
return null;
|
|
247
|
+
const rawUrl = value.slice(4, end);
|
|
248
|
+
const leadingSpaces = rawUrl.length - rawUrl.trimStart().length;
|
|
249
|
+
const trailingSpaces = rawUrl.length - rawUrl.trimEnd().length;
|
|
250
|
+
return {
|
|
251
|
+
specifier: url,
|
|
252
|
+
specifierStart: valueOffset + 4 + leadingSpaces,
|
|
253
|
+
specifierEnd: valueOffset + end - trailingSpaces,
|
|
254
|
+
};
|
|
130
255
|
}
|
|
131
256
|
}
|
|
@@ -3,8 +3,13 @@ export declare class WorkspaceStyleResolver {
|
|
|
3
3
|
private readonly config;
|
|
4
4
|
private readonly context;
|
|
5
5
|
private readonly require;
|
|
6
|
+
readonly sourceRoot: string;
|
|
6
7
|
constructor(config: ModuleStyleBuildConfig, context: ResolvedModuleStyleBuildContext);
|
|
7
8
|
resolveStyleDependency(specifier: string, fromDir?: string): string;
|
|
9
|
+
resolveSourceStyleDependency(specifier: string, fromDir?: string): string | null;
|
|
10
|
+
isInsideSourceRoot(file: string): boolean;
|
|
11
|
+
isStyleFile(file: string): boolean;
|
|
8
12
|
toOutputStyleSpecifier(specifier: string, outRoot: string): string;
|
|
9
13
|
toExternalStyleSpecifier(specifier: string, outRoot: string): string;
|
|
14
|
+
private resolveSourceImportPaths;
|
|
10
15
|
}
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { NODE_MODULES_DIR } from '#auklet/css/constants';
|
|
4
|
+
import { resolvePackageImportsSourceImport } from '#auklet/css/core/resolvers/packageImports';
|
|
5
|
+
import { resolveTsconfigPathsSourceImport } from '#auklet/css/core/resolvers/tsconfigPaths';
|
|
4
6
|
import { createExternalStyleSpecifier, createOutputStyleSpecifier, } from '#auklet/css/core/style/specifier';
|
|
5
7
|
export class WorkspaceStyleResolver {
|
|
6
8
|
config;
|
|
7
9
|
context;
|
|
8
10
|
require;
|
|
11
|
+
sourceRoot;
|
|
9
12
|
constructor(config, context) {
|
|
10
13
|
this.config = config;
|
|
11
14
|
this.context = context;
|
|
15
|
+
this.sourceRoot = path.isAbsolute(context.sourceDir)
|
|
16
|
+
? context.sourceDir
|
|
17
|
+
: path.join(context.packageRoot, context.sourceDir);
|
|
12
18
|
this.require = createRequire(path.join(this.context.packageRoot, 'package.json'));
|
|
13
19
|
}
|
|
14
20
|
resolveStyleDependency(specifier, fromDir = this.context.packageRoot) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
const sourceStyleDependency = this.resolveSourceStyleDependency(specifier, fromDir);
|
|
22
|
+
if (sourceStyleDependency)
|
|
23
|
+
return sourceStyleDependency;
|
|
18
24
|
try {
|
|
19
25
|
return this.require.resolve(specifier, {
|
|
20
26
|
paths: [this.context.packageRoot],
|
|
@@ -24,6 +30,26 @@ export class WorkspaceStyleResolver {
|
|
|
24
30
|
return path.resolve(this.context.packageRoot, NODE_MODULES_DIR, specifier);
|
|
25
31
|
}
|
|
26
32
|
}
|
|
33
|
+
resolveSourceStyleDependency(specifier, fromDir = this.context.packageRoot) {
|
|
34
|
+
if (specifier.startsWith('.')) {
|
|
35
|
+
return path.resolve(fromDir, specifier);
|
|
36
|
+
}
|
|
37
|
+
for (const sourceRelativePath of this.resolveSourceImportPaths(specifier)) {
|
|
38
|
+
const file = path.join(this.sourceRoot, sourceRelativePath);
|
|
39
|
+
if (this.isStyleFile(file))
|
|
40
|
+
return file;
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
isInsideSourceRoot(file) {
|
|
45
|
+
const relative = path.relative(this.sourceRoot, file);
|
|
46
|
+
return (Boolean(relative) &&
|
|
47
|
+
!relative.startsWith('..') &&
|
|
48
|
+
!path.isAbsolute(relative));
|
|
49
|
+
}
|
|
50
|
+
isStyleFile(file) {
|
|
51
|
+
return this.config.styleExtensions.includes(path.extname(file));
|
|
52
|
+
}
|
|
27
53
|
toOutputStyleSpecifier(specifier, outRoot) {
|
|
28
54
|
return createOutputStyleSpecifier(specifier, {
|
|
29
55
|
currentOutputFormat: path.basename(outRoot),
|
|
@@ -39,4 +65,10 @@ export class WorkspaceStyleResolver {
|
|
|
39
65
|
externalStyleFile: this.config.output.externalStyleFile,
|
|
40
66
|
});
|
|
41
67
|
}
|
|
68
|
+
resolveSourceImportPaths(specifier) {
|
|
69
|
+
return [
|
|
70
|
+
...resolvePackageImportsSourceImport(this.context.packageRoot, this.sourceRoot, specifier),
|
|
71
|
+
...resolveTsconfigPathsSourceImport(this.context.packageRoot, this.sourceRoot, specifier),
|
|
72
|
+
];
|
|
73
|
+
}
|
|
42
74
|
}
|
|
@@ -21,6 +21,7 @@ export class ModuleStyleBuilder {
|
|
|
21
21
|
const normalizedConfig = normalizeAukletConfig(rawConfig);
|
|
22
22
|
const context = this.createBuildContext(normalizedConfig);
|
|
23
23
|
const packageContext = this.createPackageContext(context, normalizedConfig);
|
|
24
|
+
packageContext.assertNoSourceRootEscapingLocalStyleImports();
|
|
24
25
|
const writerOptions = {
|
|
25
26
|
config: this.config,
|
|
26
27
|
context,
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { writeStyleFile, } from '#auklet/css/production/format/shared';
|
|
2
|
+
import { toRelativeImportSpecifier, writeStyleFile, } from '#auklet/css/production/format/shared';
|
|
3
3
|
export class ModuleStyleWriter {
|
|
4
|
+
sourceRoot;
|
|
4
5
|
config;
|
|
5
6
|
packageContext;
|
|
6
7
|
styleProcessor;
|
|
7
8
|
constructor(options) {
|
|
8
9
|
this.config = options.config;
|
|
9
10
|
this.packageContext = options.packageContext;
|
|
11
|
+
this.sourceRoot = options.packageContext.sourceRoot;
|
|
10
12
|
this.styleProcessor = options.packageContext.styleProcessor;
|
|
11
13
|
}
|
|
12
14
|
write(outRoot) {
|
|
13
15
|
const target = path.join(outRoot, this.config.output.styleDir, this.config.output.moduleStyleFile);
|
|
14
|
-
const
|
|
16
|
+
const targetDir = path.dirname(target);
|
|
15
17
|
const root = this.styleProcessor.createRoot();
|
|
16
|
-
for (const styleFile of this.packageContext.
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
this.styleProcessor.appendStyleContent(root, content, styleFile);
|
|
20
|
-
}
|
|
18
|
+
for (const styleFile of this.packageContext.getStyleEntryFiles()) {
|
|
19
|
+
const outputStyleFile = path.join(outRoot, path.relative(this.sourceRoot, styleFile));
|
|
20
|
+
this.styleProcessor.appendImportRule(root, toRelativeImportSpecifier(targetDir, outputStyleFile));
|
|
21
21
|
}
|
|
22
22
|
if (!root.nodes?.length)
|
|
23
23
|
return null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type FormatWriterOptions } from '#auklet/css/production/format/shared';
|
|
2
2
|
export declare class SourceStyleFileWriter {
|
|
3
3
|
private readonly sourceRoot;
|
|
4
|
-
private readonly
|
|
4
|
+
private readonly resolver;
|
|
5
5
|
private readonly styleProcessor;
|
|
6
6
|
constructor(options: FormatWriterOptions);
|
|
7
7
|
copy(files: Array<string>, outRoot: string): void;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { writeStyleFile, } from '#auklet/css/production/format/shared';
|
|
2
|
+
import { toRelativeImportSpecifier, writeStyleFile, } from '#auklet/css/production/format/shared';
|
|
3
3
|
export class SourceStyleFileWriter {
|
|
4
4
|
sourceRoot;
|
|
5
|
-
|
|
5
|
+
resolver;
|
|
6
6
|
styleProcessor;
|
|
7
7
|
constructor(options) {
|
|
8
8
|
this.sourceRoot = options.packageContext.sourceRoot;
|
|
9
|
-
this.
|
|
9
|
+
this.resolver = options.packageContext.resolver;
|
|
10
10
|
this.styleProcessor = options.packageContext.styleProcessor;
|
|
11
11
|
}
|
|
12
12
|
copy(files, outRoot) {
|
|
@@ -14,7 +14,13 @@ export class SourceStyleFileWriter {
|
|
|
14
14
|
const relative = path.relative(this.sourceRoot, sourceFile);
|
|
15
15
|
const target = path.join(outRoot, relative);
|
|
16
16
|
const content = this.styleProcessor.readStyleFile(sourceFile, undefined, {
|
|
17
|
-
|
|
17
|
+
mapImportSpecifier: (reference) => {
|
|
18
|
+
if (!this.resolver.isInsideSourceRoot(reference.imported)) {
|
|
19
|
+
return reference.specifier;
|
|
20
|
+
}
|
|
21
|
+
return toRelativeImportSpecifier(path.dirname(target), path.join(outRoot, path.relative(this.sourceRoot, reference.imported)));
|
|
22
|
+
},
|
|
23
|
+
shouldExpandImport: () => false,
|
|
18
24
|
});
|
|
19
25
|
writeStyleFile(target, content);
|
|
20
26
|
}
|
|
@@ -29,6 +29,7 @@ export class ModuleStyleOutputWriter {
|
|
|
29
29
|
this.moduleEntryWriter = new ModuleStyleEntryWriter(options);
|
|
30
30
|
}
|
|
31
31
|
write() {
|
|
32
|
+
this.packageContext.assertPreservedLocalStyleImports();
|
|
32
33
|
const moduleEntries = this.createModuleEntries();
|
|
33
34
|
const outputs = [];
|
|
34
35
|
for (const format of this.config.output.outputFormats) {
|
|
@@ -10,8 +10,10 @@ export declare class StyleCodeFactory {
|
|
|
10
10
|
private createDependencyStyleCode;
|
|
11
11
|
private createExternalStyleCode;
|
|
12
12
|
private createThemeStyleCode;
|
|
13
|
+
private createFullModuleStyleCode;
|
|
13
14
|
private createModuleStyleCode;
|
|
14
15
|
private createSourceModuleStyleCode;
|
|
16
|
+
private createOwnSourceStyleCode;
|
|
15
17
|
private toDevModuleImportSpecifier;
|
|
16
18
|
private toDevExternalStyleSpecifier;
|
|
17
19
|
private parsePackageStyleIdInRequest;
|
|
@@ -6,6 +6,7 @@ import { toDevDependencyImportSpecifier } from '#auklet/css/vite/moduleGraph/dev
|
|
|
6
6
|
import { EXTERNAL_ENTRY, MODULE_ENTRY, STYLE_ENTRY, THEMES_ENTRY_PREFIX, } from '#auklet/css/constants';
|
|
7
7
|
import { createModuleStyleEntryPlan, createExternalEntryParts, createStyleEntryParts, createThemeEntryParts, } from '#auklet/css/core/style/entries';
|
|
8
8
|
import { createDevExternalStyleSpecifier, createDevModuleStyleSpecifier, createImportCode, removeStyleExtension, } from '#auklet/css/core/style/specifier';
|
|
9
|
+
import { toFsSpecifier } from '#auklet/utils';
|
|
9
10
|
// 生成 Vite/dev 虚拟 CSS;production writer 共享入口语义,但写入真实文件。
|
|
10
11
|
export class StyleCodeFactory {
|
|
11
12
|
config;
|
|
@@ -57,7 +58,7 @@ export class StyleCodeFactory {
|
|
|
57
58
|
results.push(await this.createThemeStyleCode(context, cache, part.themeNames, false));
|
|
58
59
|
continue;
|
|
59
60
|
}
|
|
60
|
-
results.push(this.
|
|
61
|
+
results.push(this.createFullModuleStyleCode(context));
|
|
61
62
|
}
|
|
62
63
|
return mergeLoadResults(...results);
|
|
63
64
|
}
|
|
@@ -125,7 +126,7 @@ export class StyleCodeFactory {
|
|
|
125
126
|
watchFiles: [],
|
|
126
127
|
});
|
|
127
128
|
}
|
|
128
|
-
|
|
129
|
+
createFullModuleStyleCode(context) {
|
|
129
130
|
const { styleFiles } = context.packageContext;
|
|
130
131
|
const root = context.styleProcessor.createRoot();
|
|
131
132
|
const seen = new Set();
|
|
@@ -140,7 +141,19 @@ export class StyleCodeFactory {
|
|
|
140
141
|
watchFiles: [...context.configPaths, ...styleFiles],
|
|
141
142
|
};
|
|
142
143
|
}
|
|
144
|
+
createModuleStyleCode(context) {
|
|
145
|
+
context.packageContext.assertPreservedLocalStyleImports();
|
|
146
|
+
const { styleFiles } = context.packageContext;
|
|
147
|
+
const imports = context.packageContext
|
|
148
|
+
.getStyleEntryFiles()
|
|
149
|
+
.map((styleFile) => toFsSpecifier(styleFile));
|
|
150
|
+
return {
|
|
151
|
+
code: createImportCode(imports),
|
|
152
|
+
watchFiles: [...context.configPaths, ...styleFiles],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
143
155
|
async createSourceModuleStyleCode(context, cache, stylePath) {
|
|
156
|
+
context.packageContext.assertPreservedLocalStyleImports();
|
|
144
157
|
const sourceModuleDir = removeStyleExtension(stylePath);
|
|
145
158
|
const { styleFiles, sourceFiles } = context.packageContext;
|
|
146
159
|
const entry = createModuleStyleEntryPlan(context.packageContext, sourceModuleDir);
|
|
@@ -153,8 +166,12 @@ export class StyleCodeFactory {
|
|
|
153
166
|
const result = this.toDevModuleImportSpecifier(specifier, context, cache, sourceStyleDir);
|
|
154
167
|
const parsed = this.parsePackageStyleIdInRequest(result, cache);
|
|
155
168
|
if (parsed) {
|
|
156
|
-
const
|
|
157
|
-
moduleStyleResults.push(this.withDependencyPackage(
|
|
169
|
+
const dependencyResult = await this.createPackageStyleCode(parsed, cache);
|
|
170
|
+
moduleStyleResults.push(this.withDependencyPackage({
|
|
171
|
+
...dependencyResult,
|
|
172
|
+
code: '',
|
|
173
|
+
}, parsed.packageName));
|
|
174
|
+
moduleStyleSpecifiers.push(result);
|
|
158
175
|
continue;
|
|
159
176
|
}
|
|
160
177
|
const resolvedSpecifier = toDevDependencyImportSpecifier(context, result);
|
|
@@ -164,17 +181,7 @@ export class StyleCodeFactory {
|
|
|
164
181
|
moduleStyleWatchFiles.push(resolvedSpecifier.watchFile);
|
|
165
182
|
}
|
|
166
183
|
}
|
|
167
|
-
const
|
|
168
|
-
const seen = new Set();
|
|
169
|
-
for (const ownStyleFile of entry.ownStyleFiles) {
|
|
170
|
-
const content = context.styleProcessor.readStyleFile(ownStyleFile, seen);
|
|
171
|
-
if (content.trim()) {
|
|
172
|
-
context.styleProcessor.appendStyleContent(root, content, ownStyleFile);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
const ownStyleCode = root.nodes?.length
|
|
176
|
-
? context.styleProcessor.stringify(root)
|
|
177
|
-
: '';
|
|
184
|
+
const ownStyleCode = this.createOwnSourceStyleCode(context, entry.ownStyleFiles);
|
|
178
185
|
return mergeLoadResults(...moduleStyleResults, {
|
|
179
186
|
code: [createImportCode(moduleStyleSpecifiers), ownStyleCode]
|
|
180
187
|
.filter((code) => code.trim())
|
|
@@ -188,6 +195,24 @@ export class StyleCodeFactory {
|
|
|
188
195
|
cacheInputFiles: moduleStyleCacheInputFiles,
|
|
189
196
|
});
|
|
190
197
|
}
|
|
198
|
+
createOwnSourceStyleCode(context, styleFiles) {
|
|
199
|
+
const root = context.styleProcessor.createRoot();
|
|
200
|
+
for (const styleFile of styleFiles) {
|
|
201
|
+
const content = context.styleProcessor.readStyleFile(styleFile, undefined, {
|
|
202
|
+
mapImportSpecifier: (reference) => {
|
|
203
|
+
if (!context.resolver.isInsideSourceRoot(reference.imported)) {
|
|
204
|
+
return reference.specifier;
|
|
205
|
+
}
|
|
206
|
+
return toFsSpecifier(reference.imported);
|
|
207
|
+
},
|
|
208
|
+
shouldExpandImport: () => false,
|
|
209
|
+
});
|
|
210
|
+
if (content.trim()) {
|
|
211
|
+
context.styleProcessor.appendStyleContent(root, content, styleFile);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return root.nodes?.length ? context.styleProcessor.stringify(root) : '';
|
|
215
|
+
}
|
|
191
216
|
toDevModuleImportSpecifier(specifier, context, cache, sourceStyleDir) {
|
|
192
217
|
return createDevModuleStyleSpecifier(specifier, {
|
|
193
218
|
sourceStyleDir,
|