Skip to content

Commit

Permalink
feat(react-native): update react-native generators
Browse files Browse the repository at this point in the history
  • Loading branch information
leosvelperez committed Nov 28, 2024
1 parent 4451e8c commit 710990a
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 74 deletions.
12 changes: 8 additions & 4 deletions docs/generated/packages/react-native/generators/component.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@
"examples": [
{
"description": "Generate a component with the exported symbol matching the file name. It results in the component `Foo` at `mylib/src/lib/foo.tsx`",
"command": "nx g @nx/react-native:component mylib/src/lib/foo"
"command": "nx g @nx/react-native:component mylib/src/lib/foo.tsx"
},
{
"description": "Generate a component with the exported symbol different from the file name. It results in the component `Custom` at `mylib/src/lib/foo.tsx`",
"command": "nx g @nx/react-native:component mylib/src/lib/foo --name=custom"
"command": "nx g @nx/react-native:component mylib/src/lib/foo.tsx --name=custom"
},
{
"description": "Generate a component without providing the file extension. It results in the component `Foo` at `mylib/src/lib/foo.tsx`",
"command": "nx g @nx/react-native:component mylib/src/lib/foo"
},
{
"description": "Generate a class component at `mylib/src/lib/foo.tsx`",
Expand All @@ -25,7 +29,7 @@
"properties": {
"path": {
"type": "string",
"description": "The file path to the component without the file extension. Relative to the current working directory.",
"description": "The file path to the component. Relative to the current working directory.",
"$default": { "$source": "argv", "index": 0 },
"x-prompt": "What is the component file path?"
},
Expand All @@ -36,7 +40,7 @@
"js": {
"type": "boolean",
"description": "Generate JavaScript files rather than TypeScript files.",
"default": false
"x-deprecated": "Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21."
},
"skipTests": {
"type": "boolean",
Expand Down
78 changes: 39 additions & 39 deletions packages/react-native/src/generators/component/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
generateFiles,
getProjects,
joinPathFragments,
toJS,
Tree,
} from '@nx/devkit';
import { NormalizedSchema, normalizeOptions } from './lib/normalize-options';
Expand All @@ -26,25 +25,23 @@ export async function reactNativeComponentGenerator(
}

function createComponentFiles(host: Tree, options: NormalizedSchema) {
generateFiles(host, join(__dirname, './files'), options.directory, {
...options,
tmpl: '',
});

for (const c of host.listChanges()) {
let deleteFile = false;

if (options.skipTests && /.*spec.tsx/.test(c.path)) {
deleteFile = true;
generateFiles(
host,
join(__dirname, 'files', options.fileExtensionType),
options.directory,
{
...options,
ext: options.fileExtension,
}
);

if (deleteFile) {
host.delete(c.path);
}
}

if (options.js) {
toJS(host);
if (options.skipTests) {
host.delete(
join(
options.directory,
`${options.fileName}.spec.${options.fileExtension}`
)
);
}
}

Expand All @@ -59,29 +56,32 @@ function addExportsToBarrel(host: Tree, options: NormalizedSchema) {
workspace.get(options.projectName).projectType === 'application';

if (options.export && !isApp) {
const indexFilePath = joinPathFragments(
options.projectSourceRoot,
options.js ? 'index.js' : 'index.ts'
);
const indexSource = host.read(indexFilePath, 'utf-8');
if (indexSource !== null) {
const indexSourceFile = tsModule.createSourceFile(
indexFilePath,
indexSource,
tsModule.ScriptTarget.Latest,
true
);
const indexFilePath = [
joinPathFragments(options.projectSourceRoot, `index.ts`),
joinPathFragments(options.projectSourceRoot, `index.js`),
].find((path) => host.exists(path));

const relativePathFromIndex = getRelativeImportToFile(
indexFilePath,
options.filePath
);
const changes = applyChangesToString(
indexSource,
addImport(indexSourceFile, `export * from '${relativePathFromIndex}';`)
);
host.write(indexFilePath, changes);
if (!indexFilePath) {
return;
}

const indexSource = host.read(indexFilePath, 'utf-8');
const indexSourceFile = tsModule.createSourceFile(
indexFilePath,
indexSource,
tsModule.ScriptTarget.Latest,
true
);

const relativePathFromIndex = getRelativeImportToFile(
indexFilePath,
options.filePath
);
const changes = applyChangesToString(
indexSource,
addImport(indexSourceFile, `export * from '${relativePathFromIndex}';`)
);
host.write(indexFilePath, changes);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<%_ if (classComponent) { _%>
import { Component } from 'react';
<%_ } else { _%>
import React from 'react';
<%_ } _%>
import { View, Text } from 'react-native';

<%_ if (classComponent) { _%>
export class <%= className %> extends Component {
render() {
return (
<View>
<Text>Welcome to <%= name %>!</Text>
</View>
);
}
}
<%_ } else { _%>
export function <%= className %>(props) {
return (
<View>
<Text>Welcome to <%= name %>!</Text>
</View>
);
}
<%_ } _%>

export default <%= className %>;
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<% if (classComponent) { %>
<%_ if (classComponent) { _%>
import { Component } from 'react';
<% } else { %>
<%_ } else { _%>
import React from 'react';
<% } %>
<%_ } _%>
import { View, Text } from 'react-native';

/* eslint-disable-next-line */
export interface <%= className %>Props {
}

<% if (classComponent) { %>
<%_ if (classComponent) { _%>
export class <%= className %> extends Component<<%= className %>Props> {
render() {
return (
Expand All @@ -19,14 +19,14 @@ export class <%= className %> extends Component<<%= className %>Props> {
);
}
}
<% } else { %>
<%_ } else { _%>
export function <%= className %>(props: <%= className %>Props) {
return (
<View>
<Text>Welcome to <%= name %>!</Text>
</View>
);
}
<% } %>
<%_ } _%>

export default <%= className %>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { render } from '@testing-library/react-native';

import <%= className %> from './<%= fileName %>';

describe('<%= className %>', () => {
it('should render successfully', () => {
const { root } = render(< <%= className %> />);
expect(root).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { getProjects, logger, names, Tree } from '@nx/devkit';
import {
determineArtifactNameAndDirectoryOptions,
type FileExtensionType,
} from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
import { Schema } from '../schema';
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';

export interface NormalizedSchema extends Schema {
export interface NormalizedSchema extends Omit<Schema, 'js'> {
directory: string;
projectSourceRoot: string;
fileName: string;
className: string;
filePath: string;
fileExtension: string;
fileExtensionType: FileExtensionType;
projectName: string;
}

Expand All @@ -20,15 +25,17 @@ export async function normalizeOptions(
directory,
fileName,
filePath,
fileExtension,
fileExtensionType,
project: projectName,
} = await determineArtifactNameAndDirectoryOptions(host, {
path: options.path,
name: options.name,
fileExtension: 'tsx',
allowedFileExtensions: ['js', 'jsx', 'ts', 'tsx'],
fileExtension: options.js ? 'js' : 'tsx',
js: options.js,
});

assertValidOptions({ name, directory });

const project = getProjects(host).get(projectName);

const { className } = names(name);
Expand All @@ -50,23 +57,9 @@ export async function normalizeOptions(
className,
fileName,
filePath,
fileExtension,
fileExtensionType,
projectSourceRoot,
projectName,
};
}

function assertValidOptions(options: { name: string; directory: string }) {
const slashes = ['/', '\\'];
slashes.forEach((s) => {
if (options.name.indexOf(s) !== -1) {
const [name, ...rest] = options.name.split(s).reverse();
let suggestion = rest.map((x) => x.toLowerCase()).join(s);
if (options.directory) {
suggestion = `${options.directory}${s}${suggestion}`;
}
throw new Error(
`Found "${s}" in the component name. Did you mean to use the --path option (e.g. \`nx g c ${suggestion}/${name} \`)?`
);
}
});
}
4 changes: 4 additions & 0 deletions packages/react-native/src/generators/component/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@ export interface Schema {
skipTests?: boolean;
export?: boolean;
classComponent?: boolean;

/**
* @deprecated Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21.
*/
js?: boolean;
}
12 changes: 8 additions & 4 deletions packages/react-native/src/generators/component/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@
"examples": [
{
"description": "Generate a component with the exported symbol matching the file name. It results in the component `Foo` at `mylib/src/lib/foo.tsx`",
"command": "nx g @nx/react-native:component mylib/src/lib/foo"
"command": "nx g @nx/react-native:component mylib/src/lib/foo.tsx"
},
{
"description": "Generate a component with the exported symbol different from the file name. It results in the component `Custom` at `mylib/src/lib/foo.tsx`",
"command": "nx g @nx/react-native:component mylib/src/lib/foo --name=custom"
"command": "nx g @nx/react-native:component mylib/src/lib/foo.tsx --name=custom"
},
{
"description": "Generate a component without providing the file extension. It results in the component `Foo` at `mylib/src/lib/foo.tsx`",
"command": "nx g @nx/react-native:component mylib/src/lib/foo"
},
{
"description": "Generate a class component at `mylib/src/lib/foo.tsx`",
Expand All @@ -22,7 +26,7 @@
"properties": {
"path": {
"type": "string",
"description": "The file path to the component without the file extension. Relative to the current working directory.",
"description": "The file path to the component. Relative to the current working directory.",
"$default": {
"$source": "argv",
"index": 0
Expand All @@ -36,7 +40,7 @@
"js": {
"type": "boolean",
"description": "Generate JavaScript files rather than TypeScript files.",
"default": false
"x-deprecated": "Provide the full file path including the file extension in the `path` option. This option will be removed in Nx v21."
},
"skipTests": {
"type": "boolean",
Expand Down

0 comments on commit 710990a

Please sign in to comment.