Skip to content

Commit b0b8a8e

Browse files
committed
fix: cli should rewrite the aliases
1 parent 06ffe7e commit b0b8a8e

File tree

8 files changed

+169
-13
lines changed

8 files changed

+169
-13
lines changed

.flowconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ module.name_mapper='^@stylexjs\/shared\/lib\/\([a-zA-Z0-9_\-]+\)$' -> '<PROJECT_
3030
module.name_mapper='^@stylexjs/stylex$' -> '<PROJECT_ROOT>/packages/stylex/src/stylex.js'
3131
module.name_mapper='^@stylexjs/stylex\/lib\/\([a-zA-Z0-9_\-]+\)$' -> '<PROJECT_ROOT>/packages/stylex/src/\1'
3232
module.name_mapper='^@stylexjs/babel-plugin$' -> '<PROJECT_ROOT>/packages/babel-plugin/src/index.js'
33-
module.name_mapper='^@stylexjs/babel-plugin\/lib\/\([a-zA-Z0-9_\-]+\)$' -> '<PROJECT_ROOT>/packages/babel-plugin/src/\1'
33+
module.name_mapper='^@stylexjs/babel-plugin\/lib\/\(.+\)$' -> '<PROJECT_ROOT>/packages/babel-plugin/src/\1'
3434
; type-stubs
3535
module.system.node.resolve_dirname=flow_modules
3636
module.system.node.resolve_dirname=node_modules

