mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Prefer common interface files when building the type graph (#49494)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/49494 Changelog: [Internal] Reviewed By: huntie Differential Revision: D69786939 fbshipit-source-id: 3b0481e83a528afbdf1d29734d2aea9cad740f58
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f4927fc03c
commit
ee90f2d97f
@@ -11,10 +11,10 @@
|
||||
|
||||
const {PACKAGES_DIR, REPO_ROOT} = require('../../consts');
|
||||
const getRequireStack = require('./resolution/getRequireStack');
|
||||
const resolveTypeInputFile = require('./resolution/resolveTypeInputFile');
|
||||
const translatedModuleTemplate = require('./templates/translatedModule.d.ts-template');
|
||||
const translateSourceFile = require('./translateSourceFile');
|
||||
const debug = require('debug')('build-types:main');
|
||||
const {existsSync, promises: fs} = require('fs');
|
||||
const {promises: fs} = require('fs');
|
||||
const micromatch = require('micromatch');
|
||||
const path = require('path');
|
||||
|
||||
@@ -69,6 +69,14 @@ async function buildTypes(): Promise<void> {
|
||||
const dependencyEdges: DependencyEdges = [];
|
||||
|
||||
while (files.size > 0) {
|
||||
for (const file of files) {
|
||||
const interfaceFile = resolveTypeInputFile(file);
|
||||
if (interfaceFile) {
|
||||
files.delete(file);
|
||||
translatedFiles.add(file);
|
||||
files.add(interfaceFile);
|
||||
}
|
||||
}
|
||||
const dependencies = await translateSourceFiles(dependencyEdges, files);
|
||||
dependencyEdges.push(...dependencies);
|
||||
|
||||
@@ -93,46 +101,6 @@ async function translateSourceFiles(
|
||||
inputFiles: Iterable<string>,
|
||||
): Promise<DependencyEdges> {
|
||||
const files = new Set<string>([...inputFiles]);
|
||||
|
||||
// Require common interface file (js.flow) or base implementation (.js) for
|
||||
// platform-specific files (.android.js or .ios.js)
|
||||
for (const file of files) {
|
||||
const [pathWithoutExt, extension] = splitPathAndExtension(file);
|
||||
|
||||
if (/(\.android\.js|\.ios\.js)$/.test(extension)) {
|
||||
files.delete(file);
|
||||
|
||||
let resolved = false;
|
||||
|
||||
for (const ext of ['.js.flow', '.js']) {
|
||||
let interfaceFile = pathWithoutExt + ext;
|
||||
|
||||
if (files.has(interfaceFile)) {
|
||||
resolved = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (existsSync(interfaceFile)) {
|
||||
files.add(interfaceFile);
|
||||
resolved = true;
|
||||
debug(
|
||||
'Resolved %s to %s',
|
||||
path.relative(REPO_ROOT, file),
|
||||
path.relative(REPO_ROOT, interfaceFile),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!resolved) {
|
||||
throw new Error(
|
||||
`No common interface found for ${file}.[android|ios].js. This ` +
|
||||
'should either be a base .js implementation or a .js.flow interface file.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const dependencies: DependencyEdges = [];
|
||||
|
||||
await Promise.all(
|
||||
@@ -160,7 +128,7 @@ async function translateSourceFiles(
|
||||
console.error(`Failed to build ${path.relative(REPO_ROOT, file)}\n`, e);
|
||||
const requireStack = getRequireStack(dependencyEdges, file);
|
||||
if (requireStack.length > 0) {
|
||||
console.error('Chain of imports that led to this file:');
|
||||
console.error('Require stack:');
|
||||
for (const stackEntry of requireStack) {
|
||||
console.error(`- ${stackEntry}`);
|
||||
}
|
||||
@@ -188,15 +156,6 @@ function getBuildPath(file: string): string {
|
||||
);
|
||||
}
|
||||
|
||||
function splitPathAndExtension(file: string): [string, string] {
|
||||
const lastSep = file.lastIndexOf(path.sep);
|
||||
const extensionStart = file.indexOf('.', lastSep);
|
||||
return [
|
||||
file.substring(0, extensionStart),
|
||||
file.substring(extensionStart, file.length),
|
||||
];
|
||||
}
|
||||
|
||||
function stripDocblock(source: string): string {
|
||||
return source.replace(/\/\*\*[\s\S]*?\*\/\n/, '');
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
const {REPO_ROOT} = require('../../../consts');
|
||||
const debug = require('debug')('build-types:resolution');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const TYPEDEF_MAPPING: Record<string, $ReadOnlyArray<string>> = {
|
||||
'.android.js': ['.js.flow', '.js'],
|
||||
'.ios.js': ['.js.flow', '.js'],
|
||||
'.js': ['.js.flow'],
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve the Flow file defining the type interface for a given source file.
|
||||
*
|
||||
* Ensures common interface file (js.flow) or base implementation (.js) exists for
|
||||
* platform-specific files (.android.js or .ios.js).
|
||||
*/
|
||||
function resolveTypeInputFile(file: string): string | null {
|
||||
const [pathWithoutExt, extension] = splitPathAndExtension(file);
|
||||
|
||||
const extsToCheck = TYPEDEF_MAPPING[extension];
|
||||
|
||||
if (!extsToCheck) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const ext of extsToCheck) {
|
||||
const interfaceFile = pathWithoutExt + ext;
|
||||
|
||||
if (fs.existsSync(interfaceFile)) {
|
||||
debug(
|
||||
'Resolved %s to %s',
|
||||
path.relative(REPO_ROOT, file),
|
||||
path.relative(REPO_ROOT, interfaceFile),
|
||||
);
|
||||
return interfaceFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (extension === '.js') {
|
||||
// .js files do not require a common interface
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`No common interface found for ${file}.[android|ios].js. This ` +
|
||||
'should either be a base .js implementation or a .js.flow interface file.',
|
||||
);
|
||||
}
|
||||
|
||||
function splitPathAndExtension(file: string): [string, string] {
|
||||
const lastSep = file.lastIndexOf(path.sep);
|
||||
const extensionStart = file.indexOf('.', lastSep);
|
||||
return [
|
||||
file.substring(0, extensionStart),
|
||||
file.substring(extensionStart, file.length),
|
||||
];
|
||||
}
|
||||
|
||||
module.exports = resolveTypeInputFile;
|
||||
Reference in New Issue
Block a user