@react-native-harness/cli 1.2.0-rc.1 → 1.3.0
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/dist/__tests__/platform-commands.test.d.ts +2 -0
- package/dist/__tests__/platform-commands.test.d.ts.map +1 -0
- package/dist/__tests__/platform-commands.test.js +207 -0
- package/dist/index.js +113 -6
- package/dist/platform-commands.d.ts +18 -0
- package/dist/platform-commands.d.ts.map +1 -0
- package/dist/platform-commands.js +84 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/wizard/bundleId.js +1 -1
- package/eslint.config.mjs +1 -1
- package/package.json +8 -8
- package/skills/core.md +92 -0
- package/skills/mocking.md +87 -0
- package/skills/ui.md +59 -0
- package/src/__tests__/platform-commands.test.ts +232 -0
- package/src/index.ts +152 -5
- package/src/platform-commands.ts +148 -0
- package/src/wizard/bundleId.ts +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { ConfigNotFoundError, getConfig } from '@react-native-harness/config';
|
|
2
|
+
import type { HarnessCliCommand } from '@react-native-harness/platforms';
|
|
3
|
+
|
|
4
|
+
type ConfigLoader = typeof getConfig;
|
|
5
|
+
|
|
6
|
+
type DiscoveredPlatformCommands = {
|
|
7
|
+
commands: HarnessCliCommand[];
|
|
8
|
+
projectRoot: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
12
|
+
typeof value === 'object' && value !== null;
|
|
13
|
+
|
|
14
|
+
const getModuleCommands = (
|
|
15
|
+
importedModule: unknown,
|
|
16
|
+
modulePath: string
|
|
17
|
+
): HarnessCliCommand[] => {
|
|
18
|
+
const moduleValue = isRecord(importedModule)
|
|
19
|
+
? importedModule
|
|
20
|
+
: ({} as Record<string, unknown>);
|
|
21
|
+
const defaultExport = isRecord(moduleValue.default)
|
|
22
|
+
? moduleValue.default
|
|
23
|
+
: undefined;
|
|
24
|
+
const commandsValue = moduleValue.commands ?? defaultExport?.commands;
|
|
25
|
+
|
|
26
|
+
if (!Array.isArray(commandsValue)) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Invalid platform CLI module '${modulePath}': expected a commands array.`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return commandsValue.map((command, index) => {
|
|
33
|
+
if (!isRecord(command) || typeof command.name !== 'string') {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Invalid platform CLI module '${modulePath}': command #${index + 1} is missing a valid name.`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (typeof command.run !== 'function') {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Invalid platform CLI module '${modulePath}': command '${command.name}' is missing a run handler.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (
|
|
46
|
+
command.aliases !== undefined &&
|
|
47
|
+
(!Array.isArray(command.aliases) ||
|
|
48
|
+
command.aliases.some((alias) => typeof alias !== 'string'))
|
|
49
|
+
) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Invalid platform CLI module '${modulePath}': command '${command.name}' has invalid aliases.`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return command as HarnessCliCommand;
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const registerCommandNames = (
|
|
60
|
+
seenNames: Map<string, string>,
|
|
61
|
+
modulePath: string,
|
|
62
|
+
command: HarnessCliCommand
|
|
63
|
+
) => {
|
|
64
|
+
const names = [command.name, ...(command.aliases ?? [])];
|
|
65
|
+
|
|
66
|
+
for (const name of names) {
|
|
67
|
+
const existingSource = seenNames.get(name);
|
|
68
|
+
|
|
69
|
+
if (existingSource !== undefined) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Duplicate platform CLI command '${name}' in '${modulePath}' and '${existingSource}'.`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
seenNames.set(name, modulePath);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const discoverPlatformCommands = async (options: {
|
|
80
|
+
cwd: string;
|
|
81
|
+
loadConfig?: ConfigLoader;
|
|
82
|
+
}): Promise<DiscoveredPlatformCommands | null> => {
|
|
83
|
+
const loadConfig = options.loadConfig ?? getConfig;
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const { config, projectRoot } = await loadConfig(options.cwd);
|
|
87
|
+
const modulePaths = [...new Set(config.runners.map((runner) => runner.cli))].filter(
|
|
88
|
+
(modulePath): modulePath is string => typeof modulePath === 'string'
|
|
89
|
+
);
|
|
90
|
+
const commands: HarnessCliCommand[] = [];
|
|
91
|
+
const seenNames = new Map<string, string>();
|
|
92
|
+
|
|
93
|
+
for (const modulePath of modulePaths) {
|
|
94
|
+
const importedModule = await import(modulePath);
|
|
95
|
+
const moduleCommands = getModuleCommands(importedModule, modulePath);
|
|
96
|
+
|
|
97
|
+
for (const command of moduleCommands) {
|
|
98
|
+
registerCommandNames(seenNames, modulePath, command);
|
|
99
|
+
commands.push(command);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
commands,
|
|
105
|
+
projectRoot,
|
|
106
|
+
};
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error instanceof ConfigNotFoundError) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export const runPlatformCommand = async (options: {
|
|
117
|
+
argv: string[];
|
|
118
|
+
cwd: string;
|
|
119
|
+
loadConfig?: ConfigLoader;
|
|
120
|
+
}): Promise<boolean> => {
|
|
121
|
+
const commandName = options.argv[0];
|
|
122
|
+
|
|
123
|
+
if (typeof commandName !== 'string' || commandName.length === 0) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const discoveredCommands = await discoverPlatformCommands(options);
|
|
128
|
+
|
|
129
|
+
if (discoveredCommands === null) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const command = discoveredCommands.commands.find(
|
|
134
|
+
(entry) =>
|
|
135
|
+
entry.name === commandName || entry.aliases?.includes(commandName) === true
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
if (command === undefined) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
await command.run(options.argv.slice(1), {
|
|
143
|
+
cwd: options.cwd,
|
|
144
|
+
projectRoot: discoveredCommands.projectRoot,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
return true;
|
|
148
|
+
};
|