package-lock.json

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/babel-plugin/src/utils/state-manager.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,7 @@ const getPossibleFilePaths = (filePath: string) => {
671671

672672
// a function that resolves the absolute path of a file when given the
673673
// relative path of the file from the source file
674-
const filePathResolver = (
674+
export const filePathResolver = (
675675
relativeFilePath: string,
676676
sourceFilePath: string,
677677
aliases: StyleXStateOptions['aliases'],
@@ -719,10 +719,11 @@ const addFileExtension = (
719719
return importedFilePath + fileExtension;
720720
};
721721

722-
const matchesFileSuffix = (allowedSuffix: string) => (filename: string) =>
723-
['', ...EXTENSIONS].some((extension) =>
724-
filename.endsWith(`${allowedSuffix}${extension}`),
725-
);
722+
export const matchesFileSuffix =
723+
(allowedSuffix: string) => (filename: string) =>
724+
['', ...EXTENSIONS].some((extension) =>
725+
filename.endsWith(`${allowedSuffix}${extension}`),
726+
);
726727

727728
const getProgramPath = (path: NodePath<>): null | NodePath<t.Program> => {
728729
let programPath = path;

packages/cli/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"@babel/plugin-syntax-jsx": "^7.25.7",
2020
"@babel/plugin-syntax-typescript": "^7.25.7",
2121
"@babel/types": "^7.25.8",
22+
"@dual-bundle/import-meta-resolve": "^4.1.0",
2223
"@stylexjs/babel-plugin": "0.10.0",
2324
"ansis": "^3.3.2",
2425
"fb-watchman": "^2.0.2",

packages/cli/src/config.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* @flow strict
99
*/
1010

11-
import type { Rule } from '@stylexjs/babel-plugin';
11+
import type { Rule, Options as StyleXOptions } from '@stylexjs/babel-plugin';
1212

1313
export type ModuleType =
1414
| string
@@ -24,7 +24,7 @@ export type CliConfig = {
2424
babelPluginsPost?: $ReadOnlyArray<any>,
2525
modules_EXPERIMENTAL: $ReadOnlyArray<ModuleType>,
2626
useCSSLayers?: boolean,
27-
styleXConfig?: { +[string]: mixed },
27+
styleXConfig?: StyleXOptions,
2828
};
2929

3030
export type TransformConfig = {

packages/cli/src/index.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* @flow strict
99
*/
1010

11-
import type { Rule } from '@stylexjs/babel-plugin';
11+
import type { Rule, Options as StyleXOptions } from '@stylexjs/babel-plugin';
1212
import yargs from 'yargs';
1313
import path from 'path';
1414
import ansis from 'ansis';
@@ -71,8 +71,7 @@ const babelPresets: $ReadOnlyArray<any> = args.babelPresets;
7171
const babelPluginsPre: $ReadOnlyArray<any> = args.babelPluginsPre;
7272
const babelPluginsPost: $ReadOnlyArray<any> = args.babelPluginsPost;
7373
const useCSSLayers: boolean = args.useCSSLayers;
74-
const styleXConfig: { +[string]: mixed } =
75-
(config.styleXConfig as $FlowFixMe) ?? {};
74+
const styleXConfig: StyleXOptions = (config.styleXConfig as $FlowFixMe) ?? {};
7675

7776
const cliArgsConfig: CliConfig = {
7877
input,

packages/cli/src/plugins.js

+146-1
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,17 @@ import type { NodePath } from '@babel/traverse';
1212
import { getRelativePath } from './files';
1313
import { findModuleDir } from './modules';
1414
import * as t from '@babel/types';
15+
import { moduleResolve } from '@dual-bundle/import-meta-resolve';
16+
import url from 'url';
1517

1618
import * as nodePath from 'path';
1719

1820
type ImportModifierPlugin = $ReadOnly<{
1921
visitor: {
20-
Program: { enter(path: NodePath<t.Program>): void },
22+
Program: {
23+
enter?: (path: NodePath<t.Program>) => void,
24+
exit?: (path: NodePath<t.Program>) => void,
25+
},
2126
},
2227
}>;
2328

@@ -116,3 +121,143 @@ export const createModuleImportModifierPlugin = (
116121
},
117122
};
118123
};
124+
125+
export const createAliasRewritePlugin = (
126+
sourceFilePath: string,
127+
aliasConfig: $ReadOnly<{ [string]: string | $ReadOnlyArray<string> }>,
128+
): ImportModifierPlugin => {
129+
return {
130+
visitor: {
131+
Program: {
132+
exit(path: NodePath<t.Program>) {
133+
path.traverse({
134+
ImportDeclaration: {
135+
enter(path: NodePath<t.ImportDeclaration>) {
136+
const source = path.node.source.value;
137+
138+
const aliases =
139+
aliasConfig == null
140+
? aliasConfig
141+
: Object.fromEntries(
142+
Object.entries(aliasConfig).map(([key, value]) => {
143+
if (typeof value === 'string') {
144+
return [key, [value]];
145+
}
146+
return [key, value];
147+
}),
148+
);
149+
150+
const themeFileExtension = '.stylex';
151+
if (!matchesFileSuffix(themeFileExtension)(source)) {
152+
return;
153+
}
154+
const resolvedFilePath = filePathResolver(
155+
source,
156+
sourceFilePath,
157+
aliases,
158+
);
159+
160+
if (resolvedFilePath == null) {
161+
return;
162+
}
163+
164+
let relativeFilePath = getRelativePath(
165+
sourceFilePath,
166+
resolvedFilePath,
167+
);
168+
169+
const extension = EXTENSIONS.find((ext) =>
170+
relativeFilePath.endsWith(ext),
171+
);
172+
if (extension != null) {
173+
relativeFilePath = relativeFilePath.slice(
174+
0,
175+
-extension.length,
176+
);
177+
}
178+
179+
path.node.source.value = relativeFilePath;
180+
},
181+
},
182+
});
183+
},
184+
},
185+
},
186+
};
187+
};
188+
189+
const matchesFileSuffix = (allowedSuffix: string) => (filename: string) =>
190+
filename.endsWith(`${allowedSuffix}.js`) ||
191+
filename.endsWith(`${allowedSuffix}.ts`) ||
192+
filename.endsWith(`${allowedSuffix}.tsx`) ||
193+
filename.endsWith(`${allowedSuffix}.jsx`) ||
194+
filename.endsWith(`${allowedSuffix}.mjs`) ||
195+
filename.endsWith(`${allowedSuffix}.cjs`) ||
196+
filename.endsWith(allowedSuffix);
197+
198+
const EXTENSIONS = ['.js', '.ts', '.tsx', '.jsx', '.mjs', '.cjs'];
199+
const filePathResolver = (
200+
relativeFilePath: string,
201+
sourceFilePath: string,
202+
aliases: $ReadOnly<{ [string]: $ReadOnlyArray<string> }>,
203+
): ?string => {
204+
// Try importing without adding any extension
205+
// and then every supported extension
206+
for (const ext of ['', ...EXTENSIONS]) {
207+
const importPathStr = relativeFilePath + ext;
208+
209+
// Try to resolve relative paths as is
210+
if (importPathStr.startsWith('.')) {
211+
try {
212+
return moduleResolve(importPathStr, url.pathToFileURL(sourceFilePath))
213+
.pathname;
214+
} catch {
215+
continue;
216+
}
217+
}
218+
219+
// Otherwise, try to resolve the path with aliases
220+
const allAliases = possibleAliasedPaths(importPathStr, aliases);
221+
for (const possiblePath of allAliases) {
222+
try {
223+
return moduleResolve(possiblePath, url.pathToFileURL(sourceFilePath))
224+
.pathname;
225+
} catch {
226+
continue;
227+
}
228+
}
229+
}
230+
// Failed to resolve the file path
231+
return null;
232+
};
233+
234+
function possibleAliasedPaths(
235+
importPath: string,
236+
aliases: $ReadOnly<{ [string]: $ReadOnlyArray<string> }>,
237+
): $ReadOnlyArray<string> {
238+
const result = [importPath];
239+
if (aliases == null || Object.keys(aliases).length === 0) {
240+
return result;
241+
}
242+
243+
for (const [alias, value] of Object.entries(aliases)) {
244+
if (alias.includes('*')) {
245+
const [before, after] = alias.split('*');
246+
if (importPath.startsWith(before) && importPath.endsWith(after)) {
247+
const replacementString = importPath.slice(
248+
before.length,
249+
after.length > 0 ? -after.length : undefined,
250+
);
251+
value.forEach((v) => {
252+
result.push(v.split('*').join(replacementString));
253+
});
254+
}
255+
} else if (alias === importPath) {
256+
value.forEach((v) => {
257+
result.push(v);
258+
});
259+
}
260+
}
261+
262+
return result;
263+
}

packages/cli/src/transform.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
getDefaultCachePath,
3232
} from './cache';
3333
import {
34+
createAliasRewritePlugin,
3435
createImportPlugin,
3536
createModuleImportModifierPlugin,
3637
} from './plugins';
@@ -155,6 +156,8 @@ export async function transformFile(
155156
: path.join(config.output, config.styleXBundleName),
156157
);
157158

159+
const aliases = config.styleXConfig?.aliases;
160+
158161
const result = await babel.transformFileAsync(inputFilePath, {
159162
babelrc: false,
160163
presets: config.babelPresets,
@@ -173,7 +176,12 @@ export async function transformFile(
173176
},
174177
],
175178
createImportPlugin(relativeImport),
176-
...(config.babelPluginsPost ?? []),
179+
...[
180+
aliases != null
181+
? createAliasRewritePlugin(inputFilePath, aliases)
182+
: null,
183+
...(config.babelPluginsPost ?? []),
184+
].filter(Boolean),
177185
],
178186
});
179187
if (result == null) {

0 commit comments

Comments
 (0)