diff --git a/packages/babel-plugin/__tests__/evaluation/stylex-import-evaluation-test.js b/packages/babel-plugin/__tests__/evaluation/stylex-import-evaluation-test.js index 745bfb40d..c7034ba52 100644 --- a/packages/babel-plugin/__tests__/evaluation/stylex-import-evaluation-test.js +++ b/packages/babel-plugin/__tests__/evaluation/stylex-import-evaluation-test.js @@ -369,6 +369,7 @@ describe('Evaluation of imported values works based on configuration', () => { import 'otherFile.stylex'; import { MyTheme } from 'otherFile.stylex'; _inject2(".__hashed_var__b69i2g{--__hashed_var__1jqb1tb:var(----__hashed_var__1jqb1tb)}", 1); + _inject2("@property ----__hashed_var__1jqb1tb { inherits: false }", 0); const styles = { color: color => [{ "--__hashed_var__1jqb1tb": color == null ? null : "__hashed_var__b69i2g", @@ -389,6 +390,14 @@ describe('Evaluation of imported values works based on configuration', () => { }, 1, ], + [ + "----__hashed_var__1jqb1tb", + { + "ltr": "@property ----__hashed_var__1jqb1tb { inherits: false }", + "rtl": null, + }, + 0, + ], ] `); }); diff --git a/packages/babel-plugin/__tests__/stylex-transform-create-test.js b/packages/babel-plugin/__tests__/stylex-transform-create-test.js index d60e3f069..985a3f0e5 100644 --- a/packages/babel-plugin/__tests__/stylex-transform-create-test.js +++ b/packages/babel-plugin/__tests__/stylex-transform-create-test.js @@ -1323,6 +1323,7 @@ describe('@stylexjs/babel-plugin', () => { import stylex from 'stylex'; _inject2(".xrkmrrc{background-color:red}", 3000); _inject2(".xfx01vb{color:var(--color)}", 3000); + _inject2("@property --color { inherits: false }", 0); export const styles = { default: color => [{ backgroundColor: "xrkmrrc", @@ -1352,6 +1353,7 @@ describe('@stylexjs/babel-plugin', () => { import stylex from 'stylex'; _inject2(".xrkmrrc{background-color:red}", 3000); _inject2(".x1bl4301{width:var(--width)}", 4000); + _inject2("@property --width { inherits: false }", 0); export const styles = { default: width => [{ backgroundColor: "xrkmrrc", @@ -1385,6 +1387,7 @@ describe('@stylexjs/babel-plugin', () => { _inject2(".xrkmrrc{background-color:red}", 3000); _inject2(".xfx01vb{color:var(--color)}", 3000); _inject2(".x1mqxbix{color:black}", 3000); + _inject2("@property --color { inherits: false }", 0); export const styles = { default: color => [{ backgroundColor: "xrkmrrc", @@ -1416,6 +1419,7 @@ describe('@stylexjs/babel-plugin', () => { var _inject2 = _inject; import stylex from 'stylex'; _inject2(".x15mgraa{--background-color:var(----background-color)}", 1); + _inject2("@property ----background-color { inherits: false }", 0); export const styles = { default: bgColor => [{ "--background-color": bgColor == null ? null : "x15mgraa", @@ -1445,6 +1449,7 @@ describe('@stylexjs/babel-plugin', () => { import stylex from 'stylex'; _inject2(".x1gykpug:hover{background-color:red}", 3130); _inject2(".xtyu0qe:hover{color:var(--1ijzsae)}", 3130); + _inject2("@property --1ijzsae { inherits: false }", 0); export const styles = { default: color => [{ ":hover_backgroundColor": "x1gykpug", @@ -1477,6 +1482,7 @@ describe('@stylexjs/babel-plugin', () => { _inject2(".xrkmrrc{background-color:red}", 3000); _inject2(".xfx01vb{color:var(--color)}", 3000); _inject2(".x1mqxbix{color:black}", 3000); + _inject2("@property --color { inherits: false }", 0); export const styles = { default: color => [{ backgroundColor: "xrkmrrc", @@ -1508,6 +1514,7 @@ describe('@stylexjs/babel-plugin', () => { var _inject2 = _inject; import stylex from 'stylex'; _inject2(".x15mgraa{--background-color:var(----background-color)}", 1); + _inject2("@property ----background-color { inherits: false }", 0); export const styles = { default: bgColor => [{ "--background-color": bgColor == null ? null : "x15mgraa", @@ -1543,6 +1550,7 @@ describe('@stylexjs/babel-plugin', () => { _inject2(".x1n25116{color:var(--4xs81a)}", 3000); _inject2("@media (min-width: 1000px){.xtljkjt.xtljkjt:hover{color:green}}", 3330); _inject2(".x17z2mba:hover{color:blue}", 3130); + _inject2("@property --4xs81a { inherits: false }", 0); export const styles = { default: color => [{ backgroundColor: "xrkmrrc", @@ -1579,6 +1587,8 @@ describe('@stylexjs/babel-plugin', () => { _inject2(".x1n25116{color:var(--4xs81a)}", 3000); _inject2("@media (min-width: 1000px){.xtljkjt.xtljkjt:hover{color:green}}", 3330); _inject2(".x1d4gdy3:hover{color:var(--w5m4kq)}", 3130); + _inject2("@property --4xs81a { inherits: false }", 0); + _inject2("@property --w5m4kq { inherits: false }", 0); export const styles = { default: color => [{ backgroundColor: "xrkmrrc", @@ -1622,6 +1632,9 @@ describe('@stylexjs/babel-plugin', () => { _inject2(".x1k44ad6{margin-left:var(--14mfytm)}", 3000, ".x1k44ad6{margin-right:var(--14mfytm)}"); _inject2(".x10ktymb:hover{margin-left:var(--yepcm9)}", 3130, ".x10ktymb:hover{margin-right:var(--yepcm9)}"); _inject2(".x17zef60{margin-top:var(--marginTop)}", 4000); + _inject2("@property --14mfytm { inherits: false }", 0); + _inject2("@property --yepcm9 { inherits: false }", 0); + _inject2("@property --marginTop { inherits: false }", 0); export const styles = { default: margin => [{ backgroundColor: "xrkmrrc", diff --git a/packages/babel-plugin/src/visitors/stylex-create/index.js b/packages/babel-plugin/src/visitors/stylex-create/index.js index 4b8819bde..a3511f61b 100644 --- a/packages/babel-plugin/src/visitors/stylex-create/index.js +++ b/packages/babel-plugin/src/visitors/stylex-create/index.js @@ -117,6 +117,22 @@ export default function transformStyleXCreate( throw path.buildCodeFrameError(messages.NON_STATIC_VALUE, SyntaxError); } const plainObject = value; + + // add injection that mark variables used for dynamic styles as `inherits: false` + const injectedInheritStyles: { [string]: InjectableStyle } = {}; + if (fns != null) { + const dynamicFnsNames = Object.values(fns) + ?.map((entry) => Object.keys(entry[1])) + .flat(); + dynamicFnsNames.forEach((fnsName) => { + injectedInheritStyles[fnsName] = { + priority: 0, + ltr: `@property ${fnsName} { inherits: false }`, + rtl: null, + }; + }); + } + // eslint-disable-next-line prefer-const let [compiledStyles, injectedStylesSansKeyframes, classPathsPerNamespace] = stylexCreate(plainObject, state.options); @@ -124,6 +140,7 @@ export default function transformStyleXCreate( const injectedStyles = { ...injectedKeyframes, ...injectedStylesSansKeyframes, + ...injectedInheritStyles, }; let varName = null; diff --git a/packages/cli/__tests__/compile-stylex-folder-test.js b/packages/cli/__tests__/compile-stylex-folder-test.js index 566c762a2..aee940599 100644 --- a/packages/cli/__tests__/compile-stylex-folder-test.js +++ b/packages/cli/__tests__/compile-stylex-folder-test.js @@ -77,7 +77,7 @@ describe('compiling __mocks__/source to __mocks__/src correctly such that it mat }); test(config.output, async () => { - fs.mkdirSync(config.output); + fs.mkdirSync(config.output, { recursive: true }); expect(isDir(config.output)).toBe(true); await compileDirectory(config); const outputDir = fs.readdirSync(config.output, { recursive: true }); @@ -283,3 +283,58 @@ describe('cache mechanism works as expected', () => { writeSpy.mockRestore(); }); }); + +describe('CLI works with a custom cache path', () => { + const customCachePath = path.join(__dirname, '__custom_cache__'); + const config: TransformConfig = { + input: path.resolve('./source'), + output: path.resolve('./src'), + styleXBundleName: 'stylex_bundle.css', + modules_EXPERIMENTAL: [] as Array, + watch: false, + babelPresets: [], + cachePath: customCachePath, + state: { + compiledCSSDir: null, + compiledNodeModuleDir: null, + compiledJS: new Map(), + styleXRules: new Map(), + copiedNodeModules: false, + }, + }; + config.cachePath = customCachePath; + + beforeEach(() => { + if (fs.existsSync(customCachePath)) { + fs.rmSync(customCachePath, { recursive: true, force: true }); + } + }); + + afterAll(() => { + fs.rmSync(config.output, { recursive: true, force: true }); + if (fs.existsSync(customCachePath)) { + fs.rmSync(customCachePath, { recursive: true, force: true }); + } + }); + + test('uses the custom cache path for caching', async () => { + await compileDirectory(config); + + const customFilePath = path.join(config.input, 'index.js'); + + const cacheFilePath = path.join( + customCachePath, + path.relative(config.input, customFilePath) + '.json', + ); + + expect(fs.existsSync(customCachePath)).toBe(true); + expect(fs.existsSync(cacheFilePath)).toBe(true); + + const cacheData = JSON.parse(fs.readFileSync(cacheFilePath, 'utf-8')); + expect(cacheData).toHaveProperty('inputHash'); + expect(cacheData).toHaveProperty('outputHash'); + expect(cacheData).toHaveProperty('collectedCSS'); + + fs.rmSync(cacheFilePath, { recursive: true, force: true }); + }); +}); diff --git a/packages/cli/src/config.js b/packages/cli/src/config.js index ec46ba058..15ad9bd61 100644 --- a/packages/cli/src/config.js +++ b/packages/cli/src/config.js @@ -31,6 +31,7 @@ export type TransformConfig = { ...CliConfig, input: string, output: string, + cachePath?: string, state: { compiledCSSDir: ?string, compiledNodeModuleDir: ?string, diff --git a/packages/cli/src/files.js b/packages/cli/src/files.js index 83f1c3c9d..97087022e 100644 --- a/packages/cli/src/files.js +++ b/packages/cli/src/files.js @@ -73,7 +73,11 @@ export function isJSFile(filePath: string): boolean { // e.g. ./pages/home/index.js -> ../../stylex_bundle.css export function getRelativePath(from: string, to: string): string { const relativePath = path.relative(path.parse(from).dir, to); - return formatRelativePath(relativePath); + return formatRelativePath(toPosixPath(relativePath)); +} + +function toPosixPath(filePath: string): string { + return filePath.split(path.sep).join(path.posix.sep); } function formatRelativePath(filePath: string) { diff --git a/packages/cli/src/transform.js b/packages/cli/src/transform.js index b4c73712b..81757b981 100644 --- a/packages/cli/src/transform.js +++ b/packages/cli/src/transform.js @@ -100,7 +100,7 @@ export async function compileFile( ): Promise { const inputFilePath = path.join(config.input, filePath); const outputFilePath = path.join(config.output, filePath); - const cachePath = getDefaultCachePath(); + const cachePath = config.cachePath || getDefaultCachePath(); const inputHash = await computeHash(inputFilePath); let oldOutputHash = null; diff --git a/packages/eslint-plugin/src/stylex-valid-styles.js b/packages/eslint-plugin/src/stylex-valid-styles.js index a1bf0f710..2f36eddfd 100644 --- a/packages/eslint-plugin/src/stylex-valid-styles.js +++ b/packages/eslint-plugin/src/stylex-valid-styles.js @@ -2185,6 +2185,7 @@ const CSSProperties = { unicodeBidi: unicodeBidi, unicodeRange: unicodeRange, userSelect: userSelect, + viewTransitionName: makeUnionRule(all, isString), verticalAlign: verticalAlign, visibility: visibility, voiceBalance: voiceBalance,