mirror of
https://github.com/react/react-native.git
synced 2026-09-29 16:58:04 +08:00
SPM: allow overriding the autolinking config command (#57662)
Summary:
The SwiftPM autolinking flow hardcodes `react-native-community/cli config` to generate `autolinking.json` (`generate-spm-autolinking-config.js`). Apps that replace community autolinking — most notably **Expo**, which ships `expo-modules-autolinking` instead of `react-native-community/cli` — had no way to override that command, and any failure was swallowed. The result: the config command fails, `autolinking.json` is never written, the `Autolinked` SwiftPM package comes out empty, and `import Expo` (and every Expo module) fails to resolve — surfacing much later as an inscrutable `unable to resolve module dependency: 'Expo'`.
CocoaPods already solves the injection half: `use_native_modules!(config_command = $default_command)` accepts the command as a parameter, so an Expo `Podfile` passes `expo-modules-autolinking react-native-config` in place of the `rncli` default. This PR adds the equivalent hook to the SwiftPM path **and** closes the silent-failure trap.
### 1. Allow overriding the config command
`generateAutolinkingConfig` already accepted a `configCommand` option internally; it was just never reachable. Two ways to supply it, mirroring the CocoaPods hook:
- **`--config-command '<json>'`** — CLI flag taking a JSON array of the argv.
- **`RCT_SPM_AUTOLINKING_CONFIG_COMMAND`** — env var in the same JSON-array format. This is the vehicle for the injected Xcode build phase, which usually can't rewrite the script's argv but can read env.
Both go through one `parseConfigCommandJson` validator (rejects non-JSON, non-arrays, empty arrays, and non-string / empty-string elements, with a `source`-named error). Precedence: **`--config-command` > `RCT_SPM_AUTOLINKING_CONFIG_COMMAND` > default** (local `rncli` → `npx --no-install` fallback, unchanged). JSON (rather than whitespace-splitting) because real commands contain dashed flags and quoted script strings.
The value is the **command to execute** — its stdout is captured as the config JSON and written verbatim — exactly matching CocoaPods, not a precomputed result. An Expo app feeds the same argv it already builds for `use_native_modules!`:
```jsonc
RCT_SPM_AUTOLINKING_CONFIG_COMMAND='["node","--no-warnings","--eval","require('expo/bin/autolinking')","expo-modules-autolinking","react-native-config","--json","--platform","ios","--source-dir","/abs/path"]'
```
(Use `--platform ios`: the generator requires `project.ios.sourceDir` and everything downstream is iOS-only.)
### 2. Fail closed when the config command errors
Previously `main()` swallowed a config-command failure as a warning and continued, which is what let the empty package be produced silently. That policy is now extracted into `generateAutolinkingConfigOrFailClosed`: on a config-command error (non-zero exit, unparseable output, or a config missing `project.ios.sourceDir`) it logs an actionable message naming `RCT_SPM_AUTOLINKING_CONFIG_COMMAND` / `--config-command`, sets `process.exitCode = 2` (a hard Xcode build-phase error, matching the existing `RemoteVersionError` path), and stops.
The guard is deliberately narrow: a **genuinely native-module-free app never reaches the error path** — its command exits 0 with valid, empty-dependency JSON, so the generator returns normally and the legitimate empty-package path stays valid. Only an *erroring* command fails the build.
## Changelog:
[IOS] [ADDED] - Allow overriding the SwiftPM autolinking config command via `--config-command` / `RCT_SPM_AUTOLINKING_CONFIG_COMMAND`
[IOS] [CHANGED] - Fail closed with an actionable error when the SwiftPM autolinking config command fails, instead of silently emitting an empty Autolinked package
Pull Request resolved: https://github.com/react/react-native/pull/57662
Test Plan:
New unit tests, developed red → green:
- `generate-spm-autolinking-config-test.js` — env var honored; explicit `configCommand` beats env; invalid-JSON and invalid-shape (`[]`, `[1,2]`) throw with the source name; env unset falls back to the default command; env state saved/restored per test.
- `setup-apple-spm-test.js` — `parseArgs` parses `--config-command` into an argv array, defaults to `null` when omitted, and throws on an invalid value; `generateAutolinkingConfigOrFailClosed` returns the result on success (exit code untouched), passes `projectRoot`/`configCommand` through, and on a config-command error returns `null`, sets exit 2, and logs an actionable error that names the env var and preserves the underlying cause.
```
$ yarn jest --no-cache -i \
packages/react-native/scripts/spm/__tests__/generate-spm-autolinking-config-test.js \
packages/react-native/scripts/spm/__tests__/setup-apple-spm-test.js
Test Suites: 2 passed, 2 total
Tests: 39 passed, 39 total
```
`prettier` and `eslint` clean on all changed files.
Reviewed By: zeyap
Differential Revision: D113554857
Pulled By: cipolleschi
fbshipit-source-id: d0baeeefc91aed144cf9e405e198531ff88088a7
This commit is contained in:
committed by
meta-codesync[bot]
parent
e9eac585e2
commit
a7ba4ce522
+63
-9
@@ -55,6 +55,7 @@
|
||||
* must contain debug/ and release/ cache slots.
|
||||
* [advanced] --download <auto|skip|force> Artifact policy (default: auto).
|
||||
* [advanced] --skip-codegen Skip the react-native codegen step.
|
||||
* [advanced] --config-command <json> Override the autolinking config command.
|
||||
*
|
||||
* Steps performed (add/update):
|
||||
* 1. react-native codegen → build/generated/ios/ + install SPM codegen template
|
||||
@@ -83,6 +84,7 @@ const {
|
||||
} = require('./spm/generate-spm-autolinking');
|
||||
const {
|
||||
generateAutolinkingConfig,
|
||||
parseConfigCommandJson,
|
||||
} = require('./spm/generate-spm-autolinking-config');
|
||||
const {main: generatePackage} = require('./spm/generate-spm-package');
|
||||
const {findSourcePath} = require('./spm/generate-spm-package');
|
||||
@@ -187,6 +189,11 @@ function parseArgs(argv /*: Array<string> */) /*: SetupArgs */ {
|
||||
default: false,
|
||||
describe: '[advanced] Skip the react-native codegen step',
|
||||
})
|
||||
.option('config-command', {
|
||||
type: 'string',
|
||||
describe:
|
||||
'[advanced] JSON array of the argv used to generate autolinking.json, overriding the default @react-native-community/cli config command. Also settable via RCT_SPM_AUTOLINKING_CONFIG_COMMAND. Example: \'["npx","expo-modules-autolinking","react-native-config","--json","--platform","ios"]\'',
|
||||
})
|
||||
.usage(
|
||||
'Usage: $0 [action] [options]\n\nSets up Swift Package Manager support in a React Native app.',
|
||||
)
|
||||
@@ -214,6 +221,10 @@ function parseArgs(argv /*: Array<string> */) /*: SetupArgs */ {
|
||||
version: parsed.version ?? null,
|
||||
artifacts: parsed.artifacts ?? null,
|
||||
skipCodegen: parsed['skip-codegen'],
|
||||
configCommand:
|
||||
parsed['config-command'] != null
|
||||
? parseConfigCommandJson(parsed['config-command'], '--config-command')
|
||||
: null,
|
||||
downloadPolicy: parsed.download,
|
||||
productName: parsed['product-name'] ?? null,
|
||||
xcodeprojPath: parsed.xcodeproj ?? null,
|
||||
@@ -892,6 +903,47 @@ function logNextSteps(
|
||||
log('To remove SPM later: `npx react-native spm deinit`');
|
||||
}
|
||||
|
||||
// Generate autolinking.json, failing closed on a config-command error.
|
||||
//
|
||||
// generateAutolinkingConfig throws ONLY when the config command itself fails —
|
||||
// a non-zero exit, unparseable output, or a config missing
|
||||
// project.ios.sourceDir. Swallowing that (the old behavior) let the run proceed
|
||||
// and emit an empty Autolinked package, which only surfaced much later as an
|
||||
// inscrutable `unable to resolve module dependency` at build time. Instead we
|
||||
// set process.exitCode = 2 (a hard Xcode build-phase error, matching the
|
||||
// RemoteVersionError path) and return null so the caller stops.
|
||||
//
|
||||
// A genuinely native-module-free app does NOT reach the error path: its command
|
||||
// exits 0 with valid, empty-dependency JSON, so generateAutolinkingConfig
|
||||
// returns normally and the empty-package path downstream stays valid.
|
||||
function generateAutolinkingConfigOrFailClosed(
|
||||
opts /*: {
|
||||
projectRoot: string,
|
||||
configCommand?: Array<string>,
|
||||
generate?: typeof generateAutolinkingConfig,
|
||||
} */,
|
||||
) /*: ?AutolinkingConfigResult */ {
|
||||
const generate = opts.generate ?? generateAutolinkingConfig;
|
||||
try {
|
||||
return generate({
|
||||
projectRoot: opts.projectRoot,
|
||||
configCommand: opts.configCommand,
|
||||
});
|
||||
} catch (e) {
|
||||
logError(
|
||||
`Failed to generate autolinking.json: ${e.message}\n` +
|
||||
'The autolinking config command failed. If this app replaces ' +
|
||||
'@react-native-community/cli autolinking (e.g. an Expo app), set ' +
|
||||
'RCT_SPM_AUTOLINKING_CONFIG_COMMAND (or pass --config-command) to a ' +
|
||||
'JSON argv array whose command prints the React Native CLI config, ' +
|
||||
'e.g. \'["npx","expo-modules-autolinking","react-native-config",' +
|
||||
'"--json","--platform","ios"]\'.',
|
||||
);
|
||||
process.exitCode = 2;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function main(argv /*:: ?: Array<string> */) /*: Promise<void> */ {
|
||||
let appRoot = process.cwd();
|
||||
const projectRoot = findProjectRoot(appRoot);
|
||||
@@ -981,16 +1033,16 @@ async function main(argv /*:: ?: Array<string> */) /*: Promise<void> */ {
|
||||
let autolinkingConfigResult /*: ?AutolinkingConfigResult */ = null;
|
||||
if (needsCliConfig) {
|
||||
log('Generating autolinking.json (CLI config)...');
|
||||
try {
|
||||
autolinkingConfigResult = generateAutolinkingConfig({projectRoot});
|
||||
log(
|
||||
`Wrote ${path.relative(appRoot, autolinkingConfigResult.outputPath)}`,
|
||||
);
|
||||
} catch (e) {
|
||||
logError(
|
||||
`generate-spm-autolinking-config failed: ${e.message}. External native modules may not be discovered.`,
|
||||
);
|
||||
autolinkingConfigResult = generateAutolinkingConfigOrFailClosed({
|
||||
projectRoot,
|
||||
configCommand: args.configCommand ?? undefined,
|
||||
});
|
||||
if (autolinkingConfigResult == null) {
|
||||
// Fail closed: the config command errored and the helper already set
|
||||
// process.exitCode = 2. Stop rather than emit an empty Autolinked package.
|
||||
return;
|
||||
}
|
||||
log(`Wrote ${path.relative(appRoot, autolinkingConfigResult.outputPath)}`);
|
||||
}
|
||||
const reactNativeRoot = resolveReactNativeRoot(
|
||||
autolinkingConfigResult,
|
||||
@@ -1159,6 +1211,8 @@ module.exports = {
|
||||
main,
|
||||
detectStandardRnLayoutRedirect,
|
||||
findInjectedXcodeproj,
|
||||
generateAutolinkingConfigOrFailClosed,
|
||||
parseArgs,
|
||||
resolveAction,
|
||||
shouldAutoDeintegrate,
|
||||
ensureBothArtifactFlavors,
|
||||
|
||||
+105
@@ -36,6 +36,20 @@ const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
|
||||
let tmpProjects = [];
|
||||
let originalConfigCommandEnv;
|
||||
|
||||
beforeEach(() => {
|
||||
originalConfigCommandEnv = process.env.RCT_SPM_AUTOLINKING_CONFIG_COMMAND;
|
||||
delete process.env.RCT_SPM_AUTOLINKING_CONFIG_COMMAND;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (originalConfigCommandEnv == null) {
|
||||
delete process.env.RCT_SPM_AUTOLINKING_CONFIG_COMMAND;
|
||||
} else {
|
||||
process.env.RCT_SPM_AUTOLINKING_CONFIG_COMMAND = originalConfigCommandEnv;
|
||||
}
|
||||
});
|
||||
|
||||
function makeTmpProject() {
|
||||
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'spm-autolink-config-'));
|
||||
@@ -256,4 +270,95 @@ describe('generateAutolinkingConfig', () => {
|
||||
rawJson: raw,
|
||||
});
|
||||
});
|
||||
|
||||
describe('config command override', () => {
|
||||
it('uses the config command from RCT_SPM_AUTOLINKING_CONFIG_COMMAND', () => {
|
||||
const {projectRoot, iosDir} = makeTmpProject();
|
||||
const raw = JSON.stringify(fakeCliConfig(iosDir));
|
||||
let receivedCommand = null;
|
||||
process.env.RCT_SPM_AUTOLINKING_CONFIG_COMMAND = JSON.stringify([
|
||||
'my-cli',
|
||||
'config',
|
||||
]);
|
||||
|
||||
generateAutolinkingConfig({
|
||||
projectRoot,
|
||||
cliRunner: command => {
|
||||
receivedCommand = command;
|
||||
return {stdout: raw, stderr: '', exitCode: 0};
|
||||
},
|
||||
});
|
||||
|
||||
expect(receivedCommand).toEqual(['my-cli', 'config']);
|
||||
});
|
||||
|
||||
it('prefers an explicit configCommand over the environment variable', () => {
|
||||
const {projectRoot, iosDir} = makeTmpProject();
|
||||
const raw = JSON.stringify(fakeCliConfig(iosDir));
|
||||
let receivedCommand = null;
|
||||
process.env.RCT_SPM_AUTOLINKING_CONFIG_COMMAND = JSON.stringify([
|
||||
'environment',
|
||||
'config',
|
||||
]);
|
||||
|
||||
generateAutolinkingConfig({
|
||||
projectRoot,
|
||||
configCommand: ['explicit', 'config'],
|
||||
cliRunner: command => {
|
||||
receivedCommand = command;
|
||||
return {stdout: raw, stderr: '', exitCode: 0};
|
||||
},
|
||||
});
|
||||
|
||||
expect(receivedCommand).toEqual(['explicit', 'config']);
|
||||
});
|
||||
|
||||
it('throws when the environment variable is not JSON', () => {
|
||||
const {projectRoot} = makeTmpProject();
|
||||
process.env.RCT_SPM_AUTOLINKING_CONFIG_COMMAND = 'not json';
|
||||
|
||||
expect(() =>
|
||||
generateAutolinkingConfig({
|
||||
projectRoot,
|
||||
cliRunner: () => ({stdout: '{}', stderr: '', exitCode: 0}),
|
||||
}),
|
||||
).toThrow(/RCT_SPM_AUTOLINKING_CONFIG_COMMAND/);
|
||||
});
|
||||
|
||||
it.each(['[]', '[1,2]'])(
|
||||
'throws when the environment variable is not a non-empty string array: %s',
|
||||
rawConfigCommand => {
|
||||
const {projectRoot} = makeTmpProject();
|
||||
process.env.RCT_SPM_AUTOLINKING_CONFIG_COMMAND = rawConfigCommand;
|
||||
|
||||
expect(() =>
|
||||
generateAutolinkingConfig({
|
||||
projectRoot,
|
||||
cliRunner: () => ({stdout: '{}', stderr: '', exitCode: 0}),
|
||||
}),
|
||||
).toThrow(/RCT_SPM_AUTOLINKING_CONFIG_COMMAND/);
|
||||
},
|
||||
);
|
||||
|
||||
it('falls back to the default command when the environment variable is unset', () => {
|
||||
const {projectRoot, iosDir} = makeTmpProject();
|
||||
const raw = JSON.stringify(fakeCliConfig(iosDir));
|
||||
let receivedCommand = null;
|
||||
|
||||
generateAutolinkingConfig({
|
||||
projectRoot,
|
||||
cliRunner: command => {
|
||||
receivedCommand = command;
|
||||
return {stdout: raw, stderr: '', exitCode: 0};
|
||||
},
|
||||
});
|
||||
|
||||
expect(receivedCommand).toEqual([
|
||||
'npx',
|
||||
'--no-install',
|
||||
'@react-native-community/cli',
|
||||
'config',
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,6 +14,8 @@ const {
|
||||
detectStandardRnLayoutRedirect,
|
||||
ensureBothArtifactFlavors,
|
||||
findInjectedXcodeproj,
|
||||
generateAutolinkingConfigOrFailClosed,
|
||||
parseArgs,
|
||||
resolveAction,
|
||||
shouldAutoDeintegrate,
|
||||
} = require('../../setup-apple-spm');
|
||||
@@ -59,6 +61,102 @@ function gitInitAndCommit(dir) {
|
||||
execFileSync('git', ['commit', '-m', 'init'], opts);
|
||||
}
|
||||
|
||||
describe('parseArgs', () => {
|
||||
it('parses --config-command as a JSON argv array', () => {
|
||||
const args = parseArgs([
|
||||
'update',
|
||||
'--config-command',
|
||||
'["a","b","config"]',
|
||||
]);
|
||||
|
||||
expect(args.action).toBe('update');
|
||||
expect(args.configCommand).toEqual(['a', 'b', 'config']);
|
||||
});
|
||||
|
||||
it('sets configCommand to null when --config-command is omitted', () => {
|
||||
expect(parseArgs(['update']).configCommand).toBeNull();
|
||||
});
|
||||
|
||||
it('throws for an invalid --config-command value', () => {
|
||||
expect(() => parseArgs(['update', '--config-command', 'not json'])).toThrow(
|
||||
/--config-command/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// generateAutolinkingConfigOrFailClosed — the fail-closed policy main() applies
|
||||
// to the autolinking config step. Swallowing a config-command error (the old
|
||||
// behavior) let the build proceed with a silently-empty Autolinked package that
|
||||
// only surfaced later as `unable to resolve module dependency`. A native-
|
||||
// module-free app does NOT hit the error path: its command exits 0 with valid
|
||||
// empty-dependency JSON and the generator returns normally.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('generateAutolinkingConfigOrFailClosed', () => {
|
||||
let prevExitCode;
|
||||
let warnSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
prevExitCode = process.exitCode;
|
||||
warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.exitCode = prevExitCode;
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('returns the config result and leaves the exit code untouched on success', () => {
|
||||
const result = {
|
||||
config: {},
|
||||
outputPath: '/app/ios/autolinking.json',
|
||||
rawJson: '{}',
|
||||
};
|
||||
const out = generateAutolinkingConfigOrFailClosed({
|
||||
projectRoot: '/app',
|
||||
generate: () => result,
|
||||
});
|
||||
|
||||
expect(out).toBe(result);
|
||||
expect(process.exitCode).not.toBe(2);
|
||||
});
|
||||
|
||||
it('passes projectRoot and configCommand through to the generator', () => {
|
||||
let received;
|
||||
generateAutolinkingConfigOrFailClosed({
|
||||
projectRoot: '/proj',
|
||||
configCommand: ['my-cli', 'config'],
|
||||
generate: opts => {
|
||||
received = opts;
|
||||
return {config: {}, outputPath: '', rawJson: ''};
|
||||
},
|
||||
});
|
||||
|
||||
expect(received).toEqual({
|
||||
projectRoot: '/proj',
|
||||
configCommand: ['my-cli', 'config'],
|
||||
});
|
||||
});
|
||||
|
||||
it('fails closed (null, exit 2, actionable error) when the config command errors', () => {
|
||||
const out = generateAutolinkingConfigOrFailClosed({
|
||||
projectRoot: '/app',
|
||||
generate: () => {
|
||||
throw new Error("'my-cli config' exited with status 1");
|
||||
},
|
||||
});
|
||||
|
||||
expect(out).toBeNull();
|
||||
expect(process.exitCode).toBe(2);
|
||||
const warnings = warnSpy.mock.calls.map(c => c.join(' ')).join('\n');
|
||||
// Names the override so the next person can fix it...
|
||||
expect(warnings).toMatch(/RCT_SPM_AUTOLINKING_CONFIG_COMMAND/);
|
||||
// ...and preserves the underlying cause.
|
||||
expect(warnings).toMatch(/exited with status 1/);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// resolveAction — zero-arg default. Explicit action wins; otherwise `update`
|
||||
// when an injection marker exists, else `add` (first run).
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
*
|
||||
* Invokes the React Native community CLI to produce its config and writes the
|
||||
* raw JSON to <project.ios.sourceDir>/build/generated/autolinking/autolinking.json.
|
||||
* The config command can be overridden by `--config-command` or
|
||||
* `RCT_SPM_AUTOLINKING_CONFIG_COMMAND`, in that order, before the default.
|
||||
*
|
||||
* No filtering or reshaping happens here — the downstream consumer
|
||||
* (generate-spm-autolinking.js) does its own iOS-only filtering when reading
|
||||
@@ -60,6 +62,32 @@ const FALLBACK_CONFIG_COMMAND = [
|
||||
'config',
|
||||
];
|
||||
|
||||
function parseConfigCommandJson(
|
||||
raw /*: string */,
|
||||
source /*: string */,
|
||||
) /*: Array<string> */ {
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(raw);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`${source}: config command must be a JSON array of strings. Example: '["npx","@react-native-community/cli","config"]'`,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!Array.isArray(parsed) ||
|
||||
parsed.length === 0 ||
|
||||
!parsed.every(value => typeof value === 'string' && value.length > 0)
|
||||
) {
|
||||
throw new Error(
|
||||
`${source}: config command must be a non-empty JSON array of non-empty strings`,
|
||||
);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function resolveDefaultConfigCommand(
|
||||
projectRoot /*: string */,
|
||||
) /*: Array<string> */ {
|
||||
@@ -94,6 +122,19 @@ function resolveDefaultConfigCommand(
|
||||
return FALLBACK_CONFIG_COMMAND;
|
||||
}
|
||||
|
||||
// Env-var / default resolution for the autolinking config command. An explicit
|
||||
// `configCommand` (e.g. from `--config-command`) is handled upstream by
|
||||
// generateAutolinkingConfig's destructuring default, so it never reaches here —
|
||||
// this only decides between the env-var override and the built-in default.
|
||||
function resolveConfigCommand(projectRoot /*: string */) /*: Array<string> */ {
|
||||
const raw = process.env.RCT_SPM_AUTOLINKING_CONFIG_COMMAND;
|
||||
if (typeof raw === 'string' && raw.trim().length > 0) {
|
||||
return parseConfigCommandJson(raw, 'RCT_SPM_AUTOLINKING_CONFIG_COMMAND');
|
||||
}
|
||||
|
||||
return resolveDefaultConfigCommand(projectRoot);
|
||||
}
|
||||
|
||||
function defaultCliRunner(
|
||||
command /*: Array<string> */,
|
||||
opts /*: {cwd: string} */,
|
||||
@@ -116,7 +157,7 @@ function generateAutolinkingConfig(
|
||||
) /*: GenerateAutolinkingConfigResult */ {
|
||||
const {
|
||||
projectRoot,
|
||||
configCommand = resolveDefaultConfigCommand(projectRoot),
|
||||
configCommand = resolveConfigCommand(projectRoot),
|
||||
cliRunner = defaultCliRunner,
|
||||
} = opts;
|
||||
|
||||
@@ -158,4 +199,9 @@ function generateAutolinkingConfig(
|
||||
return {config, outputPath: outPath, rawJson};
|
||||
}
|
||||
|
||||
module.exports = {generateAutolinkingConfig, resolveDefaultConfigCommand};
|
||||
module.exports = {
|
||||
generateAutolinkingConfig,
|
||||
parseConfigCommandJson,
|
||||
resolveConfigCommand,
|
||||
resolveDefaultConfigCommand,
|
||||
};
|
||||
|
||||
@@ -16,6 +16,9 @@ export type SetupArgs = {
|
||||
// `debug/` and `release/` cache slots, each with artifacts.json.
|
||||
artifacts: string | null,
|
||||
skipCodegen: boolean,
|
||||
// Overrides the autolinking config command; also settable via
|
||||
// RCT_SPM_AUTOLINKING_CONFIG_COMMAND.
|
||||
configCommand: Array<string> | null,
|
||||
// Artifact download policy: 'auto' fetches when missing, 'skip' never
|
||||
// fetches, 'force' clears the cache slot and re-downloads.
|
||||
downloadPolicy: 'auto' | 'skip' | 'force',
|
||||
|
||||
Reference in New Issue
Block a user