diff --git a/docs/docs/solid/generators.md b/docs/docs/solid/generators.md index caf7a5c65..4949b84aa 100644 --- a/docs/docs/solid/generators.md +++ b/docs/docs/solid/generators.md @@ -60,6 +60,22 @@ Possible values: `eslint` The tool to use for running lint checks. +#### projectNameAndRootFormat + +Type: `string` + +Possible values: `as-provided`, `derived` + +Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`). + +#### rootProject (**hidden**) + +Default: `false` + +Type: `boolean` + +Create a application at the root of the workspace + #### skipFormat Default: `false` @@ -168,6 +184,14 @@ Type: `boolean` Create a publishable library. +#### simpleName + +Default: `false` + +Type: `boolean` + +Don't include the directory in the name of the module of the library. + #### skipFormat Default: `false` diff --git a/packages/solid/package.json b/packages/solid/package.json index 633975105..c56427bc1 100644 --- a/packages/solid/package.json +++ b/packages/solid/package.json @@ -1,8 +1,8 @@ { "name": "@nxext/solid", - "version": "16.7.0", + "version": "16.8.0", "license": "MIT", - "author": "Kristian Mandrup", + "author": "Dominik Pieper", "description": "Nx plugin for solid", "homepage": "https://nxext.dev/", "keywords": [ @@ -23,10 +23,10 @@ "main": "src/index.js", "generators": "./generators.json", "dependencies": { - "tslib": "^2.3.0", + "nx": "^16.8.0", "@nx/devkit": "^16.8.0", "typescript": "5.1.6", - "nx": "^16.8.0" + "tslib": "^2.3.0" }, "peerDependencies": { "@nx/linter": "^16.8.0", diff --git a/packages/solid/src/generators/application/application.spec.ts b/packages/solid/src/generators/application/application.spec.ts index 10388582a..e48ac48ed 100644 --- a/packages/solid/src/generators/application/application.spec.ts +++ b/packages/solid/src/generators/application/application.spec.ts @@ -1,4 +1,4 @@ -import { SolidApplicationSchema } from './schema'; +import { Schema } from './schema'; import { Linter } from '@nx/linter'; import applicationGenerator from './application'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; @@ -6,11 +6,12 @@ import { Tree } from '@nx/devkit'; describe('Solid app generator', () => { let tree: Tree; - const options: SolidApplicationSchema = { - name: 'test', + const options: Schema = { + name: 'myApp', linter: Linter.EsLint, unitTestRunner: 'vitest', e2eTestRunner: 'cypress', + projectNameAndRootFormat: 'derived', }; beforeEach(() => { @@ -20,8 +21,14 @@ describe('Solid app generator', () => { describe('Vite bundle', () => { it('should add vite specific files', async () => { await applicationGenerator(tree, { ...options }); - expect(tree.exists(`apps/${options.name}/public/index.html`)).toBeFalsy(); - expect(tree.exists(`apps/${options.name}/index.html`)).toBeTruthy(); + expect(tree.exists(`apps/my-app/public/index.html`)).toBeFalsy(); + expect(tree.exists(`apps/my-app/index.html`)).toBeTruthy(); + }); + + it('should add vite specific files as rootProject', async () => { + await applicationGenerator(tree, { ...options, rootProject: true }); + expect(tree.exists(`public/index.html`)).toBeFalsy(); + expect(tree.exists(`index.html`)).toBeTruthy(); }); }); }); diff --git a/packages/solid/src/generators/application/application.ts b/packages/solid/src/generators/application/application.ts index fbf6df3a0..e26e3bc87 100644 --- a/packages/solid/src/generators/application/application.ts +++ b/packages/solid/src/generators/application/application.ts @@ -1,13 +1,12 @@ import { convertNxGenerator, formatFiles, - getWorkspaceLayout, - joinPathFragments, names, Tree, runTasksInSerial, + GeneratorCallback, } from '@nx/devkit'; -import { NormalizedSchema, SolidApplicationSchema } from './schema'; +import { NormalizedSchema, Schema } from './schema'; import { addProject } from './lib/add-project'; import { initGenerator } from '../init/init'; import { addLinting } from './lib/add-linting'; @@ -17,39 +16,61 @@ import { updateJestConfig } from './lib/update-jest-config'; import { addVite } from './lib/add-vite'; import { updateViteConfig } from './lib/update-vite-config'; import { createFiles } from './lib/create-project-files'; +import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils'; -function normalizeOptions( - tree: Tree, - options: SolidApplicationSchema -): NormalizedSchema { - const { appsDir } = getWorkspaceLayout(tree); - const name = names(options.name).fileName; - const projectDirectory = options.directory - ? joinPathFragments(`${names(options.directory).fileName}/${name}`) - : name; - const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-'); - const fileName = projectName; - const projectRoot = joinPathFragments(`${appsDir}/${projectDirectory}`); +async function normalizeOptions( + host: Tree, + options: Schema, + callingGenerator = '@nxext/solid:application' +): Promise> { + const { + projectName: appProjectName, + projectRoot: appProjectRoot, + projectNameAndRootFormat, + } = await determineProjectNameAndRootOptions(host, { + name: options.name, + projectType: 'application', + directory: options.directory, + projectNameAndRootFormat: options.projectNameAndRootFormat, + rootProject: options.rootProject, + callingGenerator, + }); + options.rootProject = appProjectRoot === '.'; + options.projectNameAndRootFormat = projectNameAndRootFormat; + + const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`; + const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`; const parsedTags = options.tags ? options.tags.split(',').map((s) => s.trim()) : []; + //const fileName = options.pascalCaseFiles ? 'App' : 'app'; + const fileName = 'App'; return { ...options, - name: projectName, - projectRoot, + name: names(options.name).fileName, + projectName: appProjectName, + appProjectRoot, + e2eProjectName, + e2eProjectRoot, parsedTags, fileName, - projectDirectory, skipFormat: false, }; } export async function applicationGenerator( - tree: Tree, - schema: SolidApplicationSchema -) { - const options = normalizeOptions(tree, schema); + host: Tree, + schema: Schema +): Promise { + return await applicationGeneratorInternal(host, { + projectNameAndRootFormat: 'derived', + ...schema, + }); +} + +export async function applicationGeneratorInternal(tree: Tree, schema: Schema) { + const options = await normalizeOptions(tree, schema); const initTask = await initGenerator(tree, { ...options, skipFormat: true }); diff --git a/packages/solid/src/generators/application/files/eslintrc.js.template b/packages/solid/src/generators/application/files/eslintrc.js.template index 4906c500b..167086945 100644 --- a/packages/solid/src/generators/application/files/eslintrc.js.template +++ b/packages/solid/src/generators/application/files/eslintrc.js.template @@ -7,7 +7,7 @@ module.exports = { { "files": ["*.ts", "*.js", "*.tsx"], "parserOptions": { - "project": ["<%= projectRoot %>/tsconfig.*?.json"] + "project": ["<%= appProjectRoot %>/tsconfig.*?.json"] }, "rules": {} }, diff --git a/packages/solid/src/generators/application/lib/add-linting.ts b/packages/solid/src/generators/application/lib/add-linting.ts index 32475a367..1288c1129 100644 --- a/packages/solid/src/generators/application/lib/add-linting.ts +++ b/packages/solid/src/generators/application/lib/add-linting.ts @@ -23,17 +23,17 @@ export async function addLinting(host: Tree, options: NormalizedSchema) { linter: options.linter, project: options.name, tsConfigPaths: [ - joinPathFragments(options.projectRoot, 'tsconfig.app.json'), + joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'), ], - eslintFilePatterns: [`${options.projectRoot}/**/*.{ts,spec.ts,tsx}`], + eslintFilePatterns: [`${options.appProjectRoot}/**/*.{ts,spec.ts,tsx}`], skipFormat: true, }); host.rename( - joinPathFragments(options.projectRoot, 'eslintrc.js'), - joinPathFragments(options.projectRoot, '.eslintrc.js') + joinPathFragments(options.appProjectRoot, 'eslintrc.js'), + joinPathFragments(options.appProjectRoot, '.eslintrc.js') ); - host.delete(joinPathFragments(options.projectRoot, '.eslintrc.json')); + host.delete(joinPathFragments(options.appProjectRoot, '.eslintrc.json')); const installTask = await addDependenciesToPackageJson( host, diff --git a/packages/solid/src/generators/application/lib/add-project.ts b/packages/solid/src/generators/application/lib/add-project.ts index 2ea551b5c..6565d8c7f 100644 --- a/packages/solid/src/generators/application/lib/add-project.ts +++ b/packages/solid/src/generators/application/lib/add-project.ts @@ -8,8 +8,8 @@ import { export function addProject(tree: Tree, options: NormalizedSchema) { addProjectConfiguration(tree, options.name, { - root: options.projectRoot, - sourceRoot: `${options.projectRoot}/src`, + root: options.appProjectRoot, + sourceRoot: `${options.appProjectRoot}/src`, projectType: 'application', tags: options.parsedTags, targets: { lint: createLintTarget(options) }, @@ -21,10 +21,10 @@ function createLintTarget(options: NormalizedSchema): TargetConfiguration { executor: '@nx/linter:lint', options: { linter: 'eslint', - tsConfig: joinPathFragments(options.projectRoot, 'tsconfig.app.json'), + tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'), exclude: [ '**/node_modules/**', - `!${joinPathFragments(options.projectRoot, '**/*')}`, + `!${joinPathFragments(options.appProjectRoot, '**/*')}`, ], }, }; diff --git a/packages/solid/src/generators/application/lib/create-project-files.ts b/packages/solid/src/generators/application/lib/create-project-files.ts index 8ca1970f3..4e6087aad 100644 --- a/packages/solid/src/generators/application/lib/create-project-files.ts +++ b/packages/solid/src/generators/application/lib/create-project-files.ts @@ -11,11 +11,11 @@ export function createFiles(host: Tree, options: NormalizedSchema) { generateFiles( host, joinPathFragments(__dirname, '../files'), - options.projectRoot, + options.appProjectRoot, { ...options, ...names(options.name), - offsetFromRoot: offsetFromRoot(options.projectRoot), + offsetFromRoot: offsetFromRoot(options.appProjectRoot), } ); } diff --git a/packages/solid/src/generators/application/lib/update-jest-config.ts b/packages/solid/src/generators/application/lib/update-jest-config.ts index 496f60d56..352534a82 100644 --- a/packages/solid/src/generators/application/lib/update-jest-config.ts +++ b/packages/solid/src/generators/application/lib/update-jest-config.ts @@ -6,7 +6,7 @@ export function updateJestConfig(host: Tree, options: NormalizedSchema) { return; } - const jestConfigPath = `${options.projectRoot}/jest.config.ts`; + const jestConfigPath = `${options.appProjectRoot}/jest.config.ts`; // const svelteConfigPath = `${options.projectRoot}/jest.config.ts`; const originalContent = host.read(jestConfigPath)?.toString(); const content = updateJestConfigContent(originalContent); diff --git a/packages/solid/src/generators/application/lib/update-vite-config.ts b/packages/solid/src/generators/application/lib/update-vite-config.ts index 2122e17f7..aa774530f 100644 --- a/packages/solid/src/generators/application/lib/update-vite-config.ts +++ b/packages/solid/src/generators/application/lib/update-vite-config.ts @@ -2,7 +2,7 @@ import { Tree } from '@nx/devkit'; import { NormalizedSchema } from '../schema'; export function updateViteConfig(host: Tree, options: NormalizedSchema) { - const configPath = `${options.projectRoot}/vite.config.ts`; + const configPath = `${options.appProjectRoot}/vite.config.ts`; const originalContent = host.read(configPath, 'utf-8'); const content = updateViteConfigContent(originalContent); host.write(configPath, content); diff --git a/packages/solid/src/generators/application/schema.d.ts b/packages/solid/src/generators/application/schema.d.ts index 13aa70c4c..7d889514b 100644 --- a/packages/solid/src/generators/application/schema.d.ts +++ b/packages/solid/src/generators/application/schema.d.ts @@ -1,20 +1,24 @@ import { Linter } from '@nx/linter'; +import { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils'; -export interface SolidApplicationSchema { +export interface Schema { name: string; tags?: string; - linter: Linter; unitTestRunner: 'jest' | 'vitest' | 'none'; e2eTestRunner: 'cypress' | 'none'; directory?: string; + projectNameAndRootFormat?: ProjectNameAndRootFormat; + rootProject?: boolean; host?: string; port?: number; } -export interface NormalizedSchema extends SolidApplicationSchema { - projectRoot: string; - projectDirectory: string; +export interface NormalizedSchema extends T { + projectName: string; + appProjectRoot: string; + e2eProjectName: string; + e2eProjectRoot: string; fileName: string; parsedTags: string[]; skipFormat: boolean; diff --git a/packages/solid/src/generators/application/schema.json b/packages/solid/src/generators/application/schema.json index 324bfac31..cd451faef 100644 --- a/packages/solid/src/generators/application/schema.json +++ b/packages/solid/src/generators/application/schema.json @@ -24,6 +24,11 @@ "enum": ["eslint"], "default": "eslint" }, + "projectNameAndRootFormat": { + "description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).", + "type": "string", + "enum": ["as-provided", "derived"] + }, "unitTestRunner": { "type": "string", "enum": ["vitest", "jest", "none"], @@ -41,6 +46,12 @@ "description": "A directory where the lib is placed.", "alias": "d" }, + "rootProject": { + "description": "Create a application at the root of the workspace", + "type": "boolean", + "default": false, + "hidden": true + }, "skipFormat": { "description": "Skip formatting files.", "type": "boolean", diff --git a/packages/solid/src/generators/library/lib/add-vite.ts b/packages/solid/src/generators/library/lib/add-vite.ts index 733c325a6..124cdcc85 100644 --- a/packages/solid/src/generators/library/lib/add-vite.ts +++ b/packages/solid/src/generators/library/lib/add-vite.ts @@ -2,8 +2,9 @@ import { ensurePackage, NX_VERSION, Tree } from '@nx/devkit'; import { NormalizedSchema } from '../schema'; export async function addVite(host: Tree, options: NormalizedSchema) { - await ensurePackage('@nx/vite', NX_VERSION); - const { viteConfigurationGenerator } = await import('@nx/vite'); + const { viteConfigurationGenerator } = ensurePackage< + typeof import('@nx/vite') + >('@nx/vite', NX_VERSION); return await viteConfigurationGenerator(host, { uiFramework: 'none', diff --git a/packages/solid/src/generators/library/library.spec.ts b/packages/solid/src/generators/library/library.spec.ts index 659afe682..fe0fec973 100644 --- a/packages/solid/src/generators/library/library.spec.ts +++ b/packages/solid/src/generators/library/library.spec.ts @@ -7,7 +7,7 @@ import { libraryGenerator } from './library'; describe('solid library schematic', () => { let tree: Tree; const options: SolidLibrarySchema = { - name: 'test', + name: 'myLib', linter: Linter.EsLint, unitTestRunner: 'jest', e2eTestRunner: 'cypress', @@ -42,11 +42,11 @@ describe('solid library schematic', () => { await libraryGenerator(tree, options); // expect(tree.exists(`libs/${options.name}/solid.config.cjs`)).toBeTruthy(); - expect(tree.exists(`libs/${options.name}/tsconfig.lib.json`)).toBeTruthy(); - expect(tree.exists(`libs/${options.name}/tsconfig.spec.json`)).toBeTruthy(); - expect(tree.exists(`libs/${options.name}/tsconfig.json`)).toBeTruthy(); - expect(tree.exists(`libs/${options.name}/.eslintrc.json`)).toBeFalsy(); - expect(tree.exists(`libs/${options.name}/.eslintrc.js`)).toBeTruthy(); + expect(tree.exists(`libs/my-lib/tsconfig.lib.json`)).toBeTruthy(); + expect(tree.exists(`libs/my-lib/tsconfig.spec.json`)).toBeTruthy(); + expect(tree.exists(`libs/my-lib/tsconfig.json`)).toBeTruthy(); + expect(tree.exists(`libs/my-lib/.eslintrc.json`)).toBeFalsy(); + expect(tree.exists(`libs/my-lib/.eslintrc.js`)).toBeTruthy(); }); it('should fail if no importPath is provided with publishable', async () => { diff --git a/packages/solid/src/generators/library/library.ts b/packages/solid/src/generators/library/library.ts index 845f360fc..b309a4035 100644 --- a/packages/solid/src/generators/library/library.ts +++ b/packages/solid/src/generators/library/library.ts @@ -5,8 +5,6 @@ import { updateTsConfig } from './lib/update-tsconfig'; import { convertNxGenerator, formatFiles, - getWorkspaceLayout, - joinPathFragments, names, Tree, updateJson, @@ -19,26 +17,39 @@ import { createFiles } from './lib/create-project-files'; import { updateViteConfig } from './lib/update-vite-config'; import { addVite } from './lib/add-vite'; import { addVitest } from './lib/add-vitest'; +import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils'; -function normalizeOptions( - tree: Tree, +async function normalizeOptions( + host: Tree, options: SolidLibrarySchema -): NormalizedSchema { - const { libsDir, npmScope } = getWorkspaceLayout(tree); +): Promise { + const { + projectName, + names: projectNames, + projectRoot, + importPath, + } = await determineProjectNameAndRootOptions(host, { + name: options.name, + projectType: 'library', + directory: options.directory, + importPath: options.importPath, + projectNameAndRootFormat: options.projectNameAndRootFormat, + callingGenerator: '@nxext/solid:library', + }); const name = names(options.name).fileName; const projectDirectory = options.directory ? `${names(options.directory).fileName}/${name}` : name; - const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-'); - const fileName = projectName; - const projectRoot = joinPathFragments(`${libsDir}/${projectDirectory}`); + const fileName = options.simpleName + ? projectNames.projectSimpleName + : projectNames.projectFileName; const parsedTags = options.tags ? options.tags.split(',').map((s) => s.trim()) : []; - const importPath = options.importPath || `@${npmScope}/${projectDirectory}`; return { ...options, + inSourceTests: false, name: projectName, projectRoot, parsedTags, @@ -58,7 +69,17 @@ function updateLibPackageNpmScope(host: Tree, options: NormalizedSchema) { } export async function libraryGenerator(host: Tree, schema: SolidLibrarySchema) { - const options = normalizeOptions(host, schema); + return await libraryGeneratorInternal(host, { + projectNameAndRootFormat: 'derived', + ...schema, + }); +} + +export async function libraryGeneratorInternal( + host: Tree, + schema: SolidLibrarySchema +) { + const options = await normalizeOptions(host, schema); if (options.publishable === true && !schema.importPath) { throw new Error( `For publishable libs you have to provide a proper "--importPath" which needs to be a valid npm package name (e.g. my-awesome-lib or @myorg/my-lib)` diff --git a/packages/solid/src/generators/library/schema.d.ts b/packages/solid/src/generators/library/schema.d.ts index 548291554..33374b30c 100644 --- a/packages/solid/src/generators/library/schema.d.ts +++ b/packages/solid/src/generators/library/schema.d.ts @@ -7,11 +7,13 @@ export interface SolidLibrarySchema { linter: Linter; unitTestRunner: 'vitest' | 'jest' | 'none'; e2eTestRunner: 'cypress' | 'none'; + projectNameAndRootFormat?: ProjectNameAndRootFormat; buildable?: boolean; directory?: string; publishable?: boolean; importPath?: string; skipFormat: boolean; + simpleName?: boolean; } export interface NormalizedSchema extends SolidLibrarySchema { @@ -20,4 +22,5 @@ export interface NormalizedSchema extends SolidLibrarySchema { fileName: string; parsedTags: string[]; importPath: string; + inSourceTests: boolean; } diff --git a/packages/solid/src/generators/library/schema.json b/packages/solid/src/generators/library/schema.json index 322af8008..623db6fbc 100644 --- a/packages/solid/src/generators/library/schema.json +++ b/packages/solid/src/generators/library/schema.json @@ -58,6 +58,11 @@ "description": "Skip formatting files.", "type": "boolean", "default": false + }, + "simpleName": { + "description": "Don't include the directory in the name of the module of the library.", + "type": "boolean", + "default": false } }, "required": ["name"] diff --git a/packages/solid/src/generators/utils/versions.ts b/packages/solid/src/generators/utils/versions.ts index 08a412c8f..458a491a6 100644 --- a/packages/solid/src/generators/utils/versions.ts +++ b/packages/solid/src/generators/utils/versions.ts @@ -1,5 +1,5 @@ export const solidJestVersion = '^0.2.0'; -export const solidVersion = '^1.7.5'; +export const solidVersion = '^1.7.12'; export const solidTestingLibraryVersion = '^0.5.1'; -export const eslintPluginSolidVersion = '0.12.1'; +export const eslintPluginSolidVersion = '0.13.0'; export const vitePluginSolidVersion = '2.7.0'; diff --git a/tools/scripts/create-playground.ts b/tools/scripts/create-playground.ts index 31e509682..bec1b347b 100644 --- a/tools/scripts/create-playground.ts +++ b/tools/scripts/create-playground.ts @@ -6,7 +6,7 @@ import { writeFileSync, } from 'fs-extra'; import { getPublishableLibNames, tmpProjPath } from './utils'; -import { dirname } from 'path'; +import { dirname, basename } from 'path'; import { logger, readJsonFile, workspaceRoot } from '@nx/devkit'; import { Workspaces } from 'nx/src/config/workspaces'; import * as glob from 'glob'; @@ -25,12 +25,11 @@ removeSync(tmpProjPath()); ensureDirSync(tmpProjPath()); const localTmpDir = dirname(tmpProjPath()); +const baseName = basename(tmpProjPath()); logger.info('Creating nx workspace...'); execSync( - `node ${require.resolve( - 'nx' - )} new proj --nx-workspace-root=${localTmpDir} --no-interactive --skip-install --collection=@nx/workspace --npmScope=proj --preset=empty --packageManager=pnpm --nxCloud=false`, + `pnpx create-nx-workspace --preset=empty --name=${baseName} --skipGit=true --packageManager=pnpm --nxCloud=false`, { cwd: localTmpDir, }