Skip to content

Commit

Permalink
Update with master
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Bento committed May 9, 2019
2 parents db8e0bb + c3ed10c commit e2a1490
Show file tree
Hide file tree
Showing 13 changed files with 130 additions and 116 deletions.
7 changes: 4 additions & 3 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// added for Jest inline snapshots to not use default Prettier config
module.exports = {
singleQuote: true,
trailingComma: 'all',
bracketSpacing: false,
trailingComma: "all"
}
jsxBracketSameLine: true,
};
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ You can also add npm scripts to call it with whichever package manager you use:
}
```

## Maintainers

- Michał Pierzchała ([**@thymikee**](https://github.com/thymikee)) - [Callstack](https://callstack.com)
- Mike Grabowski ([**@grabbou**](https://github.com/grabbou)) - [Callstack](https://callstack.com)
- Kacper Wiszczuk ([**@esemesek**](https://github.com/esemesek)) - [Callstack](https://callstack.com)

## License

Everything inside this repository is [MIT licensed](./LICENSE).
Expand Down
45 changes: 25 additions & 20 deletions packages/cli/src/commands/init/__tests__/templateName.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ import {fetch} from '../../../tools/fetch';

jest.mock('../../../tools/fetch', () => ({fetch: jest.fn()}));

const VERSION = '0.58.0';
const RN_WITH_VERSION = '[email protected]';
const RN_NPM_PACKAGE = 'react-native';
const ABS_RN_PATH = '/path/to/react-native';
const ABS_RN_TARBALL_PATH = '/path/to/react-native/react-native-1.2.3-rc.0.tgz';
const PACKAGE_NAME = 'react-native';

test('should support file protocol with absolute path', async () => {
test('supports file protocol with absolute path', async () => {
jest.mock(
`${ABS_RN_PATH}/package.json`,
() => ({
Expand All @@ -20,18 +17,11 @@ test('should support file protocol with absolute path', async () => {
);
expect(await processTemplateName(`file://${ABS_RN_PATH}`)).toEqual({
uri: ABS_RN_PATH,
name: PACKAGE_NAME,
name: RN_NPM_PACKAGE,
});
});

test('should get default package if none protocols were handled', async () => {
expect(await processTemplateName(VERSION)).toEqual({
uri: VERSION,
name: VERSION,
});
});

