Skip to content

Commit a418958

Browse files
committed
refactor: extract dependencies and metadata
1 parent 9c88bae commit a418958

File tree

3 files changed

+97
-152
lines changed

3 files changed

+97
-152
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import assert from 'node:assert';
2+
import path from 'path';
3+
import fs from 'fs-extra';
4+
import type { ExampleApp } from '../input';
5+
6+
export async function getDependencyVersionsFromExample(
7+
folder: string,
8+
exampleAppType: ExampleApp
9+
) {
10+
// Set `react` and `react-native` versions of root `package.json` from example `package.json`
11+
const examplePackageJson = await fs.readJSON(
12+
path.join(folder, 'example', 'package.json')
13+
);
14+
15+
const react: string = examplePackageJson.dependencies?.react;
16+
assert(
17+
react !== undefined,
18+
"The generated example app doesn't have React installed."
19+
);
20+
const reactNative: string = examplePackageJson.dependencies?.['react-native'];
21+
assert(
22+
reactNative !== undefined,
23+
"The generated example app doesn't have React Native installed."
24+
);
25+
26+
const devDependencies: Record<string, string> = {
27+
react,
28+
'react-native': reactNative,
29+
};
30+
31+
if (exampleAppType === 'vanilla') {
32+
// React Native doesn't provide the community CLI as a dependency.
33+
// We have to get read the version from the example app and put to the root package json
34+
const exampleCommunityCLIVersion =
35+
examplePackageJson.devDependencies['@react-native-community/cli'];
36+
assert(
37+
exampleCommunityCLIVersion !== undefined,
38+
"The generated example app doesn't have community CLI installed"
39+
);
40+
41+
devDependencies['@react-native-community/cli'] = exampleCommunityCLIVersion;
42+
}
43+
44+
return {
45+
devDependencies,
46+
};
47+
}

packages/create-react-native-library/src/index.ts

Lines changed: 17 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
import path from 'path';
22
import fs from 'fs-extra';
3-
import dedent from 'dedent';
43
import kleur from 'kleur';
54
import yargs from 'yargs';
65
import ora from 'ora';
7-
import assert from 'node:assert';
86
import prompts from './utils/prompts';
97
import generateExampleApp from './exampleApp/generateExampleApp';
10-
import { version } from '../package.json';
118
import { addCodegenBuildScript } from './exampleApp/addCodegenBuildScript';
129
import { createInitialGitCommit } from './utils/initialCommit';
1310
import { assertAnswers, assertNpx } from './utils/assert';
1411
import { resolveBobVersionWithFallback } from './utils/promiseWithFallback';
1512
import { generateTemplateConfiguration } from './config';
1613
import { applyTemplates } from './template';
1714
import { createQuestions, type Answers, acceptedArgs } from './input';
15+
import { createMetadata } from './metadata';
16+
import { getDependencyVersionsFromExample } from './exampleApp/dependencies';
17+
import { printNextSteps } from './nextSteps';
1818

1919
const FALLBACK_BOB_VERSION = '0.32.0';
2020

