@rnx-kit/cli 0.9.52 → 0.9.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -3
- package/coverage/clover.xml +116 -73
- package/coverage/coverage-final.json +3 -2
- package/coverage/lcov-report/index.html +43 -28
- package/coverage/lcov-report/src/bundle/index.html +15 -15
- package/coverage/lcov-report/src/bundle/kit-config.ts.html +1 -1
- package/coverage/lcov-report/src/bundle/metro.ts.html +15 -78
- package/coverage/lcov-report/src/bundle/overrides.ts.html +1 -1
- package/coverage/lcov-report/src/index.html +21 -21
- package/coverage/lcov-report/src/metro-config.ts.html +112 -121
- package/coverage/lcov-report/src/typescript/index.html +111 -0
- package/coverage/lcov-report/src/typescript/project-cache.ts.html +614 -0
- package/coverage/lcov.info +206 -128
- package/lib/bundle/metro.d.ts +1 -2
- package/lib/bundle/metro.d.ts.map +1 -1
- package/lib/bundle/metro.js +5 -17
- package/lib/bundle/metro.js.map +1 -1
- package/lib/bundle.d.ts.map +1 -1
- package/lib/bundle.js +1 -3
- package/lib/bundle.js.map +1 -1
- package/lib/metro-config.d.ts +3 -3
- package/lib/metro-config.d.ts.map +1 -1
- package/lib/metro-config.js +58 -67
- package/lib/metro-config.js.map +1 -1
- package/lib/start.d.ts.map +1 -1
- package/lib/start.js +6 -17
- package/lib/start.js.map +1 -1
- package/lib/types.d.ts +3 -4
- package/lib/types.d.ts.map +1 -1
- package/lib/typescript/project-cache.d.ts +42 -0
- package/lib/typescript/project-cache.d.ts.map +1 -0
- package/lib/typescript/project-cache.js +110 -0
- package/lib/typescript/project-cache.js.map +1 -0
- package/package.json +15 -15
- package/src/bundle/metro.ts +6 -27
- package/src/bundle.ts +1 -4
- package/src/metro-config.ts +78 -81
- package/src/start.ts +7 -26
- package/src/types.ts +3 -5
- package/src/typescript/project-cache.ts +178 -0
- package/CHANGELOG.json +0 -3175
package/src/start.ts
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
loadMetroConfig,
|
|
6
6
|
startServer,
|
|
7
7
|
} from "@rnx-kit/metro-service";
|
|
8
|
-
import { findConfigFile, Service } from "@rnx-kit/typescript-service";
|
|
9
8
|
import chalk from "chalk";
|
|
10
9
|
import type { Reporter, ReportableEvent } from "metro";
|
|
11
10
|
import type Server from "metro/src/Server";
|
|
@@ -14,7 +13,7 @@ import path from "path";
|
|
|
14
13
|
import readline from "readline";
|
|
15
14
|
import { getKitServerConfig } from "./serve/kit-config";
|
|
16
15
|
import { customizeMetroConfig } from "./metro-config";
|
|
17
|
-
import type {
|
|
16
|
+
import type { TypeScriptValidationOptions } from "./types";
|
|
18
17
|
|
|
19
18
|
export type CLIStartOptions = {
|
|
20
19
|
host: string;
|
|
@@ -120,35 +119,17 @@ export async function rnxStart(
|
|
|
120
119
|
: undefined),
|
|
121
120
|
});
|
|
122
121
|
|
|
123
|
-
// prepare for typescript validation, if requested
|
|
124
|
-
let tsprojectInfo: TSProjectInfo | undefined;
|
|
125
|
-
if (serverConfig.typescriptValidation) {
|
|
126
|
-
const tsservice = new Service((message) => terminal.log(message));
|
|
127
|
-
|
|
128
|
-
const configFileName = findConfigFile(
|
|
129
|
-
metroConfig.projectRoot,
|
|
130
|
-
"tsconfig.json"
|
|
131
|
-
);
|
|
132
|
-
if (!configFileName) {
|
|
133
|
-
terminal.log(
|
|
134
|
-
chalk.yellow(
|
|
135
|
-
`Warning: cannot find tsconfig.json under project root '${metroConfig.projectRoot}' -- skipping TypeScript validation`
|
|
136
|
-
)
|
|
137
|
-
);
|
|
138
|
-
} else {
|
|
139
|
-
tsprojectInfo = {
|
|
140
|
-
service: tsservice,
|
|
141
|
-
configFileName,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
122
|
// customize the metro config to include plugins, presets, etc.
|
|
123
|
+
const typescriptValidationOptions: TypeScriptValidationOptions = {
|
|
124
|
+
print: (message: string): void => {
|
|
125
|
+
terminal.log(message);
|
|
126
|
+
},
|
|
127
|
+
};
|
|
147
128
|
customizeMetroConfig(
|
|
148
129
|
metroConfig,
|
|
149
130
|
serverConfig.detectCyclicDependencies,
|
|
150
131
|
serverConfig.detectDuplicateDependencies,
|
|
151
|
-
|
|
132
|
+
serverConfig.typescriptValidation ? typescriptValidationOptions : false,
|
|
152
133
|
serverConfig.experimental_treeShake
|
|
153
134
|
);
|
|
154
135
|
|
package/src/types.ts
CHANGED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { findPackageDir } from "@rnx-kit/tools-node";
|
|
2
|
+
import {
|
|
3
|
+
AllPlatforms,
|
|
4
|
+
platformExtensions,
|
|
5
|
+
} from "@rnx-kit/tools-react-native/platform";
|
|
6
|
+
import { changeHostToUseReactNativeResolver } from "@rnx-kit/typescript-react-native-resolver";
|
|
7
|
+
import {
|
|
8
|
+
createDiagnosticWriter,
|
|
9
|
+
Project,
|
|
10
|
+
readConfigFile,
|
|
11
|
+
} from "@rnx-kit/typescript-service";
|
|
12
|
+
import path from "path";
|
|
13
|
+
import ts from "typescript";
|
|
14
|
+
|
|
15
|
+
export type ProjectInfo = {
|
|
16
|
+
tsproject: Project;
|
|
17
|
+
tssourceFiles: Set<string>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Collection of TypeScript projects, separated by their target platform.
|
|
22
|
+
*
|
|
23
|
+
* Target platform is a react-native concept, not a TypeScript concept.
|
|
24
|
+
* However, each project is configured with react-native module resolution,
|
|
25
|
+
* which means the module file graph could vary by platform. And that means
|
|
26
|
+
* each platform could yield different type errors.
|
|
27
|
+
*
|
|
28
|
+
* For example, `import { f } from "./utils"` could load `./utils.android.ts`
|
|
29
|
+
* for Android and `./utils.ios.ts` iOS.
|
|
30
|
+
*/
|
|
31
|
+
export interface ProjectCache {
|
|
32
|
+
/**
|
|
33
|
+
* Discard all cached projects targeting a specific platform.
|
|
34
|
+
*
|
|
35
|
+
* @param platform Target platform
|
|
36
|
+
*/
|
|
37
|
+
clearPlatform(platform: AllPlatforms): void;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get info on the project which targets a specific platform and contains a specific
|
|
41
|
+
* source file. If the project is not cached, load it and add it to the cache.
|
|
42
|
+
*
|
|
43
|
+
* @param platform Target platform
|
|
44
|
+
* @param sourceFile Source file
|
|
45
|
+
* @returns Project targeting the given platform and containing the given source file
|
|
46
|
+
*/
|
|
47
|
+
getProjectInfo(sourceFile: string, platform: AllPlatforms): ProjectInfo;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create an empty cache for holding TypeScript projects.
|
|
52
|
+
*
|
|
53
|
+
* @param print Optional method for printing messages. When not set, messages are printed to the console.
|
|
54
|
+
* @returns Empty project cache
|
|
55
|
+
*/
|
|
56
|
+
export function createProjectCache(
|
|
57
|
+
print?: (message: string) => void
|
|
58
|
+
): ProjectCache {
|
|
59
|
+
const documentRegistry = ts.createDocumentRegistry();
|
|
60
|
+
const diagnosticWriter = createDiagnosticWriter(print);
|
|
61
|
+
|
|
62
|
+
// Collection of projects organized by root directory, then by platform.
|
|
63
|
+
const projects: Record<
|
|
64
|
+
string,
|
|
65
|
+
Partial<Record<AllPlatforms, ProjectInfo>>
|
|
66
|
+
> = {};
|
|
67
|
+
|
|
68
|
+
function findProjectRoot(sourceFile: string): string {
|
|
69
|
+
// Search known root directories to see if the source file is in one of them.
|
|
70
|
+
for (const root of Object.keys(projects)) {
|
|
71
|
+
if (sourceFile.startsWith(root)) {
|
|
72
|
+
return root;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Search the file system for the root of source file's package.
|
|
77
|
+
const root = findPackageDir(path.dirname(sourceFile));
|
|
78
|
+
if (!root) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Cannot find project root for source file '${sourceFile}'`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return root;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function readTSConfig(root: string): ts.ParsedCommandLine {
|
|
88
|
+
const configFileName = path.join(root, "tsconfig.json");
|
|
89
|
+
|
|
90
|
+
const cmdLine = readConfigFile(configFileName);
|
|
91
|
+
if (!cmdLine) {
|
|
92
|
+
throw new Error(`Failed to load '${configFileName}'`);
|
|
93
|
+
} else if (cmdLine.errors.length > 0) {
|
|
94
|
+
const writer = createDiagnosticWriter();
|
|
95
|
+
cmdLine.errors.forEach((e) => writer.print(e));
|
|
96
|
+
throw new Error(`Failed to load '${configFileName}'`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return cmdLine;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function createProjectInfo(
|
|
103
|
+
root: string,
|
|
104
|
+
platform: AllPlatforms
|
|
105
|
+
): ProjectInfo {
|
|
106
|
+
// Load the TypeScript configuration file for this project.
|
|
107
|
+
const cmdLine = readTSConfig(root);
|
|
108
|
+
|
|
109
|
+
// Create a TypeScript project using the configuration file. Enhance the
|
|
110
|
+
// underlying TS language service with our react-native module resolver.
|
|
111
|
+
const enhanceLanguageServiceHost = (host: ts.LanguageServiceHost): void => {
|
|
112
|
+
const platformExtensionNames = platformExtensions(platform);
|
|
113
|
+
const disableReactNativePackageSubstitution = true;
|
|
114
|
+
const traceReactNativeModuleResolutionErrors = false;
|
|
115
|
+
const traceResolutionLog = undefined;
|
|
116
|
+
changeHostToUseReactNativeResolver({
|
|
117
|
+
host,
|
|
118
|
+
options: cmdLine.options,
|
|
119
|
+
platform,
|
|
120
|
+
platformExtensionNames,
|
|
121
|
+
disableReactNativePackageSubstitution,
|
|
122
|
+
traceReactNativeModuleResolutionErrors,
|
|
123
|
+
traceResolutionLog,
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
const tsproject = new Project(
|
|
127
|
+
documentRegistry,
|
|
128
|
+
diagnosticWriter,
|
|
129
|
+
cmdLine,
|
|
130
|
+
enhanceLanguageServiceHost
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// Store TypeScript's source file list for this project. We'll use it later
|
|
134
|
+
// to filter files from Metro's file graph. We only want to check files that
|
|
135
|
+
// TypeScript considers to be source code, and not transpiled output.
|
|
136
|
+
const tssourceFiles = new Set(cmdLine.fileNames);
|
|
137
|
+
|
|
138
|
+
// Start with an empty project
|
|
139
|
+
tsproject.removeAllFiles();
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
tsproject,
|
|
143
|
+
tssourceFiles,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function getProjectInfo(
|
|
148
|
+
sourceFile: string,
|
|
149
|
+
platform: AllPlatforms
|
|
150
|
+
): ProjectInfo {
|
|
151
|
+
const root = findProjectRoot(sourceFile);
|
|
152
|
+
projects[root] ||= {};
|
|
153
|
+
|
|
154
|
+
let info = projects[root][platform];
|
|
155
|
+
if (!info) {
|
|
156
|
+
info = createProjectInfo(root, platform);
|
|
157
|
+
projects[root][platform] = info;
|
|
158
|
+
}
|
|
159
|
+
return info;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function clearPlatform(platform: AllPlatforms): void {
|
|
163
|
+
Object.values(projects).forEach((projectsByPlatform) => {
|
|
164
|
+
const info = projectsByPlatform[platform];
|
|
165
|
+
if (info) {
|
|
166
|
+
if (info.tsproject) {
|
|
167
|
+
info.tsproject.dispose();
|
|
168
|
+
}
|
|
169
|
+
delete projectsByPlatform[platform];
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
clearPlatform,
|
|
176
|
+
getProjectInfo,
|
|
177
|
+
};
|
|
178
|
+
}
|