diff --git a/.flowconfig b/.flowconfig index 456aa3529..cd5ec42c7 100644 --- a/.flowconfig +++ b/.flowconfig @@ -30,7 +30,7 @@ module.name_mapper='^@stylexjs\/shared\/lib\/\([a-zA-Z0-9_\-]+\)$' -> ' '/packages/stylex/src/stylex.js' module.name_mapper='^@stylexjs/stylex\/lib\/\([a-zA-Z0-9_\-]+\)$' -> '/packages/stylex/src/\1' module.name_mapper='^@stylexjs/babel-plugin$' -> '/packages/babel-plugin/src/index.js' -module.name_mapper='^@stylexjs/babel-plugin\/lib\/\([a-zA-Z0-9_\-]+\)$' -> '/packages/babel-plugin/src/\1' +module.name_mapper='^@stylexjs/babel-plugin\/lib\/\(.+\)$' -> '/packages/babel-plugin/src/\1' ; type-stubs module.system.node.resolve_dirname=flow_modules module.system.node.resolve_dirname=node_modules diff --git a/packages/babel-plugin/src/index.js b/packages/babel-plugin/src/index.js index 106ffc1a8..5361066b6 100644 --- a/packages/babel-plugin/src/index.js +++ b/packages/babel-plugin/src/index.js @@ -12,6 +12,12 @@ import type { NodePath } from '@babel/traverse'; import type { PluginObj } from '@babel/core'; import type { StyleXOptions } from './utils/state-manager'; import StateManager from './utils/state-manager'; +import { + EXTENSIONS, + filePathResolver, + matchesFileSuffix, + getRelativePath, +} from './utils/state-manager'; import { readImportDeclarations, readRequires } from './visitors/imports'; import transformStyleXCreate from './visitors/stylex-create'; import transformStyleXDefineVars from './visitors/stylex-define-vars'; @@ -74,6 +80,44 @@ function styleXTransform(): PluginObj<> { // variables entirely if they're not needed. exit: (path: NodePath) => { path.traverse({ + ImportDeclaration(path: NodePath) { + const filename = state.filename; + if (filename == null || !state.options.rewriteAliases) { + return; + } + + const source = path.node.source.value; + + const aliases = state.options.aliases; + + const themeFileExtension = '.stylex'; + if (!matchesFileSuffix(themeFileExtension)(source)) { + return; + } + const resolvedFilePath = filePathResolver( + source, + filename, + aliases, + ); + + if (resolvedFilePath == null) { + return; + } + + let relativeFilePath = getRelativePath( + filename, + resolvedFilePath, + ); + + const extension = EXTENSIONS.find((ext) => + relativeFilePath.endsWith(ext), + ); + if (extension != null) { + relativeFilePath = relativeFilePath.slice(0, -extension.length); + } + + path.node.source.value = relativeFilePath; + }, Identifier(path: NodePath) { // Look for variables bound to `stylex.create` calls that are used // outside of `stylex(...)` calls diff --git a/packages/babel-plugin/src/utils/state-manager.js b/packages/babel-plugin/src/utils/state-manager.js index 70a80d6d1..8b1c34e96 100644 --- a/packages/babel-plugin/src/utils/state-manager.js +++ b/packages/babel-plugin/src/utils/state-manager.js @@ -78,6 +78,7 @@ export type StyleXOptions = $ReadOnly<{ genConditionalClasses: boolean, unstable_moduleResolution?: ?ModuleResolution, aliases?: ?$ReadOnly<{ [string]: string | $ReadOnlyArray }>, + rewriteAliases?: boolean, ... }>; @@ -85,6 +86,7 @@ type StyleXStateOptions = $ReadOnly<{ ...StyleXOptions, runtimeInjection: ?string | $ReadOnly<{ from: string, as: ?string }>, aliases?: ?$ReadOnly<{ [string]: $ReadOnlyArray }>, + rewriteAliases: boolean, ... }>; @@ -289,6 +291,10 @@ export default class StateManager { styleResolution, unstable_moduleResolution, treeshakeCompensation, + rewriteAliases: + typeof options.rewriteAliases === 'boolean' + ? options.rewriteAliases + : false, }; return opts; } @@ -671,7 +677,7 @@ const getPossibleFilePaths = (filePath: string) => { // a function that resolves the absolute path of a file when given the // relative path of the file from the source file -const filePathResolver = ( +export const filePathResolver = ( relativeFilePath: string, sourceFilePath: string, aliases: StyleXStateOptions['aliases'], @@ -704,7 +710,7 @@ const filePathResolver = ( return null; }; -const EXTENSIONS = ['.js', '.ts', '.tsx', '.jsx', '.mjs', '.cjs']; +export const EXTENSIONS = ['.js', '.ts', '.tsx', '.jsx', '.mjs', '.cjs']; const addFileExtension = ( importedFilePath: string, @@ -721,10 +727,11 @@ const addFileExtension = ( return importedFilePath + fileExtension; }; -const matchesFileSuffix = (allowedSuffix: string) => (filename: string) => - ['', ...EXTENSIONS].some((extension) => - filename.endsWith(`${allowedSuffix}${extension}`), - ); +export const matchesFileSuffix: (string) => (string) => boolean = + (allowedSuffix) => (filename) => + ['', ...EXTENSIONS].some((extension) => + filename.endsWith(`${allowedSuffix}${extension}`), + ); const getProgramPath = (path: NodePath<>): null | NodePath => { let programPath = path; @@ -749,3 +756,16 @@ const getProgramStatement = (path: NodePath<>): NodePath<> => { } return programPath; }; + +export function getRelativePath(from: string, to: string): string { + const relativePath = path.relative(path.parse(from).dir, to); + return formatRelativePath(toPosixPath(relativePath)); +} + +function toPosixPath(filePath: string): string { + return filePath.split(path.sep).join(path.posix.sep); +} + +function formatRelativePath(filePath: string) { + return filePath.startsWith('.') ? filePath : './' + filePath; +} diff --git a/packages/cli/src/config.js b/packages/cli/src/config.js index 15ad9bd61..091551bf5 100644 --- a/packages/cli/src/config.js +++ b/packages/cli/src/config.js @@ -8,7 +8,7 @@ * @flow strict */ -import type { Rule } from '@stylexjs/babel-plugin'; +import type { Rule, Options as StyleXOptions } from '@stylexjs/babel-plugin'; export type ModuleType = | string @@ -24,7 +24,7 @@ export type CliConfig = { babelPluginsPost?: $ReadOnlyArray, modules_EXPERIMENTAL: $ReadOnlyArray, useCSSLayers?: boolean, - styleXConfig?: { +[string]: mixed }, + styleXConfig?: StyleXOptions, }; export type TransformConfig = { diff --git a/packages/cli/src/index.js b/packages/cli/src/index.js index 35f4a868e..aa8fbf15e 100755 --- a/packages/cli/src/index.js +++ b/packages/cli/src/index.js @@ -8,7 +8,7 @@ * @flow strict */ -import type { Rule } from '@stylexjs/babel-plugin'; +import type { Rule, Options as StyleXOptions } from '@stylexjs/babel-plugin'; import yargs from 'yargs'; import path from 'path'; import ansis from 'ansis'; @@ -71,8 +71,7 @@ const babelPresets: $ReadOnlyArray = args.babelPresets; const babelPluginsPre: $ReadOnlyArray = args.babelPluginsPre; const babelPluginsPost: $ReadOnlyArray = args.babelPluginsPost; const useCSSLayers: boolean = args.useCSSLayers; -const styleXConfig: { +[string]: mixed } = - (config.styleXConfig as $FlowFixMe) ?? {}; +const styleXConfig: StyleXOptions = (config.styleXConfig as $FlowFixMe) ?? {}; const cliArgsConfig: CliConfig = { input, diff --git a/packages/cli/src/plugins.js b/packages/cli/src/plugins.js index cbd69e691..db9e2fdbd 100644 --- a/packages/cli/src/plugins.js +++ b/packages/cli/src/plugins.js @@ -17,7 +17,10 @@ import * as nodePath from 'path'; type ImportModifierPlugin = $ReadOnly<{ visitor: { - Program: { enter(path: NodePath): void }, + Program: { + enter?: (path: NodePath) => void, + exit?: (path: NodePath) => void, + }, }, }>; diff --git a/packages/cli/src/transform.js b/packages/cli/src/transform.js index 75ee8d7c3..14c297a83 100644 --- a/packages/cli/src/transform.js +++ b/packages/cli/src/transform.js @@ -175,6 +175,7 @@ export async function transformFile( rootDir: path.parse(config.output).dir, }, ...(config.styleXConfig as $FlowFixMe), + rewriteAliases: true, }, ], createImportPlugin(relativeImport),