@@ -160,68 +160,25 @@ async function create(_argv: yargs.Arguments<any>) {
160160
const rootPackageJson = await fs.readJson(path.join(folder, 'package.json'));
161161

162162
if (config.example !== 'none') {
163-
// Set `react` and `react-native` versions of root `package.json` from example `package.json`
164-
const examplePackageJson = await fs.readJSON(
165-
path.join(folder, 'example', 'package.json')
163+
const { devDependencies } = await getDependencyVersionsFromExample(
164+
folder,
165+
config.example
166166
);
167167

168-
if (
169-
examplePackageJson.dependencies?.react &&
170-
examplePackageJson.dependencies?.['react-native']
171-
) {
172-
rootPackageJson.devDependencies = rootPackageJson.devDependencies || {};
173-
rootPackageJson.devDependencies.react =
174-
examplePackageJson.dependencies.react;
175-
rootPackageJson.devDependencies['react-native'] =
176-
examplePackageJson.dependencies['react-native'];
177-
}
178-
179-
if (config.example === 'vanilla') {
180-
// React Native doesn't provide the community CLI as a dependency.
181-
// We have to get read the version from the example app and put to the root package json
182-
const exampleCommunityCLIVersion =
183-
examplePackageJson.devDependencies['@react-native-community/cli'];
184-
assert(
185-
exampleCommunityCLIVersion !== undefined,
186-
"The generated example app doesn't have community CLI installed"
187-
);
188-
189-
rootPackageJson.devDependencies = rootPackageJson.devDependencies || {};
190-
rootPackageJson.devDependencies['@react-native-community/cli'] =
191-
exampleCommunityCLIVersion;
168+
rootPackageJson.devDependencies = rootPackageJson.devDependencies
169+
? {
170+
...rootPackageJson.devDependencies,
171+
...devDependencies,
172+
}
173+
: devDependencies;
174+
}
192175

193-
if (config.project.arch !== 'legacy') {
194-
addCodegenBuildScript(folder);
195-
}
196-
}
176+
if (config.example === 'vanilla' && config.project.arch !== 'legacy') {
177+
addCodegenBuildScript(folder);
197178
}
198179

199-
// Some of the passed args can already be derived from the generated package.json file.
200-
const ignoredAnswers: (keyof Answers)[] = [
201-
'name',
202-
'slug',
203-
'description',
204-
'authorName',
205-
'authorEmail',
206-
'authorUrl',
207-
'repoUrl',
208-
'example',
209-
'reactNativeVersion',
210-
'local',
211-
];
212-
213-
type AnswerEntries<T extends keyof Answers = keyof Answers> = [
214-
T,
215-
Answers[T],
216-
][];
217-
218-
const libraryMetadata = Object.fromEntries(
219-
(Object.entries(answers) as AnswerEntries).filter(
220-
([answer]) => !ignoredAnswers.includes(answer)
221-
)
222-
);
180+
const libraryMetadata = createMetadata(answers);
223181

224-
libraryMetadata.version = version;
225182
rootPackageJson['create-react-native-library'] = libraryMetadata;
226183

227184
await fs.writeJson(path.join(folder, 'package.json'), rootPackageJson, {
@@ -238,99 +195,7 @@ async function create(_argv: yargs.Arguments<any>) {
238195
)}!\n`
239196
);
240197

241-
if (local) {
242-
let linked;
243-
244-
const packageManager = (await fs.pathExists(
245-
path.join(process.cwd(), 'yarn.lock')
246-
))
247-
? 'yarn'
248-
: 'npm';
249-
250-
const packageJsonPath = path.join(process.cwd(), 'package.json');
251-
252-
if (await fs.pathExists(packageJsonPath)) {
253-
const packageJson = await fs.readJSON(packageJsonPath);
254-
const isReactNativeProject = Boolean(
255-
packageJson.dependencies?.['react-native']
256-
);
257-
258-
if (isReactNativeProject) {
259-
packageJson.dependencies = packageJson.dependencies || {};
260-
packageJson.dependencies[config.project.slug] =
261-
packageManager === 'yarn'
262-
? `link:./${path.relative(process.cwd(), folder)}`
263-
: `file:./${path.relative(process.cwd(), folder)}`;
264-
265-
await fs.writeJSON(packageJsonPath, packageJson, {
266-
spaces: 2,
267-
});
268-
269-
linked = true;
270-
}
271-
}
272-
273-
console.log(
274-
dedent(`
275-
${kleur.magenta(
276-
`${kleur.bold('Get started')} with the project`
277-
)}${kleur.gray(':')}
278-
279-
${
280-
(linked
281-
? `- Run ${kleur.blue(
282-
`${packageManager} install`
283-
)} to link the library\n`
284-
: `- Link the library at ${kleur.blue(
285-
path.relative(process.cwd(), folder)
286-
)} based on your project setup'\n`) +
287-
`- Run ${kleur.blue(
288-
'pod install --project-directory=ios'
289-
)} to install dependencies with CocoaPods\n` +
290-
`- Run ${kleur.blue('npx react-native run-android')} or ${kleur.blue(
291-
'npx react-native run-ios'
292-
)} to build and run the app\n` +
293-
`- Import from ${kleur.blue(
294-
config.project.slug
295-
)} and use it in your app.`
296-
}
297-
298-
${kleur.yellow(`Good luck!`)}
299-
`)
300-
);
301-
} else {
302-
const platforms = {
303-
ios: { name: 'iOS', color: 'cyan' },
304-
android: { name: 'Android', color: 'green' },
305-
...(config.example === 'expo'
306-
? ({ web: { name: 'Web', color: 'blue' } } as const)
307-
: null),
308-
} as const;
309-
310-
console.log(
311-
dedent(`
312-
${kleur.magenta(
313-
`${kleur.bold('Get started')} with the project`
314-
)}${kleur.gray(':')}
315-
316-
${kleur.gray('$')} yarn
317-
${Object.entries(platforms)
318-
.map(
319-
([script, { name, color }]) => `
320-
${kleur[color](`Run the example app on ${kleur.bold(name)}`)}${kleur.gray(
321-
':'
322-
)}
323-
324-
${kleur.gray('$')} yarn example ${script}`
325-
)
326-
.join('\n')}
327-
328-
${kleur.yellow(
329-
`See ${kleur.bold('CONTRIBUTING.md')} for more details. Good luck!`
330-
)}
331-
`)
332-
);
333-
}
198+
await printNextSteps(local, folder, config);
334199
}
335200

336201
yargs
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { version } from '../package.json';
2+
import type { Answers } from './input';
3+
4+
export function createMetadata(answers: Answers) {
5+
// Some of the passed args can already be derived from the generated package.json file.
6+
const ignoredAnswers: (keyof Answers)[] = [
7+
'name',
8+
'slug',
9+
'description',
10+
'authorName',
11+
'authorEmail',
12+
'authorUrl',
13+
'repoUrl',
14+
'example',
15+
'reactNativeVersion',
16+
'local',
17+
];
18+
19+
type AnswerEntries<T extends keyof Answers = keyof Answers> = [
20+
T,
21+
Answers[T],
22+
][];
23+
24+
const libraryMetadata = Object.fromEntries(
25+
(Object.entries(answers) as AnswerEntries).filter(
26+
([answer]) => !ignoredAnswers.includes(answer)
27+
)
28+
);
29+
30+
libraryMetadata.version = version;
31+
32+
return libraryMetadata;
33+
}

0 commit comments

Comments
 (0)