From 8d9db96d9435cc42f8298ddbdd6c703fbdb2ce47 Mon Sep 17 00:00:00 2001 From: Yevhenii Date: Fri, 16 Oct 2026 17:57:11 +0300 Subject: [PATCH] Fix `yarn build-types` on Windows Three steps in scripts/js-api/build-types read a native file path as /-separated: the default-export rename took the whole Windows path as the module name, the cyclic-import rewrite wrote backslash specifiers, and the api-extractor config embedded the temp directory unescaped. Use path.basename and path.dirname, and write the paths that land in a specifier or the config with /. --- scripts/js-api/build-types/buildApiSnapshot.js | 2 +- .../__tests__/replaceDefaultExportName-test.js | 6 +++++- .../transforms/typescript/replaceDefaultExportName.js | 4 +++- .../utils/resolveCyclicImportsInDefinition.js | 11 +++++++---- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/scripts/js-api/build-types/buildApiSnapshot.js b/scripts/js-api/build-types/buildApiSnapshot.js index 2816690973ea..fe53885529fd 100644 --- a/scripts/js-api/build-types/buildApiSnapshot.js +++ b/scripts/js-api/build-types/buildApiSnapshot.js @@ -296,7 +296,7 @@ async function generateConfigFiles(tempDirectory: string) { ); const adjustedApiExtractorConfig = apiExtractorConfig.replaceAll( '${typegen_directory}', - tempDirectory, + tempDirectory.split(path.sep).join('/'), ); await fs.writeFile( path.join(tempDirectory, API_EXTRACTOR_CONFIG_FILE), diff --git a/scripts/js-api/build-types/transforms/typescript/__tests__/replaceDefaultExportName-test.js b/scripts/js-api/build-types/transforms/typescript/__tests__/replaceDefaultExportName-test.js index 394ac52b8dad..dd2e6711e9ec 100644 --- a/scripts/js-api/build-types/transforms/typescript/__tests__/replaceDefaultExportName-test.js +++ b/scripts/js-api/build-types/transforms/typescript/__tests__/replaceDefaultExportName-test.js @@ -11,6 +11,7 @@ const createReplaceDefaultExportName = require('../replaceDefaultExportName'); const babel = require('@babel/core'); const flowApiTranslator = require('flow-api-translator'); +const path = require('node:path'); const prettierOptions = {parser: 'babel'}; @@ -32,7 +33,10 @@ async function translate(code: string, fileName: string): Promise { describe('replaceDefaultExportName', () => { test('should replace default export name with unambiguous one', async () => { const code = `export default Foo;`; - const result = await translate(code, 'mock/path/to/module/Foo.js'); + const result = await translate( + code, + path.join('mock', 'path', 'to', 'module', 'Foo.js'), + ); expect(result).toMatchInlineSnapshot(` "declare const $$Foo: typeof Foo; declare type $$Foo = typeof $$Foo; diff --git a/scripts/js-api/build-types/transforms/typescript/replaceDefaultExportName.js b/scripts/js-api/build-types/transforms/typescript/replaceDefaultExportName.js index 8b3dedcea885..42110551b8a8 100644 --- a/scripts/js-api/build-types/transforms/typescript/replaceDefaultExportName.js +++ b/scripts/js-api/build-types/transforms/typescript/replaceDefaultExportName.js @@ -10,11 +10,13 @@ import type {PluginObj} from '@babel/core'; +const path = require('node:path'); + function createDefaultExportNameReplacer(filePath: string): PluginObj { return { visitor: { Identifier(node) { - const fileName = filePath.split('/').pop() ?? ''; + const fileName = path.basename(filePath); const moduleName = fileName.split('.')[0]; if (node.node.name === '$$EXPORT_DEFAULT_DECLARATION$$') { diff --git a/scripts/js-api/build-types/utils/resolveCyclicImportsInDefinition.js b/scripts/js-api/build-types/utils/resolveCyclicImportsInDefinition.js index c5869df0e119..9602a7ed29d4 100644 --- a/scripts/js-api/build-types/utils/resolveCyclicImportsInDefinition.js +++ b/scripts/js-api/build-types/utils/resolveCyclicImportsInDefinition.js @@ -24,8 +24,11 @@ function getReplacementInfo( filePath: string, packages: PackageConfig, ) { - const sourceDirectory = filePath.split('/').slice(0, -1).join('/'); - const pathToRoot = path.relative(sourceDirectory, rootPath); + const sourceDirectory = path.dirname(filePath); + const pathToRoot = path + .relative(sourceDirectory, rootPath) + .split(path.sep) + .join('/'); const packageToReplace = packages.find(({name}) => source.startsWith(name)); @@ -50,7 +53,7 @@ const visitor: PluginObj<{ nodePath.node.source.value = nodePath.node.source.value.replace( packageToReplace.name, - path.join(pathToRoot, packageToReplace.directory), + path.posix.join(pathToRoot, packageToReplace.directory), ); }, ExportNamedDeclaration(nodePath, state) { @@ -72,7 +75,7 @@ const visitor: PluginObj<{ // $FlowExpectedError[incompatible-use] nodePath.node.source.value = nodePath.node.source.value.replace( packageToReplace.name, - path.join(pathToRoot, packageToReplace.directory), + path.posix.join(pathToRoot, packageToReplace.directory), ); }, },