test('should support shorthand templates', async () => {
test('supports shorthand templates', async () => {
const templateName = 'typescript';
(fetch: any).mockImplementationOnce(() => {
return Promise.resolve(`{"name": "react-native-template-${templateName}"}`);
Expand All @@ -42,7 +32,7 @@ test('should support shorthand templates', async () => {
});
});

test('should support not-found shorthand templates', async () => {
test('supports not-found shorthand templates', async () => {
const templateName = 'typescriptz';
(fetch: any).mockImplementationOnce(() => {
return Promise.resolve('Not found');
Expand All @@ -53,14 +43,29 @@ test('should support not-found shorthand templates', async () => {
});
});

test('should get package if none protocols were handled', async () => {
expect(await processTemplateName(RN_WITH_VERSION)).toEqual({
uri: RN_WITH_VERSION,
name: RN_WITH_VERSION,
test('supports npm packages as template names', async () => {
expect(await processTemplateName(RN_NPM_PACKAGE)).toEqual({
uri: RN_NPM_PACKAGE,
name: RN_NPM_PACKAGE,
});
});

test('should support path to tgz archives', async () => {
test.each`
templateName | uri | name
${'[email protected]'} | ${'[email protected]'} | ${'react-native'}
${'some-name@latest'} | ${'some-name@latest'} | ${'some-name'}
${'@scoped/[email protected]'} | ${'@scoped/[email protected]'} | ${'@scoped/name'}
${'@scoped/name@tag'} | ${'@scoped/name@tag'} | ${'@scoped/name'}
`(
'supports versioned npm package "$templateName" as template name',
async ({templateName, uri, name}) => {
expect(await processTemplateName(templateName)).toEqual({uri, name});
},
);

test('supports path to tgz archives', async () => {
const ABS_RN_TARBALL_PATH =
'/path/to/react-native/react-native-1.2.3-rc.0.tgz';
expect(await processTemplateName(`file://${ABS_RN_TARBALL_PATH}`)).toEqual({
uri: `file://${ABS_RN_TARBALL_PATH}`,
name: 'react-native',
Expand Down
110 changes: 33 additions & 77 deletions packages/cli/src/commands/init/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,39 @@ function adjustNameIfUrl(name, cwd) {
return name;
}

async function createFromExternalTemplate(
async function createFromTemplate({
projectName,
templateName,
version,
npm,
}: {
projectName: string,
templateName: string,
version?: string,
npm?: boolean,
) {
logger.debug('Initializing new project from external template');
}) {
logger.debug('Initializing new project');
logger.log(banner);

const Loader = getLoader();

const loader = new Loader({text: 'Downloading template'});
loader.start();

const templateSourceDir = fs.mkdtempSync(
path.join(os.tmpdir(), 'rncli-init-template-'),
);

if (version && semver.valid(version) && !semver.gte(version, '0.60.0-rc.0')) {
throw new Error(
'Cannot use React Native CLI to initialize project with version lower than 0.60.0.',
);
}

try {
let {uri, name} = await processTemplateName(templateName);
loader.start();
let {uri, name} = await processTemplateName(
version ? `${templateName}@${version}` : templateName,
);

await installTemplatePackage(uri, templateSourceDir, npm);

loader.succeed();
loader.start('Copying template');

Expand All @@ -71,7 +85,7 @@ async function createFromExternalTemplate(
await copyTemplate(name, templateConfig.templateDir, templateSourceDir);

loader.succeed();
loader.start('Preparing template');
loader.start('Processing template');

changePlaceholderInTemplate(projectName, templateConfig.placeholderName);

Expand Down Expand Up @@ -174,82 +188,24 @@ async function installDependencies({
loader.succeed();
}

async function createFromReactNativeTemplate(
projectName: string,
version: string,
npm?: boolean,
) {
logger.debug('Initializing new project');
logger.log(banner);

const Loader = getLoader();
const loader = new Loader({text: 'Downloading template'});
loader.start();
const templateSourceDir = fs.mkdtempSync(
path.join(os.tmpdir(), 'rncli-init-template-'),
);
try {
if (semver.valid(version) && !semver.gte(version, '0.60.0')) {
throw new Error(
'Cannot use React Native CLI to initialize project with version lower than 0.60.0',
);
}

const TEMPLATE_NAME = 'react-native';

const {uri} = await processTemplateName(`${TEMPLATE_NAME}@${version}`);

await installTemplatePackage(uri, templateSourceDir, npm);

loader.succeed();
loader.start('Copying template');

const templateConfig = getTemplateConfig(TEMPLATE_NAME, templateSourceDir);
await copyTemplate(
TEMPLATE_NAME,
templateConfig.templateDir,
templateSourceDir,
);

loader.succeed();
loader.start('Processing template');

changePlaceholderInTemplate(projectName, templateConfig.placeholderName);

loader.succeed();
const {postInitScript} = templateConfig;
if (postInitScript) {
loader.start('Executing post init script');
await executePostInitScript(
TEMPLATE_NAME,
postInitScript,
templateSourceDir,
);
loader.succeed();
}

await installDependencies({npm, loader});
} catch (e) {
loader.fail();
throw new Error(e);
} finally {
fs.removeSync(templateSourceDir);
}
}

function createProject(projectName: string, options: Options, version: string) {
fs.mkdirSync(projectName);
process.chdir(projectName);

if (options.template) {
return createFromExternalTemplate(
return createFromTemplate({
projectName,
options.template,
options.npm,
);
templateName: options.template,
npm: options.npm,
});
}

return createFromReactNativeTemplate(projectName, version, options.npm);
return createFromTemplate({
projectName,
templateName: 'react-native',
version,
npm: options.npm,
});
}

export default (async function initialize(
Expand Down
17 changes: 17 additions & 0 deletions packages/cli/src/commands/init/templateName.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const FILE_PROTOCOL = /file:/;
const HTTP_PROTOCOL = /https?:/;
const TARBALL = /\.tgz$/;
const VERSION_POSTFIX = /(.*)(-\d+\.\d+\.\d+)/;
const VERSIONED_PACKAGE = /(@?.*)(@)(.*)/;

function handleFileProtocol(filePath: string) {
const uri = new URL(filePath).pathname;
Expand All @@ -32,13 +33,29 @@ function handleTarball(filePath: string) {
};
}

function handleVersionedPackage(versionedPackage: string) {
const versionedPackageMatch = versionedPackage.match(VERSIONED_PACKAGE);
if (!versionedPackageMatch) {
throw new Error(
`Failed to retrieve package name. We expect the package to include name and version, e.g.: "[email protected]", but received: "${versionedPackage}".`,
);
}
return {
uri: versionedPackage,
name: versionedPackageMatch[1],
};
}

export async function processTemplateName(templateName: string) {
if (templateName.match(TARBALL)) {
return handleTarball(templateName);
}
if (templateName.match(FILE_PROTOCOL)) {
return handleFileProtocol(templateName);
}
if (templateName.match(VERSIONED_PACKAGE)) {
return handleVersionedPackage(templateName);
}

const name = await tryTemplateShorthand(templateName);

Expand Down
12 changes: 12 additions & 0 deletions packages/cli/src/tools/config/__mocks__/resolveNodeModuleDir.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @flow
*/

const path = require('path');

export default function resolveNodeModuleDir(
root: string,
packageName: string,
): string {
return path.join(root, 'node_modules', packageName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
getTempDirectory,
} from '../../../../../../jest/helpers';

jest.mock('../resolveNodeModuleDir');

beforeEach(() => {
cleanup(DIR);
jest.resetModules();
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/tools/config/__tests__/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {

import {logger} from '@react-native-community/cli-tools';

jest.mock('../resolveNodeModuleDir');

const DIR = getTempDirectory('resolve_config_path_test');

// Removes string from all key/values within an object
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/src/tools/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {type ConfigT} from 'types';

import assign from '../assign';
import merge from '../merge';
import resolveNodeModuleDir from './resolveNodeModuleDir';
/**
* Built-in platforms
*/
Expand All @@ -34,10 +35,10 @@ function loadConfig(projectRoot: string = process.cwd()): ConfigT {

const finalConfig = findDependencies(projectRoot).reduce(
(acc: ConfigT, dependencyName) => {
const root = path.join(projectRoot, 'node_modules', dependencyName);

let root;
let config;
try {
root = resolveNodeModuleDir(projectRoot, dependencyName);
config =
readLegacyDependencyConfigFromDisk(root) ||
readDependencyConfigFromDisk(root);
Expand Down
19 changes: 19 additions & 0 deletions packages/cli/src/tools/config/resolveNodeModuleDir.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* @flow
*/
import path from 'path';

/**
* Finds a path inside `node_modules`
*/
export default function resolveNodeModuleDir(
root: string,
packageName: string,
): string {
return path.dirname(
// $FlowIssue: Wrong `require.resolve` type definition
require.resolve(path.join(packageName, 'package.json'), {
paths: [root],
}),
);
}
10 changes: 3 additions & 7 deletions packages/cli/src/tools/config/resolveReactNativePath.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
/**
* @flow
*/
import path from 'path';
import {CLIError} from '@react-native-community/cli-tools';

import resolveNodeModuleDir from './resolveNodeModuleDir';

/**
* Finds path to React Native inside `node_modules` or throws
* an error otherwise.
*/
export default function resolveReactNativePath(root: string) {
try {
return path.dirname(
// $FlowIssue: Wrong `require.resolve` type definition
require.resolve('react-native/package.json', {
paths: [root],
}),
);
return resolveNodeModuleDir(root, 'react-native');
} catch (_ignored) {
throw new CLIError(`
Unable to find React Native files. Make sure "react-native" module is installed
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/src/tools/loadMetroConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ export type ConfigOptionsT = {|
*/
export default function load(ctx: ConfigT, options?: ConfigOptionsT) {
const defaultConfig = getDefaultConfig(ctx);

return loadConfig({cwd: ctx.root, ...options}, defaultConfig);
return loadConfig(
{cwd: ctx.root, ...options},
{...defaultConfig, reporter: options && options.reporter},
);
}
Loading

0 comments on commit e2a1490

Please sign in to comment.