fix(misc): fix misc issues in project generators for the ts solution setup (#30111)
The following are the main changes in the context of the TS solution setup: - Ensure `name` in `package.json` files is set to the import path for all projects - Set `nx.name` in `package.json` files when the user provides a name different than the package name (import path) - Clean up project generators so they don't set the `nx` property in `package.json` files unless strictly needed - Fix `@nx/vue:application` generator so it creates the Nx config in a `package.json` file for e2e projects - Ensure `@types/node` is installed in `vitest` generator - Fix generated Vite config typing error (surfaced with Vite 6) - Ensure `jsonc-eslint-parser` is installed when the `@nx/dependency-checks` rule is added to the ESLint config - Misc minor alignment changes ## Current Behavior ## Expected Behavior ## Related Issue(s) Fixes #
This commit is contained in:
parent
121d9973a8
commit
ada8be473d
@ -169,7 +169,6 @@ describe('EsBuild Plugin', () => {
|
||||
expect(
|
||||
readJson(`dist/libs/${parentLib}/package.json`).dependencies
|
||||
).toEqual({
|
||||
'jsonc-eslint-parser': expect.any(String),
|
||||
// Don't care about the versions, just that they exist
|
||||
rambda: expect.any(String),
|
||||
lodash: expect.any(String),
|
||||
|
||||
@ -3,6 +3,7 @@ import {
|
||||
getPackageManagerCommand,
|
||||
getSelectedPackageManager,
|
||||
newProject,
|
||||
readJson,
|
||||
runCLI,
|
||||
runCommand,
|
||||
uniq,
|
||||
@ -177,4 +178,28 @@ ${content}`
|
||||
`Successfully ran target test for project @proj/${viteParentLib}`
|
||||
);
|
||||
}, 300_000);
|
||||
|
||||
it('should respect and support generating libraries with a name different than the import path', () => {
|
||||
const lib1 = uniq('lib1');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/js:lib packages/${lib1} --name=${lib1} --bundler=vite --linter=eslint --unitTestRunner=jest`
|
||||
);
|
||||
|
||||
const packageJson = readJson(`packages/${lib1}/package.json`);
|
||||
expect(packageJson.nx.name).toBe(lib1);
|
||||
|
||||
expect(runCLI(`build ${lib1}`)).toContain(
|
||||
`Successfully ran target build for project ${lib1}`
|
||||
);
|
||||
expect(runCLI(`typecheck ${lib1}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${lib1}`
|
||||
);
|
||||
expect(runCLI(`lint ${lib1}`)).toContain(
|
||||
`Successfully ran target lint for project ${lib1}`
|
||||
);
|
||||
expect(runCLI(`test ${lib1}`)).toContain(
|
||||
`Successfully ran target test for project ${lib1}`
|
||||
);
|
||||
}, 300_000);
|
||||
});
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
killPorts,
|
||||
newProject,
|
||||
promisifiedTreeKill,
|
||||
readJson,
|
||||
runCLI,
|
||||
runCommand,
|
||||
runCommandUntil,
|
||||
@ -169,6 +170,30 @@ describe('Node Applications', () => {
|
||||
expect(err).toBeFalsy();
|
||||
}
|
||||
}, 300_000);
|
||||
|
||||
it('should respect and support generating libraries with a name different than the import path', () => {
|
||||
const nodeLib = uniq('node-lib');
|
||||
const nestLib = uniq('nest-lib');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/node:lib packages/${nodeLib} --name=${nodeLib} --buildable`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/nest:lib packages/${nestLib} --name=${nestLib} --buildable`
|
||||
);
|
||||
|
||||
const packageJson = readJson(`packages/${nodeLib}/package.json`);
|
||||
expect(packageJson.nx.name).toBe(nodeLib);
|
||||
const nestPackageJson = readJson(`packages/${nestLib}/package.json`);
|
||||
expect(nestPackageJson.nx.name).toBe(nestLib);
|
||||
|
||||
expect(runCLI(`build ${nodeLib}`)).toContain(
|
||||
`Successfully ran target build for project ${nodeLib}`
|
||||
);
|
||||
expect(runCLI(`build ${nestLib}`)).toContain(
|
||||
`Successfully ran target build for project ${nestLib}`
|
||||
);
|
||||
}, 300_000);
|
||||
});
|
||||
|
||||
function getRandomPort() {
|
||||
|
||||
@ -3,8 +3,10 @@ import {
|
||||
cleanupProject,
|
||||
createFile,
|
||||
newProject,
|
||||
readJson,
|
||||
renameFile,
|
||||
runCLI,
|
||||
runCommand,
|
||||
uniq,
|
||||
updateFile,
|
||||
updateJson,
|
||||
@ -103,12 +105,10 @@ describe('Nx Plugin (TS solution)', () => {
|
||||
|
||||
// Register plugin in nx.json (required for inference)
|
||||
updateJson(`nx.json`, (nxJson) => {
|
||||
nxJson.plugins = [
|
||||
{
|
||||
nxJson.plugins.push({
|
||||
plugin: `@${workspaceName}/${plugin}`,
|
||||
options: { inferredTags: ['my-tag'] },
|
||||
},
|
||||
];
|
||||
});
|
||||
return nxJson;
|
||||
});
|
||||
|
||||
@ -262,4 +262,22 @@ describe('Nx Plugin (TS solution)', () => {
|
||||
expect(() => checkFilesExist(`libs/${generatedProject}`)).not.toThrow();
|
||||
expect(() => runCLI(`execute ${generatedProject}`)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should respect and support generating plugins with a name different than the import path', async () => {
|
||||
const plugin = uniq('plugin');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/plugin:plugin packages/${plugin} --name=${plugin} --linter=eslint --publishable`
|
||||
);
|
||||
|
||||
const packageJson = readJson(`packages/${plugin}/package.json`);
|
||||
expect(packageJson.nx.name).toBe(plugin);
|
||||
|
||||
expect(runCLI(`build ${plugin}`)).toContain(
|
||||
`Successfully ran target build for project ${plugin}`
|
||||
);
|
||||
expect(runCLI(`lint ${plugin}`)).toContain(
|
||||
`Successfully ran target lint for project ${plugin}`
|
||||
);
|
||||
}, 90000);
|
||||
});
|
||||
|
||||
41
e2e/react/src/react-ts-solution.test.ts
Normal file
41
e2e/react/src/react-ts-solution.test.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import {
|
||||
cleanupProject,
|
||||
newProject,
|
||||
readJson,
|
||||
runCLI,
|
||||
uniq,
|
||||
} from '@nx/e2e/utils';
|
||||
|
||||
describe('React (TS solution)', () => {
|
||||
let workspaceName: string;
|
||||
|
||||
beforeAll(() => {
|
||||
workspaceName = newProject({ preset: 'ts', packages: ['@nx/react'] });
|
||||
});
|
||||
|
||||
afterAll(() => cleanupProject());
|
||||
|
||||
it('should respect and support generating libraries with a name different than the import path', async () => {
|
||||
const lib = uniq('lib');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/react:library packages/${lib} --name=${lib} --bundler=vite --linter=eslint --unitTestRunner=vitest`
|
||||
);
|
||||
|
||||
const packageJson = readJson(`packages/${lib}/package.json`);
|
||||
expect(packageJson.nx.name).toBe(lib);
|
||||
|
||||
expect(runCLI(`build ${lib}`)).toContain(
|
||||
`Successfully ran target build for project ${lib}`
|
||||
);
|
||||
expect(runCLI(`typecheck ${lib}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${lib}`
|
||||
);
|
||||
expect(runCLI(`lint ${lib}`)).toContain(
|
||||
`Successfully ran target lint for project ${lib}`
|
||||
);
|
||||
expect(runCLI(`test ${lib}`)).toContain(
|
||||
`Successfully ran target test for project ${lib}`
|
||||
);
|
||||
}, 90000);
|
||||
});
|
||||
@ -1,4 +1,10 @@
|
||||
import { cleanupProject, newProject, runCLI, uniq } from '@nx/e2e/utils';
|
||||
import {
|
||||
cleanupProject,
|
||||
newProject,
|
||||
readJson,
|
||||
runCLI,
|
||||
uniq,
|
||||
} from '@nx/e2e/utils';
|
||||
|
||||
describe('Remix - TS solution setup', () => {
|
||||
beforeAll(() => {
|
||||
@ -113,4 +119,28 @@ describe('Remix - TS solution setup', () => {
|
||||
`Successfully ran target test for project @proj/${buildableLibJest}`
|
||||
);
|
||||
}, 120_000);
|
||||
|
||||
it('should respect and support generating libraries with a name different than the import path', async () => {
|
||||
const lib = uniq('lib');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/remix:library packages/${lib} --name=${lib} --linter=eslint --unitTestRunner=vitest --buildable`
|
||||
);
|
||||
|
||||
const packageJson = readJson(`packages/${lib}/package.json`);
|
||||
expect(packageJson.nx.name).toBe(lib);
|
||||
|
||||
expect(runCLI(`build ${lib}`)).toContain(
|
||||
`Successfully ran target build for project ${lib}`
|
||||
);
|
||||
expect(runCLI(`typecheck ${lib}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${lib}`
|
||||
);
|
||||
expect(runCLI(`lint ${lib}`)).toContain(
|
||||
`Successfully ran target lint for project ${lib}`
|
||||
);
|
||||
expect(runCLI(`test ${lib}`)).toContain(
|
||||
`Successfully ran target test for project ${lib}`
|
||||
);
|
||||
}, 120_000);
|
||||
});
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
import {
|
||||
cleanupProject,
|
||||
getSelectedPackageManager,
|
||||
newProject,
|
||||
readJson,
|
||||
runCLI,
|
||||
uniq,
|
||||
updateFile,
|
||||
updateJson,
|
||||
} from '@nx/e2e/utils';
|
||||
|
||||
describe('Vue Plugin', () => {
|
||||
describe('Vue (TS solution)', () => {
|
||||
let proj: string;
|
||||
|
||||
const pm = getSelectedPackageManager();
|
||||
|
||||
beforeAll(() => {
|
||||
proj = newProject({
|
||||
packages: ['@nx/vue'],
|
||||
@ -57,4 +54,32 @@ describe('Vue Plugin', () => {
|
||||
expect(() => runCLI(`test @proj/${lib}`)).not.toThrow();
|
||||
expect(() => runCLI(`build @proj/${lib}`)).not.toThrow();
|
||||
}, 300_000);
|
||||
|
||||
it('should respect and support generating libraries with a name different than the import path', async () => {
|
||||
const lib = uniq('lib');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/vue:library packages/${lib} --name=${lib} --bundler=vite --unitTestRunner=vitest`
|
||||
);
|
||||
// lib generator doesn't generate specs, add one
|
||||
updateFile(
|
||||
`packages/${lib}/src/foo.spec.ts`,
|
||||
`test('it should run', () => {
|
||||
expect(true).toBeTruthy();
|
||||
});`
|
||||
);
|
||||
|
||||
const packageJson = readJson(`packages/${lib}/package.json`);
|
||||
expect(packageJson.nx.name).toBe(lib);
|
||||
|
||||
expect(runCLI(`build ${lib}`)).toContain(
|
||||
`Successfully ran target build for project ${lib}`
|
||||
);
|
||||
expect(runCLI(`typecheck ${lib}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${lib}`
|
||||
);
|
||||
expect(runCLI(`test ${lib}`)).toContain(
|
||||
`Successfully ran target test for project ${lib}`
|
||||
);
|
||||
}, 300_000);
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { joinPathFragments, type Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners';
|
||||
@ -12,7 +12,7 @@ export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Partial<Schema>
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(host, options as Schema, 'application');
|
||||
await ensureRootProjectName(options as Schema, 'application');
|
||||
const { projectName: appProjectName, projectRoot: appProjectRoot } =
|
||||
await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
|
||||
@ -7,7 +7,7 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { isValidVariable } from '@nx/js';
|
||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
@ -53,7 +53,7 @@ export async function host(tree: Tree, schema: Schema) {
|
||||
});
|
||||
}
|
||||
|
||||
await ensureProjectName(tree, options, 'application');
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const { projectName: hostProjectName, projectRoot: appRoot } =
|
||||
await determineProjectNameAndRootOptions(tree, {
|
||||
name: options.name,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { names, Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { UnitTestRunner } from '../../../utils/test-runners';
|
||||
@ -29,7 +29,7 @@ export async function normalizeOptions(
|
||||
...schema,
|
||||
};
|
||||
|
||||
await ensureProjectName(host, options, 'library');
|
||||
await ensureRootProjectName(options, 'library');
|
||||
const {
|
||||
projectName,
|
||||
names: projectNames,
|
||||
|
||||
@ -8,7 +8,7 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { swcHelpersVersion } from '@nx/js/src/utils/versions';
|
||||
@ -32,7 +32,7 @@ export async function remote(tree: Tree, schema: Schema) {
|
||||
);
|
||||
}
|
||||
|
||||
await ensureProjectName(tree, options, 'application');
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const { projectName: remoteProjectName } =
|
||||
await determineProjectNameAndRootOptions(tree, {
|
||||
name: options.name,
|
||||
|
||||
@ -474,10 +474,10 @@ function createPackageJson(tree: Tree, options: NormalizedSchema) {
|
||||
name: importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
name: options.project,
|
||||
},
|
||||
};
|
||||
if (options.project !== importPath) {
|
||||
packageJson.nx = { name: options.project };
|
||||
}
|
||||
writeJson(tree, packageJsonPath, packageJson);
|
||||
}
|
||||
|
||||
|
||||
@ -548,12 +548,10 @@ describe('detox application generator', () => {
|
||||
expect(tree.read('apps/my-app-e2e/package.json', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"{
|
||||
"name": "my-app-e2e",
|
||||
"name": "@proj/my-app-e2e",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"nx": {
|
||||
"sourceRoot": "apps/my-app-e2e/src",
|
||||
"projectType": "application",
|
||||
"implicitDependencies": [
|
||||
"my-app"
|
||||
]
|
||||
@ -660,5 +658,34 @@ describe('detox application generator', () => {
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should respect the provided e2e name', async () => {
|
||||
writeJson(tree, 'apps/my-app/package.json', {
|
||||
name: 'my-app',
|
||||
});
|
||||
|
||||
await detoxApplicationGenerator(tree, {
|
||||
e2eDirectory: 'apps/my-app-e2e',
|
||||
appProject: 'my-app',
|
||||
e2eName: 'my-app-e2e',
|
||||
linter: Linter.None,
|
||||
framework: 'react-native',
|
||||
addPlugin: true,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const packageJson = readJson(tree, 'apps/my-app-e2e/package.json');
|
||||
expect(packageJson.name).toBe('@proj/my-app-e2e');
|
||||
expect(packageJson.nx.name).toBe('my-app-e2e');
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -13,6 +13,7 @@ describe('Add Linting', () => {
|
||||
e2eDirectory: 'my-app-e2e',
|
||||
e2eProjectName: 'my-app-e2e',
|
||||
e2eProjectRoot: 'apps/my-app-e2e',
|
||||
importPath: '@proj/my-app-e2e',
|
||||
appProject: 'my-app',
|
||||
appFileName: 'my-app',
|
||||
appClassName: 'MyApp',
|
||||
@ -30,6 +31,7 @@ describe('Add Linting', () => {
|
||||
e2eDirectory: 'my-app-e2e',
|
||||
e2eProjectName: 'my-app-e2e',
|
||||
e2eProjectRoot: 'apps/my-app-e2e',
|
||||
importPath: '@proj/my-app-e2e',
|
||||
appProject: 'my-app',
|
||||
appFileName: 'my-app',
|
||||
appClassName: 'MyApp',
|
||||
@ -49,6 +51,7 @@ describe('Add Linting', () => {
|
||||
e2eDirectory: 'my-app-e2e',
|
||||
e2eProjectName: 'my-app-e2e',
|
||||
e2eProjectRoot: 'apps/my-app-e2e',
|
||||
importPath: '@proj/my-app-e2e',
|
||||
appProject: 'my-app',
|
||||
appFileName: 'my-app',
|
||||
appClassName: 'MyApp',
|
||||
|
||||
@ -32,6 +32,7 @@ describe('Add Project', () => {
|
||||
e2eDirectory: 'my-app-e2e',
|
||||
e2eProjectName: 'my-app-e2e',
|
||||
e2eProjectRoot: 'apps/my-app-e2e',
|
||||
importPath: '@proj/my-app-e2e',
|
||||
appProject: 'my-app',
|
||||
appFileName: 'my-app',
|
||||
appClassName: 'MyApp',
|
||||
@ -81,6 +82,7 @@ describe('Add Project', () => {
|
||||
e2eDirectory: 'my-dir-my-app-e2e',
|
||||
e2eProjectName: 'my-dir-my-app-e2e',
|
||||
e2eProjectRoot: 'apps/my-dir/my-app-e2e',
|
||||
importPath: '@proj/my-dir-my-app-e2e',
|
||||
appProject: 'my-dir-my-app',
|
||||
appFileName: 'my-app',
|
||||
appClassName: 'MyApp',
|
||||
|
||||
@ -25,12 +25,14 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
|
||||
if (isUsingTsSolutionSetup(host)) {
|
||||
writeJson(host, joinPathFragments(options.e2eProjectRoot, 'package.json'), {
|
||||
name: options.e2eProjectName,
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
sourceRoot: `${options.e2eProjectRoot}/src`,
|
||||
projectType: 'application',
|
||||
name:
|
||||
options.e2eProjectName !== options.importPath
|
||||
? options.e2eProjectName
|
||||
: undefined,
|
||||
targets: hasPlugin ? undefined : getTargets(options),
|
||||
implicitDependencies: [options.appProject],
|
||||
},
|
||||
|
||||
@ -15,6 +15,7 @@ describe('Create Files', () => {
|
||||
e2eDirectory: 'my-app-e2e',
|
||||
e2eProjectName: 'my-app-e2e',
|
||||
e2eProjectRoot: 'apps/my-app-e2e',
|
||||
importPath: '@proj/my-app-e2e',
|
||||
appProject: 'my-app',
|
||||
appFileName: 'my-app',
|
||||
appClassName: 'MyApp',
|
||||
|
||||
@ -27,10 +27,10 @@ describe('Normalize Options', () => {
|
||||
expect(options).toEqual({
|
||||
addPlugin: true,
|
||||
framework: 'react-native',
|
||||
e2eName: 'my-app-e2e',
|
||||
e2eDirectory: 'apps/my-app-e2e',
|
||||
e2eProjectName: 'my-app-e2e',
|
||||
e2eProjectRoot: 'apps/my-app-e2e',
|
||||
importPath: '@proj/my-app-e2e',
|
||||
appProject: 'my-app',
|
||||
appFileName: 'my-app',
|
||||
appClassName: 'MyApp',
|
||||
@ -62,11 +62,11 @@ describe('Normalize Options', () => {
|
||||
appClassName: 'MyApp',
|
||||
appFileName: 'my-app',
|
||||
appRoot: 'apps/my-app',
|
||||
e2eName: 'my-app-e2e',
|
||||
e2eDirectory: 'apps/my-app-e2e',
|
||||
appProject: 'my-app',
|
||||
e2eProjectName: 'my-app-e2e',
|
||||
e2eProjectRoot: 'apps/my-app-e2e',
|
||||
importPath: '@proj/my-app-e2e',
|
||||
framework: 'react-native',
|
||||
isUsingTsSolutionConfig: false,
|
||||
js: false,
|
||||
@ -94,6 +94,7 @@ describe('Normalize Options', () => {
|
||||
appFileName: 'my-app',
|
||||
appRoot: 'apps/my-app',
|
||||
e2eProjectRoot: 'directory',
|
||||
importPath: '@proj/directory-my-app-e2e',
|
||||
e2eName: 'directory-my-app-e2e',
|
||||
e2eDirectory: 'directory',
|
||||
e2eProjectName: 'directory-my-app-e2e',
|
||||
|
||||
@ -1,18 +1,16 @@
|
||||
import { names, readNxJson, readProjectConfiguration, Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
export interface NormalizedSchema extends Omit<Schema, 'e2eName'> {
|
||||
appFileName: string; // the file name of app to be tested in kebab case
|
||||
appClassName: string; // the class name of app to be tested in pascal case
|
||||
appExpoName: string; // the expo name of app to be tested in class case
|
||||
appRoot: string; // the root path of e2e project. e.g. apps/app-directory/app
|
||||
e2eProjectName: string; // the name of e2e project
|
||||
e2eProjectRoot: string; // the root path of e2e project. e.g. apps/e2e-directory/e2e-app
|
||||
importPath: string;
|
||||
isUsingTsSolutionConfig?: boolean;
|
||||
}
|
||||
|
||||
@ -20,8 +18,11 @@ export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
const { projectName: e2eProjectName, projectRoot: e2eProjectRoot } =
|
||||
await determineProjectNameAndRootOptions(host, {
|
||||
const {
|
||||
projectName,
|
||||
projectRoot: e2eProjectRoot,
|
||||
importPath,
|
||||
} = await determineProjectNameAndRootOptions(host, {
|
||||
name: options.e2eName,
|
||||
projectType: 'application',
|
||||
directory: options.e2eDirectory,
|
||||
@ -37,6 +38,10 @@ export async function normalizeOptions(
|
||||
);
|
||||
const { root: appRoot } = readProjectConfiguration(host, options.appProject);
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
const e2eProjectName =
|
||||
!isUsingTsSolutionConfig || options.e2eName ? projectName : importPath;
|
||||
|
||||
return {
|
||||
...options,
|
||||
appFileName,
|
||||
@ -44,10 +49,10 @@ export async function normalizeOptions(
|
||||
appDisplayName: options.appDisplayName || appClassName,
|
||||
appExpoName: options.appDisplayName?.replace(/\s/g, '') || appClassName,
|
||||
appRoot,
|
||||
e2eName: e2eProjectName,
|
||||
e2eProjectName,
|
||||
e2eProjectRoot,
|
||||
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||
importPath,
|
||||
isUsingTsSolutionConfig,
|
||||
js: options.js ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ import { determineProjectNameAndRootOptions } from './project-name-and-root-util
|
||||
describe('determineProjectNameAndRootOptions', () => {
|
||||
let tree: Tree;
|
||||
|
||||
describe('no layout', () => {
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
|
||||
@ -265,5 +264,4 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
projectRoot: 'shared/@foo/@scope/libName',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -42,7 +42,7 @@ export type ProjectNameAndRootOptions = {
|
||||
/**
|
||||
* Normalized import path for the project.
|
||||
*/
|
||||
importPath?: string;
|
||||
importPath: string;
|
||||
};
|
||||
|
||||
export async function determineProjectNameAndRootOptions(
|
||||
@ -88,11 +88,8 @@ export async function determineProjectNameAndRootOptions(
|
||||
}
|
||||
}
|
||||
|
||||
let importPath: string | undefined = undefined;
|
||||
if (options.projectType === 'library') {
|
||||
importPath =
|
||||
const importPath =
|
||||
options.importPath ?? resolveImportPath(tree, name, projectRoot);
|
||||
}
|
||||
|
||||
return {
|
||||
projectName: name,
|
||||
@ -125,24 +122,17 @@ export function resolveImportPath(
|
||||
return importPath;
|
||||
}
|
||||
|
||||
export async function ensureProjectName(
|
||||
tree: Tree,
|
||||
options: Omit<ProjectGenerationOptions, 'projectType'>,
|
||||
export async function ensureRootProjectName(
|
||||
options: { directory: string; name?: string },
|
||||
projectType: 'application' | 'library'
|
||||
): Promise<void> {
|
||||
if (!options.name) {
|
||||
if (options.directory === '.' && getRelativeCwd() === '') {
|
||||
if (!options.name && options.directory === '.' && getRelativeCwd() === '') {
|
||||
const result = await prompt<{ name: string }>({
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: `What do you want to name the ${projectType}?`,
|
||||
}).then(({ name }) => (options.name = name));
|
||||
}
|
||||
const { projectName } = await determineProjectNameAndRootOptions(tree, {
|
||||
...options,
|
||||
projectType,
|
||||
});
|
||||
options.name = projectName;
|
||||
options.name = result.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,10 @@ import {
|
||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||
import { getOutputDir, getUpdatedPackageJsonContent } from '@nx/js';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import {
|
||||
getProjectSourceRoot,
|
||||
isUsingTsSolutionSetup,
|
||||
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { basename, dirname, join } from 'node:path/posix';
|
||||
import { mergeTargetConfigurations } from 'nx/src/devkit-internals';
|
||||
import { PackageJson } from 'nx/src/utils/package-json';
|
||||
@ -78,10 +81,11 @@ function addBuildTarget(
|
||||
};
|
||||
|
||||
if (isTsSolutionSetup) {
|
||||
buildOptions.declarationRootDir =
|
||||
project.sourceRoot ?? tree.exists(`${project.root}/src`)
|
||||
? `${project.root}/src`
|
||||
: project.root;
|
||||
buildOptions.declarationRootDir = getProjectSourceRoot(
|
||||
tree,
|
||||
project.sourceRoot,
|
||||
project.root
|
||||
);
|
||||
} else {
|
||||
buildOptions.assets = [];
|
||||
|
||||
|
||||
@ -505,6 +505,9 @@ describe('@nx/eslint:lint-project', () => {
|
||||
}
|
||||
"
|
||||
`);
|
||||
expect(
|
||||
readJson(tree, 'package.json').devDependencies['jsonc-eslint-parser']
|
||||
).toBeDefined();
|
||||
});
|
||||
|
||||
it('should generate a project config for buildable lib with lintFilePatterns if provided', async () => {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
createProjectGraphAsync,
|
||||
formatFiles,
|
||||
GeneratorCallback,
|
||||
@ -38,6 +39,7 @@ import {
|
||||
BASE_ESLINT_CONFIG_FILENAMES,
|
||||
} from '../../utils/config-file';
|
||||
import { hasEslintPlugin } from '../utils/plugin';
|
||||
import { jsoncEslintParserVersion } from '../../utils/versions';
|
||||
import { setupRootEsLint } from './setup-root-eslint';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
@ -165,13 +167,29 @@ export async function lintProjectGeneratorInternal(
|
||||
// additionally, the companion e2e app would have `rootProject: true`
|
||||
// so we need to check for the root path as well
|
||||
if (!options.rootProject || projectConfig.root !== '.') {
|
||||
const addDependencyChecks =
|
||||
options.addPackageJsonDependencyChecks ||
|
||||
isBuildableLibraryProject(tree, projectConfig);
|
||||
createEsLintConfiguration(
|
||||
tree,
|
||||
options,
|
||||
projectConfig,
|
||||
options.setParserOptionsProject,
|
||||
options.rootProject
|
||||
options.rootProject,
|
||||
addDependencyChecks
|
||||
);
|
||||
|
||||
if (addDependencyChecks) {
|
||||
tasks.push(
|
||||
addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{ 'jsonc-eslint-parser': jsoncEslintParserVersion },
|
||||
undefined,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Buildable libs need source analysis enabled for linting `package.json`.
|
||||
@ -201,7 +219,8 @@ function createEsLintConfiguration(
|
||||
options: LintProjectOptions,
|
||||
projectConfig: ProjectConfiguration,
|
||||
setParserOptionsProject: boolean,
|
||||
rootProject: boolean
|
||||
rootProject: boolean,
|
||||
addDependencyChecks: boolean
|
||||
) {
|
||||
// we are only extending root for non-standalone projects or their complementary e2e apps
|
||||
const extendedRootConfig = rootProject ? undefined : findEslintFile(tree);
|
||||
@ -224,10 +243,6 @@ function createEsLintConfiguration(
|
||||
}
|
||||
}
|
||||
|
||||
const addDependencyChecks =
|
||||
options.addPackageJsonDependencyChecks ||
|
||||
isBuildableLibraryProject(tree, projectConfig);
|
||||
|
||||
const overrides: Linter.ConfigOverride<Linter.RulesRecord>[] = useFlatConfig(
|
||||
tree
|
||||
)
|
||||
|
||||
@ -4,6 +4,7 @@ export const eslintVersion = '~8.57.0';
|
||||
export const eslintrcVersion = '^2.1.1';
|
||||
export const eslintConfigPrettierVersion = '^9.0.0';
|
||||
export const typescriptESLintVersion = '^7.16.0';
|
||||
export const jsoncEslintParserVersion = '^2.1.0';
|
||||
|
||||
// Updated linting stack for ESLint v9, typescript-eslint v8
|
||||
export const eslint9__typescriptESLintVersion = '^8.19.0';
|
||||
|
||||
@ -331,8 +331,10 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
describe('TS solution setup', () => {
|
||||
it('should add project references when using TS solution', async () => {
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
tree.write('.gitignore', '');
|
||||
updateJson(tree, 'package.json', (json) => {
|
||||
json.workspaces = ['packages/*', 'apps/*'];
|
||||
@ -349,7 +351,9 @@ describe('app', () => {
|
||||
files: [],
|
||||
references: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should add project references when using TS solution', async () => {
|
||||
await expoApplicationGenerator(tree, {
|
||||
directory: 'my-app',
|
||||
displayName: 'myApp',
|
||||
@ -368,14 +372,15 @@ describe('app', () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
const packageJson = readJson(tree, 'my-app/package.json');
|
||||
expect(packageJson.name).toBe('@proj/my-app');
|
||||
expect(packageJson.nx).toBeUndefined();
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(readJson(tree, 'my-app/package.json')))
|
||||
.toMatchInlineSnapshot(`
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
expect(readJson(tree, 'my-app/tsconfig.json')).toMatchInlineSnapshot(`
|
||||
@ -476,5 +481,32 @@ describe('app', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should respect provided name', async () => {
|
||||
await expoApplicationGenerator(tree, {
|
||||
directory: 'my-app',
|
||||
name: 'my-app',
|
||||
displayName: 'myApp',
|
||||
linter: Linter.EsLint,
|
||||
e2eTestRunner: 'none',
|
||||
skipFormat: false,
|
||||
js: false,
|
||||
unitTestRunner: 'jest',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
const packageJson = readJson(tree, 'my-app/package.json');
|
||||
expect(packageJson.name).toBe('@proj/my-app');
|
||||
expect(packageJson.nx.name).toBe('my-app');
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -62,6 +62,12 @@ export async function expoApplicationGeneratorInternal(
|
||||
await createApplicationFiles(host, options);
|
||||
addProject(host, options);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isTsSolutionSetup) {
|
||||
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
|
||||
}
|
||||
|
||||
const lintTask = await addLinting(host, {
|
||||
...options,
|
||||
projectRoot: options.appProjectRoot,
|
||||
@ -100,12 +106,6 @@ export async function expoApplicationGeneratorInternal(
|
||||
: undefined
|
||||
);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.useTsSolution) {
|
||||
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(host, options.appProjectRoot);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
|
||||
@ -51,8 +51,6 @@ export async function addE2e(
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
projectType: 'application',
|
||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||
implicitDependencies: [options.projectName],
|
||||
},
|
||||
}
|
||||
@ -134,8 +132,6 @@ export async function addE2e(
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
projectType: 'application',
|
||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||
implicitDependencies: [options.projectName],
|
||||
},
|
||||
}
|
||||
@ -205,7 +201,7 @@ export async function addE2e(
|
||||
e2eDirectory: options.e2eProjectRoot,
|
||||
appProject: options.projectName,
|
||||
appDisplayName: options.displayName,
|
||||
appName: options.name,
|
||||
appName: options.simpleName,
|
||||
framework: 'expo',
|
||||
setParserOptionsProject: options.setParserOptionsProject,
|
||||
skipFormat: true,
|
||||
|
||||
@ -2,7 +2,6 @@ import {
|
||||
addProjectConfiguration,
|
||||
joinPathFragments,
|
||||
ProjectConfiguration,
|
||||
readNxJson,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
writeJson,
|
||||
@ -12,10 +11,9 @@ import { hasExpoPlugin } from '../../../utils/has-expo-plugin';
|
||||
import { NormalizedSchema } from './normalize-options';
|
||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
const nxJson = readNxJson(host);
|
||||
const hasPlugin = hasExpoPlugin(host);
|
||||
|
||||
if (!hasPlugin) {
|
||||
@ -31,19 +29,29 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
};
|
||||
|
||||
if (isUsingTsSolutionSetup(host)) {
|
||||
const packageName = getImportPath(host, options.name);
|
||||
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||
name: packageName,
|
||||
const packageJson: PackageJson = {
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
name: packageName === options.name ? undefined : options.name,
|
||||
projectType: 'application',
|
||||
sourceRoot: `${options.appProjectRoot}/src`,
|
||||
targets: hasPlugin ? undefined : getTargets(options),
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (options.importPath !== options.projectName) {
|
||||
packageJson.nx = { name: options.projectName };
|
||||
}
|
||||
if (!hasPlugin) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.targets = getTargets(options);
|
||||
}
|
||||
if (options.parsedTags?.length) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.tags = options.parsedTags;
|
||||
}
|
||||
|
||||
writeJson(
|
||||
host,
|
||||
joinPathFragments(options.appProjectRoot, 'package.json'),
|
||||
packageJson
|
||||
);
|
||||
} else {
|
||||
addProjectConfiguration(
|
||||
host,
|
||||
|
||||
@ -28,11 +28,12 @@ describe('Normalize Options', () => {
|
||||
directory: 'my-app',
|
||||
displayName: 'MyApp',
|
||||
lowerCaseName: 'myapp',
|
||||
name: 'my-app',
|
||||
simpleName: 'my-app',
|
||||
parsedTags: [],
|
||||
projectName: 'my-app',
|
||||
linter: Linter.EsLint,
|
||||
e2eTestRunner: 'none',
|
||||
importPath: '@proj/my-app',
|
||||
unitTestRunner: 'jest',
|
||||
skipFormat: false,
|
||||
js: true,
|
||||
@ -60,11 +61,12 @@ describe('Normalize Options', () => {
|
||||
directory: 'myApp',
|
||||
displayName: 'MyApp',
|
||||
lowerCaseName: 'myapp',
|
||||
name: 'myApp',
|
||||
simpleName: 'myApp',
|
||||
parsedTags: [],
|
||||
projectName: 'myApp',
|
||||
linter: Linter.EsLint,
|
||||
e2eTestRunner: 'none',
|
||||
importPath: '@proj/myApp',
|
||||
skipFormat: false,
|
||||
js: true,
|
||||
unitTestRunner: 'jest',
|
||||
@ -93,10 +95,12 @@ describe('Normalize Options', () => {
|
||||
displayName: 'MyApp',
|
||||
lowerCaseName: 'myapp',
|
||||
name: 'my-app',
|
||||
simpleName: 'my-app',
|
||||
directory: 'directory',
|
||||
parsedTags: [],
|
||||
projectName: 'my-app',
|
||||
e2eTestRunner: 'none',
|
||||
importPath: '@proj/my-app',
|
||||
unitTestRunner: 'jest',
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: false,
|
||||
@ -125,10 +129,11 @@ describe('Normalize Options', () => {
|
||||
directory: 'directory/my-app',
|
||||
displayName: 'MyApp',
|
||||
lowerCaseName: 'myapp',
|
||||
name: 'my-app',
|
||||
simpleName: 'my-app',
|
||||
parsedTags: [],
|
||||
projectName: 'my-app',
|
||||
e2eTestRunner: 'none',
|
||||
importPath: '@proj/my-app',
|
||||
unitTestRunner: 'jest',
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: false,
|
||||
@ -158,10 +163,11 @@ describe('Normalize Options', () => {
|
||||
className: 'MyApp',
|
||||
displayName: 'My App',
|
||||
lowerCaseName: 'myapp',
|
||||
name: 'my-app',
|
||||
simpleName: 'my-app',
|
||||
parsedTags: [],
|
||||
projectName: 'my-app',
|
||||
e2eTestRunner: 'none',
|
||||
importPath: '@proj/my-app',
|
||||
unitTestRunner: 'jest',
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: false,
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
import { names, readNxJson, Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { Schema } from '../schema';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
export interface NormalizedSchema
|
||||
extends Omit<Schema, 'name' | 'useTsSolution'> {
|
||||
className: string;
|
||||
simpleName: string;
|
||||
projectName: string;
|
||||
appProjectRoot: string;
|
||||
importPath: string;
|
||||
lowerCaseName: string;
|
||||
parsedTags: string[];
|
||||
rootProject: boolean;
|
||||
@ -22,11 +25,12 @@ export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(host, options, 'application');
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const {
|
||||
projectName: appProjectName,
|
||||
projectName,
|
||||
names: projectNames,
|
||||
projectRoot: appProjectRoot,
|
||||
importPath,
|
||||
} = await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
@ -38,12 +42,16 @@ export async function normalizeOptions(
|
||||
nxJson.useInferencePlugins !== false;
|
||||
options.addPlugin ??= addPluginDefault;
|
||||
|
||||
const { className } = names(options.name);
|
||||
const { className } = names(projectName);
|
||||
const parsedTags = options.tags
|
||||
? options.tags.split(',').map((s) => s.trim())
|
||||
: [];
|
||||
const rootProject = appProjectRoot === '.';
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(host);
|
||||
const appProjectName =
|
||||
!isTsSolutionSetup || options.name ? projectName : importPath;
|
||||
|
||||
const e2eProjectName = rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||
const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
||||
|
||||
@ -51,16 +59,17 @@ export async function normalizeOptions(
|
||||
...options,
|
||||
unitTestRunner: options.unitTestRunner || 'jest',
|
||||
e2eTestRunner: options.e2eTestRunner || 'none',
|
||||
name: projectNames.projectSimpleName,
|
||||
simpleName: projectNames.projectSimpleName,
|
||||
className,
|
||||
lowerCaseName: className.toLowerCase(),
|
||||
displayName: options.displayName || className,
|
||||
projectName: appProjectName,
|
||||
appProjectRoot,
|
||||
importPath,
|
||||
parsedTags,
|
||||
rootProject,
|
||||
e2eProjectName,
|
||||
e2eProjectRoot,
|
||||
isTsSolutionSetup: isUsingTsSolutionSetup(host),
|
||||
isTsSolutionSetup,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import { readNxJson, Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
name: string;
|
||||
fileName: string;
|
||||
projectName: string;
|
||||
projectRoot: string;
|
||||
importPath: string;
|
||||
routePath: string;
|
||||
parsedTags: string[];
|
||||
isUsingTsSolutionConfig: boolean;
|
||||
@ -21,7 +21,7 @@ export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(host, options, 'library');
|
||||
await ensureRootProjectName(options, 'library');
|
||||
const {
|
||||
projectName,
|
||||
names: projectNames,
|
||||
@ -49,9 +49,8 @@ export async function normalizeOptions(
|
||||
fileName: projectName,
|
||||
routePath: `/${projectNames.projectSimpleName}`,
|
||||
name: projectName,
|
||||
projectName: isUsingTsSolutionConfig
|
||||
? importPath ?? getImportPath(host, projectName)
|
||||
: projectName,
|
||||
projectName:
|
||||
isUsingTsSolutionConfig && !options.name ? importPath : projectName,
|
||||
projectRoot,
|
||||
parsedTags,
|
||||
importPath,
|
||||
|
||||
@ -503,7 +503,6 @@ describe('lib', () => {
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"name": "@proj/my-lib",
|
||||
"nx": {},
|
||||
"peerDependencies": {
|
||||
"react": "~18.3.1",
|
||||
"react-native": "0.76.3",
|
||||
@ -520,7 +519,6 @@ describe('lib', () => {
|
||||
"main",
|
||||
"types",
|
||||
"exports",
|
||||
"nx",
|
||||
"peerDependencies",
|
||||
]
|
||||
`);
|
||||
@ -639,7 +637,6 @@ describe('lib', () => {
|
||||
"main": "./src/index.ts",
|
||||
"module": "./dist/index.esm.js",
|
||||
"name": "@proj/my-lib",
|
||||
"nx": {},
|
||||
"peerDependencies": {
|
||||
"react": "~18.3.1",
|
||||
"react-native": "0.76.3",
|
||||
@ -649,5 +646,38 @@ describe('lib', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||
await expoLibraryGenerator(appTree, {
|
||||
...defaultSchema,
|
||||
directory: 'my-lib',
|
||||
name: 'my-lib', // import path contains the npm scope, so it would be different
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(appTree, 'my-lib/package.json').nx).toStrictEqual({
|
||||
name: 'my-lib',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the provided name matches the package name', async () => {
|
||||
await expoLibraryGenerator(appTree, {
|
||||
...defaultSchema,
|
||||
directory: 'my-lib',
|
||||
name: '@proj/my-lib',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(appTree, 'my-lib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the user does not provide a name', async () => {
|
||||
await expoLibraryGenerator(appTree, {
|
||||
...defaultSchema, // defaultSchema has no name
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(appTree, 'my-lib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -176,19 +176,30 @@ async function addProject(
|
||||
};
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
writeJson(host, joinPathFragments(options.projectRoot, 'package.json'), {
|
||||
const packageJson: PackageJson = {
|
||||
name: options.projectName,
|
||||
version: '0.0.1',
|
||||
...determineEntryFields(options),
|
||||
nx: {
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
|
||||
peerDependencies: {
|
||||
react: reactVersion,
|
||||
'react-native': reactNativeVersion,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (options.projectName !== options.importPath) {
|
||||
packageJson.nx = { name: options.projectName };
|
||||
}
|
||||
if (options.parsedTags?.length) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.tags = options.parsedTags;
|
||||
}
|
||||
|
||||
writeJson(
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, 'package.json'),
|
||||
packageJson
|
||||
);
|
||||
} else {
|
||||
addProjectConfiguration(host, options.name, project);
|
||||
}
|
||||
|
||||
@ -185,9 +185,6 @@ describe('app', () => {
|
||||
{
|
||||
"name": "@proj/myapp",
|
||||
"nx": {
|
||||
"name": "myapp",
|
||||
"projectType": "application",
|
||||
"sourceRoot": "myapp/src",
|
||||
"targets": {
|
||||
"build": {
|
||||
"configurations": {
|
||||
@ -217,10 +214,10 @@ describe('app', () => {
|
||||
"serve": {
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "myapp:build:development",
|
||||
"buildTarget": "@proj/myapp:build:development",
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "myapp:build:production",
|
||||
"buildTarget": "@proj/myapp:build:production",
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
@ -229,7 +226,7 @@ describe('app', () => {
|
||||
],
|
||||
"executor": "@nx/js:node",
|
||||
"options": {
|
||||
"buildTarget": "myapp:build",
|
||||
"buildTarget": "@proj/myapp:build",
|
||||
"runBuildTargetDependencies": false,
|
||||
},
|
||||
},
|
||||
|
||||
@ -9,7 +9,7 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
|
||||
import { tslibVersion } from '@nx/node/src/utils/versions';
|
||||
@ -106,7 +106,7 @@ async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(host, options, 'application');
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const { projectName: appProjectName, projectRoot: appProjectRoot } =
|
||||
await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
|
||||
@ -2126,6 +2126,7 @@ describe('lib', () => {
|
||||
directory: 'my-lib',
|
||||
unitTestRunner: 'jest',
|
||||
bundler,
|
||||
useProjectJson: false,
|
||||
});
|
||||
|
||||
expect(tree.exists('my-lib/tsconfig.spec.json')).toBeTruthy();
|
||||
@ -2338,5 +2339,72 @@ describe('lib', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name and "useProjectJson" is "false"', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultOptions,
|
||||
directory: 'my-lib',
|
||||
name: 'my-lib',
|
||||
useProjectJson: false,
|
||||
bundler: 'none',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'my-lib/package.json').nx).toStrictEqual({
|
||||
name: 'my-lib',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the provided name matches the package name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultOptions,
|
||||
directory: 'my-lib',
|
||||
name: '@proj/my-lib',
|
||||
useProjectJson: false,
|
||||
bundler: 'none',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'my-lib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the user does not provide a name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultOptions,
|
||||
directory: 'my-lib',
|
||||
useProjectJson: false,
|
||||
bundler: 'none',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'my-lib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should set "name" in project.json to the import path when "useProjectJson" is "true"', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultOptions,
|
||||
directory: 'my-lib',
|
||||
useProjectJson: true,
|
||||
bundler: 'none',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'my-lib/project.json').name).toBe('@proj/my-lib');
|
||||
expect(readJson(tree, 'my-lib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should set "name" in project.json to the user-provided name when "useProjectJson" is "true"', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultOptions,
|
||||
directory: 'my-lib',
|
||||
name: 'my-lib',
|
||||
useProjectJson: true,
|
||||
bundler: 'none',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'my-lib/project.json').name).toBe('my-lib');
|
||||
expect(readJson(tree, 'my-lib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -22,7 +22,7 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { promptWhenInteractive } from '@nx/devkit/src/generators/prompt';
|
||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||
@ -63,7 +63,6 @@ import type {
|
||||
NormalizedLibraryGeneratorOptions,
|
||||
} from './schema';
|
||||
import { sortPackageJsonFields } from '../../utils/package-json/sort-fields';
|
||||
import { getImportPath } from '../../utils/get-import-path';
|
||||
import {
|
||||
addReleaseConfigForNonTsSolution,
|
||||
addReleaseConfigForTsSolution,
|
||||
@ -368,13 +367,7 @@ async function configureProject(
|
||||
}
|
||||
|
||||
// empty targets are cleaned up automatically by `updateProjectConfiguration`
|
||||
updateProjectConfiguration(
|
||||
tree,
|
||||
options.isUsingTsSolutionConfig
|
||||
? options.importPath ?? options.name
|
||||
: options.name,
|
||||
projectConfiguration
|
||||
);
|
||||
updateProjectConfiguration(tree, options.name, projectConfiguration);
|
||||
} else if (options.config === 'workspace' || options.config === 'project') {
|
||||
addProjectConfiguration(tree, options.name, projectConfiguration);
|
||||
} else {
|
||||
@ -682,6 +675,12 @@ function createFiles(tree: Tree, options: NormalizedLibraryGeneratorOptions) {
|
||||
});
|
||||
}
|
||||
|
||||
if (!options.useProjectJson && options.name !== options.importPath) {
|
||||
packageJson.nx = {
|
||||
name: options.name,
|
||||
};
|
||||
}
|
||||
|
||||
writeJson<PackageJson>(tree, packageJsonPath, packageJson);
|
||||
}
|
||||
|
||||
@ -760,7 +759,7 @@ async function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: LibraryGeneratorSchema
|
||||
): Promise<NormalizedLibraryGeneratorOptions> {
|
||||
await ensureProjectName(tree, options, 'library');
|
||||
await ensureRootProjectName(options, 'library');
|
||||
const nxJson = readNxJson(tree);
|
||||
options.addPlugin ??=
|
||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
@ -901,9 +900,7 @@ async function normalizeOptions(
|
||||
return {
|
||||
...options,
|
||||
fileName,
|
||||
name: isUsingTsSolutionConfig
|
||||
? getImportPath(tree, projectName)
|
||||
: projectName,
|
||||
name: isUsingTsSolutionConfig && !options.name ? importPath : projectName,
|
||||
projectNames,
|
||||
projectRoot,
|
||||
parsedTags,
|
||||
|
||||
@ -270,3 +270,16 @@ export function getProjectType(
|
||||
if (!packageJson?.exports) return 'application';
|
||||
return 'library';
|
||||
}
|
||||
|
||||
export function getProjectSourceRoot(
|
||||
tree: Tree,
|
||||
projectSourceRoot: string | undefined,
|
||||
projectRoot: string
|
||||
): string | undefined {
|
||||
return (
|
||||
projectSourceRoot ??
|
||||
(tree.exists(joinPathFragments(projectRoot, 'src'))
|
||||
? joinPathFragments(projectRoot, 'src')
|
||||
: projectRoot)
|
||||
);
|
||||
}
|
||||
|
||||
@ -209,9 +209,6 @@ describe('application generator', () => {
|
||||
{
|
||||
"name": "@proj/myapp",
|
||||
"nx": {
|
||||
"name": "myapp",
|
||||
"projectType": "application",
|
||||
"sourceRoot": "myapp/src",
|
||||
"targets": {
|
||||
"build": {
|
||||
"configurations": {
|
||||
@ -232,10 +229,10 @@ describe('application generator', () => {
|
||||
"serve": {
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "myapp:build:development",
|
||||
"buildTarget": "@proj/myapp:build:development",
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "myapp:build:production",
|
||||
"buildTarget": "@proj/myapp:build:production",
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
@ -244,7 +241,7 @@ describe('application generator', () => {
|
||||
],
|
||||
"executor": "@nx/js:node",
|
||||
"options": {
|
||||
"buildTarget": "myapp:build",
|
||||
"buildTarget": "@proj/myapp:build",
|
||||
"runBuildTargetDependencies": false,
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Tree, readNxJson } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import type { Schema as NodeApplicationGeneratorOptions } from '@nx/node/src/generators/application/schema';
|
||||
@ -11,7 +11,7 @@ export async function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: ApplicationGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
await ensureProjectName(tree, options, 'application');
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const { projectName: appProjectName, projectRoot: appProjectRoot } =
|
||||
await determineProjectNameAndRootOptions(tree, {
|
||||
name: options.name,
|
||||
|
||||
@ -9,8 +9,8 @@ import type { NormalizedOptions } from '../schema';
|
||||
|
||||
export function createFiles(tree: Tree, options: NormalizedOptions): void {
|
||||
const substitutions = {
|
||||
...options,
|
||||
...names(options.projectName),
|
||||
...options,
|
||||
tmpl: '',
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
||||
fileName: options.fileName,
|
||||
|
||||
@ -1,20 +1,19 @@
|
||||
import { Tree, readNxJson } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { getNpmScope } from '@nx/js/src/utils/package-json/get-npm-scope';
|
||||
import type { LibraryGeneratorSchema as JsLibraryGeneratorSchema } from '@nx/js/src/generators/library/schema';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import type { LibraryGeneratorOptions, NormalizedOptions } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export async function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: LibraryGeneratorOptions
|
||||
): Promise<NormalizedOptions> {
|
||||
await ensureProjectName(tree, options, 'library');
|
||||
await ensureRootProjectName(options, 'library');
|
||||
const {
|
||||
projectName,
|
||||
names: projectNames,
|
||||
@ -50,9 +49,8 @@ export async function normalizeOptions(
|
||||
linter: options.linter ?? Linter.EsLint,
|
||||
parsedTags,
|
||||
prefix: getNpmScope(tree), // we could also allow customizing this
|
||||
projectName: isUsingTsSolutionsConfig
|
||||
? getImportPath(tree, projectName)
|
||||
: projectName,
|
||||
projectName:
|
||||
isUsingTsSolutionsConfig && !options.name ? importPath : projectName,
|
||||
projectRoot,
|
||||
importPath,
|
||||
service: options.service ?? false,
|
||||
|
||||
@ -409,7 +409,6 @@ describe('lib', () => {
|
||||
},
|
||||
},
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"types": "./src/index.ts",
|
||||
"version": "0.0.1",
|
||||
}
|
||||
@ -497,5 +496,42 @@ describe('lib', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
directory: 'mylib',
|
||||
name: 'my-lib', // import path contains the npm scope, so it would be different
|
||||
linter: 'none',
|
||||
unitTestRunner: 'none',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json').nx).toStrictEqual({
|
||||
name: 'my-lib',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the provided name matches the package name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
directory: 'mylib',
|
||||
name: '@proj/my-lib',
|
||||
linter: 'none',
|
||||
unitTestRunner: 'none',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the user does not provide a name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
directory: 'mylib',
|
||||
linter: 'none',
|
||||
unitTestRunner: 'none',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,6 +1,15 @@
|
||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||
import { formatFiles, runTasksInSerial } from '@nx/devkit';
|
||||
import {
|
||||
formatFiles,
|
||||
joinPathFragments,
|
||||
readJson,
|
||||
runTasksInSerial,
|
||||
writeJson,
|
||||
} from '@nx/devkit';
|
||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||
import initGenerator from '../init/init';
|
||||
import {
|
||||
addExportsToBarrelFile,
|
||||
addProject,
|
||||
@ -10,10 +19,7 @@ import {
|
||||
toJsLibraryGeneratorOptions,
|
||||
updateTsConfig,
|
||||
} from './lib';
|
||||
import type { LibraryGeneratorOptions } from './schema';
|
||||
import initGenerator from '../init/init';
|
||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||
import type { LibraryGeneratorOptions, NormalizedOptions } from './schema';
|
||||
|
||||
export async function libraryGenerator(
|
||||
tree: Tree,
|
||||
@ -34,6 +40,7 @@ export async function libraryGeneratorInternal(
|
||||
tree,
|
||||
toJsLibraryGeneratorOptions(options)
|
||||
);
|
||||
updatePackageJson(tree, options);
|
||||
const initTask = await initGenerator(tree, rawOptions);
|
||||
const depsTask = ensureDependencies(tree);
|
||||
deleteFiles(tree, options);
|
||||
@ -59,3 +66,23 @@ export async function libraryGeneratorInternal(
|
||||
}
|
||||
|
||||
export default libraryGenerator;
|
||||
|
||||
function updatePackageJson(tree: Tree, options: NormalizedOptions) {
|
||||
const packageJsonPath = joinPathFragments(
|
||||
options.projectRoot,
|
||||
'package.json'
|
||||
);
|
||||
if (!tree.exists(packageJsonPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const packageJson = readJson(tree, packageJsonPath);
|
||||
|
||||
if (packageJson.type === 'module') {
|
||||
// The @nx/js:lib generator can set the type to 'module' which would
|
||||
// potentially break consumers of the library.
|
||||
delete packageJson.type;
|
||||
}
|
||||
|
||||
writeJson(tree, packageJsonPath, packageJson);
|
||||
}
|
||||
|
||||
@ -938,7 +938,6 @@ describe('app (legacy)', () => {
|
||||
...schema,
|
||||
addPlugin: true,
|
||||
directory: 'myapp',
|
||||
name: 'myapp',
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||
@ -951,14 +950,15 @@ describe('app (legacy)', () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
const packageJson = readJson(tree, 'myapp/package.json');
|
||||
expect(packageJson.name).toBe('@proj/myapp');
|
||||
expect(packageJson.nx).toBeUndefined();
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(readJson(tree, 'myapp/package.json')))
|
||||
.toMatchInlineSnapshot(`
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
"dependencies",
|
||||
]
|
||||
`);
|
||||
@ -1086,6 +1086,29 @@ describe('app (legacy)', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should respect the provided name', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
...schema,
|
||||
addPlugin: true,
|
||||
directory: 'myapp',
|
||||
name: 'myapp',
|
||||
});
|
||||
|
||||
const packageJson = readJson(tree, 'myapp/package.json');
|
||||
expect(packageJson.name).toBe('@proj/myapp');
|
||||
expect(packageJson.nx.name).toBe('myapp');
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
"dependencies",
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -54,8 +54,8 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
||||
js: options.js,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
skipFormat: true,
|
||||
addTsPlugin: schema.useTsSolution,
|
||||
formatter: schema.formatter,
|
||||
addTsPlugin: options.isTsSolutionSetup,
|
||||
formatter: options.formatter,
|
||||
platform: 'web',
|
||||
});
|
||||
tasks.push(jsInitTask);
|
||||
@ -70,6 +70,12 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
||||
|
||||
addProject(host, options);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isTsSolutionSetup) {
|
||||
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
|
||||
}
|
||||
|
||||
const e2eTask = await addE2e(host, options);
|
||||
tasks.push(e2eTask);
|
||||
|
||||
@ -145,12 +151,6 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
||||
options.src ? 'src' : '.'
|
||||
);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.useTsSolution) {
|
||||
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(host, options.appProjectRoot);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
|
||||
@ -54,8 +54,6 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
projectType: 'application',
|
||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||
implicitDependencies: [options.projectName],
|
||||
},
|
||||
}
|
||||
@ -135,8 +133,6 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
projectType: 'application',
|
||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||
implicitDependencies: [options.projectName],
|
||||
},
|
||||
}
|
||||
|
||||
@ -16,18 +16,20 @@ describe('updateEslint', () => {
|
||||
beforeEach(async () => {
|
||||
schema = {
|
||||
projectName: 'my-app',
|
||||
projectSimpleName: 'my-app',
|
||||
appProjectRoot: 'my-app',
|
||||
directory: 'my-app',
|
||||
importPath: '@proj/my-app',
|
||||
linter: Linter.EsLint,
|
||||
unitTestRunner: 'jest',
|
||||
e2eProjectName: 'my-app-e2e',
|
||||
e2eProjectRoot: 'my-app-e2e',
|
||||
outputPath: 'dist/my-app',
|
||||
name: 'my-app',
|
||||
parsedTags: [],
|
||||
fileName: 'index',
|
||||
e2eTestRunner: 'cypress',
|
||||
styledModule: null,
|
||||
isTsSolutionSetup: false,
|
||||
};
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
const project: ProjectConfiguration = {
|
||||
|
||||
@ -9,9 +9,9 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
import { nextVersion } from '../../../utils/versions';
|
||||
import { reactDomVersion, reactVersion } from '@nx/react';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
const targets: Record<string, any> = {};
|
||||
@ -73,8 +73,8 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
};
|
||||
|
||||
if (isUsingTsSolutionSetup(host)) {
|
||||
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||
name: getImportPath(host, options.name),
|
||||
const packageJson: PackageJson = {
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
dependencies: {
|
||||
@ -82,13 +82,21 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
react: reactVersion,
|
||||
'react-dom': reactDomVersion,
|
||||
},
|
||||
nx: {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
sourceRoot: options.appProjectRoot,
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (options.projectName !== options.importPath) {
|
||||
packageJson.nx = { name: options.projectName };
|
||||
}
|
||||
if (options.parsedTags?.length) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.tags = options.parsedTags;
|
||||
}
|
||||
|
||||
writeJson(
|
||||
host,
|
||||
joinPathFragments(options.appProjectRoot, 'package.json'),
|
||||
packageJson
|
||||
);
|
||||
} else {
|
||||
addProjectConfiguration(host, options.projectName, {
|
||||
...project,
|
||||
|
||||
@ -41,7 +41,7 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||
: '';
|
||||
|
||||
const templateVariables = {
|
||||
...names(options.name),
|
||||
...names(options.projectSimpleName),
|
||||
...options,
|
||||
dot: '.',
|
||||
tmpl: '',
|
||||
|
||||
@ -1,21 +1,26 @@
|
||||
import { joinPathFragments, names, readNxJson, Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { assertValidStyle } from '@nx/react/src/utils/assertion';
|
||||
import { Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
export interface NormalizedSchema
|
||||
extends Omit<Schema, 'name' | 'useTsSolution'> {
|
||||
projectName: string;
|
||||
projectSimpleName: string;
|
||||
appProjectRoot: string;
|
||||
importPath: string;
|
||||
outputPath: string;
|
||||
e2eProjectName: string;
|
||||
e2eProjectRoot: string;
|
||||
parsedTags: string[];
|
||||
fileName: string;
|
||||
styledModule: null | string;
|
||||
isTsSolutionSetup: boolean;
|
||||
js?: boolean;
|
||||
}
|
||||
|
||||
@ -23,9 +28,13 @@ export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(host, options, 'application');
|
||||
const { projectName: appProjectName, projectRoot: appProjectRoot } =
|
||||
await determineProjectNameAndRootOptions(host, {
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const {
|
||||
projectName,
|
||||
names: projectNames,
|
||||
projectRoot: appProjectRoot,
|
||||
importPath,
|
||||
} = await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
directory: options.directory,
|
||||
@ -40,15 +49,18 @@ export async function normalizeOptions(
|
||||
|
||||
options.addPlugin ??= addPlugin;
|
||||
|
||||
const isTsSolutionSetup =
|
||||
options.useTsSolution || isUsingTsSolutionSetup(host);
|
||||
const appProjectName =
|
||||
!isTsSolutionSetup || options.name ? projectName : importPath;
|
||||
|
||||
const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||
const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
||||
|
||||
const name = names(options.name).fileName;
|
||||
|
||||
const outputPath = joinPathFragments(
|
||||
'dist',
|
||||
appProjectRoot,
|
||||
...(options.rootProject ? [name] : [])
|
||||
...(options.rootProject ? [projectNames.projectFileName] : [])
|
||||
);
|
||||
|
||||
const parsedTags = options.tags
|
||||
@ -76,12 +88,14 @@ export async function normalizeOptions(
|
||||
e2eTestRunner: options.e2eTestRunner || 'playwright',
|
||||
fileName,
|
||||
linter: options.linter || Linter.EsLint,
|
||||
name,
|
||||
outputPath,
|
||||
parsedTags,
|
||||
projectName: appProjectName,
|
||||
projectSimpleName: projectNames.projectSimpleName,
|
||||
style: options.style || 'css',
|
||||
styledModule,
|
||||
unitTestRunner: options.unitTestRunner || 'jest',
|
||||
importPath,
|
||||
isTsSolutionSetup,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { readNxJson, Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
@ -16,7 +16,7 @@ export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(host, options, 'library');
|
||||
await ensureRootProjectName(options, 'library');
|
||||
const { projectRoot, importPath } = await determineProjectNameAndRootOptions(
|
||||
host,
|
||||
{
|
||||
|
||||
@ -256,5 +256,45 @@ describe('next library', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
directory: 'mylib',
|
||||
name: 'my-lib', // import path contains the npm scope, so it would be different
|
||||
linter: 'none',
|
||||
unitTestRunner: 'none',
|
||||
style: 'css',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json').nx).toStrictEqual({
|
||||
name: 'my-lib',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the provided name matches the package name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
directory: 'mylib',
|
||||
name: '@proj/my-lib',
|
||||
linter: 'none',
|
||||
unitTestRunner: 'none',
|
||||
style: 'css',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the user does not provide a name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
directory: 'mylib',
|
||||
linter: 'none',
|
||||
unitTestRunner: 'none',
|
||||
style: 'css',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -599,9 +599,11 @@ describe('app', () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
const packageJson = readJson(tree, 'myapp/package.json');
|
||||
expect(packageJson.name).toBe('@proj/myapp');
|
||||
expect(packageJson.nx.name).toBeUndefined();
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(readJson(tree, 'myapp/package.json')))
|
||||
.toMatchInlineSnapshot(`
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
@ -613,17 +615,14 @@ describe('app', () => {
|
||||
{
|
||||
"name": "@proj/myapp",
|
||||
"nx": {
|
||||
"name": "myapp",
|
||||
"projectType": "application",
|
||||
"sourceRoot": "myapp/src",
|
||||
"targets": {
|
||||
"serve": {
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "myapp:build:development",
|
||||
"buildTarget": "@proj/myapp:build:development",
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "myapp:build:production",
|
||||
"buildTarget": "@proj/myapp:build:production",
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
@ -632,7 +631,7 @@ describe('app', () => {
|
||||
],
|
||||
"executor": "@nx/js:node",
|
||||
"options": {
|
||||
"buildTarget": "myapp:build",
|
||||
"buildTarget": "@proj/myapp:build",
|
||||
"runBuildTargetDependencies": false,
|
||||
},
|
||||
},
|
||||
@ -717,6 +716,29 @@ describe('app', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should respect the provided name', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
directory: 'myapp',
|
||||
name: 'myapp',
|
||||
bundler: 'webpack',
|
||||
unitTestRunner: 'jest',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
const packageJson = readJson(tree, 'myapp/package.json');
|
||||
expect(packageJson.name).toBe('@proj/myapp');
|
||||
expect(packageJson.nx.name).toBe('myapp');
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should use @swc/jest for jest', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
directory: 'apps/my-app',
|
||||
@ -737,7 +759,7 @@ describe('app', () => {
|
||||
swcJestConfig.swcrc = false;
|
||||
|
||||
export default {
|
||||
displayName: 'my-app',
|
||||
displayName: '@proj/my-app',
|
||||
preset: '../../jest.preset.js',
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
@ -819,7 +841,7 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
expect(
|
||||
readProjectConfiguration(tree, 'my-app').targets.build.options
|
||||
readProjectConfiguration(tree, '@proj/my-app').targets.build.options
|
||||
.outputPath
|
||||
).toBe('apps/my-app/dist');
|
||||
});
|
||||
@ -833,7 +855,7 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
expect(
|
||||
readProjectConfiguration(tree, 'my-app').targets.build.options
|
||||
readProjectConfiguration(tree, '@proj/my-app').targets.build.options
|
||||
.outputPath
|
||||
).toBe('apps/my-app/dist');
|
||||
});
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
addProjectConfiguration,
|
||||
@ -24,7 +23,7 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { configurationGenerator } from '@nx/jest';
|
||||
import {
|
||||
@ -62,10 +61,11 @@ import {
|
||||
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { sortPackageJsonFields } from '@nx/js/src/utils/package-json/sort-fields';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
export interface NormalizedSchema extends Omit<Schema, 'useTsSolution'> {
|
||||
appProjectRoot: string;
|
||||
parsedTags: string[];
|
||||
outputPath: string;
|
||||
importPath: string;
|
||||
isUsingTsSolutionConfig: boolean;
|
||||
}
|
||||
|
||||
@ -208,13 +208,11 @@ function addProject(tree: Tree, options: NormalizedSchema) {
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
writeJson(tree, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||
name: getImportPath(tree, options.name),
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
sourceRoot: project.sourceRoot,
|
||||
name: options.name !== options.importPath ? options.name : undefined,
|
||||
targets: project.targets,
|
||||
tags: project.tags?.length ? project.tags : undefined,
|
||||
},
|
||||
@ -515,6 +513,12 @@ export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
||||
addAppFiles(tree, options);
|
||||
addProject(tree, options);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
|
||||
}
|
||||
|
||||
updateTsConfigOptions(tree, options);
|
||||
|
||||
if (options.linter === Linter.EsLint) {
|
||||
@ -595,12 +599,6 @@ export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
||||
);
|
||||
}
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(tree, options.appProjectRoot);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
@ -618,9 +616,12 @@ async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(host, options, 'application');
|
||||
const { projectName: appProjectName, projectRoot: appProjectRoot } =
|
||||
await determineProjectNameAndRootOptions(host, {
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const {
|
||||
projectName,
|
||||
projectRoot: appProjectRoot,
|
||||
importPath,
|
||||
} = await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
directory: options.directory,
|
||||
@ -643,6 +644,9 @@ async function normalizeOptions(
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
const swcJest = options.swcJest ?? isUsingTsSolutionConfig;
|
||||
|
||||
const appProjectName =
|
||||
!isUsingTsSolutionConfig || options.name ? projectName : importPath;
|
||||
|
||||
return {
|
||||
addPlugin,
|
||||
...options,
|
||||
@ -651,6 +655,7 @@ async function normalizeOptions(
|
||||
? names(options.frontendProject).fileName
|
||||
: undefined,
|
||||
appProjectRoot,
|
||||
importPath,
|
||||
parsedTags,
|
||||
linter: options.linter ?? Linter.EsLint,
|
||||
unitTestRunner: options.unitTestRunner ?? 'jest',
|
||||
@ -660,7 +665,7 @@ async function normalizeOptions(
|
||||
? joinPathFragments(appProjectRoot, 'dist')
|
||||
: joinPathFragments(
|
||||
'dist',
|
||||
options.rootProject ? options.name : appProjectRoot
|
||||
options.rootProject ? appProjectName : appProjectRoot
|
||||
),
|
||||
isUsingTsSolutionConfig,
|
||||
swcJest,
|
||||
|
||||
@ -176,7 +176,7 @@ describe('e2eProjectGenerator', () => {
|
||||
});
|
||||
await e2eProjectGenerator(tree, {
|
||||
projectType: 'server',
|
||||
project: 'api',
|
||||
project: '@proj/api',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
@ -217,7 +217,7 @@ describe('e2eProjectGenerator', () => {
|
||||
});
|
||||
await e2eProjectGenerator(tree, {
|
||||
projectType: 'server',
|
||||
project: 'api',
|
||||
project: '@proj/api',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
@ -285,7 +285,7 @@ describe('e2eProjectGenerator', () => {
|
||||
});
|
||||
await e2eProjectGenerator(tree, {
|
||||
projectType: 'cli',
|
||||
project: 'cli',
|
||||
project: '@proj/cli',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
|
||||
@ -34,7 +34,6 @@ import {
|
||||
addProjectToTsSolutionWorkspace,
|
||||
isUsingTsSolutionSetup,
|
||||
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
import { relative } from 'node:path/posix';
|
||||
import { addSwcTestConfig } from '@nx/js/src/utils/swc/add-swc-config';
|
||||
|
||||
@ -57,17 +56,19 @@ export async function e2eProjectGeneratorInternal(
|
||||
// TODO(@ndcunningham): This is broken.. the outputs are wrong.. and this isn't using the jest generator
|
||||
if (isUsingTsSolutionConfig) {
|
||||
writeJson(host, joinPathFragments(options.e2eProjectRoot, 'package.json'), {
|
||||
name: getImportPath(host, options.e2eProjectName),
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
name: options.e2eProjectName,
|
||||
projectType: 'application',
|
||||
name:
|
||||
options.e2eProjectName !== options.importPath
|
||||
? options.e2eProjectName
|
||||
: undefined,
|
||||
implicitDependencies: [options.project],
|
||||
targets: {
|
||||
e2e: {
|
||||
executor: '@nx/jest:jest',
|
||||
outputs: ['{workspaceRoot}/coverage/{e2eProjectRoot}'],
|
||||
outputs: ['{projectRoot}/test-output/jest/coverage'],
|
||||
options: {
|
||||
jestConfig: `${options.e2eProjectRoot}/jest.config.ts`,
|
||||
passWithNoTests: true,
|
||||
@ -131,6 +132,7 @@ export async function e2eProjectGeneratorInternal(
|
||||
const coverageDirectory = isUsingTsSolutionConfig
|
||||
? 'test-output/jest/coverage'
|
||||
: joinPathFragments(rootOffset, 'coverage', options.e2eProjectName);
|
||||
const projectSimpleName = options.project.split('/').pop();
|
||||
if (options.projectType === 'server') {
|
||||
generateFiles(
|
||||
host,
|
||||
@ -138,7 +140,7 @@ export async function e2eProjectGeneratorInternal(
|
||||
options.e2eProjectRoot,
|
||||
{
|
||||
...options,
|
||||
...names(options.rootProject ? 'server' : options.project),
|
||||
...names(options.rootProject ? 'server' : projectSimpleName),
|
||||
tsConfigFile,
|
||||
offsetFromRoot: rootOffset,
|
||||
jestPreset,
|
||||
@ -155,7 +157,7 @@ export async function e2eProjectGeneratorInternal(
|
||||
options.e2eProjectRoot,
|
||||
{
|
||||
...options,
|
||||
...names(options.rootProject ? 'server' : options.project),
|
||||
...names(options.rootProject ? 'server' : projectSimpleName),
|
||||
tsConfigFile,
|
||||
offsetFromRoot: rootOffset,
|
||||
tmpl: '',
|
||||
@ -170,7 +172,7 @@ export async function e2eProjectGeneratorInternal(
|
||||
options.e2eProjectRoot,
|
||||
{
|
||||
...options,
|
||||
...names(options.rootProject ? 'cli' : options.project),
|
||||
...names(options.rootProject ? 'cli' : projectSimpleName),
|
||||
mainFile,
|
||||
tsConfigFile,
|
||||
offsetFromRoot: rootOffset,
|
||||
@ -275,14 +277,25 @@ async function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: Schema
|
||||
): Promise<
|
||||
Omit<Schema, 'name'> & { e2eProjectRoot: string; e2eProjectName: string }
|
||||
Omit<Schema, 'name'> & {
|
||||
e2eProjectRoot: string;
|
||||
e2eProjectName: string;
|
||||
importPath: string;
|
||||
}
|
||||
> {
|
||||
options.directory = options.directory ?? `${options.project}-e2e`;
|
||||
const { projectName: e2eProjectName, projectRoot: e2eProjectRoot } =
|
||||
await determineProjectNameAndRootOptions(tree, {
|
||||
let directory = options.rootProject ? 'e2e' : options.directory;
|
||||
if (!directory) {
|
||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||
directory = `${projectConfig.root}-e2e`;
|
||||
}
|
||||
const {
|
||||
projectName: e2eProjectName,
|
||||
projectRoot: e2eProjectRoot,
|
||||
importPath,
|
||||
} = await determineProjectNameAndRootOptions(tree, {
|
||||
name: options.name,
|
||||
projectType: 'library',
|
||||
directory: options.rootProject ? 'e2e' : options.directory,
|
||||
projectType: 'application',
|
||||
directory,
|
||||
});
|
||||
|
||||
const nxJson = readNxJson(tree);
|
||||
@ -295,6 +308,7 @@ async function normalizeOptions(
|
||||
...options,
|
||||
e2eProjectRoot,
|
||||
e2eProjectName,
|
||||
importPath,
|
||||
port: options.port ?? 3000,
|
||||
rootProject: !!options.rootProject,
|
||||
};
|
||||
|
||||
@ -519,6 +519,7 @@ describe('lib', () => {
|
||||
expect(tree.exists('my-dir/my-lib/src/lib/my-lib.spec.js')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('TS solution setup', () => {
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
@ -700,5 +701,45 @@ describe('lib', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
directory: 'mylib',
|
||||
name: 'my-lib',
|
||||
linter: 'none',
|
||||
unitTestRunner: 'none',
|
||||
addPlugin: true,
|
||||
skipFormat: true,
|
||||
} as Schema);
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json').nx).toStrictEqual({
|
||||
name: 'my-lib',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the provided name matches the package name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
directory: 'mylib',
|
||||
name: '@proj/my-lib',
|
||||
linter: 'none',
|
||||
unitTestRunner: 'none',
|
||||
addPlugin: true,
|
||||
skipFormat: true,
|
||||
} as Schema);
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the user does not provide a name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
directory: 'mylib',
|
||||
linter: 'none',
|
||||
unitTestRunner: 'none',
|
||||
addPlugin: true,
|
||||
skipFormat: true,
|
||||
} as Schema);
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -19,7 +19,7 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
||||
import { addSwcConfig } from '@nx/js/src/utils/swc/add-swc-config';
|
||||
@ -33,7 +33,6 @@ import {
|
||||
addProjectToTsSolutionWorkspace,
|
||||
isUsingTsSolutionSetup,
|
||||
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
import { sortPackageJsonFields } from '@nx/js/src/utils/package-json/sort-fields';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
@ -76,7 +75,7 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
||||
options.buildable
|
||||
) {
|
||||
writeJson(tree, joinPathFragments(options.projectRoot, 'package.json'), {
|
||||
name: getImportPath(tree, options.name),
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
|
||||
@ -134,7 +133,7 @@ async function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(tree, options, 'library');
|
||||
await ensureRootProjectName(options, 'library');
|
||||
const {
|
||||
projectName,
|
||||
names: projectNames,
|
||||
@ -168,9 +167,8 @@ async function normalizeOptions(
|
||||
return {
|
||||
...options,
|
||||
fileName,
|
||||
projectName: isUsingTsSolutionConfig
|
||||
? getImportPath(tree, projectName)
|
||||
: projectName,
|
||||
projectName:
|
||||
isUsingTsSolutionConfig && !options.name ? importPath : projectName,
|
||||
projectRoot,
|
||||
parsedTags,
|
||||
importPath,
|
||||
|
||||
@ -255,14 +255,15 @@ describe('app', () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
const packageJson = readJson(tree, 'myapp/package.json');
|
||||
expect(packageJson.name).toBe('@proj/myapp');
|
||||
expect(packageJson.nx).toBeUndefined();
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(readJson(tree, 'myapp/package.json')))
|
||||
.toMatchInlineSnapshot(`
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
expect(readJson(tree, 'myapp/tsconfig.json')).toMatchInlineSnapshot(`
|
||||
@ -386,5 +387,28 @@ describe('app', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should respect the provided name', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
directory: 'myapp',
|
||||
name: 'myapp',
|
||||
e2eTestRunner: 'playwright',
|
||||
unitTestRunner: 'vitest',
|
||||
linter: 'eslint',
|
||||
});
|
||||
|
||||
const packageJson = readJson(tree, 'myapp/package.json');
|
||||
expect(packageJson.name).toBe('@proj/myapp');
|
||||
expect(packageJson.nx.name).toBe('myapp');
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -32,12 +32,12 @@ import {
|
||||
getNxCloudAppOnBoardingUrl,
|
||||
createNxCloudOnboardingURLForWelcomeApp,
|
||||
} from 'nx/src/nx-cloud/utilities/onboarding';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
import {
|
||||
addProjectToTsSolutionWorkspace,
|
||||
updateTsconfigFiles,
|
||||
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { sortPackageJsonFields } from '@nx/js/src/utils/package-json/sort-fields';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
@ -67,17 +67,25 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||
tasks.push(ensureDependencies(tree, options));
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
writeJson(tree, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||
name: getImportPath(tree, options.name),
|
||||
const packageJson: PackageJson = {
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
sourceRoot: `${options.appProjectRoot}/src`,
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (options.projectName !== options.importPath) {
|
||||
packageJson.nx = { name: options.projectName };
|
||||
}
|
||||
if (options.parsedTags?.length) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.tags = options.parsedTags;
|
||||
}
|
||||
|
||||
writeJson(
|
||||
tree,
|
||||
joinPathFragments(options.appProjectRoot, 'package.json'),
|
||||
packageJson
|
||||
);
|
||||
} else {
|
||||
addProjectConfiguration(tree, options.projectName, {
|
||||
root: options.appProjectRoot,
|
||||
@ -140,6 +148,12 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||
|
||||
updateGitIgnore(tree);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
|
||||
}
|
||||
|
||||
tasks.push(
|
||||
await addLinting(tree, {
|
||||
projectName: options.projectName,
|
||||
@ -193,12 +207,6 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||
);
|
||||
}
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(tree, options.appProjectRoot);
|
||||
|
||||
if (!options.skipFormat) await formatFiles(tree);
|
||||
|
||||
@ -34,8 +34,6 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
projectType: 'application',
|
||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||
implicitDependencies: [options.projectName],
|
||||
},
|
||||
}
|
||||
@ -106,8 +104,6 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
projectType: 'application',
|
||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||
implicitDependencies: [options.projectName],
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { names, Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { NormalizedSchema, Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
@ -10,9 +10,13 @@ export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(host, options, 'application');
|
||||
const { projectName: appProjectName, projectRoot: appProjectRoot } =
|
||||
await determineProjectNameAndRootOptions(host, {
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const {
|
||||
projectName,
|
||||
names: projectNames,
|
||||
projectRoot: appProjectRoot,
|
||||
importPath,
|
||||
} = await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
directory: options.directory,
|
||||
@ -20,6 +24,10 @@ export async function normalizeOptions(
|
||||
});
|
||||
options.rootProject = appProjectRoot === '.';
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
const appProjectName =
|
||||
!isUsingTsSolutionConfig || options.name ? projectName : importPath;
|
||||
|
||||
const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||
const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
||||
|
||||
@ -29,14 +37,15 @@ export async function normalizeOptions(
|
||||
|
||||
const normalized = {
|
||||
...options,
|
||||
name: names(options.name).fileName,
|
||||
name: projectNames.projectFileName,
|
||||
projectName: appProjectName,
|
||||
appProjectRoot,
|
||||
importPath,
|
||||
e2eProjectName,
|
||||
e2eProjectRoot,
|
||||
parsedTags,
|
||||
style: options.style ?? 'none',
|
||||
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||
isUsingTsSolutionConfig,
|
||||
} as NormalizedSchema;
|
||||
|
||||
normalized.unitTestRunner ??= 'vitest';
|
||||
|
||||
@ -18,9 +18,10 @@ export interface Schema {
|
||||
useTsSolution?: boolean;
|
||||
}
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
export interface NormalizedSchema extends Omit<Schema, 'useTsSolution'> {
|
||||
projectName: string;
|
||||
appProjectRoot: string;
|
||||
importPath: string;
|
||||
e2eProjectName: string;
|
||||
e2eProjectRoot: string;
|
||||
parsedTags: string[];
|
||||
|
||||
@ -65,7 +65,6 @@ describe('Workspaces', () => {
|
||||
},
|
||||
"name": "my-package",
|
||||
"root": "packages/my-package",
|
||||
"sourceRoot": "packages/my-package",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
|
||||
@ -69,7 +69,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "root",
|
||||
"root": ".",
|
||||
"sourceRoot": ".",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
@ -123,7 +122,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "lib-a",
|
||||
"root": "packages/lib-a",
|
||||
"sourceRoot": "packages/lib-a",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
@ -185,7 +183,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "lib-b",
|
||||
"root": "packages/lib-b",
|
||||
"sourceRoot": "packages/lib-b",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
@ -290,7 +287,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "vite",
|
||||
"root": "packages/vite",
|
||||
"sourceRoot": "packages/vite",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
@ -394,7 +390,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "vite",
|
||||
"root": "packages/vite",
|
||||
"sourceRoot": "packages/vite",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
@ -494,7 +489,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "vite",
|
||||
"root": "packages/vite",
|
||||
"sourceRoot": "packages/vite",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
@ -582,7 +576,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "root",
|
||||
"root": "packages/a",
|
||||
"sourceRoot": "packages/a",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
@ -667,7 +660,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "root",
|
||||
"root": "packages/a",
|
||||
"sourceRoot": "packages/a",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
@ -753,7 +745,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "root",
|
||||
"root": "packages/a",
|
||||
"sourceRoot": "packages/a",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
@ -939,7 +930,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "lib-a",
|
||||
"root": "packages/lib-a",
|
||||
"sourceRoot": "packages/lib-a",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
@ -990,7 +980,6 @@ describe('nx package.json workspaces plugin', () => {
|
||||
},
|
||||
"name": "lib-b",
|
||||
"root": "libs/lib-b",
|
||||
"sourceRoot": "libs/lib-b",
|
||||
"tags": [
|
||||
"npm:public",
|
||||
],
|
||||
|
||||
@ -143,6 +143,9 @@ export function createNodeFromPackageJson(
|
||||
...json,
|
||||
root: projectRoot,
|
||||
isInPackageManagerWorkspaces,
|
||||
// change this to bust the cache when making changes that result in different
|
||||
// results for the same hash
|
||||
bust: 1,
|
||||
});
|
||||
|
||||
const cached = cache[hash];
|
||||
@ -209,7 +212,6 @@ export function buildProjectConfigurationFromPackageJson(
|
||||
|
||||
const projectConfiguration: ProjectConfiguration & { name: string } = {
|
||||
root: projectRoot,
|
||||
sourceRoot: projectRoot,
|
||||
name,
|
||||
...packageJson.nx,
|
||||
targets: readTargetsFromPackageJson(packageJson, nxJson),
|
||||
|
||||
@ -179,10 +179,10 @@ export async function configurationGeneratorInternal(
|
||||
name: importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
name: options.project,
|
||||
},
|
||||
};
|
||||
if (options.project !== importPath) {
|
||||
packageJson.nx = { name: options.project };
|
||||
}
|
||||
writeJson(tree, packageJsonPath, packageJson);
|
||||
}
|
||||
|
||||
|
||||
@ -17,10 +17,7 @@ import {
|
||||
type ProjectConfiguration,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
resolveImportPath,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { LinterType, lintProjectGenerator } from '@nx/eslint';
|
||||
import { addPropertyToJestConfig, configurationGenerator } from '@nx/jest';
|
||||
import { getRelativePathToRootTsConfig } from '@nx/js';
|
||||
@ -106,12 +103,14 @@ function addFiles(host: Tree, options: NormalizedSchema) {
|
||||
join(projectConfiguration.root, 'package.json')
|
||||
);
|
||||
|
||||
const simplePluginName = options.pluginName.split('/').pop();
|
||||
generateFiles(host, join(__dirname, './files'), options.projectRoot, {
|
||||
...options,
|
||||
tmpl: '',
|
||||
rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot),
|
||||
packageManagerCommands: getPackageManagerCommand(),
|
||||
pluginPackageName,
|
||||
simplePluginName,
|
||||
});
|
||||
}
|
||||
|
||||
@ -129,7 +128,7 @@ async function addJest(host: Tree, options: NormalizedSchema) {
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, 'package.json'),
|
||||
{
|
||||
name: resolveImportPath(host, options.projectName, options.projectRoot),
|
||||
name: options.projectName,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
}
|
||||
|
||||
@ -354,6 +354,7 @@ describe('NxPlugin Plugin Generator', () => {
|
||||
getSchema({
|
||||
directory: 'my-plugin',
|
||||
unitTestRunner: 'jest',
|
||||
useProjectJson: false,
|
||||
})
|
||||
);
|
||||
|
||||
@ -530,5 +531,50 @@ describe('NxPlugin Plugin Generator', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name and "useProjectJson" is "false"', async () => {
|
||||
await pluginGenerator(tree, {
|
||||
directory: 'my-plugin',
|
||||
name: 'my-plugin', // import path contains the npm scope, so it would be different
|
||||
useProjectJson: false,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'my-plugin/package.json').nx.name).toBe(
|
||||
'my-plugin'
|
||||
);
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the provided name matches the package name', async () => {
|
||||
await pluginGenerator(tree, {
|
||||
directory: 'my-plugin',
|
||||
name: '@proj/my-plugin',
|
||||
useProjectJson: false,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'my-plugin/package.json').nx.name).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not set "nx" in package.json when "useProjectJson" is "true"', async () => {
|
||||
await pluginGenerator(tree, {
|
||||
directory: 'my-plugin',
|
||||
name: '@proj/my-plugin',
|
||||
useProjectJson: true,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'my-plugin/package.json').nx).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the user does not provide a name', async () => {
|
||||
await pluginGenerator(tree, {
|
||||
directory: 'my-plugin',
|
||||
useProjectJson: false,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'my-plugin/package.json').nx.name).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -94,7 +94,7 @@ export async function pluginGeneratorInternal(host: Tree, schema: Schema) {
|
||||
config: 'project',
|
||||
bundler: options.bundler,
|
||||
publishable: options.publishable,
|
||||
importPath: options.npmPackageName,
|
||||
importPath: options.importPath,
|
||||
linter: options.linter,
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
useProjectJson: options.useProjectJson,
|
||||
@ -149,9 +149,9 @@ export async function pluginGeneratorInternal(host: Tree, schema: Schema) {
|
||||
projectDirectory: options.projectDirectory,
|
||||
pluginOutputPath: joinPathFragments(
|
||||
'dist',
|
||||
options.rootProject ? options.name : options.projectRoot
|
||||
options.rootProject ? options.projectName : options.projectRoot
|
||||
),
|
||||
npmPackageName: options.npmPackageName,
|
||||
npmPackageName: options.importPath,
|
||||
skipFormat: true,
|
||||
rootProject: options.rootProject,
|
||||
linter: options.linter,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { readNxJson, type Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import type { LinterType } from '@nx/eslint';
|
||||
import {
|
||||
@ -10,16 +10,14 @@ import {
|
||||
} from '@nx/js/src/utils/generator-prompts';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import type { Schema } from '../schema';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
name: string;
|
||||
projectName: string;
|
||||
fileName: string;
|
||||
projectRoot: string;
|
||||
projectDirectory: string;
|
||||
parsedTags: string[];
|
||||
npmPackageName: string;
|
||||
importPath: string;
|
||||
bundler: 'swc' | 'tsc';
|
||||
publishable: boolean;
|
||||
unitTestRunner: 'jest' | 'vitest' | 'none';
|
||||
@ -48,12 +46,9 @@ export async function normalizeOptions(
|
||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
nxJson.useInferencePlugins !== false);
|
||||
|
||||
await ensureProjectName(host, options, 'application');
|
||||
const {
|
||||
projectName,
|
||||
projectRoot,
|
||||
importPath: npmPackageName,
|
||||
} = await determineProjectNameAndRootOptions(host, {
|
||||
await ensureRootProjectName(options, 'library');
|
||||
const { projectName, projectRoot, importPath } =
|
||||
await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
projectType: 'library',
|
||||
directory: options.directory,
|
||||
@ -72,14 +67,11 @@ export async function normalizeOptions(
|
||||
...options,
|
||||
bundler: options.compiler ?? 'tsc',
|
||||
fileName: projectName,
|
||||
name: projectName,
|
||||
projectName: isTsSolutionSetup
|
||||
? getImportPath(host, projectName)
|
||||
: projectName,
|
||||
projectName: isTsSolutionSetup && !options.name ? importPath : projectName,
|
||||
projectRoot,
|
||||
projectDirectory,
|
||||
parsedTags,
|
||||
npmPackageName,
|
||||
importPath,
|
||||
publishable: options.publishable ?? false,
|
||||
linter,
|
||||
unitTestRunner,
|
||||
|
||||
@ -253,8 +253,10 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
describe('TS solution setup', () => {
|
||||
it('should add project references when using TS solution', async () => {
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
tree.write('.gitignore', '');
|
||||
updateJson(tree, 'package.json', (json) => {
|
||||
json.workspaces = ['packages/*', 'apps/*'];
|
||||
@ -271,7 +273,9 @@ describe('app', () => {
|
||||
files: [],
|
||||
references: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should add project references when using TS solution', async () => {
|
||||
await reactNativeApplicationGenerator(tree, {
|
||||
directory: 'my-app',
|
||||
displayName: 'myApp',
|
||||
@ -291,9 +295,11 @@ describe('app', () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
const packageJson = readJson(tree, 'my-app/package.json');
|
||||
expect(packageJson.name).toBe('@proj/my-app');
|
||||
expect(packageJson.nx.name).toBeUndefined();
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(readJson(tree, 'my-app/package.json')))
|
||||
.toMatchInlineSnapshot(`
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
@ -403,5 +409,33 @@ describe('app', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should respect the provided name', async () => {
|
||||
await reactNativeApplicationGenerator(tree, {
|
||||
directory: 'my-app',
|
||||
name: 'my-app',
|
||||
displayName: 'myApp',
|
||||
tags: 'one,two',
|
||||
linter: Linter.EsLint,
|
||||
e2eTestRunner: 'none',
|
||||
install: false,
|
||||
unitTestRunner: 'jest',
|
||||
bundler: 'vite',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
const packageJson = readJson(tree, 'my-app/package.json');
|
||||
expect(packageJson.name).toBe('@proj/my-app');
|
||||
expect(packageJson.nx.name).toBe('my-app');
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -66,6 +66,12 @@ export async function reactNativeApplicationGeneratorInternal(
|
||||
await createApplicationFiles(host, options);
|
||||
addProject(host, options);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isTsSolutionSetup) {
|
||||
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
|
||||
}
|
||||
|
||||
const lintTask = await addLinting(host, {
|
||||
...options,
|
||||
projectRoot: options.appProjectRoot,
|
||||
@ -149,12 +155,6 @@ export async function reactNativeApplicationGeneratorInternal(
|
||||
: undefined
|
||||
);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.useTsSolution) {
|
||||
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(host, options.appProjectRoot);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { addE2e as addE2eReact } from '@nx/react/src/generators/application/lib/add-e2e';
|
||||
import { GeneratorCallback, Tree, ensurePackage } from '@nx/devkit';
|
||||
import { GeneratorCallback, Tree, ensurePackage, names } from '@nx/devkit';
|
||||
|
||||
import { nxVersion } from '../../../utils/versions';
|
||||
|
||||
@ -18,6 +18,7 @@ export async function addE2e(
|
||||
styledModule: null,
|
||||
hasStyles: false,
|
||||
unitTestRunner: 'none',
|
||||
names: names(options.name),
|
||||
});
|
||||
case 'playwright':
|
||||
return addE2eReact(host, {
|
||||
@ -27,6 +28,7 @@ export async function addE2e(
|
||||
styledModule: null,
|
||||
hasStyles: false,
|
||||
unitTestRunner: 'none',
|
||||
names: names(options.name),
|
||||
});
|
||||
case 'detox':
|
||||
const { detoxApplicationGenerator } = ensurePackage<
|
||||
|
||||
@ -9,7 +9,7 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import { NormalizedSchema } from './normalize-options';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
const nxJson = readNxJson(host);
|
||||
@ -28,15 +28,29 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
};
|
||||
|
||||
if (isUsingTsSolutionSetup(host)) {
|
||||
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||
name: options.projectName,
|
||||
const packageJson: PackageJson = {
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
targets: hasPlugin ? {} : getTargets(options),
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (options.projectName !== options.importPath) {
|
||||
packageJson.nx = { name: options.projectName };
|
||||
}
|
||||
if (!hasPlugin) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.targets = getTargets(options);
|
||||
}
|
||||
if (options.parsedTags?.length) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.tags = options.parsedTags;
|
||||
}
|
||||
|
||||
writeJson(
|
||||
host,
|
||||
joinPathFragments(options.appProjectRoot, 'package.json'),
|
||||
packageJson
|
||||
);
|
||||
} else {
|
||||
addProjectConfiguration(host, options.projectName, {
|
||||
...project,
|
||||
|
||||
@ -25,6 +25,7 @@ describe('Normalize Options', () => {
|
||||
addPlugin: true,
|
||||
androidProjectRoot: 'my-app/android',
|
||||
appProjectRoot: 'my-app',
|
||||
importPath: '@proj/my-app',
|
||||
fileName: 'my-app',
|
||||
className: 'MyApp',
|
||||
directory: 'my-app',
|
||||
@ -61,6 +62,7 @@ describe('Normalize Options', () => {
|
||||
addPlugin: true,
|
||||
androidProjectRoot: 'myApp/android',
|
||||
appProjectRoot: 'myApp',
|
||||
importPath: '@proj/myApp',
|
||||
className: 'MyApp',
|
||||
fileName: 'my-app',
|
||||
directory: 'myApp',
|
||||
@ -98,6 +100,7 @@ describe('Normalize Options', () => {
|
||||
addPlugin: true,
|
||||
androidProjectRoot: 'directory/my-app/android',
|
||||
appProjectRoot: 'directory/my-app',
|
||||
importPath: '@proj/my-app',
|
||||
className: 'MyApp',
|
||||
fileName: 'my-app',
|
||||
directory: 'directory/my-app',
|
||||
@ -134,6 +137,7 @@ describe('Normalize Options', () => {
|
||||
addPlugin: true,
|
||||
androidProjectRoot: 'directory/my-app/android',
|
||||
appProjectRoot: 'directory/my-app',
|
||||
importPath: '@proj/my-app',
|
||||
className: 'MyApp',
|
||||
directory: 'directory/my-app',
|
||||
fileName: 'my-app',
|
||||
@ -171,6 +175,7 @@ describe('Normalize Options', () => {
|
||||
addPlugin: true,
|
||||
androidProjectRoot: 'my-app/android',
|
||||
appProjectRoot: 'my-app',
|
||||
importPath: '@proj/my-app',
|
||||
className: 'MyApp',
|
||||
fileName: 'my-app',
|
||||
directory: 'my-app',
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
import { joinPathFragments, names, readNxJson, Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
export interface NormalizedSchema extends Omit<Schema, 'useTsSolution'> {
|
||||
className: string; // app name in class case
|
||||
fileName: string; // app name in file class
|
||||
projectName: string; // directory + app name, case based on user input
|
||||
@ -20,6 +19,7 @@ export interface NormalizedSchema extends Schema {
|
||||
rootProject: boolean;
|
||||
e2eProjectName: string;
|
||||
e2eProjectRoot: string;
|
||||
importPath: string;
|
||||
isTsSolutionSetup: boolean;
|
||||
}
|
||||
|
||||
@ -27,11 +27,12 @@ export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(host, options, 'application');
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const {
|
||||
projectName: appProjectName,
|
||||
projectName,
|
||||
names: projectNames,
|
||||
projectRoot: appProjectRoot,
|
||||
importPath,
|
||||
} = await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
@ -43,11 +44,15 @@ export async function normalizeOptions(
|
||||
nxJson.useInferencePlugins !== false;
|
||||
options.addPlugin ??= addPluginDefault;
|
||||
|
||||
const { className, fileName } = names(options.name);
|
||||
const { className, fileName } = names(projectNames.projectSimpleName);
|
||||
const iosProjectRoot = joinPathFragments(appProjectRoot, 'ios');
|
||||
const androidProjectRoot = joinPathFragments(appProjectRoot, 'android');
|
||||
const rootProject = appProjectRoot === '.';
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(host);
|
||||
const appProjectName =
|
||||
!isTsSolutionSetup || options.name ? projectName : importPath;
|
||||
|
||||
const e2eProjectName = rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||
const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
||||
|
||||
@ -57,8 +62,6 @@ export async function normalizeOptions(
|
||||
|
||||
const entryFile = options.js ? 'src/main.js' : 'src/main.tsx';
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(host);
|
||||
|
||||
return {
|
||||
...options,
|
||||
name: projectNames.projectSimpleName,
|
||||
@ -66,10 +69,9 @@ export async function normalizeOptions(
|
||||
fileName,
|
||||
lowerCaseName: className.toLowerCase(),
|
||||
displayName: options.displayName || className,
|
||||
projectName: isTsSolutionSetup
|
||||
? getImportPath(host, appProjectName)
|
||||
: appProjectName,
|
||||
projectName: appProjectName,
|
||||
appProjectRoot,
|
||||
importPath,
|
||||
iosProjectRoot,
|
||||
androidProjectRoot,
|
||||
parsedTags,
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { readNxJson, Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
name: string;
|
||||
fileName: string;
|
||||
projectRoot: string;
|
||||
importPath: string;
|
||||
routePath: string;
|
||||
parsedTags: string[];
|
||||
appMain?: string;
|
||||
@ -22,7 +22,7 @@ export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
await ensureProjectName(host, options, 'library');
|
||||
await ensureRootProjectName(options, 'library');
|
||||
const {
|
||||
projectName,
|
||||
names: projectNames,
|
||||
@ -50,9 +50,7 @@ export async function normalizeOptions(
|
||||
...options,
|
||||
fileName: projectName,
|
||||
routePath: `/${projectNames.projectSimpleName}`,
|
||||
name: isUsingTsSolutionConfig
|
||||
? options.importPath ?? getImportPath(host, projectName)
|
||||
: projectName,
|
||||
name: isUsingTsSolutionConfig && !options.name ? importPath : projectName,
|
||||
projectRoot,
|
||||
parsedTags,
|
||||
importPath,
|
||||
|
||||
@ -450,7 +450,7 @@ describe('lib', () => {
|
||||
});
|
||||
|
||||
describe('TS solution setup', () => {
|
||||
it('should add project references when using TS solution', async () => {
|
||||
beforeEach(() => {
|
||||
updateJson(appTree, 'package.json', (json) => {
|
||||
json.workspaces = ['packages/*', 'apps/*'];
|
||||
return json;
|
||||
@ -466,7 +466,9 @@ describe('lib', () => {
|
||||
files: [],
|
||||
references: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should add project references when using TS solution', async () => {
|
||||
await libraryGenerator(appTree, {
|
||||
...defaultSchema,
|
||||
});
|
||||
@ -492,7 +494,6 @@ describe('lib', () => {
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"name": "@proj/my-lib",
|
||||
"nx": {},
|
||||
"peerDependencies": {
|
||||
"react": "~18.3.1",
|
||||
"react-native": "~0.76.3",
|
||||
@ -593,5 +594,39 @@ describe('lib', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||
await libraryGenerator(appTree, {
|
||||
...defaultSchema,
|
||||
directory: 'my-lib',
|
||||
name: 'my-lib', // import path contains the npm scope, so it would be different
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(appTree, 'my-lib/package.json').nx).toStrictEqual({
|
||||
name: 'my-lib',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the provided name matches the package name', async () => {
|
||||
await libraryGenerator(appTree, {
|
||||
...defaultSchema,
|
||||
directory: 'my-lib',
|
||||
name: '@proj/my-lib',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(appTree, 'my-lib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the user does not provide a name', async () => {
|
||||
await libraryGenerator(appTree, {
|
||||
...defaultSchema,
|
||||
directory: 'my-lib',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(appTree, 'my-lib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -87,6 +87,10 @@ export async function reactNativeLibraryGeneratorInternal(
|
||||
tasks.push(addProjectTask);
|
||||
}
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(host, options.projectRoot);
|
||||
}
|
||||
|
||||
const lintTask = await addLinting(host, {
|
||||
...options,
|
||||
projectName: options.name,
|
||||
@ -146,10 +150,6 @@ export async function reactNativeLibraryGeneratorInternal(
|
||||
: undefined
|
||||
);
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(host, options.projectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(host, options.projectRoot);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
@ -181,19 +181,30 @@ async function addProject(
|
||||
};
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
writeJson(host, joinPathFragments(options.projectRoot, 'package.json'), {
|
||||
name: options.name,
|
||||
const packageJson: PackageJson = {
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
...determineEntryFields(options),
|
||||
nx: {
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
|
||||
peerDependencies: {
|
||||
react: reactVersion,
|
||||
'react-native': reactNativeVersion,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (options.name !== options.importPath) {
|
||||
packageJson.nx = { name: options.name };
|
||||
}
|
||||
if (options.parsedTags?.length) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.tags = options.parsedTags;
|
||||
}
|
||||
|
||||
writeJson(
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, 'package.json'),
|
||||
packageJson
|
||||
);
|
||||
} else {
|
||||
addProjectConfiguration(host, options.name, project);
|
||||
}
|
||||
|
||||
@ -1330,9 +1330,11 @@ describe('app', () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
const packageJson = readJson(appTree, 'myapp/package.json');
|
||||
expect(packageJson.name).toBe('@proj/myapp');
|
||||
expect(packageJson.nx).toBeUndefined();
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(readJson(appTree, 'myapp/package.json')))
|
||||
.toMatchInlineSnapshot(`
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
@ -1473,6 +1475,32 @@ describe('app', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should respect the provided name', async () => {
|
||||
await applicationGenerator(appTree, {
|
||||
directory: 'myapp',
|
||||
name: 'myapp',
|
||||
addPlugin: true,
|
||||
linter: Linter.EsLint,
|
||||
style: 'none',
|
||||
bundler: 'vite',
|
||||
unitTestRunner: 'vitest',
|
||||
e2eTestRunner: 'playwright',
|
||||
});
|
||||
|
||||
const packageJson = readJson(appTree, 'myapp/package.json');
|
||||
expect(packageJson.name).toBe('@proj/myapp');
|
||||
expect(packageJson.nx.name).toBe('myapp');
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should add project to workspaces when using TS solution (npm, yarn, bun)', async () => {
|
||||
await applicationGenerator(appTree, {
|
||||
directory: 'myapp',
|
||||
|
||||
@ -111,8 +111,6 @@ export async function addE2e(
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
projectType: 'application',
|
||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||
implicitDependencies: [options.projectName],
|
||||
},
|
||||
}
|
||||
@ -209,8 +207,6 @@ export async function addE2e(
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
projectType: 'application',
|
||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||
implicitDependencies: [options.projectName],
|
||||
},
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
import { hasWebpackPlugin } from '../../../utils/has-webpack-plugin';
|
||||
import { maybeJs } from '../../../utils/maybe-js';
|
||||
import { hasRspackPlugin } from '../../../utils/has-rspack-plugin';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
const project: ProjectConfiguration = {
|
||||
@ -39,11 +40,29 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
}
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||
name: options.projectName,
|
||||
const packageJson: PackageJson = {
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
});
|
||||
};
|
||||
|
||||
if (options.projectName !== options.importPath) {
|
||||
packageJson.nx = { name: options.projectName };
|
||||
}
|
||||
if (Object.keys(project.targets).length) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.targets = project.targets;
|
||||
}
|
||||
if (options.parsedTags?.length) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.tags = options.parsedTags;
|
||||
}
|
||||
|
||||
writeJson(
|
||||
host,
|
||||
joinPathFragments(options.appProjectRoot, 'package.json'),
|
||||
packageJson
|
||||
);
|
||||
}
|
||||
|
||||
if (!options.isUsingTsSolutionConfig || options.alwaysGenerateProjectJson) {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import {
|
||||
generateFiles,
|
||||
joinPathFragments,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
toJS,
|
||||
Tree,
|
||||
@ -59,7 +58,7 @@ export async function createApplicationFiles(
|
||||
);
|
||||
const appTests = getAppTests(options);
|
||||
const templateVariables = {
|
||||
...names(options.name),
|
||||
...options.names,
|
||||
...options,
|
||||
js: !!options.js, // Ensure this is defined in template
|
||||
tmpl: '',
|
||||
|
||||
@ -1,33 +1,24 @@
|
||||
import { Tree, extractLayoutDirectory, names, readNxJson } from '@nx/devkit';
|
||||
import { Tree, names, readNxJson } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { assertValidStyle } from '../../../utils/assertion';
|
||||
import { NormalizedSchema, Schema } from '../schema';
|
||||
import { findFreePort } from './find-free-port';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export function normalizeDirectory(options: Schema) {
|
||||
options.directory = options.directory?.replace(/\\{1,2}/g, '/');
|
||||
const { projectDirectory } = extractLayoutDirectory(options.directory);
|
||||
return projectDirectory
|
||||
? `${names(projectDirectory).fileName}/${names(options.name).fileName}`
|
||||
: names(options.name).fileName;
|
||||
}
|
||||
|
||||
export function normalizeProjectName(options: Schema) {
|
||||
return normalizeDirectory(options).replace(new RegExp('/', 'g'), '-');
|
||||
}
|
||||
|
||||
export async function normalizeOptions<T extends Schema = Schema>(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema<T>> {
|
||||
await ensureProjectName(host, options, 'application');
|
||||
const { projectName: appProjectName, projectRoot: appProjectRoot } =
|
||||
await determineProjectNameAndRootOptions(host, {
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const {
|
||||
projectName,
|
||||
names: projectNames,
|
||||
projectRoot: appProjectRoot,
|
||||
importPath,
|
||||
} = await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
directory: options.directory,
|
||||
@ -43,6 +34,10 @@ export async function normalizeOptions<T extends Schema = Schema>(
|
||||
|
||||
options.rootProject = appProjectRoot === '.';
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
const appProjectName =
|
||||
!isUsingTsSolutionConfig || options.name ? projectName : importPath;
|
||||
|
||||
const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||
const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
||||
|
||||
@ -58,20 +53,18 @@ export async function normalizeOptions<T extends Schema = Schema>(
|
||||
|
||||
assertValidStyle(options.style);
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
const normalized = {
|
||||
...options,
|
||||
name: appProjectName,
|
||||
projectName: isUsingTsSolutionConfig
|
||||
? getImportPath(host, appProjectName)
|
||||
: appProjectName,
|
||||
projectName: appProjectName,
|
||||
appProjectRoot,
|
||||
importPath,
|
||||
e2eProjectName,
|
||||
e2eProjectRoot,
|
||||
parsedTags,
|
||||
fileName,
|
||||
styledModule,
|
||||
hasStyles: options.style !== 'none',
|
||||
names: names(projectNames.projectSimpleName),
|
||||
isUsingTsSolutionConfig,
|
||||
} as NormalizedSchema;
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import type { names } from '@nx/devkit';
|
||||
import type { Linter, LinterType } from '@nx/eslint';
|
||||
import type { SupportedStyles } from '../../../typings/style';
|
||||
|
||||
@ -38,11 +39,13 @@ export interface NormalizedSchema<T extends Schema = Schema> extends T {
|
||||
appProjectRoot: string;
|
||||
e2eProjectName: string;
|
||||
e2eProjectRoot: string;
|
||||
importPath: string;
|
||||
parsedTags: string[];
|
||||
fileName: string;
|
||||
styledModule: null | SupportedStyles;
|
||||
hasStyles: boolean;
|
||||
unitTestRunner: 'jest' | 'vitest' | 'none';
|
||||
addPlugin?: boolean;
|
||||
names: ReturnType<typeof names>;
|
||||
isUsingTsSolutionConfig?: boolean;
|
||||
}
|
||||
|
||||
@ -13,10 +13,7 @@ import { Schema } from './schema';
|
||||
|
||||
import { remoteGenerator } from '../remote/remote';
|
||||
import { addPathToExposes, checkRemoteExists } from './lib/utils';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { addTsConfigPath, getRootTsConfigPathInTree } from '@nx/js';
|
||||
|
||||
export async function federateModuleGenerator(tree: Tree, schema: Schema) {
|
||||
|
||||
@ -27,7 +27,7 @@ import {
|
||||
moduleFederationEnhancedVersion,
|
||||
nxVersion,
|
||||
} from '../../utils/versions';
|
||||
import { ensureProjectName } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { ensureRootProjectName } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { updateModuleFederationTsconfig } from './lib/update-module-federation-tsconfig';
|
||||
|
||||
export async function hostGenerator(
|
||||
@ -36,7 +36,10 @@ export async function hostGenerator(
|
||||
): Promise<GeneratorCallback> {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const options: NormalizedSchema = {
|
||||
...(await normalizeOptions<Schema>(host, schema)),
|
||||
...(await normalizeOptions<Schema>(host, {
|
||||
...schema,
|
||||
alwaysGenerateProjectJson: true,
|
||||
})),
|
||||
js: schema.js ?? false,
|
||||
typescriptConfiguration: schema.js
|
||||
? false
|
||||
@ -60,7 +63,7 @@ export async function hostGenerator(
|
||||
});
|
||||
}
|
||||
|
||||
await ensureProjectName(host, options, 'application');
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const initTask = await applicationGenerator(host, {
|
||||
...options,
|
||||
directory: options.appProjectRoot,
|
||||
|
||||
@ -126,7 +126,7 @@ export default defineConfig(() => ({
|
||||
fileName: 'index',
|
||||
// Change this to the formats you want to support.
|
||||
// Don't forget to update your package.json as well.
|
||||
formats: ['es'],
|
||||
formats: ['es' as const],
|
||||
},
|
||||
rollupOptions: {
|
||||
// External packages that should not be bundled into your library.
|
||||
|
||||
@ -8,11 +8,15 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
ensureRootProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { assertValidStyle } from '../../../utils/assertion';
|
||||
import { NormalizedSchema, Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import {
|
||||
getProjectSourceRoot,
|
||||
getProjectType,
|
||||
isUsingTsSolutionSetup,
|
||||
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export async function normalizeOptions(
|
||||
host: Tree,
|
||||
@ -20,7 +24,7 @@ export async function normalizeOptions(
|
||||
): Promise<NormalizedSchema> {
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
|
||||
await ensureProjectName(host, options, 'library');
|
||||
await ensureRootProjectName(options, 'library');
|
||||
const {
|
||||
projectName,
|
||||
names: projectNames,
|
||||
@ -70,7 +74,7 @@ export async function normalizeOptions(
|
||||
bundler,
|
||||
fileName,
|
||||
routePath: `/${projectNames.projectSimpleName}`,
|
||||
name: isUsingTsSolutionConfig ? importPath : projectName,
|
||||
name: isUsingTsSolutionConfig && !options.name ? importPath : projectName,
|
||||
projectRoot,
|
||||
parsedTags,
|
||||
importPath,
|
||||
@ -85,17 +89,28 @@ export async function normalizeOptions(
|
||||
|
||||
if (options.appProject) {
|
||||
const appProjectConfig = getProjects(host).get(options.appProject);
|
||||
const appProjectType = getProjectType(
|
||||
host,
|
||||
appProjectConfig.root,
|
||||
appProjectConfig.projectType
|
||||
);
|
||||
|
||||
if (appProjectConfig.projectType !== 'application') {
|
||||
if (appProjectType !== 'application') {
|
||||
throw new Error(
|
||||
`appProject expected type of "application" but got "${appProjectConfig.projectType}"`
|
||||
`appProject expected type of "application" but got "${appProjectType}"`
|
||||
);
|
||||
}
|
||||
|
||||
const appSourceRoot = getProjectSourceRoot(
|
||||
host,
|
||||
appProjectConfig.sourceRoot,
|
||||
appProjectConfig.root
|
||||
);
|
||||
|
||||
normalized.appMain =
|
||||
appProjectConfig.targets.build?.options?.main ??
|
||||
findMainEntry(host, appProjectConfig.root);
|
||||
normalized.appSourceRoot = normalizePath(appProjectConfig.sourceRoot);
|
||||
normalized.appSourceRoot = normalizePath(appSourceRoot);
|
||||
|
||||
// TODO(jack): We should use appEntryFile instead of appProject so users can directly set it rather than us inferring it.
|
||||
if (!normalized.appMain) {
|
||||
|
||||
@ -988,7 +988,7 @@ module.exports = withNx(
|
||||
fileName: 'index',
|
||||
// Change this to the formats you want to support.
|
||||
// Don't forget to update your package.json as well.
|
||||
formats: ['es']
|
||||
formats: ['es' as const]
|
||||
},
|
||||
rollupOptions: {
|
||||
// External packages that should not be bundled into your library.
|
||||
@ -1275,5 +1275,39 @@ module.exports = withNx(
|
||||
|
||||
expect(pnpmWorkspaceFile.packages).toEqual(['mylib']);
|
||||
});
|
||||
|
||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
directory: 'libs/my-lib',
|
||||
name: 'my-lib', // import path contains the npm scope, so it would be different
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'libs/my-lib/package.json').nx).toStrictEqual({
|
||||
name: 'my-lib',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the provided name matches the package name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
directory: 'libs/my-lib',
|
||||
name: '@proj/my-lib',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'libs/my-lib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not set "nx.name" in package.json when the user does not provide a name', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
directory: 'libs/my-lib',
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'libs/my-lib/package.json').nx).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -41,6 +41,7 @@ import {
|
||||
addReleaseConfigForTsSolution,
|
||||
releaseTasks,
|
||||
} from '@nx/js/src/generators/library/utils/add-release-config';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
export async function libraryGenerator(host: Tree, schema: Schema) {
|
||||
return await libraryGeneratorInternal(host, {
|
||||
@ -80,17 +81,22 @@ export async function libraryGeneratorInternal(host: Tree, schema: Schema) {
|
||||
tasks.push(initTask);
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
writeJson(host, `${options.projectRoot}/package.json`, {
|
||||
name: options.importPath ?? options.name,
|
||||
const packageJson: PackageJson = {
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
...determineEntryFields(options),
|
||||
nx: options.parsedTags?.length
|
||||
? {
|
||||
tags: options.parsedTags,
|
||||
}
|
||||
: undefined,
|
||||
files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
|
||||
});
|
||||
};
|
||||
|
||||
if (options.name !== options.importPath) {
|
||||
packageJson.nx = { name: options.name };
|
||||
}
|
||||
if (options.parsedTags?.length) {
|
||||
packageJson.nx ??= {};
|
||||
packageJson.nx.tags = options.parsedTags;
|
||||
}
|
||||
|
||||
writeJson(host, `${options.projectRoot}/package.json`, packageJson);
|
||||
} else {
|
||||
addProjectConfiguration(host, options.name, {
|
||||
root: options.projectRoot,
|
||||
|
||||
@ -36,6 +36,7 @@ export interface NormalizedSchema extends Schema {
|
||||
projectRoot: string;
|
||||
routePath: string;
|
||||
parsedTags: string[];
|
||||
importPath: string;
|
||||
appMain?: string;
|
||||
appSourceRoot?: string;
|
||||
unitTestRunner: 'jest' | 'vitest' | 'none';
|
||||
|
||||
@ -30,7 +30,7 @@ import {
|
||||
moduleFederationEnhancedVersion,
|
||||
nxVersion,
|
||||
} from '../../utils/versions';
|
||||
import { ensureProjectName } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { ensureRootProjectName } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
|
||||
export function addModuleFederationFiles(
|
||||
host: Tree,
|
||||
@ -96,7 +96,10 @@ export function addModuleFederationFiles(
|
||||
export async function remoteGenerator(host: Tree, schema: Schema) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const options: NormalizedSchema<Schema> = {
|
||||
...(await normalizeOptions<Schema>(host, schema)),
|
||||
...(await normalizeOptions<Schema>(host, {
|
||||
...schema,
|
||||
alwaysGenerateProjectJson: true,
|
||||
})),
|
||||
// when js is set to true, we want to use the js configuration
|
||||
js: schema.js ?? false,
|
||||
typescriptConfiguration: schema.js
|
||||
@ -111,20 +114,20 @@ export async function remoteGenerator(host: Tree, schema: Schema) {
|
||||
if (options.dynamic) {
|
||||
// Dynamic remotes generate with library { type: 'var' } by default.
|
||||
// We need to ensure that the remote name is a valid variable name.
|
||||
const isValidRemote = isValidVariable(options.name);
|
||||
const isValidRemote = isValidVariable(options.projectName);
|
||||
if (!isValidRemote.isValid) {
|
||||
throw new Error(
|
||||
`Invalid remote name provided: ${options.name}. ${isValidRemote.message}`
|
||||
`Invalid remote name provided: ${options.projectName}. ${isValidRemote.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await ensureProjectName(host, options, 'application');
|
||||
await ensureRootProjectName(options, 'application');
|
||||
const REMOTE_NAME_REGEX = '^[a-zA-Z_$][a-zA-Z_$0-9]*$';
|
||||
const remoteNameRegex = new RegExp(REMOTE_NAME_REGEX);
|
||||
if (!remoteNameRegex.test(options.name)) {
|
||||
if (!remoteNameRegex.test(options.projectName)) {
|
||||
throw new Error(
|
||||
stripIndents`Invalid remote name: ${options.name}. Remote project names must:
|
||||
stripIndents`Invalid remote name: ${options.projectName}. Remote project names must:
|
||||
- Start with a letter, dollar sign ($) or underscore (_)
|
||||
- Followed by any valid character (letters, digits, underscores, or dollar signs)
|
||||
The regular expression used is ${REMOTE_NAME_REGEX}.`
|
||||
@ -132,14 +135,14 @@ export async function remoteGenerator(host: Tree, schema: Schema) {
|
||||
}
|
||||
const initAppTask = await applicationGenerator(host, {
|
||||
...options,
|
||||
name: options.name,
|
||||
name: options.projectName,
|
||||
skipFormat: true,
|
||||
alwaysGenerateProjectJson: true,
|
||||
});
|
||||
tasks.push(initAppTask);
|
||||
|
||||
if (options.host) {
|
||||
updateHostWithRemote(host, options.host, options.name);
|
||||
updateHostWithRemote(host, options.host, options.projectName);
|
||||
}
|
||||
|
||||
// Module federation requires bootstrap code to be dynamically imported.
|
||||
|
||||
@ -462,9 +462,9 @@ describe('Remix Application', () => {
|
||||
tags: 'foo',
|
||||
});
|
||||
|
||||
const packageJson = readJson(tree, 'myapp/package.json');
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(readJson(tree, 'myapp/package.json')))
|
||||
.toMatchInlineSnapshot(`
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"private",
|
||||
@ -477,7 +477,7 @@ describe('Remix Application', () => {
|
||||
"devDependencies",
|
||||
]
|
||||
`);
|
||||
expect(readJson(tree, 'myapp/package.json')).toMatchInlineSnapshot(`
|
||||
expect(packageJson).toMatchInlineSnapshot(`
|
||||
{
|
||||
"dependencies": {
|
||||
"@remix-run/node": "^2.15.0",
|
||||
@ -655,6 +655,35 @@ describe('Remix Application', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should respect the provided name', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
directory: 'myapp',
|
||||
name: 'myapp',
|
||||
e2eTestRunner: 'playwright',
|
||||
unitTestRunner: 'jest',
|
||||
addPlugin: true,
|
||||
tags: 'foo',
|
||||
});
|
||||
|
||||
const packageJson = readJson(tree, 'myapp/package.json');
|
||||
expect(packageJson.name).toBe('@proj/myapp');
|
||||
expect(packageJson.nx.name).toBe('myapp');
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(packageJson)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
"private",
|
||||
"type",
|
||||
"scripts",
|
||||
"engines",
|
||||
"sideEffects",
|
||||
"nx",
|
||||
"dependencies",
|
||||
"devDependencies",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should skip nx property in package.json when no tags are provided', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
directory: 'apps/myapp',
|
||||
|
||||
@ -161,6 +161,21 @@ export async function remixApplicationGeneratorInternal(
|
||||
options.projectRoot,
|
||||
vars
|
||||
);
|
||||
|
||||
updateJson(
|
||||
tree,
|
||||
joinPathFragments(options.projectRoot, 'package.json'),
|
||||
(json) => {
|
||||
if (options.projectName !== options.importPath) {
|
||||
json.nx = { name: options.projectName };
|
||||
}
|
||||
if (options.parsedTags?.length) {
|
||||
json.nx ??= {};
|
||||
json.nx.tags = options.parsedTags;
|
||||
}
|
||||
return json;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (options.unitTestRunner !== 'none') {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "<%= projectName %>",
|
||||
"name": "<%= importPath %>",
|
||||
"scripts": {},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
@ -19,8 +19,5 @@
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"sideEffects": false<% if (isUsingTsSolutionConfig && parsedTags?.length) { %>,
|
||||
"nx": {
|
||||
"tags": <%- JSON.stringify(parsedTags) %>
|
||||
}<% } %>
|
||||
"sideEffects": false
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user