diff --git a/.eslintrc.json b/.eslintrc.json index c2f66fb5..1f04036a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,7 +1,7 @@ { "root": true, "ignorePatterns": ["**/*"], - "plugins": ["@nrwl/nx"], + "plugins": ["@nrwl/nx", "eslint-plugin-unused-imports"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], @@ -24,7 +24,24 @@ { "files": ["*.ts", "*.tsx"], "extends": ["plugin:@nrwl/nx/typescript"], - "rules": {} + "rules": { + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "unused-imports/no-unused-imports": "error", + "no-duplicate-imports": "error", + "unused-imports/no-unused-vars": "error", + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "enum", + "format": ["PascalCase"] + }, + { + "selector": "enumMember", + "format": ["PascalCase"] + } + ] + } }, { "files": ["*.js", "*.jsx"], @@ -36,7 +53,9 @@ "env": { "jest": true }, - "rules": {} + "rules": { + "no-restricted-globals": ["error", "fdescribe", "fit"] + } }, { "files": "*.json", diff --git a/e2e/qwik-nx-e2e/tests/application.spec.ts b/e2e/qwik-nx-e2e/tests/application.spec.ts index d60d39d3..e5de6cff 100644 --- a/e2e/qwik-nx-e2e/tests/application.spec.ts +++ b/e2e/qwik-nx-e2e/tests/application.spec.ts @@ -59,7 +59,7 @@ describe('appGenerator e2e', () => { } ); try { - await promisifiedTreeKill(p.pid, 'SIGKILL'); + await promisifiedTreeKill(p.pid!, 'SIGKILL'); await killPort(port); } catch { // ignore @@ -75,7 +75,7 @@ describe('appGenerator e2e', () => { } ); try { - await promisifiedTreeKill(p.pid, 'SIGKILL'); + await promisifiedTreeKill(p.pid!, 'SIGKILL'); await killPort(port); } catch { // ignore diff --git a/e2e/qwik-nx-e2e/tests/qwik-nx-vite.spec.ts b/e2e/qwik-nx-e2e/tests/qwik-nx-vite.spec.ts index d73cd1d4..53ad48de 100644 --- a/e2e/qwik-nx-e2e/tests/qwik-nx-vite.spec.ts +++ b/e2e/qwik-nx-e2e/tests/qwik-nx-vite.spec.ts @@ -127,7 +127,7 @@ describe('qwikNxVite plugin e2e', () => { } ); try { - await promisifiedTreeKill(p.pid, 'SIGKILL'); + await promisifiedTreeKill(p.pid!, 'SIGKILL'); await killPort(port); } catch { // ignore diff --git a/e2e/utils/index.ts b/e2e/utils/index.ts index 7b3d2ef6..724ec269 100644 --- a/e2e/utils/index.ts +++ b/e2e/utils/index.ts @@ -20,27 +20,31 @@ export const promisifiedTreeKill: ( signal: string ) => Promise = promisify(treeKill); -function getAdditionalPackageManagerCommands() { +function getAdditionalPackageManagerCommands(): { + createWorkspace: string; + runNx: string; +} { const pm = detectPackageManager(); const [npmMajorVersion] = execSync(`npm -v`).toString().split('.'); const publishedVersion = execSync('npm view nx version'); - if (pm === 'npm') { - return { - createWorkspace: `npx ${ - +npmMajorVersion >= 7 ? '--yes' : '' - } create-nx-workspace@${publishedVersion}`, - runNx: `npx nx`, - }; - } else if (pm === 'yarn') { - return { - createWorkspace: `yarn global add create-nx-workspace@${publishedVersion} && create-nx-workspace`, - runNx: `yarn nx`, - }; - } else if (pm === 'pnpm') { - return { - createWorkspace: `pnpm dlx create-nx-workspace@${publishedVersion}`, - runNx: `pnpm exec nx`, - }; + switch (pm) { + case 'npm': + return { + createWorkspace: `npx ${ + +npmMajorVersion >= 7 ? '--yes' : '' + } create-nx-workspace@${publishedVersion}`, + runNx: `npx nx`, + }; + case 'yarn': + return { + createWorkspace: `yarn global add create-nx-workspace@${publishedVersion} && create-nx-workspace`, + runNx: `yarn nx`, + }; + case 'pnpm': + return { + createWorkspace: `pnpm dlx create-nx-workspace@${publishedVersion}`, + runNx: `pnpm exec nx`, + }; } } @@ -149,7 +153,7 @@ export function runCommandUntil( let output = ''; let complete = false; - function checkCriteria(c) { + function checkCriteria(c: any) { output += c.toString(); if (criteria(stripConsoleColors(output)) && !complete) { complete = true; diff --git a/package.json b/package.json index 142a38db..4cd0e681 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,10 @@ "@swc-node/register": "^1.4.2", "@swc/cli": "~0.1.55", "@swc/core": "^1.2.173", + "@types/fs-extra": "11.0.1", "@types/jest": "28.1.1", "@types/node": "16.11.7", + "@types/tcp-port-used": "1.0.1", "@typescript-eslint/eslint-plugin": "^5.36.1", "@typescript-eslint/parser": "^5.36.1", "all-contributors-cli": "^6.24.0", @@ -42,8 +44,10 @@ "cz-conventional-changelog": "^3.3.0", "eslint": "~8.15.0", "eslint-config-prettier": "8.1.0", + "eslint-plugin-unused-imports": "2.0.0", "fs-extra": "11.1.0", "husky": "^8.0.1", + "is-windows": "1.0.2", "jest": "28.1.1", "jest-environment-jsdom": "28.1.1", "jsonc-eslint-parser": "^2.1.0", diff --git a/packages/add-nx-to-qwik/src/add-nx-to-qwik.ts b/packages/add-nx-to-qwik/src/add-nx-to-qwik.ts index 756b2b14..ba213811 100644 --- a/packages/add-nx-to-qwik/src/add-nx-to-qwik.ts +++ b/packages/add-nx-to-qwik/src/add-nx-to-qwik.ts @@ -44,7 +44,7 @@ async function addNxToMonorepo() { let targetDefaults: string[]; let cacheableOperations: string[]; - let scriptOutputs = {}; + const scriptOutputs = {}; let useCloud: boolean; if (parsedArgs.yes !== true) { diff --git a/packages/qwik-nx/src/generators/application/generator.spec.ts b/packages/qwik-nx/src/generators/application/generator.spec.ts index 9bb81559..c50e8db1 100644 --- a/packages/qwik-nx/src/generators/application/generator.spec.ts +++ b/packages/qwik-nx/src/generators/application/generator.spec.ts @@ -7,6 +7,7 @@ import { Linter } from '@nrwl/linter'; // eslint-disable-next-line @typescript-eslint/no-var-requires const devkit = require('@nrwl/devkit'); +const getInstalledNxVersionModule = require('../../utils/get-installed-nx-version'); describe('qwik-nx generator', () => { let appTree: Tree; @@ -21,6 +22,9 @@ describe('qwik-nx generator', () => { }; jest.spyOn(devkit, 'ensurePackage').mockReturnValue(Promise.resolve()); + jest + .spyOn(getInstalledNxVersionModule, 'getInstalledNxVersion') + .mockReturnValue('15.6.0'); beforeEach(() => { appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); @@ -50,7 +54,7 @@ describe('qwik-nx generator', () => { }); const config = readProjectConfiguration(appTree, 'myapp-e2e'); expect(config).toBeDefined(); - expect(config.targets.e2e.executor).toEqual('@nxkit/playwright:test'); + expect(config.targets?.e2e.executor).toEqual('@nxkit/playwright:test'); expect( appTree.exists('apps/myapp-e2e/playwright.config.ts') ).toBeTruthy(); @@ -63,7 +67,7 @@ describe('qwik-nx generator', () => { }); const config = readProjectConfiguration(appTree, 'myapp-e2e'); expect(config).toBeDefined(); - expect(config.targets.e2e.executor).toEqual('@nrwl/cypress:cypress'); + expect(config.targets?.e2e.executor).toEqual('@nrwl/cypress:cypress'); expect(appTree.exists('apps/myapp-e2e/cypress.config.ts')).toBeTruthy(); }); }); diff --git a/packages/qwik-nx/src/generators/application/generator.ts b/packages/qwik-nx/src/generators/application/generator.ts index 35e871bd..4d030fd6 100644 --- a/packages/qwik-nx/src/generators/application/generator.ts +++ b/packages/qwik-nx/src/generators/application/generator.ts @@ -5,6 +5,7 @@ import { GeneratorCallback, joinPathFragments, names, + TargetConfiguration, Tree, } from '@nrwl/devkit'; import { Linter } from '@nrwl/linter'; @@ -41,7 +42,8 @@ export async function appGenerator( const normalizedOptions = normalizeOptions(tree, options); const tasks: GeneratorCallback[] = []; - const targets = getQwikApplicationProjectTargets(normalizedOptions); + const targets: Record = + getQwikApplicationProjectTargets(normalizedOptions); if (!normalizedOptions.setupVitest) { delete targets['test']; @@ -69,7 +71,7 @@ export async function appGenerator( tasks.push(configureEslint(tree, normalizedOptions.projectName, true)); } - if (normalizedOptions.style !== 'none') { + if (normalizedOptions.styleExtension) { tasks.push( addStyledModuleDependencies(tree, normalizedOptions.styleExtension) ); @@ -77,7 +79,10 @@ export async function appGenerator( tasks.push(addCommonQwikDependencies(tree)); - if (normalizedOptions.e2eTestRunner !== 'none') { + if ( + normalizedOptions.e2eTestRunner && + normalizedOptions.e2eTestRunner !== 'none' + ) { const e2eProjectTask = await addE2eProject(tree, { project: normalizedOptions.projectName, directory: normalizedOptions.directory, diff --git a/packages/qwik-nx/src/generators/application/utils/get-qwik-application-project-params.ts b/packages/qwik-nx/src/generators/application/utils/get-qwik-application-project-params.ts index 9f2a3f35..0d285051 100644 --- a/packages/qwik-nx/src/generators/application/utils/get-qwik-application-project-params.ts +++ b/packages/qwik-nx/src/generators/application/utils/get-qwik-application-project-params.ts @@ -8,7 +8,7 @@ export interface UpdateQwikAppConfigurationParams { export function getQwikApplicationProjectTargets( params: UpdateQwikAppConfigurationParams -) { +): Record { return { build: getBuildTarget(params), 'build-ssr': getBuildSsrTarget(params), diff --git a/packages/qwik-nx/src/generators/component/generator.ts b/packages/qwik-nx/src/generators/component/generator.ts index 0b72b1a5..3debf692 100644 --- a/packages/qwik-nx/src/generators/component/generator.ts +++ b/packages/qwik-nx/src/generators/component/generator.ts @@ -1,6 +1,7 @@ import { formatFiles, generateFiles, + GeneratorCallback, getProjects, joinPathFragments, logger, @@ -23,7 +24,7 @@ function getDirectory(host: Tree, options: ComponentGeneratorSchema) { baseDir = options.directory; } else { baseDir = - workspace.get(options.project).projectType === 'application' + workspace.get(options.project)!.projectType === 'application' ? 'components' : 'lib'; } @@ -45,7 +46,8 @@ function normalizeOptions( throw new Error(); } - const { sourceRoot: projectRoot } = project; + const projectRoot = + project.sourceRoot ?? joinPathFragments(project.root, 'src'); const directory = getDirectory(host, options); @@ -98,7 +100,7 @@ function createComponentFiles(tree: Tree, options: NormalizedSchema) { export async function componentGenerator( tree: Tree, options: ComponentGeneratorSchema -) { +): Promise { const normalizedOptions = normalizeOptions(tree, options); createComponentFiles(tree, normalizedOptions); await formatFiles(tree); diff --git a/packages/qwik-nx/src/generators/e2e-project/generator.spec.ts b/packages/qwik-nx/src/generators/e2e-project/generator.spec.ts index cc686481..1f5b4ef2 100644 --- a/packages/qwik-nx/src/generators/e2e-project/generator.spec.ts +++ b/packages/qwik-nx/src/generators/e2e-project/generator.spec.ts @@ -7,6 +7,7 @@ import { E2eProjectGeneratorSchema } from './schema'; // eslint-disable-next-line @typescript-eslint/no-var-requires const devkit = require('@nrwl/devkit'); +const getInstalledNxVersionModule = require('../../utils/get-installed-nx-version'); describe('e2e project', () => { let appTree: Tree; @@ -15,6 +16,9 @@ describe('e2e project', () => { }; jest.spyOn(devkit, 'ensurePackage').mockReturnValue(Promise.resolve()); + jest + .spyOn(getInstalledNxVersionModule, 'getInstalledNxVersion') + .mockReturnValue('15.6.0'); beforeEach(() => { appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); @@ -31,7 +35,7 @@ describe('e2e project', () => { }); const config = readProjectConfiguration(appTree, 'myapp-e2e'); expect(config).toBeDefined(); - expect(config.targets.e2e.executor).toEqual('@nxkit/playwright:test'); + expect(config.targets?.e2e.executor).toEqual('@nxkit/playwright:test'); expect(appTree.exists('apps/myapp-e2e/playwright.config.ts')).toBeTruthy(); }); @@ -42,7 +46,7 @@ describe('e2e project', () => { }); const config = readProjectConfiguration(appTree, 'myapp-e2e'); expect(config).toBeDefined(); - expect(config.targets.e2e.executor).toEqual('@nrwl/cypress:cypress'); + expect(config.targets?.e2e.executor).toEqual('@nrwl/cypress:cypress'); expect(appTree.exists('apps/myapp-e2e/cypress.config.ts')).toBeTruthy(); }); }); diff --git a/packages/qwik-nx/src/generators/e2e-project/generator.ts b/packages/qwik-nx/src/generators/e2e-project/generator.ts index 35133a18..a5c19a20 100644 --- a/packages/qwik-nx/src/generators/e2e-project/generator.ts +++ b/packages/qwik-nx/src/generators/e2e-project/generator.ts @@ -27,6 +27,8 @@ export async function addE2eProject( if (options.e2eTestRunner === 'playwright') { return addPlaywright(tree, normalizedOptions); } + + return () => void 0; } async function addCypress(tree: Tree, options: NormalizedSchema) { diff --git a/packages/qwik-nx/src/generators/index.ts b/packages/qwik-nx/src/generators/index.ts index ea0e29f8..32e59c09 100644 --- a/packages/qwik-nx/src/generators/index.ts +++ b/packages/qwik-nx/src/generators/index.ts @@ -1,16 +1,16 @@ export { appGenerator } from './application/generator'; -export { QwikAppGeneratorSchema } from './application/schema'; +export type { QwikAppGeneratorSchema } from './application/schema'; export { componentGenerator } from './component/generator'; -export { ComponentGeneratorSchema } from './component/schema'; +export type { ComponentGeneratorSchema } from './component/schema'; export { addE2eProject } from './e2e-project/generator'; -export { E2eProjectGeneratorSchema } from './e2e-project/schema'; +export type { E2eProjectGeneratorSchema } from './e2e-project/schema'; export { qwikInitGenerator } from './init/init'; -export { InitGeneratorSchema } from './init/schema'; +export type { InitGeneratorSchema } from './init/schema'; export { cloudflarePagesIntegrationGenerator } from './integrations/cloudflare-pages-integration/generator'; -export { CloudflarePagesIntegrationGeneratorSchema } from './integrations/cloudflare-pages-integration/schema'; +export type { CloudflarePagesIntegrationGeneratorSchema } from './integrations/cloudflare-pages-integration/schema'; export { libraryGenerator } from './library/generator'; -export { LibraryGeneratorSchema } from './library/schema'; +export type { LibraryGeneratorSchema } from './library/schema'; export { routeGenerator } from './route/generator'; -export { RouteGeneratorSchema } from './route/schema'; +export type { RouteGeneratorSchema } from './route/schema'; export { setupTailwindGenerator } from './setup-tailwind/setup-tailwind'; -export { SetupTailwindOptions } from './setup-tailwind/schema'; +export type { SetupTailwindOptions } from './setup-tailwind/schema'; diff --git a/packages/qwik-nx/src/generators/integrations/cloudflare-pages-integration/generator.spec.ts b/packages/qwik-nx/src/generators/integrations/cloudflare-pages-integration/generator.spec.ts index bd03f429..8f97df85 100644 --- a/packages/qwik-nx/src/generators/integrations/cloudflare-pages-integration/generator.spec.ts +++ b/packages/qwik-nx/src/generators/integrations/cloudflare-pages-integration/generator.spec.ts @@ -36,25 +36,25 @@ describe('cloudflare-pages-integration generator', () => { await cloudflarePagesIntegrationGenerator(appTree, options); const config = readProjectConfiguration(appTree, projectName); expect( - config.targets['build-ssr'].configurations['cloudflare-pages'] + config.targets!['build-ssr'].configurations!['cloudflare-pages'] ).toEqual({ configFile: `apps/${projectName}/adaptors/cloudflare-pages/vite.config.ts`, }); - expect(config.targets['deploy']).toEqual({ + expect(config.targets!['deploy']).toEqual({ executor: '@k11r/nx-cloudflare-wrangler:deploy-page', options: { dist: `dist/apps/${projectName}/client`, }, dependsOn: ['build-ssr-cloudflare-pages'], }); - expect(config.targets['preview-cloudflare-pages']).toEqual({ + expect(config.targets!['preview-cloudflare-pages']).toEqual({ executor: '@k11r/nx-cloudflare-wrangler:serve-page', options: { dist: `dist/apps/${projectName}/client`, }, dependsOn: ['build-ssr-cloudflare-pages'], }); - expect(config.targets['build-ssr-cloudflare-pages']).toEqual({ + expect(config.targets!['build-ssr-cloudflare-pages']).toEqual({ executor: 'nx:run-commands', options: { command: `npx nx run ${projectName}:build-ssr:cloudflare-pages`, @@ -72,7 +72,7 @@ describe('cloudflare-pages-integration generator', () => { describe('should throw if project configuration does not meet the expectations', () => { it('deploy target is already defined', async () => { const config = readProjectConfiguration(appTree, projectName); - config.targets['deploy'] = { executor: 'nx:noop' }; + config.targets!['deploy'] = { executor: 'nx:noop' }; updateProjectConfiguration(appTree, projectName, config); expect( @@ -95,7 +95,7 @@ describe('cloudflare-pages-integration generator', () => { it('project does not have Qwik\'s "build-ssr" target', async () => { const config = readProjectConfiguration(appTree, projectName); - delete config.targets['build-ssr']; + delete config.targets!['build-ssr']; updateProjectConfiguration(appTree, projectName, config); expect( diff --git a/packages/qwik-nx/src/generators/integrations/cloudflare-pages-integration/generator.ts b/packages/qwik-nx/src/generators/integrations/cloudflare-pages-integration/generator.ts index 75f3657a..428f969b 100644 --- a/packages/qwik-nx/src/generators/integrations/cloudflare-pages-integration/generator.ts +++ b/packages/qwik-nx/src/generators/integrations/cloudflare-pages-integration/generator.ts @@ -25,6 +25,8 @@ export async function cloudflarePagesIntegrationGenerator( options: CloudflarePagesIntegrationGeneratorSchema ) { const config = readProjectConfiguration(tree, options.project); + config.targets ??= {}; + if (config.projectType !== 'application' || !config.targets['build-ssr']) { throw new Error( 'Cannot setup cloudflare integration for the given project.' @@ -107,7 +109,7 @@ function normalizeOptions( function addFiles(tree: Tree, options: NormalizedOptions): void { const templateOptions = { - ...names(options.projectConfig.name), + ...names(options.projectConfig.name!), projectRoot: options.projectConfig.root, offsetFromRoot: options.offsetFromRoot, }; diff --git a/packages/qwik-nx/src/generators/library/generator.ts b/packages/qwik-nx/src/generators/library/generator.ts index 117d17a5..fd058c68 100644 --- a/packages/qwik-nx/src/generators/library/generator.ts +++ b/packages/qwik-nx/src/generators/library/generator.ts @@ -129,6 +129,8 @@ async function configureVite(tree: Tree, options: NormalizedSchema) { const targets = getQwikLibProjectTargets(options); + projectConfig.targets ??= {}; + projectConfig.targets['build'] = targets.build; if (options.setupVitest) { diff --git a/packages/qwik-nx/src/generators/route/generator.spec.ts b/packages/qwik-nx/src/generators/route/generator.spec.ts index 6b80ae25..39ecdb5c 100644 --- a/packages/qwik-nx/src/generators/route/generator.spec.ts +++ b/packages/qwik-nx/src/generators/route/generator.spec.ts @@ -1,5 +1,4 @@ import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; -import { Tree } from '@nrwl/devkit'; import { routeGenerator } from './generator'; import { RouteGeneratorSchema } from './schema'; diff --git a/packages/qwik-nx/src/generators/route/generator.ts b/packages/qwik-nx/src/generators/route/generator.ts index c59fb10f..9fdf32a9 100644 --- a/packages/qwik-nx/src/generators/route/generator.ts +++ b/packages/qwik-nx/src/generators/route/generator.ts @@ -2,6 +2,7 @@ import { formatFiles, generateFiles, getProjects, + joinPathFragments, logger, names, offsetFromRoot, @@ -34,7 +35,6 @@ function normalizeOptions( ): NormalizedSchema { const name = names(options.name).fileName; const project = getProjects(tree).get(options.project); - const projectSourceRoot = project.sourceRoot; if (!project) { logger.error( @@ -51,7 +51,8 @@ function normalizeOptions( return { ...options, routeName, - projectSourceRoot, + projectSourceRoot: + project.sourceRoot ?? joinPathFragments(project.root, 'src'), routeDirectory, }; } diff --git a/packages/qwik-nx/src/generators/setup-tailwind/lib/add-tailwind-style-imports.ts b/packages/qwik-nx/src/generators/setup-tailwind/lib/add-tailwind-style-imports.ts index 356d35e4..b884bb91 100644 --- a/packages/qwik-nx/src/generators/setup-tailwind/lib/add-tailwind-style-imports.ts +++ b/packages/qwik-nx/src/generators/setup-tailwind/lib/add-tailwind-style-imports.ts @@ -6,8 +6,6 @@ import { Tree, } from '@nrwl/devkit'; -import { SetupTailwindOptions } from '../schema'; - const knownLocations = [ 'src/global.css', 'src/global.scss', @@ -17,8 +15,7 @@ const knownLocations = [ export function addTailwindStyleImports( tree: Tree, - project: ProjectConfiguration, - _options: SetupTailwindOptions + project: ProjectConfiguration ) { const candidates = knownLocations.map((x) => joinPathFragments(project.root, x) @@ -26,11 +23,12 @@ export function addTailwindStyleImports( const stylesPath = candidates.find((x) => tree.exists(x)); if (stylesPath) { - const content = tree.read(stylesPath).toString(); - tree.write( - stylesPath, - `@tailwind components;\n@tailwind base;\n@tailwind utilities;\n${content}` - ); + const content = tree.read(stylesPath)?.toString(); + content && + tree.write( + stylesPath, + `@tailwind components;\n@tailwind base;\n@tailwind utilities;\n${content}` + ); } else { logger.warn( stripIndents` diff --git a/packages/qwik-nx/src/generators/setup-tailwind/setup-tailwind.spec.ts b/packages/qwik-nx/src/generators/setup-tailwind/setup-tailwind.spec.ts index aaf190b9..e5106a35 100644 --- a/packages/qwik-nx/src/generators/setup-tailwind/setup-tailwind.spec.ts +++ b/packages/qwik-nx/src/generators/setup-tailwind/setup-tailwind.spec.ts @@ -27,7 +27,7 @@ describe('setup-tailwind', () => { project: 'example', }); - expect(tree.read(`apps/example/${stylesPath}`).toString()).toEqual( + expect(tree.read(`apps/example/${stylesPath}`)?.toString()).toEqual( stripIndents` @tailwind components; @tailwind base; @@ -80,7 +80,7 @@ describe('setup-tailwind', () => { await update(tree, { project: 'example' }); - expect(tree.read('apps/example/postcss.config.js').toString()).toEqual( + expect(tree.read('apps/example/postcss.config.js')?.toString()).toEqual( '// existing' ); }); @@ -97,7 +97,7 @@ describe('setup-tailwind', () => { await update(tree, { project: 'example' }); - expect(tree.read('apps/example/tailwind.config.js').toString()).toEqual( + expect(tree.read('apps/example/tailwind.config.js')?.toString()).toEqual( '// existing' ); }); diff --git a/packages/qwik-nx/src/generators/setup-tailwind/setup-tailwind.ts b/packages/qwik-nx/src/generators/setup-tailwind/setup-tailwind.ts index 8a78d94a..5b0ac23f 100644 --- a/packages/qwik-nx/src/generators/setup-tailwind/setup-tailwind.ts +++ b/packages/qwik-nx/src/generators/setup-tailwind/setup-tailwind.ts @@ -1,5 +1,6 @@ -import type { GeneratorCallback, Tree } from '@nrwl/devkit'; import { + GeneratorCallback, + Tree, addDependenciesToPackageJson, formatFiles, generateFiles, @@ -19,7 +20,7 @@ import { addTailwindStyleImports } from './lib/add-tailwind-style-imports'; export async function setupTailwindGenerator( tree: Tree, options: SetupTailwindOptions -) { +): Promise { const tasks: GeneratorCallback[] = []; const project = readProjectConfiguration(tree, options.project); @@ -30,14 +31,14 @@ export async function setupTailwindGenerator( logger.info( `Skipping setup since there are existing PostCSS or Tailwind configuration files. For manual setup instructions, see https://qwik.builder.io/integrations/integration/tailwind/.` ); - return; + return () => void 0; } generateFiles(tree, joinPathFragments(__dirname, './files'), project.root, { tmpl: '', }); - addTailwindStyleImports(tree, project, options); + addTailwindStyleImports(tree, project); if (!options.skipPackageJson) { tasks.push( diff --git a/packages/qwik-nx/src/plugins/qwik-nx-vite.plugin.spec.ts b/packages/qwik-nx/src/plugins/qwik-nx-vite.plugin.spec.ts index 267fc721..388437a2 100644 --- a/packages/qwik-nx/src/plugins/qwik-nx-vite.plugin.spec.ts +++ b/packages/qwik-nx/src/plugins/qwik-nx-vite.plugin.spec.ts @@ -77,9 +77,11 @@ describe('qwik-nx-vite plugin', () => { .mockReturnValue(workspaceConfig1); jest.spyOn(fs, 'readFileSync').mockReturnValue(tsConfigString1); - const getDecoratedPaths = async (options?: QwikNxVitePluginOptions) => { + const getDecoratedPaths = async ( + options?: QwikNxVitePluginOptions + ): Promise => { const plugin = qwikNxVite(options); - const vendorRoots = []; + const vendorRoots: string[] = []; const qwikViteMock = { name: 'vite-plugin-qwik', api: { diff --git a/packages/qwik-nx/src/plugins/qwik-nx-vite.plugin.ts b/packages/qwik-nx/src/plugins/qwik-nx-vite.plugin.ts index 51fefbfe..0cefc01e 100644 --- a/packages/qwik-nx/src/plugins/qwik-nx-vite.plugin.ts +++ b/packages/qwik-nx/src/plugins/qwik-nx-vite.plugin.ts @@ -75,7 +75,7 @@ function getVendorRoots(options?: QwikNxVitePluginOptions): string[] { } projects = projects.filter((p) => - decoratedPaths.some((path) => path.startsWith(p.sourceRoot)) + decoratedPaths.some((path) => path.startsWith(p.sourceRoot!)) ); if (options?.debug) { @@ -85,7 +85,7 @@ function getVendorRoots(options?: QwikNxVitePluginOptions): string[] { ); } - return projects.map((p) => p.sourceRoot).map((p) => join(workspaceRoot, p)); + return projects.map((p) => p.sourceRoot).map((p) => join(workspaceRoot, p!)); } function filterProjects( @@ -104,7 +104,7 @@ function filterProjects( } if (typeof filterConfig?.customFilter === 'function') { projects = projects.filter((p) => { - const matches = filterConfig.customFilter(p); + const matches = filterConfig.customFilter!(p); return exclusive ? !matches : matches; }); } @@ -119,12 +119,13 @@ function filterProjectsByName( if (Array.isArray(options)) { const optionsSet = new Set(options); return projects.filter((p) => { - const matches = optionsSet.has(p.name); + const matches = optionsSet.has(p.name!); return exclusive ? !matches : matches; }); } else if (options instanceof RegExp) { - return filterByRegex(projects, options, exclusive, (p) => p.name); + return filterByRegex(projects, options, exclusive, (p) => p.name!); } + return projects; } function filterProjectsByPath( @@ -133,8 +134,9 @@ function filterProjectsByPath( exclusive: boolean ): ProjectConfiguration[] { if (options instanceof RegExp) { - return filterByRegex(projects, options, exclusive, (p) => p.sourceRoot); + return filterByRegex(projects, options, exclusive, (p) => p.sourceRoot!); } + return projects; } function filterByRegex( @@ -153,6 +155,7 @@ function filterByRegex( return exclusive ? !matches : matches; }); } + return projects; } function filterProjectsByTags( @@ -162,11 +165,11 @@ function filterProjectsByTags( ): ProjectConfiguration[] { if (exclusive) { return projects.filter((p) => { - return tags.every((t) => !p.tags.includes(t)); + return tags.every((t) => !p.tags?.includes(t)); }); } else { return projects.filter((p) => { - return tags.every((t) => p.tags.includes(t)); + return tags.every((t) => p.tags?.includes(t)); }); } } diff --git a/packages/qwik-nx/src/utils/add-styled-dependencies.ts b/packages/qwik-nx/src/utils/add-styled-dependencies.ts index 336a88c7..cb3663ee 100644 --- a/packages/qwik-nx/src/utils/add-styled-dependencies.ts +++ b/packages/qwik-nx/src/utils/add-styled-dependencies.ts @@ -12,9 +12,9 @@ type PackageDependencies = Record< export function addStyledModuleDependencies( host: Tree, - styledModule: string + styledModule: string | undefined ): GeneratorCallback { - const extraDependencies = STYLE_DEPENDENCIES.get(styledModule); + const extraDependencies = STYLE_DEPENDENCIES.get(styledModule!); if (extraDependencies) { return addDependenciesToPackageJson( @@ -23,8 +23,7 @@ export function addStyledModuleDependencies( extraDependencies.devDependencies ); } else { - // eslint-disable-next-line @typescript-eslint/no-empty-function - return () => {}; + return () => void 0; } } diff --git a/packages/qwik-nx/src/utils/configure-eslint.ts b/packages/qwik-nx/src/utils/configure-eslint.ts index 5ce8b94c..dbbe728d 100644 --- a/packages/qwik-nx/src/utils/configure-eslint.ts +++ b/packages/qwik-nx/src/utils/configure-eslint.ts @@ -20,7 +20,7 @@ export function configureEslint( '.eslintrc.json' ); - let existingLibEslintConfig: Buffer | undefined; + let existingLibEslintConfig: Buffer | null | undefined; if (tree.exists(existingLibEslintConfigPath)) { existingLibEslintConfig = tree.read(existingLibEslintConfigPath); diff --git a/packages/qwik-nx/src/utils/get-installed-nx-version.ts b/packages/qwik-nx/src/utils/get-installed-nx-version.ts index 6cf0ac6b..f93a888e 100644 --- a/packages/qwik-nx/src/utils/get-installed-nx-version.ts +++ b/packages/qwik-nx/src/utils/get-installed-nx-version.ts @@ -1,9 +1,9 @@ import { readJson, Tree } from '@nrwl/devkit'; -export function getInstalledNxVersion(tree: Tree): string | null { +export function getInstalledNxVersion(tree: Tree): string { const pkgJson = readJson(tree, 'package.json'); if (pkgJson.devDependencies && pkgJson.devDependencies['@nrwl/workspace']) { return pkgJson.devDependencies['@nrwl/workspace']; } - return; + throw new Error('Could not resolve nx version from the package.json'); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 837bbf08..12cc8e89 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,8 +23,10 @@ importers: '@swc/cli': ~0.1.55 '@swc/core': ^1.2.173 '@swc/helpers': ~0.4.11 + '@types/fs-extra': 11.0.1 '@types/jest': 28.1.1 '@types/node': 16.11.7 + '@types/tcp-port-used': 1.0.1 '@typescript-eslint/eslint-plugin': ^5.36.1 '@typescript-eslint/parser': ^5.36.1 all-contributors-cli: ^6.24.0 @@ -34,8 +36,10 @@ importers: cz-conventional-changelog: ^3.3.0 eslint: ~8.15.0 eslint-config-prettier: 8.1.0 + eslint-plugin-unused-imports: 2.0.0 fs-extra: 11.1.0 husky: ^8.0.1 + is-windows: 1.0.2 jest: 28.1.1 jest-environment-jsdom: 28.1.1 jsonc-eslint-parser: ^2.1.0 @@ -74,8 +78,10 @@ importers: '@swc-node/register': 1.5.4_a6ehxei6k73t2xc6ggukxhgzve '@swc/cli': 0.1.57_@swc+core@1.3.19 '@swc/core': 1.3.19 + '@types/fs-extra': 11.0.1 '@types/jest': 28.1.1 '@types/node': 16.11.7 + '@types/tcp-port-used': 1.0.1 '@typescript-eslint/eslint-plugin': 5.44.0_bjqz7gzhqr3kjaidq2xvldwvzq '@typescript-eslint/parser': 5.44.0_oy7hgmlo6357d5kkcjbkfgtg4q all-contributors-cli: 6.24.0 @@ -85,8 +91,10 @@ importers: cz-conventional-changelog: 3.3.0_@swc+core@1.3.19 eslint: 8.15.0 eslint-config-prettier: 8.1.0_eslint@8.15.0 + eslint-plugin-unused-imports: 2.0.0_6rm2se2hodxb5mij3wg3njkg6e fs-extra: 11.1.0 husky: 8.0.2 + is-windows: 1.0.2 jest: 28.1.1_6m7kcbkkzjz4ln6z66tlzx44we jest-environment-jsdom: 28.1.1 jsonc-eslint-parser: 2.1.0 @@ -3582,6 +3590,16 @@ packages: } dev: true + /@types/fs-extra/11.0.1: + resolution: + { + integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==, + } + dependencies: + '@types/jsonfile': 6.1.1 + '@types/node': 16.11.7 + dev: true + /@types/graceful-fs/4.1.5: resolution: { @@ -3644,6 +3662,15 @@ packages: } dev: true + /@types/jsonfile/6.1.1: + resolution: + { + integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==, + } + dependencies: + '@types/node': 16.11.7 + dev: true + /@types/minimatch/3.0.5: resolution: { @@ -3713,6 +3740,13 @@ packages: } dev: true + /@types/tcp-port-used/1.0.1: + resolution: + { + integrity: sha512-6pwWTx8oUtWvsiZUCrhrK/53MzKVLnuNSSaZILPy3uMes9QnTrLMar9BDlJArbMOjDcjb3QXFk6Rz8qmmuySZw==, + } + dev: true + /@types/tough-cookie/4.0.2: resolution: { @@ -5633,6 +5667,32 @@ packages: eslint: 8.15.0 dev: true + /eslint-plugin-unused-imports/2.0.0_6rm2se2hodxb5mij3wg3njkg6e: + resolution: + { + integrity: sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + peerDependencies: + '@typescript-eslint/eslint-plugin': ^5.0.0 + eslint: ^8.0.0 + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 5.44.0_bjqz7gzhqr3kjaidq2xvldwvzq + eslint: 8.15.0 + eslint-rule-composer: 0.3.0 + dev: true + + /eslint-rule-composer/0.3.0: + resolution: + { + integrity: sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==, + } + engines: { node: '>=4.0.0' } + dev: true + /eslint-scope/5.1.1: resolution: { diff --git a/tsconfig.base.json b/tsconfig.base.json index ff7cbc5f..28fb8e43 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,6 +1,7 @@ { "compileOnSave": false, "compilerOptions": { + "strict": true, "rootDir": ".", "sourceMap": true, "declaration": false, @@ -8,6 +9,7 @@ "emitDecoratorMetadata": true, "experimentalDecorators": true, "importHelpers": true, + "isolatedModules": true, "target": "es2015", "module": "esnext", "lib": ["es2017", "dom"],