From eae4c00c63de40d0168faf661e33d93f3f672ff5 Mon Sep 17 00:00:00 2001 From: Adel Khamatov Date: Thu, 23 Oct 2025 16:08:29 +0300 Subject: [PATCH 1/9] chore(devextreme-react): remove gulp --- packages/devextreme-react/build.config.js | 16 -- packages/devextreme-react/gulpfile.js | 240 ---------------------- packages/devextreme-react/package.json | 11 +- pnpm-lock.yaml | 33 +-- 4 files changed, 13 insertions(+), 287 deletions(-) delete mode 100644 packages/devextreme-react/build.config.js delete mode 100644 packages/devextreme-react/gulpfile.js diff --git a/packages/devextreme-react/build.config.js b/packages/devextreme-react/build.config.js deleted file mode 100644 index f7ce811b5e38..000000000000 --- a/packages/devextreme-react/build.config.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - src: './src/**/*.{ts,tsx}', - testSrc: './src/**/__tests__/**/*.*', - npm: { - dist: './npm/', - package: 'package.json', - license: 'LICENSE', - readme: 'README.md' - }, - generatedComponentsDir: './src', - coreComponentsDir: './src/core', - indexFileName: './src/index.ts', - baseComponent: './core/component', - extensionComponent: './core/extension-component', - configComponent: './core/nested-option' -}; diff --git a/packages/devextreme-react/gulpfile.js b/packages/devextreme-react/gulpfile.js deleted file mode 100644 index fa897037d4e8..000000000000 --- a/packages/devextreme-react/gulpfile.js +++ /dev/null @@ -1,240 +0,0 @@ -const fs = require('fs'); -const del = require('del'); -const gulp = require('gulp'); -const shell = require('gulp-shell'); -const header = require('gulp-header'); -const ts = require('gulp-typescript'); -const config = require('./build.config'); -const path = require('path'); -const generateReactComponents = require('devextreme-internal-tools').generateReactComponents; -const { reactConfig } = require('../../tools/generators-config'); - -const GENERATE = 'generate'; -const CLEAN = 'clean'; -const GEN_RUN = 'generator.run'; -const NPM_CLEAN = 'npm.clean'; -const NPM_PACKAGE = 'npm.package'; -const NPM_LICENSE = 'npm.license'; -const NPM_BUILD_WITH_HEADERS = 'npm.license-headers'; -const NPM_README = 'npm.readme'; -const NPM_BUILD = 'npm.build'; -const NPM_BUILD_ESM = 'npm.build-esm'; -const NPM_BUILD_CJS = 'npm.build-cjs'; -const NPM_PREPARE_MODULES = 'npm.prepare-modules'; -const NPM_PACK = 'npm.pack'; - -gulp.task(CLEAN, (c) => - del([`${config.generatedComponentsDir}\\*`, `!${config.coreComponentsDir}`], c) -); - -gulp.task(GEN_RUN, (done) => { - generateReactComponents({ - metaData: JSON.parse(fs.readFileSync(require.resolve('devextreme-metadata/integration-data.json')).toString()), - components: { - baseComponent: config.baseComponent, - extensionComponent: config.extensionComponent, - configComponent: config.configComponent - }, - out: { - componentsDir: config.generatedComponentsDir, - indexFileName: config.indexFileName - }, - widgetsPackage: 'devextreme', - typeGenerationOptions: { - generateReexports: true, - generateCustomTypes: true, - }, - templatingOptions: { - quotes: 'double', - excplicitIndexInImports: true, - }, - unifiedConfig: reactConfig, - }); - - done(); -}); - -gulp.task(GENERATE, gulp.series( - CLEAN, - GEN_RUN -)); - -gulp.task(NPM_CLEAN, (c) => - del(config.npm.dist, c) -); - -gulp.task(NPM_PACKAGE, (done) => { - const pkg = require('./package.json'); - delete pkg.publishConfig; - fs.writeFileSync(path.join(config.npm.dist, 'package.json'), JSON.stringify(pkg, null, 2)) - done(); -}); - -gulp.task(NPM_LICENSE, gulp.series( - () => gulp.src(config.npm.license).pipe(gulp.dest(config.npm.dist)) -)); - -gulp.task(NPM_README, gulp.series( - () => gulp.src(config.npm.readme).pipe(gulp.dest(config.npm.dist)) -)); - -gulp.task( - NPM_BUILD_ESM, - gulp.series(() => - gulp - .src([config.src, `!${config.testSrc}`]) - .pipe(ts('tsconfig.esm.json')) - .pipe(gulp.dest(config.npm.dist + '/esm')) - ) -); - -gulp.task( - NPM_BUILD_CJS, - gulp.series(() => - gulp - .src([config.src, `!${config.testSrc}`]) - .pipe(ts('tsconfig.json')) - .pipe(gulp.dest(config.npm.dist + '/cjs')) - ) -); - -gulp.task(NPM_PREPARE_MODULES, (done) => { - const packParamsForFolders = [ - ['common'], - ['core', ['template', 'config', 'nested-option', 'component', 'extension-component']], - ['common/core'], - ['common/data'], - ['common/export'], - ]; - const modulesImportsFromIndex = fs.readFileSync( - config.npm.dist + 'esm/index.js', - 'utf8' - ); - const modulesPaths = modulesImportsFromIndex.matchAll(/from "\.\/([^;]+)";/g); - const packParamsForModules = [...modulesPaths].map(([, modulePath]) => { - const [, , moduleFilePath, moduleFileName] = - modulePath.match(/((.*)\/)?([^/]+$)/); - - return ['', [moduleFileName], moduleFilePath]; - }); - - [ ...packParamsForModules, ...packParamsForFolders].forEach( - ([folder, moduleFileNames, moduleFilePath]) => - makeModule(folder, moduleFileNames, moduleFilePath) - ); - - done(); -}); - -gulp.task(NPM_BUILD, gulp.series( - NPM_CLEAN, - gulp.parallel( - NPM_LICENSE, - NPM_README, - NPM_BUILD_ESM, - NPM_BUILD_CJS - ), - NPM_PACKAGE -)); - -gulp.task(NPM_BUILD_WITH_HEADERS, gulp.series( - NPM_BUILD, - () => { - const pkg = require('./package.json'); - const now = new Date(); - const data = { - pkg, - date: now.toDateString(), - year: now.getFullYear() - }; - - const banner = [ - '/*!', - ' * <%= pkg.name %>', - ' * Version: <%= pkg.version %>', - ' * Build date: <%= date %>', - ' *', - ' * Copyright (c) 2012 - <%= year %> Developer Express Inc. ALL RIGHTS RESERVED', - ' *', - ' * This software may be modified and distributed under the terms', - ' * of the MIT license. See the LICENSE file in the root of the project for details.', - ' *', - ' * https://github.com/DevExpress/devextreme-react', - ' */', - '\n' - ].join('\n'); - - return gulp.src(`${config.npm.dist}**/*.{ts,js}`) - .pipe(header(banner, data)) - .pipe(gulp.dest(config.npm.dist)); - } -)); - -gulp.task(NPM_PACK, gulp.series( - NPM_BUILD_WITH_HEADERS, - NPM_PREPARE_MODULES, - shell.task(['pnpm pack']) -)); - - -function makeModule(folder, moduleFileNames, moduleFilePath) { - const distFolder = path.join(__dirname, config.npm.dist); - const distModuleFolder = path.join(distFolder, folder); - const distEsmFolder = path.join(distFolder, 'esm', folder); - const moduleNames = moduleFileNames || findJsModuleFileNamesInFolder(distEsmFolder); - - try { - if (!fs.existsSync(distModuleFolder)) { - fs.mkdirSync(distModuleFolder); - } - - if (folder && fs.existsSync(path.join(distEsmFolder, 'index.js'))) { - generatePackageJsonFile(folder); - } - - moduleNames.forEach((moduleFileName) => { - fs.mkdirSync(path.join(distModuleFolder, moduleFileName)); - - generatePackageJsonFile(folder, moduleFileName, moduleFilePath); - }) - } catch (error) { - error.message = `Exception while makeModule(${folder}).\n ${error.message}`; - throw error; - } -} -function generatePackageJsonFile(folder, moduleFileName, filePath = folder) { - const moduleName = moduleFileName || ''; - const absoluteModulePath = path.join(__dirname, config.npm.dist, folder, moduleName); - const moduleFilePath = (filePath ? filePath + '/' : '') + (moduleName || 'index'); - const relativePath = path.relative( - absoluteModulePath, - path.join(__dirname, config.npm.dist, 'esm', moduleFilePath + '.js') - ); - - const relativeBase = '../'.repeat(relativePath.split('..').length - 1); - - fs.writeFileSync( - path.join(absoluteModulePath, 'package.json'), - JSON.stringify( - { - sideEffects: false, - main: `${relativeBase}cjs/${moduleFilePath}.js`, - module: `${relativeBase}esm/${moduleFilePath}.js`, - typings: `${relativeBase}cjs/${moduleFilePath}.d.ts`, - }, - null, - 2 - ) - ); -} - -function findJsModuleFileNamesInFolder(dir) { - return fs.readdirSync(dir).filter((file) => { - const filePath = path.join(dir, file); - - return !fs.statSync(filePath).isDirectory() - && file.includes('.js') - && !file.includes('index.js') - } - ).map((filePath) => path.parse(filePath).name); -} diff --git a/packages/devextreme-react/package.json b/packages/devextreme-react/package.json index 7cfc4bdac3ce..5bedd1a7cc21 100644 --- a/packages/devextreme-react/package.json +++ b/packages/devextreme-react/package.json @@ -12,10 +12,10 @@ "module": "./esm/index.js", "types": "./cjs/index.d.ts", "scripts": { - "clean": "gulp clean", - "regenerate": "pnpm run clean && gulp generate", + "clean": "nx clean devextreme-react", + "regenerate": "nx regenerate devextreme-react", "lint": "eslint src/core", - "pack": "gulp npm.pack", + "pack": "nx pack devextreme-react", "test": "jest" }, "keywords": [ @@ -69,12 +69,7 @@ "@testing-library/user-event": "14.5.2", "@types/react": "~18.0.0", "@types/react-dom": "~18.0.0", - "del": "3.0.0", "devextreme-metadata": "workspace:*", - "gulp": "4.0.2", - "gulp-header": "2.0.9", - "gulp-shell": "0.8.0", - "gulp-typescript": "5.0.1", "jest-environment-jsdom": "29.7.0", "react": "18.0.0", "react-dom": "18.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec310667af5e..4cd29416dd36 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1929,9 +1929,6 @@ importers: '@typescript-eslint/parser': specifier: 'catalog:' version: 8.23.0(eslint@9.18.0(jiti@1.21.6))(typescript@4.9.5) - del: - specifier: 3.0.0 - version: 3.0.0 devextreme-metadata: specifier: workspace:* version: link:../devextreme-metadata @@ -1950,18 +1947,6 @@ importers: eslint-plugin-import: specifier: 'catalog:' version: 2.31.0(@typescript-eslint/parser@8.23.0(eslint@9.18.0(jiti@1.21.6))(typescript@4.9.5))(eslint@9.18.0(jiti@1.21.6)) - gulp: - specifier: 4.0.2 - version: 4.0.2 - gulp-header: - specifier: 2.0.9 - version: 2.0.9 - gulp-shell: - specifier: 0.8.0 - version: 0.8.0 - gulp-typescript: - specifier: 5.0.1 - version: 5.0.1(typescript@4.9.5) jest-environment-jsdom: specifier: 29.7.0 version: 29.7.0 @@ -24707,7 +24692,7 @@ snapshots: '@parcel/source-map': 2.1.1 '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) abortcontroller-polyfill: 1.7.6 base-x: 3.0.10 browserslist: 4.25.3 @@ -24735,7 +24720,7 @@ snapshots: '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/utils': 2.12.0 '@parcel/watcher': 2.5.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) transitivePeerDependencies: - '@swc/helpers' @@ -24809,7 +24794,7 @@ snapshots: '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@parcel/rust': 2.12.0 '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/optimizer-svgo@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))': dependencies: @@ -24841,7 +24826,7 @@ snapshots: '@parcel/node-resolver-core': 3.3.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@swc/core': 1.9.2(@swc/helpers@0.5.15) semver: 7.7.2 transitivePeerDependencies: @@ -25030,7 +25015,7 @@ snapshots: '@parcel/core': 2.12.0(@swc/helpers@0.5.15) '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) nullthrows: 1.1.1 '@parcel/transformer-js@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))': @@ -25041,7 +25026,7 @@ snapshots: '@parcel/rust': 2.12.0 '@parcel/source-map': 2.1.1 '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@swc/helpers': 0.5.15 browserslist: 4.25.3 nullthrows: 1.1.1 @@ -25114,7 +25099,7 @@ snapshots: '@parcel/fs': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/package-manager': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/source-map': 2.1.1 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) utility-types: 3.11.0 transitivePeerDependencies: - '@parcel/core' @@ -25191,7 +25176,7 @@ snapshots: '@parcel/watcher-win32-ia32': 2.5.0 '@parcel/watcher-win32-x64': 2.5.0 - '@parcel/workers@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))': + '@parcel/workers@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)': dependencies: '@parcel/core': 2.12.0(@swc/helpers@0.5.15) '@parcel/diagnostic': 2.12.0 @@ -25200,6 +25185,8 @@ snapshots: '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/utils': 2.12.0 nullthrows: 1.1.1 + transitivePeerDependencies: + - '@swc/helpers' '@phenomnomnominal/tsquery@5.0.1(typescript@5.9.2)': dependencies: From cae8b7b49ff972071b7ab996f14590df24c8ec00 Mon Sep 17 00:00:00 2001 From: Adel Khamatov Date: Thu, 23 Oct 2025 16:16:42 +0300 Subject: [PATCH 2/9] chore(devextreme-react): replace gulp with nx plugin --- nx.json | 1 + packages/devextreme-react/project.json | 131 ++++- packages/nx-infra-plugin/executors.json | 44 ++ packages/nx-infra-plugin/jest.config.ts | 10 + packages/nx-infra-plugin/package.json | 26 + packages/nx-infra-plugin/prod/executors.json | 44 ++ packages/nx-infra-plugin/prod/package.json | 31 ++ .../add-license-headers/executor.d.ts | 4 + .../executors/add-license-headers/executor.js | 119 +++++ .../executors/add-license-headers/schema.d.ts | 4 + .../executors/add-license-headers/schema.js | 2 + .../executors/add-license-headers/schema.json | 16 + .../executors/build-typescript/executor.d.ts | 4 + .../executors/build-typescript/executor.js | 114 +++++ .../executors/build-typescript/schema.d.ts | 7 + .../src/executors/build-typescript/schema.js | 2 + .../executors/build-typescript/schema.json | 33 ++ .../prod/src/executors/clean/executor.d.ts | 4 + .../prod/src/executors/clean/executor.js | 107 +++++ .../prod/src/executors/clean/schema.d.ts | 5 + .../prod/src/executors/clean/schema.js | 2 + .../prod/src/executors/clean/schema.json | 25 + .../src/executors/copy-files/executor.d.ts | 4 + .../prod/src/executors/copy-files/executor.js | 57 +++ .../prod/src/executors/copy-files/schema.d.ts | 6 + .../prod/src/executors/copy-files/schema.js | 2 + .../prod/src/executors/copy-files/schema.json | 22 + .../generate-react-components/executor.d.ts | 4 + .../generate-react-components/executor.js | 225 +++++++++ .../generate-react-components/schema.d.ts | 8 + .../generate-react-components/schema.js | 2 + .../generate-react-components/schema.json | 35 ++ .../prod/src/executors/pack-npm/executor.d.ts | 4 + .../prod/src/executors/pack-npm/executor.js | 37 ++ .../prod/src/executors/pack-npm/schema.d.ts | 3 + .../prod/src/executors/pack-npm/schema.js | 2 + .../prod/src/executors/pack-npm/schema.json | 11 + .../prepare-package-json/executor.d.ts | 4 + .../prepare-package-json/executor.js | 55 +++ .../prepare-package-json/schema.d.ts | 4 + .../executors/prepare-package-json/schema.js | 2 + .../prepare-package-json/schema.json | 16 + .../prepare-submodules/executor.d.ts | 4 + .../executors/prepare-submodules/executor.js | 129 +++++ .../executors/prepare-submodules/schema.d.ts | 5 + .../executors/prepare-submodules/schema.js | 2 + .../executors/prepare-submodules/schema.json | 18 + packages/nx-infra-plugin/prod/src/index.d.ts | 3 + packages/nx-infra-plugin/prod/src/index.js | 8 + .../prod/src/utils/error-handler.d.ts | 3 + .../prod/src/utils/error-handler.js | 20 + .../prod/src/utils/file-operations.d.ts | 10 + .../prod/src/utils/file-operations.js | 87 ++++ .../nx-infra-plugin/prod/src/utils/index.d.ts | 4 + .../nx-infra-plugin/prod/src/utils/index.js | 20 + .../prod/src/utils/path-resolver.d.ts | 4 + .../prod/src/utils/path-resolver.js | 53 +++ .../prod/src/utils/test-utils.d.ts | 10 + .../prod/src/utils/test-utils.js | 55 +++ .../nx-infra-plugin/prod/src/utils/types.d.ts | 48 ++ .../nx-infra-plugin/prod/src/utils/types.js | 2 + packages/nx-infra-plugin/project.json | 47 ++ .../add-license-headers/executor.e2e.spec.ts | 355 ++++++++++++++ .../executors/add-license-headers/executor.ts | 123 +++++ .../executors/add-license-headers/schema.json | 16 + .../executors/add-license-headers/schema.ts | 4 + .../build-typescript/executor.e2e.spec.ts | 172 +++++++ .../executors/build-typescript/executor.ts | 139 ++++++ .../executors/build-typescript/schema.json | 33 ++ .../src/executors/build-typescript/schema.ts | 7 + .../src/executors/clean/executor.e2e.spec.ts | 447 ++++++++++++++++++ .../src/executors/clean/executor.ts | 131 +++++ .../src/executors/clean/schema.json | 25 + .../src/executors/clean/schema.ts | 5 + .../executors/copy-files/executor.e2e.spec.ts | 118 +++++ .../src/executors/copy-files/executor.ts | 43 ++ .../src/executors/copy-files/schema.json | 22 + .../src/executors/copy-files/schema.ts | 6 + .../executor.e2e.spec.ts | 288 +++++++++++ .../generate-react-components/executor.ts | 279 +++++++++++ .../generate-react-components/schema.d.ts | 8 + .../generate-react-components/schema.json | 35 ++ .../generate-react-components/schema.ts | 8 + .../executors/pack-npm/executor.e2e.spec.ts | 127 +++++ .../src/executors/pack-npm/executor.ts | 44 ++ .../src/executors/pack-npm/schema.json | 11 + .../src/executors/pack-npm/schema.ts | 3 + .../prepare-package-json/executor.e2e.spec.ts | 110 +++++ .../prepare-package-json/executor.ts | 50 ++ .../prepare-package-json/schema.json | 16 + .../executors/prepare-package-json/schema.ts | 4 + .../prepare-submodules/executor.e2e.spec.ts | 221 +++++++++ .../executors/prepare-submodules/executor.ts | 174 +++++++ .../executors/prepare-submodules/schema.json | 18 + .../executors/prepare-submodules/schema.ts | 6 + packages/nx-infra-plugin/src/index.ts | 5 + .../src/utils/error-handler.ts | 17 + .../src/utils/file-operations.ts | 72 +++ packages/nx-infra-plugin/src/utils/index.ts | 4 + .../src/utils/path-resolver.ts | 38 ++ .../nx-infra-plugin/src/utils/test-utils.ts | 44 ++ packages/nx-infra-plugin/src/utils/types.ts | 51 ++ packages/nx-infra-plugin/tsconfig.json | 16 + packages/nx-infra-plugin/tsconfig.lib.json | 12 + packages/nx-infra-plugin/tsconfig.spec.json | 14 + pnpm-lock.yaml | 347 ++++++++------ tools/scripts/build-all.ts | 2 +- 107 files changed, 5262 insertions(+), 178 deletions(-) create mode 100644 packages/nx-infra-plugin/executors.json create mode 100644 packages/nx-infra-plugin/jest.config.ts create mode 100644 packages/nx-infra-plugin/package.json create mode 100644 packages/nx-infra-plugin/prod/executors.json create mode 100644 packages/nx-infra-plugin/prod/package.json create mode 100644 packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.json create mode 100644 packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.json create mode 100644 packages/nx-infra-plugin/prod/src/executors/clean/executor.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/clean/executor.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/clean/schema.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/clean/schema.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/clean/schema.json create mode 100644 packages/nx-infra-plugin/prod/src/executors/copy-files/executor.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/copy-files/executor.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/copy-files/schema.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/copy-files/schema.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/copy-files/schema.json create mode 100644 packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.json create mode 100644 packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.json create mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.json create mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.js create mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.json create mode 100644 packages/nx-infra-plugin/prod/src/index.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/index.js create mode 100644 packages/nx-infra-plugin/prod/src/utils/error-handler.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/utils/error-handler.js create mode 100644 packages/nx-infra-plugin/prod/src/utils/file-operations.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/utils/file-operations.js create mode 100644 packages/nx-infra-plugin/prod/src/utils/index.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/utils/index.js create mode 100644 packages/nx-infra-plugin/prod/src/utils/path-resolver.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/utils/path-resolver.js create mode 100644 packages/nx-infra-plugin/prod/src/utils/test-utils.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/utils/test-utils.js create mode 100644 packages/nx-infra-plugin/prod/src/utils/types.d.ts create mode 100644 packages/nx-infra-plugin/prod/src/utils/types.js create mode 100644 packages/nx-infra-plugin/project.json create mode 100644 packages/nx-infra-plugin/src/executors/add-license-headers/executor.e2e.spec.ts create mode 100644 packages/nx-infra-plugin/src/executors/add-license-headers/executor.ts create mode 100644 packages/nx-infra-plugin/src/executors/add-license-headers/schema.json create mode 100644 packages/nx-infra-plugin/src/executors/add-license-headers/schema.ts create mode 100644 packages/nx-infra-plugin/src/executors/build-typescript/executor.e2e.spec.ts create mode 100644 packages/nx-infra-plugin/src/executors/build-typescript/executor.ts create mode 100644 packages/nx-infra-plugin/src/executors/build-typescript/schema.json create mode 100644 packages/nx-infra-plugin/src/executors/build-typescript/schema.ts create mode 100644 packages/nx-infra-plugin/src/executors/clean/executor.e2e.spec.ts create mode 100644 packages/nx-infra-plugin/src/executors/clean/executor.ts create mode 100644 packages/nx-infra-plugin/src/executors/clean/schema.json create mode 100644 packages/nx-infra-plugin/src/executors/clean/schema.ts create mode 100644 packages/nx-infra-plugin/src/executors/copy-files/executor.e2e.spec.ts create mode 100644 packages/nx-infra-plugin/src/executors/copy-files/executor.ts create mode 100644 packages/nx-infra-plugin/src/executors/copy-files/schema.json create mode 100644 packages/nx-infra-plugin/src/executors/copy-files/schema.ts create mode 100644 packages/nx-infra-plugin/src/executors/generate-react-components/executor.e2e.spec.ts create mode 100644 packages/nx-infra-plugin/src/executors/generate-react-components/executor.ts create mode 100644 packages/nx-infra-plugin/src/executors/generate-react-components/schema.d.ts create mode 100644 packages/nx-infra-plugin/src/executors/generate-react-components/schema.json create mode 100644 packages/nx-infra-plugin/src/executors/generate-react-components/schema.ts create mode 100644 packages/nx-infra-plugin/src/executors/pack-npm/executor.e2e.spec.ts create mode 100644 packages/nx-infra-plugin/src/executors/pack-npm/executor.ts create mode 100644 packages/nx-infra-plugin/src/executors/pack-npm/schema.json create mode 100644 packages/nx-infra-plugin/src/executors/pack-npm/schema.ts create mode 100644 packages/nx-infra-plugin/src/executors/prepare-package-json/executor.e2e.spec.ts create mode 100644 packages/nx-infra-plugin/src/executors/prepare-package-json/executor.ts create mode 100644 packages/nx-infra-plugin/src/executors/prepare-package-json/schema.json create mode 100644 packages/nx-infra-plugin/src/executors/prepare-package-json/schema.ts create mode 100644 packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts create mode 100644 packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts create mode 100644 packages/nx-infra-plugin/src/executors/prepare-submodules/schema.json create mode 100644 packages/nx-infra-plugin/src/executors/prepare-submodules/schema.ts create mode 100644 packages/nx-infra-plugin/src/index.ts create mode 100644 packages/nx-infra-plugin/src/utils/error-handler.ts create mode 100644 packages/nx-infra-plugin/src/utils/file-operations.ts create mode 100644 packages/nx-infra-plugin/src/utils/index.ts create mode 100644 packages/nx-infra-plugin/src/utils/path-resolver.ts create mode 100644 packages/nx-infra-plugin/src/utils/test-utils.ts create mode 100644 packages/nx-infra-plugin/src/utils/types.ts create mode 100644 packages/nx-infra-plugin/tsconfig.json create mode 100644 packages/nx-infra-plugin/tsconfig.lib.json create mode 100644 packages/nx-infra-plugin/tsconfig.spec.json diff --git a/nx.json b/nx.json index f26b8af2e552..67daac063585 100644 --- a/nx.json +++ b/nx.json @@ -2,6 +2,7 @@ "extends": "nx/presets/npm.json", "$schema": "./node_modules/nx/schemas/nx-schema.json", "nxCloudAccessToken": "ZDFmMzkyZTYtZmU5MC00MDMyLWI3NDktYjhhYWUxZWM4YTg3fHJlYWQ=", + "plugins": ["./packages/nx-infra-plugin/prod"], "namedInputs": { "metadataToolsCommonInputs": [ "{projectRoot}/**/*.ts", diff --git a/packages/devextreme-react/project.json b/packages/devextreme-react/project.json index 3cf1edcf8cc8..f1806b0c4ad0 100644 --- a/packages/devextreme-react/project.json +++ b/packages/devextreme-react/project.json @@ -4,40 +4,120 @@ "sourceRoot": "packages/devextreme-react", "projectType": "library", "targets": { - "build": { - "executor": "nx:run-script", - "dependsOn": ["^build"], + "clean": { + "executor": "devextreme-nx-infra-plugin:clean", + "options": { + "targetDirectory": "./src", + "excludePatterns": ["./src/core", "./src/common"], + "mode": "recursive" + } + }, + "regenerate": { + "executor": "devextreme-nx-infra-plugin:generate-react-components", + "dependsOn": ["devextreme-metadata:generate","clean"], "options": { - "script": "pack" + "metadataPath": "../devextreme-metadata/dist/integration-data.json", + "componentsDir": "./src", + "indexFileName": "./src/index.ts", + "baseComponent": "./core/component", + "extensionComponent": "./core/extension-component", + "configComponent": "./core/nested-option" + } + }, + "build:esm": { + "executor": "devextreme-nx-infra-plugin:build-typescript", + "dependsOn": ["npm:clean"], + "options": { + "srcPattern": "./src/**/*.{ts,tsx}", + "excludePattern": "./src/**/__tests__/**/*", + "tsconfig": "./tsconfig.esm.json", + "outDir": "./npm/esm", + "module": "esm" }, - "inputs": [ - "default" - ], - "outputs": [ - "{projectRoot}/npm" - ], - "cache": true + "outputs": ["{projectRoot}/npm/esm"], + "cache": true, + "inputs": ["default"] }, - "pack": { - "executor": "nx:run-script", + "build:cjs": { + "executor": "devextreme-nx-infra-plugin:build-typescript", + "dependsOn": ["npm:clean"], "options": { - "script": "pack" + "srcPattern": "./src/**/*.{ts,tsx}", + "excludePattern": "./src/**/__tests__/**/*", + "tsconfig": "./tsconfig.json", + "outDir": "./npm/cjs", + "module": "cjs" }, - "inputs": [ - "default" - ], - "outputs": [ - "{projectRoot}/npm" - ], - "cache": true + "outputs": ["{projectRoot}/npm/cjs"], + "cache": true, + "inputs": ["default"] }, - "regenerate": { - "executor": "nx:run-script", - "dependsOn": ["devextreme-metadata:generate"], + "npm:clean": { + "executor": "devextreme-nx-infra-plugin:clean", + "options": { + "targetDirectory": "./npm", + "mode": "simple" + } + }, + "prepare-package-json": { + "executor": "devextreme-nx-infra-plugin:prepare-package-json", + "dependsOn": ["npm:clean", "build:esm", "build:cjs"], + "options": {} + }, + "license-headers": { + "executor": "devextreme-nx-infra-plugin:add-license-headers", + "dependsOn": ["prepare-package-json"], + "options": { + "targetDirectory": "./npm", + "packageJsonPath": "./package.json" + } + }, + "npm:prepare-modules": { + "executor": "devextreme-nx-infra-plugin:prepare-submodules", + "dependsOn": ["npm:clean", "license-headers", "copy-files"], + "options": { + "distDirectory": "./npm" + } + }, + "copy-files": { + "executor": "devextreme-nx-infra-plugin:copy-files", + "dependsOn": ["prepare-package-json"], "options": { - "script": "regenerate" + "files": [ + { + "from": "./LICENSE", + "to": "./npm/LICENSE" + }, + { + "from": "./README.md", + "to": "./npm/README.md" + } + ] } }, + "pack": { + "executor": "devextreme-nx-infra-plugin:pack-npm", + "dependsOn": ["npm:prepare-modules"], + "options": { + "workingDirectory": "./npm" + }, + "outputs": ["{projectRoot}/npm/*.tgz"], + "cache": true, + "inputs": ["default"] + }, + "build": { + "executor": "devextreme-nx-infra-plugin:pack-npm", + "dependsOn": ["npm:prepare-modules", "^build"], + "options": { + "workingDirectory": "./npm" + }, + "outputs": [ + "{projectRoot}/npm", + "{projectRoot}/*.tgz" + ], + "cache": true, + "inputs": ["default"] + }, "test": { "executor": "nx:run-script", "options": { @@ -56,7 +136,6 @@ "{projectRoot}/src/**/*", "!{projectRoot}/src/**/__tests__/*", "{projectRoot}/build.config.js", - "{projectRoot}/gulpfile.js", "{projectRoot}/tsconfig*", "{workspaceRoot}/tsconfig.json" ], diff --git a/packages/nx-infra-plugin/executors.json b/packages/nx-infra-plugin/executors.json new file mode 100644 index 000000000000..b429a50f06a6 --- /dev/null +++ b/packages/nx-infra-plugin/executors.json @@ -0,0 +1,44 @@ +{ + "executors": { + "generate-react-components": { + "implementation": "./src/executors/generate-react-components/executor", + "schema": "./src/executors/generate-react-components/schema.json", + "description": "Generate React components from DevExtreme metadata" + }, + "clean": { + "implementation": "./src/executors/clean/executor", + "schema": "./src/executors/clean/schema.json", + "description": "Clean directories with support for simple or recursive mode" + }, + "add-license-headers": { + "implementation": "./src/executors/add-license-headers/executor", + "schema": "./src/executors/add-license-headers/schema.json", + "description": "Add license headers to compiled files" + }, + "prepare-submodules": { + "implementation": "./src/executors/prepare-submodules/executor", + "schema": "./src/executors/prepare-submodules/schema.json", + "description": "Prepare submodule entry points with package.json files" + }, + "copy-files": { + "implementation": "./src/executors/copy-files/executor", + "schema": "./src/executors/copy-files/schema.json", + "description": "Copy files to destination" + }, + "build-typescript": { + "implementation": "./src/executors/build-typescript/executor", + "schema": "./src/executors/build-typescript/schema.json", + "description": "Build TypeScript modules (CJS or ESM) with configurable output format" + }, + "prepare-package-json": { + "implementation": "./src/executors/prepare-package-json/executor", + "schema": "./src/executors/prepare-package-json/schema.json", + "description": "Create npm distribution package.json" + }, + "pack-npm": { + "implementation": "./src/executors/pack-npm/executor", + "schema": "./src/executors/pack-npm/schema.json", + "description": "Run pnpm pack for npm distribution" + } + } +} diff --git a/packages/nx-infra-plugin/jest.config.ts b/packages/nx-infra-plugin/jest.config.ts new file mode 100644 index 000000000000..e4469f98d5f8 --- /dev/null +++ b/packages/nx-infra-plugin/jest.config.ts @@ -0,0 +1,10 @@ +export default { + displayName: 'nx-infra-plugin', + preset: '../../jest.config.base.js', + testEnvironment: 'node', + roots: ['/src'], + transform: { + '^.+\\.ts$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], +}; diff --git a/packages/nx-infra-plugin/package.json b/packages/nx-infra-plugin/package.json new file mode 100644 index 000000000000..de7196a6522a --- /dev/null +++ b/packages/nx-infra-plugin/package.json @@ -0,0 +1,26 @@ +{ + "name": "devextreme-nx-infra-plugin", + "version": "0.0.1", + "type": "commonjs", + "private": true, + "executors": "./prod/executors.json", + "exports": { + ".": { + "require": "./prod/src/index.js", + "types": "./prod/src/index.d.ts" + }, + "./package.json": "./package.json" + }, + "dependencies": { + "glob": "10.4.5", + "rimraf": "3.0.2" + }, + "devDependencies": { + "@types/node": "^18.0.0", + "typescript": "4.9.5" + }, + "scripts": { + "build": "nx build nx-infra-plugin", + "test": "nx test nx-infra-plugin" + } +} diff --git a/packages/nx-infra-plugin/prod/executors.json b/packages/nx-infra-plugin/prod/executors.json new file mode 100644 index 000000000000..b429a50f06a6 --- /dev/null +++ b/packages/nx-infra-plugin/prod/executors.json @@ -0,0 +1,44 @@ +{ + "executors": { + "generate-react-components": { + "implementation": "./src/executors/generate-react-components/executor", + "schema": "./src/executors/generate-react-components/schema.json", + "description": "Generate React components from DevExtreme metadata" + }, + "clean": { + "implementation": "./src/executors/clean/executor", + "schema": "./src/executors/clean/schema.json", + "description": "Clean directories with support for simple or recursive mode" + }, + "add-license-headers": { + "implementation": "./src/executors/add-license-headers/executor", + "schema": "./src/executors/add-license-headers/schema.json", + "description": "Add license headers to compiled files" + }, + "prepare-submodules": { + "implementation": "./src/executors/prepare-submodules/executor", + "schema": "./src/executors/prepare-submodules/schema.json", + "description": "Prepare submodule entry points with package.json files" + }, + "copy-files": { + "implementation": "./src/executors/copy-files/executor", + "schema": "./src/executors/copy-files/schema.json", + "description": "Copy files to destination" + }, + "build-typescript": { + "implementation": "./src/executors/build-typescript/executor", + "schema": "./src/executors/build-typescript/schema.json", + "description": "Build TypeScript modules (CJS or ESM) with configurable output format" + }, + "prepare-package-json": { + "implementation": "./src/executors/prepare-package-json/executor", + "schema": "./src/executors/prepare-package-json/schema.json", + "description": "Create npm distribution package.json" + }, + "pack-npm": { + "implementation": "./src/executors/pack-npm/executor", + "schema": "./src/executors/pack-npm/schema.json", + "description": "Run pnpm pack for npm distribution" + } + } +} diff --git a/packages/nx-infra-plugin/prod/package.json b/packages/nx-infra-plugin/prod/package.json new file mode 100644 index 000000000000..2a3cd48002c0 --- /dev/null +++ b/packages/nx-infra-plugin/prod/package.json @@ -0,0 +1,31 @@ +{ + "name": "devextreme-nx-infra-plugin", + "version": "0.0.1", + "type": "commonjs", + "private": true, + "executors": "./prod/executors.json", + "exports": { + ".": { + "require": "./prod/src/index.js", + "types": "./prod/src/index.d.ts" + }, + "./package.json": "./package.json" + }, + "dependencies": { + "glob": "10.4.5", + "rimraf": "3.0.2" + }, + "devDependencies": { + "@types/node": "^18.0.0", + "typescript": "4.9.5", + "prettier": "catalog:tools" + }, + "scripts": { + "format:check": "prettier --check .", + "format": "prettier --write .", + "build": "nx build nx-infra-plugin", + "test": "nx test nx-infra-plugin", + "lint": "pnpm run format:check" + }, + "main": "./src/index.js" +} \ No newline at end of file diff --git a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.d.ts new file mode 100644 index 000000000000..2ac1ee9ab623 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.d.ts @@ -0,0 +1,4 @@ +import { PromiseExecutor } from '@nx/devkit'; +import { AddLicenseHeadersExecutorSchema } from './schema'; +declare const runExecutor: PromiseExecutor; +export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.js b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.js new file mode 100644 index 000000000000..11b511be6977 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.js @@ -0,0 +1,119 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const devkit_1 = require("@nx/devkit"); +const path = __importStar(require("path")); +const glob_1 = require("glob"); +const path_resolver_1 = require("../../utils/path-resolver"); +const error_handler_1 = require("../../utils/error-handler"); +const file_operations_1 = require("../../utils/file-operations"); +const DEFAULT_TARGET_DIR = './npm'; +const DEFAULT_PACKAGE_JSON = './package.json'; +const GLOB_PATTERN = '**/*.{ts,js}'; +const LICENSE_MARKER = '/*!'; +const COMMENT_END = ' */'; +const COMMENT_PREFIX = ' *'; +const NEWLINE = '\n'; +const EMPTY_LINE = ''; +const GITHUB_URL = 'https://github.com/DevExpress/devextreme-react'; +const COPYRIGHT_START = ' * Copyright (c) 2012 - <%= year %> Developer Express Inc. ALL RIGHTS RESERVED'; +const BANNER_PKG_NAME = COMMENT_PREFIX + ' ' + '<%= pkg.name %>'; +const BANNER_VERSION = COMMENT_PREFIX + ' ' + 'Version: <%= pkg.version %>'; +const BANNER_BUILD_DATE = COMMENT_PREFIX + ' ' + 'Build date: <%= date %>'; +const BANNER_LICENSE_LINE1 = COMMENT_PREFIX + ' ' + 'This software may be modified and distributed under the terms'; +const BANNER_LICENSE_LINE2 = COMMENT_PREFIX + + ' ' + + 'of the MIT license. See the LICENSE file in the root of the project for details.'; +const BANNER_GITHUB = COMMENT_PREFIX + ' ' + GITHUB_URL; +const TEMPLATE_REGEX = /<%=\s*(\w+(?:\.\w+)*)\s*%>/g; +const runExecutor = async (options, context) => { + const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); + const targetDirectory = path.join(absoluteProjectRoot, options.targetDirectory || DEFAULT_TARGET_DIR); + const packageJsonPath = path.join(absoluteProjectRoot, options.packageJsonPath || DEFAULT_PACKAGE_JSON); + let pkg; + try { + pkg = await (0, file_operations_1.readJson)(packageJsonPath); + } + catch (error) { + (0, error_handler_1.logError)('Failed to read package.json', error); + return { success: false }; + } + const now = new Date(); + const data = { + pkg, + date: now.toDateString(), + year: now.getFullYear(), + }; + const bannerTemplate = [ + LICENSE_MARKER, + BANNER_PKG_NAME, + BANNER_VERSION, + BANNER_BUILD_DATE, + COMMENT_PREFIX, + COPYRIGHT_START, + COMMENT_PREFIX, + BANNER_LICENSE_LINE1, + BANNER_LICENSE_LINE2, + COMMENT_PREFIX, + BANNER_GITHUB, + COMMENT_END, + EMPTY_LINE, + ].join(NEWLINE); + const banner = renderTemplate(bannerTemplate, data); + try { + const pattern = path.join(targetDirectory, GLOB_PATTERN); + const files = await (0, glob_1.glob)(pattern); + devkit_1.logger.info(`Adding license headers to ${files.length} files...`); + await Promise.all(files.map(async (file) => { + const content = await (0, file_operations_1.readFileText)(file); + if (content.startsWith(LICENSE_MARKER)) { + return; + } + await (0, file_operations_1.writeFileText)(file, banner + NEWLINE + content); + })); + devkit_1.logger.info('License headers added successfully'); + return { success: true }; + } + catch (error) { + (0, error_handler_1.logError)('Failed to add license headers', error); + return { success: false }; + } +}; +function renderTemplate(template, data) { + return template.replace(TEMPLATE_REGEX, (_match, key) => { + const keys = key.split('.'); + let value = data; + for (const k of keys) { + if (value && typeof value === 'object' && k in value) { + value = value[k]; + } + else { + return ''; + } + } + return String(value); + }); +} +exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.d.ts new file mode 100644 index 000000000000..7f04a8d2d9e4 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.d.ts @@ -0,0 +1,4 @@ +export interface AddLicenseHeadersExecutorSchema { + targetDirectory?: string; + packageJsonPath?: string; +} diff --git a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.js b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.js new file mode 100644 index 000000000000..c8ad2e549bdc --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.json b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.json new file mode 100644 index 000000000000..d9c56f52207b --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.json @@ -0,0 +1,16 @@ +{ + "type": "object", + "properties": { + "targetDirectory": { + "type": "string", + "description": "Directory containing files to add headers to", + "default": "./npm" + }, + "packageJsonPath": { + "type": "string", + "description": "Path to package.json for version info", + "default": "./package.json" + } + }, + "required": [] +} diff --git a/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.d.ts new file mode 100644 index 000000000000..504ea8d892fb --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.d.ts @@ -0,0 +1,4 @@ +import { PromiseExecutor } from '@nx/devkit'; +import { BuildTypescriptExecutorSchema } from './schema'; +declare const runExecutor: PromiseExecutor; +export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.js b/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.js new file mode 100644 index 000000000000..f8fd96aaf834 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.js @@ -0,0 +1,114 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const devkit_1 = require("@nx/devkit"); +const ts = __importStar(require("typescript")); +const path = __importStar(require("path")); +const glob_1 = require("glob"); +const path_resolver_1 = require("../../utils/path-resolver"); +const error_handler_1 = require("../../utils/error-handler"); +const file_operations_1 = require("../../utils/file-operations"); +const MODULE_TYPE_ESM = 'esm'; +const MODULE_TYPE_CJS = 'cjs'; +const DEFAULT_MODULE_TYPE = MODULE_TYPE_ESM; +const DEFAULT_TSCONFIG_CJS = './tsconfig.json'; +const DEFAULT_TSCONFIG_ESM = './tsconfig.esm.json'; +const DEFAULT_OUT_DIR_CJS = './npm/cjs'; +const DEFAULT_OUT_DIR_ESM = './npm/esm'; +const DEFAULT_SRC_PATTERN = './src/**/*.{ts,tsx}'; +const ERROR_COMPILATION_FAILED = 'Compilation failed'; +const NEWLINE_CHAR = '\n'; +async function loadTsConfig(tsconfigPath) { + if (!(await (0, file_operations_1.exists)(tsconfigPath))) { + throw new Error(`TypeScript config file not found: ${tsconfigPath}`); + } + const tsconfigContentRaw = await (0, file_operations_1.readFileText)(tsconfigPath); + const content = JSON.parse(tsconfigContentRaw); + return { + content, + compilerOptions: content.compilerOptions || {}, + }; +} +function formatDiagnostics(diagnostics) { + return diagnostics.map((diagnostic) => { + if (diagnostic.file) { + const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); + const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, NEWLINE_CHAR); + return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`; + } + return ts.flattenDiagnosticMessageText(diagnostic.messageText, NEWLINE_CHAR); + }); +} +function compile(sourceFiles, compilerOptions) { + return ts.createProgram(sourceFiles, compilerOptions); +} +const runExecutor = async (options, context) => { + const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); + const module = options.module || DEFAULT_MODULE_TYPE; + const defaultTsconfigPath = module === MODULE_TYPE_CJS ? DEFAULT_TSCONFIG_CJS : DEFAULT_TSCONFIG_ESM; + const tsconfigPath = path.join(absoluteProjectRoot, options.tsconfig || defaultTsconfigPath); + const defaultOutDir = module === MODULE_TYPE_CJS ? DEFAULT_OUT_DIR_CJS : DEFAULT_OUT_DIR_ESM; + const outDir = path.join(absoluteProjectRoot, options.outDir || defaultOutDir); + try { + const { content: tsconfigContent, compilerOptions } = await loadTsConfig(tsconfigPath); + compilerOptions.outDir = outDir; + await (0, file_operations_1.ensureDir)(outDir); + const srcPattern = options.srcPattern || DEFAULT_SRC_PATTERN; + const globPattern = path.join(absoluteProjectRoot, srcPattern); + const excludePattern = options.excludePattern + ? path.join(absoluteProjectRoot, options.excludePattern) + : undefined; + const sourceFiles = await (0, glob_1.glob)(globPattern, { + absolute: true, + nodir: true, + ignore: excludePattern ? [excludePattern] : [], + }); + devkit_1.logger.info(`Building ${module.toUpperCase()} for ${sourceFiles.length} source files...`); + if (sourceFiles.length === 0) { + devkit_1.logger.warn(`No source files matched pattern: ${srcPattern}`); + } + const parsedConfig = ts.parseJsonConfigFileContent(tsconfigContent, ts.sys, path.dirname(tsconfigPath)); + const finalCompilerOptions = { + ...parsedConfig.options, + outDir: compilerOptions.outDir, + paths: {}, + }; + const program = compile(sourceFiles, finalCompilerOptions); + const result = program.emit(); + if (result.emitSkipped) { + devkit_1.logger.error(ERROR_COMPILATION_FAILED); + const diagnostics = ts.getPreEmitDiagnostics(program).concat(result.diagnostics); + formatDiagnostics(diagnostics).forEach((msg) => devkit_1.logger.error(msg)); + return { success: false }; + } + devkit_1.logger.info(`โœ“ ${module.toUpperCase()} build completed successfully`); + return { success: true }; + } + catch (error) { + (0, error_handler_1.logError)(`Failed to build ${module.toUpperCase()}`, error); + return { success: false }; + } +}; +exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.d.ts new file mode 100644 index 000000000000..9b219138da34 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.d.ts @@ -0,0 +1,7 @@ +export interface BuildTypescriptExecutorSchema { + module?: 'cjs' | 'esm'; + srcPattern?: string; + excludePattern?: string; + tsconfig?: string; + outDir?: string; +} diff --git a/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.js b/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.js new file mode 100644 index 000000000000..c8ad2e549bdc --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.json b/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.json new file mode 100644 index 000000000000..838ad534df45 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/schema", + "type": "object", + "title": "Build TypeScript Executor", + "description": "Compile TypeScript code to CommonJS or ESM modules", + "properties": { + "module": { + "type": "string", + "description": "Target module format. 'esm' generates ES modules with import/export statements, 'cjs' generates CommonJS with require/module.exports. This affects output file structure, TypeScript compiler module settings, and determines the default tsconfig and output directory.", + "enum": ["cjs", "esm"], + "default": "esm" + }, + "srcPattern": { + "type": "string", + "description": "Glob pattern for source files to include in compilation. Supports standard glob syntax with wildcards. Default pattern includes all .ts and .tsx files in src directory recursively.", + "default": "./src/**/*.{ts,tsx}" + }, + "excludePattern": { + "type": "string", + "description": "Glob pattern for files to exclude from compilation (e.g., test files, stories). Files matching this pattern will be ignored even if they match srcPattern. Commonly used to exclude __tests__, __mocks__, or *.spec.ts files." + }, + "tsconfig": { + "type": "string", + "description": "Path to TypeScript configuration file relative to project root. If not specified, defaults to './tsconfig.json' for CJS builds or './tsconfig.esm.json' for ESM builds. The tsconfig should contain appropriate module and target settings for the desired output format." + }, + "outDir": { + "type": "string", + "description": "Output directory path relative to project root where compiled JavaScript and declaration files will be written. If not specified, defaults to './npm/cjs' for CJS builds or './npm/esm' for ESM builds. Directory will be created if it doesn't exist." + } + }, + "required": [], + "additionalProperties": false +} diff --git a/packages/nx-infra-plugin/prod/src/executors/clean/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/clean/executor.d.ts new file mode 100644 index 000000000000..24881bef85fb --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/clean/executor.d.ts @@ -0,0 +1,4 @@ +import { PromiseExecutor } from '@nx/devkit'; +import { CleanExecutorSchema } from './schema'; +declare const runExecutor: PromiseExecutor; +export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/clean/executor.js b/packages/nx-infra-plugin/prod/src/executors/clean/executor.js new file mode 100644 index 000000000000..30bd1b315c74 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/clean/executor.js @@ -0,0 +1,107 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const devkit_1 = require("@nx/devkit"); +const fs = __importStar(require("fs")); +const path = __importStar(require("path")); +const rimraf = __importStar(require("rimraf")); +const glob_1 = require("glob"); +const path_resolver_1 = require("../../utils/path-resolver"); +const error_handler_1 = require("../../utils/error-handler"); +const CLEAN_MODE_SIMPLE = 'simple'; +const CLEAN_MODE_SHALLOW = 'shallow'; +const CLEAN_MODE_RECURSIVE = 'recursive'; +const DEFAULT_TARGET_DIR = './src'; +const DEFAULT_CLEAN_MODE = CLEAN_MODE_SIMPLE; +const GLOB_ALL_FILES = '**/*'; +function resolveExcludePaths(patterns, absoluteProjectRoot) { + return patterns.map((pattern) => path.isAbsolute(pattern) ? pattern : path.join(absoluteProjectRoot, pattern)); +} +function shouldPreservePath(filePath, excludePaths, exactMatch) { + const normalized = path.normalize(filePath); + return excludePaths.some((excludePath) => { + const normalizedExclude = path.normalize(excludePath); + return exactMatch ? normalized === normalizedExclude : normalized.startsWith(normalizedExclude); + }); +} +function cleanSimple(targetDirectory) { + if (fs.existsSync(targetDirectory)) { + fs.rmSync(targetDirectory, { recursive: true, force: true }); + } +} +function cleanShallow(targetDirectory, absoluteExcludePaths) { + if (!fs.existsSync(targetDirectory)) { + return; + } + const entries = fs.readdirSync(targetDirectory, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(targetDirectory, entry.name); + if (!shouldPreservePath(fullPath, absoluteExcludePaths, true)) { + fs.rmSync(fullPath, { recursive: true, force: true }); + } + } +} +async function cleanRecursive(targetDirectory, absoluteExcludePaths) { + const filesToDelete = await (0, glob_1.glob)(GLOB_ALL_FILES, { + cwd: targetDirectory, + dot: true, + absolute: true, + }); + const filteredFiles = filesToDelete.filter((file) => !shouldPreservePath(file, absoluteExcludePaths, false)); + for (const file of filteredFiles) { + rimraf.sync(file); + } +} +const runExecutor = async (options, context) => { + const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); + const targetDirectory = path.join(absoluteProjectRoot, options.targetDirectory || DEFAULT_TARGET_DIR); + const mode = options.mode || DEFAULT_CLEAN_MODE; + const excludePatterns = options.excludePatterns || []; + devkit_1.logger.info(`Cleaning ${targetDirectory} in ${mode} mode...`); + if (excludePatterns.length > 0) { + devkit_1.logger.info(`Excluding patterns: ${excludePatterns.join(', ')}`); + } + try { + const absoluteExcludePaths = resolveExcludePaths(excludePatterns, absoluteProjectRoot); + switch (mode) { + case CLEAN_MODE_SIMPLE: + cleanSimple(targetDirectory); + break; + case CLEAN_MODE_SHALLOW: + cleanShallow(targetDirectory, absoluteExcludePaths); + break; + case CLEAN_MODE_RECURSIVE: + await cleanRecursive(targetDirectory, absoluteExcludePaths); + break; + } + devkit_1.logger.info(`Successfully cleaned ${targetDirectory}`); + return { success: true }; + } + catch (error) { + (0, error_handler_1.logError)(`Failed to clean ${targetDirectory}`, error); + return { success: false }; + } +}; +exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/clean/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/clean/schema.d.ts new file mode 100644 index 000000000000..fc3426a2ac4d --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/clean/schema.d.ts @@ -0,0 +1,5 @@ +export interface CleanExecutorSchema { + targetDirectory?: string; + excludePatterns?: string[]; + mode?: 'simple' | 'recursive' | 'shallow'; +} diff --git a/packages/nx-infra-plugin/prod/src/executors/clean/schema.js b/packages/nx-infra-plugin/prod/src/executors/clean/schema.js new file mode 100644 index 000000000000..c8ad2e549bdc --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/clean/schema.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/clean/schema.json b/packages/nx-infra-plugin/prod/src/executors/clean/schema.json new file mode 100644 index 000000000000..fc80aabf8b13 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/clean/schema.json @@ -0,0 +1,25 @@ +{ + "type": "object", + "properties": { + "targetDirectory": { + "type": "string", + "description": "Directory to clean", + "default": "./src" + }, + "excludePatterns": { + "type": "array", + "description": "Patterns to exclude (only used with recursive mode)", + "items": { + "type": "string" + }, + "default": [] + }, + "mode": { + "type": "string", + "enum": ["simple", "recursive", "shallow"], + "description": "Cleaning mode: 'simple' removes entire directory, 'recursive' removes contents recursively with exclusions, 'shallow' removes only first-level items with exclusions", + "default": "simple" + } + }, + "required": [] +} diff --git a/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.d.ts new file mode 100644 index 000000000000..b3b6ac66eaa2 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.d.ts @@ -0,0 +1,4 @@ +import { PromiseExecutor } from '@nx/devkit'; +import { CopyFilesExecutorSchema } from './schema'; +declare const runExecutor: PromiseExecutor; +export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.js b/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.js new file mode 100644 index 000000000000..7218b487784e --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.js @@ -0,0 +1,57 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const devkit_1 = require("@nx/devkit"); +const path = __importStar(require("path")); +const path_resolver_1 = require("../../utils/path-resolver"); +const error_handler_1 = require("../../utils/error-handler"); +const file_operations_1 = require("../../utils/file-operations"); +const ERROR_FILES_MUST_BE_ARRAY = 'Files option must be an array'; +const ERROR_FAILED_TO_COPY = 'Failed to copy files'; +const runExecutor = async (options, context) => { + const projectRoot = (0, path_resolver_1.resolveProjectPath)(context); + if (!options.files || !Array.isArray(options.files)) { + devkit_1.logger.error(ERROR_FILES_MUST_BE_ARRAY); + return { success: false }; + } + try { + for (const { from, to } of options.files) { + const sourcePath = path.resolve(projectRoot, from); + const destPath = path.resolve(projectRoot, to); + if (!(await (0, file_operations_1.exists)(sourcePath))) { + devkit_1.logger.error(`Source file not found: ${sourcePath}`); + return { success: false }; + } + await (0, file_operations_1.copyFile)(sourcePath, destPath); + devkit_1.logger.info(`Copied ${sourcePath} -> ${destPath}`); + } + return { success: true }; + } + catch (error) { + (0, error_handler_1.logError)(ERROR_FAILED_TO_COPY, error); + return { success: false }; + } +}; +exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.d.ts new file mode 100644 index 000000000000..490d39c9b14d --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.d.ts @@ -0,0 +1,6 @@ +export interface CopyFilesExecutorSchema { + files: Array<{ + from: string; + to: string; + }>; +} diff --git a/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.js b/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.js new file mode 100644 index 000000000000..c8ad2e549bdc --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.json b/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.json new file mode 100644 index 000000000000..7c777b705386 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.json @@ -0,0 +1,22 @@ +{ + "type": "object", + "properties": { + "files": { + "type": "array", + "description": "Files to copy (array of {from, to})", + "items": { + "type": "object", + "properties": { + "from": { + "type": "string" + }, + "to": { + "type": "string" + } + }, + "required": ["from", "to"] + } + } + }, + "required": ["files"] +} diff --git a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.d.ts new file mode 100644 index 000000000000..39fa2d52b464 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.d.ts @@ -0,0 +1,4 @@ +import { PromiseExecutor } from '@nx/devkit'; +import { GenerateReactComponentsExecutorSchema } from './schema'; +declare const runExecutor: PromiseExecutor; +export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.js b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.js new file mode 100644 index 000000000000..0c094ace1ac0 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.js @@ -0,0 +1,225 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const devkit_1 = require("@nx/devkit"); +const fs = __importStar(require("fs")); +const path = __importStar(require("path")); +const path_resolver_1 = require("../../utils/path-resolver"); +const error_handler_1 = require("../../utils/error-handler"); +const executor_1 = __importDefault(require("../clean/executor")); +const DEFAULT_COMPONENTS_DIR = './src'; +const DEFAULT_INDEX_FILE_NAME = './src/index.ts'; +const CORE_DIR = 'core'; +const COMMON_DIR = 'common'; +const TOOLS_DIR = 'tools'; +const GENERATORS_CONFIG_FILE = 'generators-config.js'; +const METADATA_PACKAGE = 'devextreme-metadata'; +const METADATA_FILE = 'integration-data.json'; +const INTERNAL_TOOLS_PACKAGE = 'devextreme-internal-tools'; +const GENERATION_FUNCTION = 'generateReactComponents'; +const DEFAULT_BASE_COMPONENT = './core/component'; +const DEFAULT_EXTENSION_COMPONENT = './core/extension-component'; +const DEFAULT_CONFIG_COMPONENT = './core/nested-option'; +const WIDGETS_PACKAGE = 'devextreme'; +const CLEAN_MODE = 'shallow'; +const MSG_CLEANING = '๐Ÿงน Cleaning generated components'; +const MSG_CLEANED = 'โœ“ Successfully cleaned components directory'; +const MSG_LOADING_METADATA = '๐Ÿ“‹ Loading metadata'; +const MSG_GENERATORS_CONFIG_NOT_FOUND = 'โš ๏ธ generators-config.js not found, proceeding without unifiedConfig'; +const MSG_LOADED_REACT_CONFIG = 'โœ“ Loaded React configuration from generators-config.js'; +const MSG_GENERATING = 'โš™๏ธ Generating React components'; +const MSG_GENERATION_COMPLETED = 'โœ“ Component generation completed'; +const MSG_GENERATION_SUCCESS = 'โœจ React component generation successful!'; +const MSG_STARTING = '๐Ÿ”ง Starting React component generation'; +const MSG_GENERATION_FAILED = 'โŒ Component generation failed'; +const ERROR_METADATA_NOT_FOUND = 'Could not find devextreme-metadata/integration-data.json. Please ensure devextreme-metadata is installed or provide a metadataPath option.'; +const ERROR_CLEAN_FAILED = 'Failed to clean components directory'; +const PARENT_DIR_PREFIX = '../'; +const DOT_SLASH_PREFIX = './'; +const ENCODING_UTF8 = 'utf-8'; +const GENERATE_REEXPORTS = 'generateReexports'; +const GENERATE_CUSTOM_TYPES = 'generateCustomTypes'; +const QUOTES_DOUBLE = 'double'; +const EXPLICIT_INDEX_IN_IMPORTS = 'excplicitIndexInImports'; +const EXPORT_PATTERN = /export \{/g; +async function cleanComponentsDirectory(absoluteComponentsDir, preservePaths, context) { + devkit_1.logger.info(MSG_CLEANING); + const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); + const relativeComponentsDir = path.relative(absoluteProjectRoot, absoluteComponentsDir); + const cleanOptions = { + targetDirectory: DOT_SLASH_PREFIX + relativeComponentsDir, + excludePatterns: preservePaths.map((currentPath) => { + if (path.isAbsolute(currentPath)) { + const relative = path.relative(absoluteProjectRoot, currentPath); + return DOT_SLASH_PREFIX + relative; + } + return currentPath; + }), + mode: CLEAN_MODE, + }; + const result = await (0, executor_1.default)(cleanOptions, context); + if (result.success) { + devkit_1.logger.info(MSG_CLEANED); + } + else { + throw new Error(ERROR_CLEAN_FAILED); + } +} +function resolveMetadataPath(options, absoluteProjectRoot, workspaceRoot) { + if (options.metadataPath) { + return resolveCustomMetadataPath(options.metadataPath, absoluteProjectRoot, workspaceRoot); + } + return resolveDefaultMetadataPath(); +} +function resolveCustomMetadataPath(metadataPath, absoluteProjectRoot, workspaceRoot) { + const relativeToProject = path.resolve(absoluteProjectRoot, metadataPath); + if (fs.existsSync(relativeToProject)) { + return relativeToProject; + } + const relativeToWorkspace = path.resolve(workspaceRoot, metadataPath); + if (fs.existsSync(relativeToWorkspace)) { + return relativeToWorkspace; + } + if (metadataPath.startsWith(PARENT_DIR_PREFIX)) { + return path.resolve(workspaceRoot, metadataPath); + } + return relativeToProject; +} +function resolveDefaultMetadataPath() { + try { + return require.resolve(`${METADATA_PACKAGE}/${METADATA_FILE}`); + } + catch (error) { + throw new Error(ERROR_METADATA_NOT_FOUND); + } +} +function loadMetadata(metadataPath) { + devkit_1.logger.info(MSG_LOADING_METADATA); + devkit_1.logger.info(` Path: ${metadataPath}`); + if (!fs.existsSync(metadataPath)) { + throw new Error(`Metadata file not found: ${metadataPath}`); + } + const metadataContent = fs.readFileSync(metadataPath, ENCODING_UTF8); + const metaData = JSON.parse(metadataContent); + const widgetCount = Object.keys(metaData.Widgets || {}).length; + devkit_1.logger.info(`โœ“ Loaded ${widgetCount} widget definitions`); + return metaData; +} +function loadReactConfig(workspaceRoot) { + const generatorsConfigPath = path.join(workspaceRoot, TOOLS_DIR, GENERATORS_CONFIG_FILE); + if (!fs.existsSync(generatorsConfigPath)) { + devkit_1.logger.warn(MSG_GENERATORS_CONFIG_NOT_FOUND); + return undefined; + } + try { + const generatorsConfig = require(generatorsConfigPath); + devkit_1.logger.info(MSG_LOADED_REACT_CONFIG); + return generatorsConfig.reactConfig; + } + catch (error) { + devkit_1.logger.warn(`โš ๏ธ Could not load generators-config.js: ${(0, error_handler_1.getErrorMessage)(error)}`); + return undefined; + } +} +function loadGenerationFunction() { + try { + const internalTools = require(INTERNAL_TOOLS_PACKAGE); + return internalTools[GENERATION_FUNCTION]; + } + catch (error) { + throw new Error(`Could not load devextreme-internal-tools. Please ensure devextreme-internal-tools is installed as a dependency. Error: ${(0, error_handler_1.getErrorMessage)(error)}`); + } +} +function buildGenerationConfig(options, componentsDir, indexFileName, reactConfig) { + return { + metaData: undefined, + components: { + baseComponent: options.baseComponent || DEFAULT_BASE_COMPONENT, + extensionComponent: options.extensionComponent || DEFAULT_EXTENSION_COMPONENT, + configComponent: options.configComponent || DEFAULT_CONFIG_COMPONENT, + }, + out: { + componentsDir, + indexFileName, + }, + widgetsPackage: WIDGETS_PACKAGE, + typeGenerationOptions: { + [GENERATE_REEXPORTS]: true, + [GENERATE_CUSTOM_TYPES]: true, + }, + templatingOptions: { + quotes: QUOTES_DOUBLE, + [EXPLICIT_INDEX_IN_IMPORTS]: true, + }, + unifiedConfig: reactConfig, + }; +} +async function executeGeneration(generateReactComponents, config, metaData, componentsDir, indexFileName) { + devkit_1.logger.info(MSG_GENERATING); + config.metaData = metaData; + await generateReactComponents(config); + devkit_1.logger.info(MSG_GENERATION_COMPLETED); + if (fs.existsSync(indexFileName)) { + const indexContent = fs.readFileSync(indexFileName, ENCODING_UTF8); + const exportCount = (indexContent.match(EXPORT_PATTERN) || []).length; + devkit_1.logger.info(` Exports: ${exportCount}`); + } + if (fs.existsSync(componentsDir)) { + const dirCount = fs + .readdirSync(componentsDir, { withFileTypes: true }) + .filter((entry) => entry.isDirectory() && entry.name !== CORE_DIR).length; + devkit_1.logger.info(` Component Directories: ${dirCount}`); + } + devkit_1.logger.info(MSG_GENERATION_SUCCESS); +} +const runExecutor = async (options, context) => { + const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); + const workspaceRoot = context.root; + devkit_1.logger.info(MSG_STARTING); + const projectRelativePath = path.relative(workspaceRoot, absoluteProjectRoot) || DOT_SLASH_PREFIX; + devkit_1.logger.info(` Project root: ${projectRelativePath}`); + try { + const componentsDir = path.resolve(absoluteProjectRoot, options.componentsDir || DEFAULT_COMPONENTS_DIR); + const indexFileName = path.resolve(absoluteProjectRoot, options.indexFileName || DEFAULT_INDEX_FILE_NAME); + const coreDir = path.join(componentsDir, CORE_DIR); + const commonDir = path.join(componentsDir, COMMON_DIR); + await cleanComponentsDirectory(componentsDir, [coreDir, commonDir, indexFileName], context); + const metadataPath = resolveMetadataPath(options, absoluteProjectRoot, workspaceRoot); + const metaData = loadMetadata(metadataPath); + const reactConfig = loadReactConfig(workspaceRoot); + const generateReactComponents = loadGenerationFunction(); + const config = buildGenerationConfig(options, componentsDir, indexFileName, reactConfig); + await executeGeneration(generateReactComponents, config, metaData, componentsDir, indexFileName); + return { success: true }; + } + catch (error) { + (0, error_handler_1.logError)(MSG_GENERATION_FAILED, error); + return { success: false }; + } +}; +exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.d.ts new file mode 100644 index 000000000000..1811b30b598b --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.d.ts @@ -0,0 +1,8 @@ +export interface GenerateReactComponentsExecutorSchema { + metadataPath?: string; + componentsDir?: string; + indexFileName?: string; + baseComponent?: string; + extensionComponent?: string; + configComponent?: string; +} diff --git a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.js b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.js new file mode 100644 index 000000000000..c8ad2e549bdc --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.json b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.json new file mode 100644 index 000000000000..5c48579dd30c --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.json @@ -0,0 +1,35 @@ +{ + "type": "object", + "properties": { + "metadataPath": { + "type": "string", + "description": "Path to metadata JSON file" + }, + "componentsDir": { + "type": "string", + "description": "Output directory for generated components", + "default": "./src" + }, + "indexFileName": { + "type": "string", + "description": "Index file name", + "default": "./src/index.ts" + }, + "baseComponent": { + "type": "string", + "description": "Base component path", + "default": "./core/component" + }, + "extensionComponent": { + "type": "string", + "description": "Extension component path", + "default": "./core/extension-component" + }, + "configComponent": { + "type": "string", + "description": "Config component path", + "default": "./core/nested-option" + } + }, + "required": ["metadataPath"] +} diff --git a/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.d.ts new file mode 100644 index 000000000000..15a2f65bff94 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.d.ts @@ -0,0 +1,4 @@ +import { PromiseExecutor } from '@nx/devkit'; +import { PackNpmExecutorSchema } from './schema'; +declare const runExecutor: PromiseExecutor; +export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.js b/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.js new file mode 100644 index 000000000000..cba2fa542969 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.js @@ -0,0 +1,37 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const devkit_1 = require("@nx/devkit"); +const child_process_1 = require("child_process"); +const path_1 = __importDefault(require("path")); +const path_resolver_1 = require("../../utils/path-resolver"); +const error_handler_1 = require("../../utils/error-handler"); +const DEFAULT_DIST_DIR = './npm'; +const MSG_PACK_SUCCESS = 'pnpm pack completed successfully'; +const MSG_PACK_FAILED = 'Failed to run pnpm pack'; +const runExecutor = async (options, context) => { + const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); + const distDirectory = options.workingDirectory || DEFAULT_DIST_DIR; + const workspaceRoot = context.root; + if (!context.projectName) { + (0, error_handler_1.logError)(MSG_PACK_FAILED, 'Project name is not defined in context'); + return { success: false }; + } + try { + devkit_1.logger.info(`Running pnpm pack from ${absoluteProjectRoot} (packaging ${distDirectory})...`); + const projectPath = path_1.default.join(workspaceRoot, 'packages', context.projectName); + (0, child_process_1.execSync)(`pnpm pack`, { + cwd: projectPath, + stdio: 'inherit', + }); + devkit_1.logger.info(MSG_PACK_SUCCESS); + return { success: true }; + } + catch (error) { + (0, error_handler_1.logError)(MSG_PACK_FAILED, error); + return { success: false }; + } +}; +exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.d.ts new file mode 100644 index 000000000000..c979e6541f3c --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.d.ts @@ -0,0 +1,3 @@ +export interface PackNpmExecutorSchema { + workingDirectory?: string; +} diff --git a/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.js b/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.js new file mode 100644 index 000000000000..c8ad2e549bdc --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.json b/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.json new file mode 100644 index 000000000000..888e8312ae4f --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.json @@ -0,0 +1,11 @@ +{ + "type": "object", + "properties": { + "workingDirectory": { + "type": "string", + "description": "Working directory for pnpm pack", + "default": "./" + } + }, + "required": [] +} diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.d.ts new file mode 100644 index 000000000000..975c85d0e9ba --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.d.ts @@ -0,0 +1,4 @@ +import { PromiseExecutor } from '@nx/devkit'; +import { NpmPackageExecutorSchema } from './schema'; +declare const runExecutor: PromiseExecutor; +export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.js b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.js new file mode 100644 index 000000000000..1eeb97e4eca2 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.js @@ -0,0 +1,55 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const devkit_1 = require("@nx/devkit"); +const path = __importStar(require("path")); +const path_resolver_1 = require("../../utils/path-resolver"); +const error_handler_1 = require("../../utils/error-handler"); +const file_operations_1 = require("../../utils/file-operations"); +const DEFAULT_SOURCE_PACKAGE_JSON = './package.json'; +const DEFAULT_DIST_DIR = './npm'; +const PACKAGE_JSON_FILE = 'package.json'; +const PUBLISH_CONFIG_FIELD = 'publishConfig'; +const JSON_INDENT = 2; +const ERROR_PREPARE_PACKAGE_JSON = 'Failed to prepare package.json'; +const runExecutor = async (options, context) => { + const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); + const sourcePackageJson = path.join(absoluteProjectRoot, options.sourcePackageJson || DEFAULT_SOURCE_PACKAGE_JSON); + const distDirectory = path.join(absoluteProjectRoot, options.distDirectory || DEFAULT_DIST_DIR); + try { + await (0, file_operations_1.ensureDir)(distDirectory); + const pkg = await (0, file_operations_1.readJson)(sourcePackageJson); + delete pkg[PUBLISH_CONFIG_FIELD]; + const distPackageJson = path.join(distDirectory, PACKAGE_JSON_FILE); + await (0, file_operations_1.writeJson)(distPackageJson, pkg, JSON_INDENT); + devkit_1.logger.info(`Created ${distPackageJson}`); + return { success: true }; + } + catch (error) { + (0, error_handler_1.logError)(ERROR_PREPARE_PACKAGE_JSON, error); + return { success: false }; + } +}; +exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.d.ts new file mode 100644 index 000000000000..5b20a50c39ac --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.d.ts @@ -0,0 +1,4 @@ +export interface NpmPackageExecutorSchema { + sourcePackageJson?: string; + distDirectory?: string; +} diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.js b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.js new file mode 100644 index 000000000000..c8ad2e549bdc --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.json b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.json new file mode 100644 index 000000000000..d555d19c5d7f --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.json @@ -0,0 +1,16 @@ +{ + "type": "object", + "properties": { + "sourcePackageJson": { + "type": "string", + "description": "Path to source package.json", + "default": "./package.json" + }, + "distDirectory": { + "type": "string", + "description": "Distribution directory", + "default": "./npm" + } + }, + "required": [] +} diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.d.ts new file mode 100644 index 000000000000..f16c9e5cddb8 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.d.ts @@ -0,0 +1,4 @@ +import { PromiseExecutor } from '@nx/devkit'; +import { PrepareSubmodulesExecutorSchema } from './schema'; +declare const runExecutor: PromiseExecutor; +export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js new file mode 100644 index 000000000000..45ff62be8670 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js @@ -0,0 +1,129 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const devkit_1 = require("@nx/devkit"); +const fs = __importStar(require("fs/promises")); +const fsSync = __importStar(require("fs")); +const path = __importStar(require("path")); +const path_resolver_1 = require("../../utils/path-resolver"); +const error_handler_1 = require("../../utils/error-handler"); +const file_operations_1 = require("../../utils/file-operations"); +const DEFAULT_DIST_DIR = './npm'; +const ESM_DIR = 'esm'; +const CJS_DIR = 'cjs'; +const ENCODING_UTF8 = 'utf8'; +const JS_EXTENSION = '.js'; +const DTS_EXTENSION = '.d.ts'; +const REGEX_IMPORTS = /from "\.\/([^;]+)";/g; +const REGEX_PARSE_MODULE = /((.*)\/)?([^/]+$)/; +const MSG_PREPARING = '๐Ÿ“ฆ Preparing submodules'; +const MSG_SUCCESS = 'โœ“ Submodules prepared successfully'; +const ERROR_PREPARE_SUBMODULES = 'Failed to prepare submodules'; +const INDEX_FILE_NAME = 'index.js'; +const PACKAGE_JSON_FILE = 'package.json'; +const PATH_SLASH = '/'; +const RELATIVE_DIR_PREFIX = '../'; +const DEFAULT_SUBMODULE_FOLDERS = [ + ['common'], + ['core', ['template', 'config', 'nested-option', 'component', 'extension-component']], + ['common/core'], + ['common/data'], + ['common/export'], +]; +const runExecutor = async (options, context) => { + const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); + const distDirectory = path.join(absoluteProjectRoot, options.distDirectory || DEFAULT_DIST_DIR); + try { + devkit_1.logger.info(MSG_PREPARING); + const packParamsForFolders = options.submoduleFolders || DEFAULT_SUBMODULE_FOLDERS; + const esmIndexPath = path.join(distDirectory, ESM_DIR, 'index.js'); + let modulesImportsFromIndex = ''; + if (fsSync.existsSync(esmIndexPath)) { + modulesImportsFromIndex = await fs.readFile(esmIndexPath, ENCODING_UTF8); + } + const modulesPaths = modulesImportsFromIndex.matchAll(REGEX_IMPORTS); + const packParamsForModules = Array.from(modulesPaths).map(([, modulePath]) => { + const match = modulePath.match(REGEX_PARSE_MODULE) || []; + const moduleFilePath = match[2]; + const moduleFileName = match[3]; + return ['', moduleFileName ? [moduleFileName] : undefined, moduleFilePath]; + }); + const allModuleParams = [...packParamsForModules, ...packParamsForFolders]; + devkit_1.logger.info(`Processing ${allModuleParams.length} submodules...`); + await Promise.all(allModuleParams.map(([folder, moduleFileNames, moduleFilePath]) => makeModule(distDirectory, folder, moduleFileNames, moduleFilePath))); + devkit_1.logger.info(MSG_SUCCESS); + return { success: true }; + } + catch (error) { + (0, error_handler_1.logError)(ERROR_PREPARE_SUBMODULES, error); + return { success: false }; + } +}; +async function makeModule(distFolder, folder, moduleFileNames, moduleFilePath) { + const distModuleFolder = path.join(distFolder, folder); + const distEsmFolder = path.join(distFolder, ESM_DIR, folder); + const moduleNames = moduleFileNames || (await findJsModuleFileNamesInFolder(distEsmFolder)); + try { + await (0, file_operations_1.ensureDir)(distModuleFolder); + if (folder && fsSync.existsSync(path.join(distEsmFolder, 'index.js'))) { + await generatePackageJsonFile(distFolder, folder); + } + await Promise.all(moduleNames.map(async (moduleFileName) => { + const moduleDir = path.join(distModuleFolder, moduleFileName); + await (0, file_operations_1.ensureDir)(moduleDir); + await generatePackageJsonFile(distFolder, folder, moduleFileName, moduleFilePath || folder); + })); + } + catch (error) { + throw new Error(`Exception while makeModule(${folder}): ${(0, error_handler_1.getErrorMessage)(error)}`); + } +} +async function generatePackageJsonFile(distFolder, folder, moduleFileName, filePath) { + const moduleName = moduleFileName || ''; + const absoluteModulePath = path.join(distFolder, folder, moduleName); + const moduleFilePathResolved = (filePath ? filePath + PATH_SLASH : '') + (moduleName || 'index'); + const esmFilePath = path.join(distFolder, ESM_DIR, moduleFilePathResolved + JS_EXTENSION); + const relativePath = path.relative(absoluteModulePath, esmFilePath); + const relativeBase = RELATIVE_DIR_PREFIX.repeat(relativePath.split('..').length - 1); + const packageJson = { + sideEffects: false, + main: `${relativeBase}${CJS_DIR}/${moduleFilePathResolved}${JS_EXTENSION}`, + module: `${relativeBase}${ESM_DIR}/${moduleFilePathResolved}${JS_EXTENSION}`, + typings: `${relativeBase}${CJS_DIR}/${moduleFilePathResolved}${DTS_EXTENSION}`, + }; + await (0, file_operations_1.ensureDir)(absoluteModulePath); + await (0, file_operations_1.writeJson)(path.join(absoluteModulePath, PACKAGE_JSON_FILE), packageJson); +} +async function findJsModuleFileNamesInFolder(dir) { + if (!fsSync.existsSync(dir)) { + return []; + } + const entries = await fs.readdir(dir, { withFileTypes: true }); + return entries.filter(isJsModule).map((entry) => path.parse(entry.name).name); +} +function isJsModule(entry) { + return (!entry.isDirectory() && entry.name.endsWith(JS_EXTENSION) && entry.name !== INDEX_FILE_NAME); +} +exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.d.ts new file mode 100644 index 000000000000..6e0bd8674257 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.d.ts @@ -0,0 +1,5 @@ +import { PackParam } from '../../utils/types'; +export interface PrepareSubmodulesExecutorSchema { + distDirectory?: string; + submoduleFolders?: PackParam[]; +} diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.js b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.js new file mode 100644 index 000000000000..c8ad2e549bdc --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.json b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.json new file mode 100644 index 000000000000..e84a530524f9 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.json @@ -0,0 +1,18 @@ +{ + "type": "object", + "properties": { + "distDirectory": { + "type": "string", + "description": "Distribution directory containing ESM and CJS builds. This directory will be scanned to generate submodule package.json files.", + "default": "./npm" + }, + "submoduleFolders": { + "type": "array", + "description": "Custom submodule folder configurations. Each entry is [folder, moduleFileNames?, moduleFilePath?].", + "items": { + "type": "array" + } + } + }, + "required": [] +} diff --git a/packages/nx-infra-plugin/prod/src/index.d.ts b/packages/nx-infra-plugin/prod/src/index.d.ts new file mode 100644 index 000000000000..98e4ca30c454 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/index.d.ts @@ -0,0 +1,3 @@ +export default function (): { + name: string; +}; diff --git a/packages/nx-infra-plugin/prod/src/index.js b/packages/nx-infra-plugin/prod/src/index.js new file mode 100644 index 000000000000..6d2abf23dcef --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/index.js @@ -0,0 +1,8 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function default_1() { + return { + name: 'nx-infra-plugin', + }; +} +exports.default = default_1; diff --git a/packages/nx-infra-plugin/prod/src/utils/error-handler.d.ts b/packages/nx-infra-plugin/prod/src/utils/error-handler.d.ts new file mode 100644 index 000000000000..120f5dd81af8 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/error-handler.d.ts @@ -0,0 +1,3 @@ +export declare function getErrorMessage(error: unknown): string; +export declare function getErrorStack(error: unknown): string | undefined; +export declare function logError(message: string, error: unknown): void; diff --git a/packages/nx-infra-plugin/prod/src/utils/error-handler.js b/packages/nx-infra-plugin/prod/src/utils/error-handler.js new file mode 100644 index 000000000000..5a274aea1353 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/error-handler.js @@ -0,0 +1,20 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.logError = exports.getErrorStack = exports.getErrorMessage = void 0; +const devkit_1 = require("@nx/devkit"); +function getErrorMessage(error) { + return error instanceof Error ? error.message : String(error); +} +exports.getErrorMessage = getErrorMessage; +function getErrorStack(error) { + return error instanceof Error ? error.stack : undefined; +} +exports.getErrorStack = getErrorStack; +function logError(message, error) { + devkit_1.logger.error(`${message}: ${getErrorMessage(error)}`); + const stack = getErrorStack(error); + if (stack) { + devkit_1.logger.error(stack); + } +} +exports.logError = logError; diff --git a/packages/nx-infra-plugin/prod/src/utils/file-operations.d.ts b/packages/nx-infra-plugin/prod/src/utils/file-operations.d.ts new file mode 100644 index 000000000000..1a51021909d1 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/file-operations.d.ts @@ -0,0 +1,10 @@ +export declare function ensureDir(dirPath: string): Promise; +export declare function readJson(filePath: string): Promise; +export declare function writeJson(filePath: string, data: unknown, spaces?: number): Promise; +export declare function processFiles(pattern: string, processor: (filePath: string) => Promise, options?: { + ignore?: string[]; +}): Promise; +export declare function exists(filePath: string): Promise; +export declare function copyFile(from: string, to: string): Promise; +export declare function readFileText(filePath: string): Promise; +export declare function writeFileText(filePath: string, content: string): Promise; diff --git a/packages/nx-infra-plugin/prod/src/utils/file-operations.js b/packages/nx-infra-plugin/prod/src/utils/file-operations.js new file mode 100644 index 000000000000..01c2b2ba142d --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/file-operations.js @@ -0,0 +1,87 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.writeFileText = exports.readFileText = exports.copyFile = exports.exists = exports.processFiles = exports.writeJson = exports.readJson = exports.ensureDir = void 0; +const fs = __importStar(require("fs/promises")); +const path = __importStar(require("path")); +const glob_1 = require("glob"); +const ENCODING_UTF8 = 'utf-8'; +const ERROR_CODE_EXIST = 'EEXIST'; +async function ensureDir(dirPath) { + try { + await fs.mkdir(dirPath, { recursive: true }); + } + catch (error) { + if (error instanceof Error && 'code' in error && error.code === ERROR_CODE_EXIST) { + return; + } + throw error; + } +} +exports.ensureDir = ensureDir; +async function readJson(filePath) { + const content = await fs.readFile(filePath, ENCODING_UTF8); + return JSON.parse(content); +} +exports.readJson = readJson; +async function writeJson(filePath, data, spaces = 2) { + const content = JSON.stringify(data, null, spaces); + await fs.writeFile(filePath, content, ENCODING_UTF8); +} +exports.writeJson = writeJson; +async function processFiles(pattern, processor, options = {}) { + const files = await (0, glob_1.glob)(pattern, { + absolute: true, + nodir: true, + ignore: options.ignore, + }); + await Promise.all(files.map(processor)); + return files.length; +} +exports.processFiles = processFiles; +async function exists(filePath) { + try { + await fs.access(filePath); + return true; + } + catch { + return false; + } +} +exports.exists = exists; +async function copyFile(from, to) { + await ensureDir(path.dirname(to)); + await fs.copyFile(from, to); +} +exports.copyFile = copyFile; +async function readFileText(filePath) { + return fs.readFile(filePath, ENCODING_UTF8); +} +exports.readFileText = readFileText; +async function writeFileText(filePath, content) { + await ensureDir(path.dirname(filePath)); + await fs.writeFile(filePath, content, ENCODING_UTF8); +} +exports.writeFileText = writeFileText; diff --git a/packages/nx-infra-plugin/prod/src/utils/index.d.ts b/packages/nx-infra-plugin/prod/src/utils/index.d.ts new file mode 100644 index 000000000000..81ead4bb9a44 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/index.d.ts @@ -0,0 +1,4 @@ +export * from './types'; +export * from './path-resolver'; +export * from './error-handler'; +export * from './file-operations'; diff --git a/packages/nx-infra-plugin/prod/src/utils/index.js b/packages/nx-infra-plugin/prod/src/utils/index.js new file mode 100644 index 000000000000..fe88aab75ab6 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/index.js @@ -0,0 +1,20 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./types"), exports); +__exportStar(require("./path-resolver"), exports); +__exportStar(require("./error-handler"), exports); +__exportStar(require("./file-operations"), exports); diff --git a/packages/nx-infra-plugin/prod/src/utils/path-resolver.d.ts b/packages/nx-infra-plugin/prod/src/utils/path-resolver.d.ts new file mode 100644 index 000000000000..cd99c66b2e7c --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/path-resolver.d.ts @@ -0,0 +1,4 @@ +import { ExecutorContext } from '@nx/devkit'; +export declare function resolveProjectPath(context: ExecutorContext): string; +export declare function resolveFromProject(context: ExecutorContext, relativePath: string): string; +export declare function resolveFromWorkspace(context: ExecutorContext, relativePath: string): string; diff --git a/packages/nx-infra-plugin/prod/src/utils/path-resolver.js b/packages/nx-infra-plugin/prod/src/utils/path-resolver.js new file mode 100644 index 000000000000..e089f9628593 --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/path-resolver.js @@ -0,0 +1,53 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.resolveFromWorkspace = exports.resolveFromProject = exports.resolveProjectPath = void 0; +const path = __importStar(require("path")); +const ERROR_CONFIGURATIONS_NOT_FOUND = 'Project configurations not found in executor context'; +const ERROR_PROJECT_NAME_NOT_FOUND = 'Project name not found in executor context'; +const ERROR_PROJECT_NOT_FOUND = 'Project "{0}" not found in workspace'; +function resolveProjectPath(context) { + if (!context.projectsConfigurations) { + throw new Error(ERROR_CONFIGURATIONS_NOT_FOUND); + } + if (!context.projectName) { + throw new Error(ERROR_PROJECT_NAME_NOT_FOUND); + } + const project = context.projectsConfigurations.projects[context.projectName]; + if (!project) { + throw new Error(ERROR_PROJECT_NOT_FOUND.replace('{0}', context.projectName)); + } + return path.resolve(context.root, project.root); +} +exports.resolveProjectPath = resolveProjectPath; +function resolveFromProject(context, relativePath) { + const projectRoot = resolveProjectPath(context); + return path.join(projectRoot, relativePath); +} +exports.resolveFromProject = resolveFromProject; +function resolveFromWorkspace(context, relativePath) { + return path.join(context.root, relativePath); +} +exports.resolveFromWorkspace = resolveFromWorkspace; diff --git a/packages/nx-infra-plugin/prod/src/utils/test-utils.d.ts b/packages/nx-infra-plugin/prod/src/utils/test-utils.d.ts new file mode 100644 index 000000000000..cb50f3362eee --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/test-utils.d.ts @@ -0,0 +1,10 @@ +import { ExecutorContext } from '@nx/devkit'; +export declare function createTempDir(prefix: string): string; +export declare function cleanupTempDir(dirPath: string): void; +export interface MockContextOptions { + root?: string; + projectName?: string; + projectRoot?: string; + isVerbose?: boolean; +} +export declare function createMockContext(options?: MockContextOptions): ExecutorContext; diff --git a/packages/nx-infra-plugin/prod/src/utils/test-utils.js b/packages/nx-infra-plugin/prod/src/utils/test-utils.js new file mode 100644 index 000000000000..8394daac9cdb --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/test-utils.js @@ -0,0 +1,55 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createMockContext = exports.cleanupTempDir = exports.createTempDir = void 0; +const fs = __importStar(require("fs")); +const path = __importStar(require("path")); +const os = __importStar(require("os")); +function createTempDir(prefix) { + return fs.mkdtempSync(path.join(os.tmpdir(), prefix)); +} +exports.createTempDir = createTempDir; +function cleanupTempDir(dirPath) { + if (fs.existsSync(dirPath)) { + fs.rmSync(dirPath, { recursive: true, force: true }); + } +} +exports.cleanupTempDir = cleanupTempDir; +function createMockContext(options = {}) { + const { root = '/tmp/test', projectName = 'test-lib', projectRoot = 'packages/test-lib', isVerbose = false, } = options; + return { + root, + cwd: root, + isVerbose, + projectName, + projectsConfigurations: { + projects: { + [projectName]: { root: projectRoot }, + }, + version: 2, + }, + }; +} +exports.createMockContext = createMockContext; diff --git a/packages/nx-infra-plugin/prod/src/utils/types.d.ts b/packages/nx-infra-plugin/prod/src/utils/types.d.ts new file mode 100644 index 000000000000..8529556b628d --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/types.d.ts @@ -0,0 +1,48 @@ +export interface TsConfig { + compilerOptions?: CompilerOptions; + extends?: string; + include?: string[]; + exclude?: string[]; + files?: string[]; + references?: Array<{ + path: string; + }>; +} +export interface CompilerOptions { + target?: string; + module?: string; + lib?: string[]; + outDir?: string; + rootDir?: string; + declaration?: boolean; + declarationMap?: boolean; + sourceMap?: boolean; + strict?: boolean; + esModuleInterop?: boolean; + skipLibCheck?: boolean; + forceConsistentCasingInFileNames?: boolean; + resolveJsonModule?: boolean; + jsx?: string; + paths?: Record; + [key: string]: any; +} +export type PackParam = [string, string[]?, string?]; +export interface TemplateData { + pkg: { + name: string; + version: string; + [key: string]: any; + }; + date: string; + year: number; + [key: string]: any; +} +export interface FileCopyOperation { + from: string; + to: string; +} +export interface SubmoduleConfig { + folder: string; + moduleFileNames?: string[]; + moduleFilePath?: string; +} diff --git a/packages/nx-infra-plugin/prod/src/utils/types.js b/packages/nx-infra-plugin/prod/src/utils/types.js new file mode 100644 index 000000000000..c8ad2e549bdc --- /dev/null +++ b/packages/nx-infra-plugin/prod/src/utils/types.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/project.json b/packages/nx-infra-plugin/project.json new file mode 100644 index 000000000000..eadd60ed20ac --- /dev/null +++ b/packages/nx-infra-plugin/project.json @@ -0,0 +1,47 @@ +{ + "name": "devextreme-nx-infra-plugin", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/nx-infra-plugin/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "{projectRoot}/prod", + "main": "{projectRoot}/src/index.ts", + "tsConfig": "packages/nx-infra-plugin/tsconfig.lib.json", + "generateExportsField": true, + "assets": [ + "packages/nx-infra-plugin/*.md", + { + "input": "./packages/nx-infra-plugin/src", + "glob": "**/!(*.ts)", + "output": "./src" + }, + { + "input": "./packages/nx-infra-plugin/src", + "glob": "**/*.d.ts", + "output": "./src" + }, + { + "input": "./packages/nx-infra-plugin", + "glob": "executors.json", + "output": "." + } + ] + } + }, + "lint": { + "executor": "@nx/eslint:lint" + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "packages/nx-infra-plugin/jest.config.ts" + } + } + } +} diff --git a/packages/nx-infra-plugin/src/executors/add-license-headers/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/add-license-headers/executor.e2e.spec.ts new file mode 100644 index 000000000000..098f4c4d492e --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/add-license-headers/executor.e2e.spec.ts @@ -0,0 +1,355 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import executor from './executor'; +import { AddLicenseHeadersExecutorSchema } from './schema'; +import { + createTempDir, + cleanupTempDir, + createMockContext, +} from '../../utils/test-utils'; +import { writeFileText, writeJson, readFileText } from '../../utils'; + +describe('AddLicenseHeadersExecutor E2E', () => { + let tempDir: string; + let context = createMockContext(); + + beforeEach(async () => { + tempDir = createTempDir('nx-license-e2e-'); + context = createMockContext({ root: tempDir }); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const npmDir = path.join(projectDir, 'npm'); + + fs.mkdirSync(npmDir, { recursive: true }); + + await writeJson(path.join(projectDir, 'package.json'), { + name: 'test-package', + version: '1.0.0', + }); + + await writeFileText( + path.join(npmDir, 'index.js'), + `export function hello() {\n return 'Hello';\n}\n` + ); + + await writeFileText( + path.join(npmDir, 'utils.js'), + `export const add = (a, b) => a + b;\n` + ); + + fs.mkdirSync(path.join(npmDir, 'components'), { recursive: true }); + await writeFileText( + path.join(npmDir, 'components', 'button.js'), + `export const Button = () => {};\n` + ); + + await writeFileText( + path.join(npmDir, 'types.ts'), + `export interface Config { name: string; }\n` + ); + }); + + afterEach(() => { + cleanupTempDir(tempDir); + }); + + describe('Basic functionality', () => { + it('should add license headers to all JS and TS files', async () => { + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + + const indexContent = await readFileText(path.join(npmDir, 'index.js')); + expect(indexContent).toMatch(/^\/\*!/); + expect(indexContent).toContain('test-package'); + expect(indexContent).toContain('Version: 1.0.0'); + expect(indexContent).toContain('Developer Express Inc.'); + + const utilsContent = await readFileText(path.join(npmDir, 'utils.js')); + expect(utilsContent).toMatch(/^\/\*!/); + + const typesContent = await readFileText(path.join(npmDir, 'types.ts')); + expect(typesContent).toMatch(/^\/\*!/); + }); + + it('should add headers to nested files', async () => { + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + const buttonContent = await readFileText( + path.join(npmDir, 'components', 'button.js') + ); + + expect(buttonContent).toMatch(/^\/\*!/); + expect(buttonContent).toContain('test-package'); + }); + + it('should preserve original file content after header', async () => { + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + const originalContent = await readFileText(path.join(npmDir, 'index.js')); + + await executor(options, context); + + const newContent = await readFileText(path.join(npmDir, 'index.js')); + + expect(newContent).toMatch(/^\/\*!/); + + expect(newContent).toContain(originalContent.trim()); + }); + }); + + describe('Idempotence', () => { + it('should not add duplicate headers on multiple runs', async () => { + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + + const result1 = await executor(options, context); + expect(result1.success).toBe(true); + + const contentAfterFirst = await readFileText(path.join(npmDir, 'index.js')); + const headerCount1 = (contentAfterFirst.match(/\/\*!/g) || []).length; + + const result2 = await executor(options, context); + expect(result2.success).toBe(true); + + const contentAfterSecond = await readFileText(path.join(npmDir, 'index.js')); + const headerCount2 = (contentAfterSecond.match(/\/\*!/g) || []).length; + + expect(headerCount1).toBe(1); + expect(headerCount2).toBe(1); + expect(contentAfterFirst).toBe(contentAfterSecond); + }); + + it('should skip files that already have license headers', async () => { + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + + await writeFileText( + path.join(npmDir, 'with-header.js'), + `/*!\n * Existing header\n */\nexport const foo = 'bar';\n` + ); + + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + const result = await executor(options, context); + expect(result.success).toBe(true); + + const content = await readFileText(path.join(npmDir, 'with-header.js')); + + expect(content).toMatch(/^\/\*!/); + expect(content).toContain('Existing header'); + expect(content).not.toContain('test-package'); + }); + }); + + describe('Header content validation', () => { + it('should include package name in header', async () => { + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + await executor(options, context); + + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + const content = await readFileText(path.join(npmDir, 'index.js')); + + expect(content).toContain('test-package'); + }); + + it('should include version in header', async () => { + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + await executor(options, context); + + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + const content = await readFileText(path.join(npmDir, 'index.js')); + + expect(content).toContain('Version: 1.0.0'); + }); + + it('should include current year in header', async () => { + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + await executor(options, context); + + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + const content = await readFileText(path.join(npmDir, 'index.js')); + + const currentYear = new Date().getFullYear(); + expect(content).toContain(`2012 - ${currentYear}`); + }); + + it('should include build date in header', async () => { + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + await executor(options, context); + + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + const content = await readFileText(path.join(npmDir, 'index.js')); + + expect(content).toMatch(/Build date:/); + }); + }); + + describe('Error handling', () => { + it('should fail gracefully with missing package.json', async () => { + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './nonexistent-package.json', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(false); + }); + + it('should fail gracefully with invalid package.json', async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + + await writeFileText( + path.join(projectDir, 'package.json'), + 'not valid json {{{}' + ); + + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(false); + }); + + it('should handle empty target directory', async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const emptyDir = path.join(projectDir, 'empty'); + fs.mkdirSync(emptyDir, { recursive: true }); + + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './empty', + packageJsonPath: './package.json', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + }); + }); + + describe('Custom paths', () => { + it('should work with custom target directory', async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const customDir = path.join(projectDir, 'dist'); + fs.mkdirSync(customDir, { recursive: true }); + + await writeFileText( + path.join(customDir, 'custom.js'), + `export const custom = true;\n` + ); + + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './dist', + packageJsonPath: './package.json', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const content = await readFileText(path.join(customDir, 'custom.js')); + expect(content).toMatch(/^\/\*!/); + expect(content).toContain('test-package'); + }); + + it('should work with custom package.json path', async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + + await writeJson( + path.join(projectDir, 'custom-package.json'), + { + name: 'custom-package-name', + version: '2.0.0', + } + ); + + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './custom-package.json', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const npmDir = path.join(projectDir, 'npm'); + const content = await readFileText(path.join(npmDir, 'index.js')); + + expect(content).toContain('custom-package-name'); + expect(content).toContain('Version: 2.0.0'); + }); + }); + + it('should preserve formatting and whitespace', async () => { + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + + const originalContent = `export function complex() { + if (true) { + return 'formatted'; + } +} + +export const value = 42; +`; + + await writeFileText(path.join(npmDir, 'formatted.js'), originalContent); + + const options: AddLicenseHeadersExecutorSchema = { + targetDirectory: './npm', + packageJsonPath: './package.json', + }; + + await executor(options, context); + + const newContent = await readFileText(path.join(npmDir, 'formatted.js')); + + const contentWithoutHeader = newContent.replace(/^\/\*![\s\S]*?\*\/\n\n/, ''); + + expect(contentWithoutHeader).toBe(originalContent); + }); +}); diff --git a/packages/nx-infra-plugin/src/executors/add-license-headers/executor.ts b/packages/nx-infra-plugin/src/executors/add-license-headers/executor.ts new file mode 100644 index 000000000000..1b2fda35895b --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/add-license-headers/executor.ts @@ -0,0 +1,123 @@ +import { PromiseExecutor, logger } from '@nx/devkit'; +import * as path from 'path'; +import { glob } from 'glob'; +import { AddLicenseHeadersExecutorSchema } from './schema'; +import { resolveProjectPath } from '../../utils/path-resolver'; +import { logError } from '../../utils/error-handler'; +import { readJson, readFileText, writeFileText } from '../../utils/file-operations'; + +const DEFAULT_TARGET_DIR = './npm'; +const DEFAULT_PACKAGE_JSON = './package.json'; + +const GLOB_PATTERN = '**/*.{ts,js}'; + +const LICENSE_MARKER = '/*!'; +const COMMENT_END = ' */'; +const COMMENT_PREFIX = ' *'; +const NEWLINE = '\n'; +const EMPTY_LINE = ''; + +const GITHUB_URL = 'https://github.com/DevExpress/devextreme-react'; + +const COPYRIGHT_START = ' * Copyright (c) 2012 - <%= year %> Developer Express Inc. ALL RIGHTS RESERVED'; + +const BANNER_PKG_NAME = COMMENT_PREFIX + ' ' + '<%= pkg.name %>'; +const BANNER_VERSION = COMMENT_PREFIX + ' ' + 'Version: <%= pkg.version %>'; +const BANNER_BUILD_DATE = COMMENT_PREFIX + ' ' + 'Build date: <%= date %>'; +const BANNER_LICENSE_LINE1 = COMMENT_PREFIX + ' ' + 'This software may be modified and distributed under the terms'; +const BANNER_LICENSE_LINE2 = COMMENT_PREFIX + ' ' + 'of the MIT license. See the LICENSE file in the root of the project for details.'; +const BANNER_GITHUB = COMMENT_PREFIX + ' ' + GITHUB_URL; + +const TEMPLATE_REGEX = /<%=\s*(\w+(?:\.\w+)*)\s*%>/g; + +const runExecutor: PromiseExecutor = async ( + options, + context +) => { + const absoluteProjectRoot = resolveProjectPath(context); + const targetDirectory = path.join( + absoluteProjectRoot, + options.targetDirectory || DEFAULT_TARGET_DIR + ); + const packageJsonPath = path.join( + absoluteProjectRoot, + options.packageJsonPath || DEFAULT_PACKAGE_JSON + ); + + let pkg; + try { + pkg = await readJson(packageJsonPath); + } catch (error) { + logError('Failed to read package.json', error); + return { success: false }; + } + + const now = new Date(); + const data = { + pkg, + date: now.toDateString(), + year: now.getFullYear(), + }; + + const bannerTemplate = [ + LICENSE_MARKER, + BANNER_PKG_NAME, + BANNER_VERSION, + BANNER_BUILD_DATE, + COMMENT_PREFIX, + COPYRIGHT_START, + COMMENT_PREFIX, + BANNER_LICENSE_LINE1, + BANNER_LICENSE_LINE2, + COMMENT_PREFIX, + BANNER_GITHUB, + COMMENT_END, + EMPTY_LINE, + ].join(NEWLINE); + + const banner = renderTemplate(bannerTemplate, data); + + try { + const pattern = path.join(targetDirectory, GLOB_PATTERN); + const files = await glob(pattern); + + logger.info(`Adding license headers to ${files.length} files...`); + + await Promise.all( + files.map(async (file) => { + const content = await readFileText(file); + + if (content.startsWith(LICENSE_MARKER)) { + return; + } + + await writeFileText(file, banner + NEWLINE + content); + }) + ); + + logger.info('License headers added successfully'); + return { success: true }; + } catch (error) { + logError('Failed to add license headers', error); + return { success: false }; + } +}; + +function renderTemplate(template: string, data: unknown): string { + return template.replace(TEMPLATE_REGEX, (_match, key) => { + const keys = key.split('.'); + let value = data; + + for (const k of keys) { + if (value && typeof value === 'object' && k in value) { + value = (value as Record)[k]; + } else { + return ''; + } + } + + return String(value); + }); +} + +export default runExecutor; diff --git a/packages/nx-infra-plugin/src/executors/add-license-headers/schema.json b/packages/nx-infra-plugin/src/executors/add-license-headers/schema.json new file mode 100644 index 000000000000..d9c56f52207b --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/add-license-headers/schema.json @@ -0,0 +1,16 @@ +{ + "type": "object", + "properties": { + "targetDirectory": { + "type": "string", + "description": "Directory containing files to add headers to", + "default": "./npm" + }, + "packageJsonPath": { + "type": "string", + "description": "Path to package.json for version info", + "default": "./package.json" + } + }, + "required": [] +} diff --git a/packages/nx-infra-plugin/src/executors/add-license-headers/schema.ts b/packages/nx-infra-plugin/src/executors/add-license-headers/schema.ts new file mode 100644 index 000000000000..f5e916cd2dc9 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/add-license-headers/schema.ts @@ -0,0 +1,4 @@ +export interface AddLicenseHeadersExecutorSchema { + targetDirectory?: string; + packageJsonPath?: string; +} diff --git a/packages/nx-infra-plugin/src/executors/build-typescript/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/build-typescript/executor.e2e.spec.ts new file mode 100644 index 000000000000..47a66ebe1417 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/build-typescript/executor.e2e.spec.ts @@ -0,0 +1,172 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import executor from './executor'; +import { BuildTypescriptExecutorSchema } from './schema'; +import { + createTempDir, + cleanupTempDir, + createMockContext, +} from '../../utils/test-utils'; +import { writeFileText, writeJson, readFileText } from '../../utils'; + +describe('BuildTypescriptExecutor E2E', () => { + let tempDir: string; + let context = createMockContext(); + + beforeEach(async () => { + tempDir = createTempDir('nx-build-ts-e2e-'); + context = createMockContext({ root: tempDir }); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + + const srcDir = path.join(projectDir, 'src'); + fs.mkdirSync(srcDir, { recursive: true }); + + await writeFileText( + path.join(srcDir, 'index.ts'), + `export function hello(name: string): string {\n return \`Hello, \${name}!\`;\n}\n` + ); + + await writeFileText( + path.join(srcDir, 'utils.ts'), + `export const add = (a: number, b: number): number => a + b;\n` + ); + + fs.mkdirSync(path.join(srcDir, '__tests__'), { recursive: true }); + await writeFileText( + path.join(srcDir, '__tests__', 'index.spec.ts'), + `import { hello } from '../index';\ntest('hello', () => {});\n` + ); + + await writeJson( + path.join(projectDir, 'tsconfig.esm.json'), + { + compilerOptions: { + target: 'ES2020', + module: 'ESNext', + declaration: true, + declarationMap: true, + sourceMap: true, + outDir: './npm/esm', + rootDir: './src', + strict: true, + esModuleInterop: true, + skipLibCheck: true, + }, + include: ['src/**/*'], + exclude: ['**/*.spec.ts', '**/__tests__/**'], + } + ); + + await writeJson( + path.join(projectDir, 'tsconfig.json'), + { + compilerOptions: { + target: 'ES2020', + module: 'CommonJS', + declaration: true, + declarationMap: true, + sourceMap: true, + outDir: './npm/cjs', + rootDir: './src', + strict: true, + esModuleInterop: true, + skipLibCheck: true, + }, + include: ['src/**/*'], + exclude: ['**/*.spec.ts', '**/__tests__/**'], + } + ); + }); + + afterEach(() => { + cleanupTempDir(tempDir); + }); + + describe('ESM build', () => { + it('should compile TypeScript to ESM successfully', async () => { + const options: BuildTypescriptExecutorSchema = { + module: 'esm', + srcPattern: './src/**/*.{ts,tsx}', + excludePattern: './src/**/__tests__/**/*', + tsconfig: './tsconfig.esm.json', + outDir: './npm/esm', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const outDir = path.join(projectDir, 'npm', 'esm'); + + expect(fs.existsSync(path.join(outDir, 'index.js'))).toBe(true); + expect(fs.existsSync(path.join(outDir, 'utils.js'))).toBe(true); + + expect(fs.existsSync(path.join(outDir, 'index.d.ts'))).toBe(true); + expect(fs.existsSync(path.join(outDir, 'utils.d.ts'))).toBe(true); + + const indexContent = await readFileText(path.join(outDir, 'index.js')); + expect(indexContent).toContain('export'); + expect(indexContent).not.toContain('module.exports'); + }, 10000); + }); + + describe('CJS build', () => { + it('should compile TypeScript to CommonJS successfully', async () => { + const options: BuildTypescriptExecutorSchema = { + module: 'cjs', + srcPattern: './src/**/*.{ts,tsx}', + excludePattern: './src/**/__tests__/**/*', + tsconfig: './tsconfig.json', + outDir: './npm/cjs', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const outDir = path.join(projectDir, 'npm', 'cjs'); + + expect(fs.existsSync(path.join(outDir, 'index.js'))).toBe(true); + expect(fs.existsSync(path.join(outDir, 'utils.js'))).toBe(true); + + const indexContent = await readFileText(path.join(outDir, 'index.js')); + expect(indexContent).toContain('exports'); + expect(indexContent).not.toContain('export function'); + }, 10000); + }); + + describe('Error handling', () => { + it('should handle missing tsconfig file', async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + + fs.unlinkSync(path.join(projectDir, 'tsconfig.esm.json')); + + const options: BuildTypescriptExecutorSchema = { + module: 'esm', + tsconfig: './tsconfig.esm.json', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(false); + }); + + it('should handle empty source directory', async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + + fs.rmSync(path.join(projectDir, 'src'), { recursive: true, force: true }); + fs.mkdirSync(path.join(projectDir, 'src')); + + const options: BuildTypescriptExecutorSchema = { + module: 'esm', + }; + + const result = await executor(options, context); + + expect(result).toHaveProperty('success'); + }); + }); +}); diff --git a/packages/nx-infra-plugin/src/executors/build-typescript/executor.ts b/packages/nx-infra-plugin/src/executors/build-typescript/executor.ts new file mode 100644 index 000000000000..696b10ac6450 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/build-typescript/executor.ts @@ -0,0 +1,139 @@ +import { PromiseExecutor, logger } from '@nx/devkit'; +import * as ts from 'typescript'; +import * as path from 'path'; +import { glob } from 'glob'; +import { BuildTypescriptExecutorSchema } from './schema'; +import { TsConfig, CompilerOptions } from '../../utils/types'; +import { resolveProjectPath } from '../../utils/path-resolver'; +import { logError } from '../../utils/error-handler'; +import { readFileText, exists, ensureDir } from '../../utils/file-operations'; + +const MODULE_TYPE_ESM = 'esm'; +const MODULE_TYPE_CJS = 'cjs'; + +const DEFAULT_MODULE_TYPE = MODULE_TYPE_ESM; +const DEFAULT_TSCONFIG_CJS = './tsconfig.json'; +const DEFAULT_TSCONFIG_ESM = './tsconfig.esm.json'; +const DEFAULT_OUT_DIR_CJS = './npm/cjs'; +const DEFAULT_OUT_DIR_ESM = './npm/esm'; +const DEFAULT_SRC_PATTERN = './src/**/*.{ts,tsx}'; + +const ERROR_COMPILATION_FAILED = 'Compilation failed'; + +const NEWLINE_CHAR = '\n'; + +async function loadTsConfig( + tsconfigPath: string +): Promise<{ content: TsConfig; compilerOptions: CompilerOptions }> { + if (!await exists(tsconfigPath)) { + throw new Error(`TypeScript config file not found: ${tsconfigPath}`); + } + + const tsconfigContentRaw = await readFileText(tsconfigPath); + const content = JSON.parse(tsconfigContentRaw) as TsConfig; + return { + content, + compilerOptions: content.compilerOptions || {}, + }; +} + +function formatDiagnostics( + diagnostics: ts.Diagnostic[] +): string[] { + return diagnostics.map((diagnostic) => { + if (diagnostic.file) { + const { line, character } = + diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!); + const message = ts.flattenDiagnosticMessageText( + diagnostic.messageText, + NEWLINE_CHAR + ); + return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`; + } + return ts.flattenDiagnosticMessageText(diagnostic.messageText, NEWLINE_CHAR); + }); +} + +function compile( + sourceFiles: string[], + compilerOptions: ts.CompilerOptions +): ts.Program { + return ts.createProgram(sourceFiles, compilerOptions); +} + +const runExecutor: PromiseExecutor = async ( + options, + context +) => { + const absoluteProjectRoot = resolveProjectPath(context); + const module = options.module || DEFAULT_MODULE_TYPE; + + const defaultTsconfigPath = module === MODULE_TYPE_CJS ? DEFAULT_TSCONFIG_CJS : DEFAULT_TSCONFIG_ESM; + const tsconfigPath = path.join( + absoluteProjectRoot, + options.tsconfig || defaultTsconfigPath + ); + + const defaultOutDir = module === MODULE_TYPE_CJS ? DEFAULT_OUT_DIR_CJS : DEFAULT_OUT_DIR_ESM; + const outDir = path.join( + absoluteProjectRoot, + options.outDir || defaultOutDir + ); + + try { + const { content: tsconfigContent, compilerOptions } = await loadTsConfig(tsconfigPath); + compilerOptions.outDir = outDir; + await ensureDir(outDir); + + const srcPattern = options.srcPattern || DEFAULT_SRC_PATTERN; + const globPattern = path.join(absoluteProjectRoot, srcPattern); + const excludePattern = options.excludePattern + ? path.join(absoluteProjectRoot, options.excludePattern) + : undefined; + + const sourceFiles = await glob(globPattern, { + absolute: true, + nodir: true, + ignore: excludePattern ? [excludePattern] : [], + }); + + logger.info(`Building ${module.toUpperCase()} for ${sourceFiles.length} source files...`); + + if (sourceFiles.length === 0) { + logger.warn(`No source files matched pattern: ${srcPattern}`); + } + + const parsedConfig = ts.parseJsonConfigFileContent( + tsconfigContent, + ts.sys, + path.dirname(tsconfigPath) + ); + + const finalCompilerOptions: ts.CompilerOptions = { + ...parsedConfig.options, + outDir: compilerOptions.outDir, + paths: {}, + }; + + const program = compile(sourceFiles, finalCompilerOptions); + const result = program.emit(); + + if (result.emitSkipped) { + logger.error(ERROR_COMPILATION_FAILED); + const diagnostics = ts + .getPreEmitDiagnostics(program) + .concat(result.diagnostics); + + formatDiagnostics(diagnostics).forEach(msg => logger.error(msg)); + return { success: false }; + } + + logger.info(`โœ“ ${module.toUpperCase()} build completed successfully`); + return { success: true }; + } catch (error) { + logError(`Failed to build ${module.toUpperCase()}`, error); + return { success: false }; + } +}; + +export default runExecutor; diff --git a/packages/nx-infra-plugin/src/executors/build-typescript/schema.json b/packages/nx-infra-plugin/src/executors/build-typescript/schema.json new file mode 100644 index 000000000000..838ad534df45 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/build-typescript/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/schema", + "type": "object", + "title": "Build TypeScript Executor", + "description": "Compile TypeScript code to CommonJS or ESM modules", + "properties": { + "module": { + "type": "string", + "description": "Target module format. 'esm' generates ES modules with import/export statements, 'cjs' generates CommonJS with require/module.exports. This affects output file structure, TypeScript compiler module settings, and determines the default tsconfig and output directory.", + "enum": ["cjs", "esm"], + "default": "esm" + }, + "srcPattern": { + "type": "string", + "description": "Glob pattern for source files to include in compilation. Supports standard glob syntax with wildcards. Default pattern includes all .ts and .tsx files in src directory recursively.", + "default": "./src/**/*.{ts,tsx}" + }, + "excludePattern": { + "type": "string", + "description": "Glob pattern for files to exclude from compilation (e.g., test files, stories). Files matching this pattern will be ignored even if they match srcPattern. Commonly used to exclude __tests__, __mocks__, or *.spec.ts files." + }, + "tsconfig": { + "type": "string", + "description": "Path to TypeScript configuration file relative to project root. If not specified, defaults to './tsconfig.json' for CJS builds or './tsconfig.esm.json' for ESM builds. The tsconfig should contain appropriate module and target settings for the desired output format." + }, + "outDir": { + "type": "string", + "description": "Output directory path relative to project root where compiled JavaScript and declaration files will be written. If not specified, defaults to './npm/cjs' for CJS builds or './npm/esm' for ESM builds. Directory will be created if it doesn't exist." + } + }, + "required": [], + "additionalProperties": false +} diff --git a/packages/nx-infra-plugin/src/executors/build-typescript/schema.ts b/packages/nx-infra-plugin/src/executors/build-typescript/schema.ts new file mode 100644 index 000000000000..7e774878893b --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/build-typescript/schema.ts @@ -0,0 +1,7 @@ +export interface BuildTypescriptExecutorSchema { + module?: 'cjs' | 'esm'; + srcPattern?: string; + excludePattern?: string; + tsconfig?: string; + outDir?: string; +} diff --git a/packages/nx-infra-plugin/src/executors/clean/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/clean/executor.e2e.spec.ts new file mode 100644 index 000000000000..28285c31464f --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/clean/executor.e2e.spec.ts @@ -0,0 +1,447 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import executor from './executor'; +import { CleanExecutorSchema } from './schema'; +import { + createTempDir, + cleanupTempDir, + createMockContext, +} from '../../utils/test-utils'; +import { writeFileText } from '../../utils'; + +describe('CleanExecutor E2E', () => { + let tempDir: string; + let context = createMockContext(); + + beforeEach(() => { + tempDir = createTempDir('nx-clean-e2e-'); + context = createMockContext({ root: tempDir }); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const srcDir = path.join(projectDir, 'src'); + + fs.mkdirSync(srcDir, { recursive: true }); + }); + + afterEach(() => { + cleanupTempDir(tempDir); + }); + + describe('Simple mode', () => { + beforeEach(async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const npmDir = path.join(projectDir, 'npm'); + + fs.mkdirSync(npmDir, { recursive: true }); + + await writeFileText(path.join(npmDir, 'index.js'), 'export const foo = "bar";'); + await writeFileText(path.join(npmDir, 'package.json'), '{"name": "test"}'); + await writeFileText(path.join(npmDir, 'README.md'), '# Test'); + + fs.mkdirSync(path.join(npmDir, 'esm'), { recursive: true }); + await writeFileText(path.join(npmDir, 'esm', 'index.js'), 'export * from "./foo";'); + + fs.mkdirSync(path.join(npmDir, 'cjs'), { recursive: true }); + await writeFileText(path.join(npmDir, 'cjs', 'index.js'), 'module.exports = {};'); + + fs.mkdirSync(path.join(npmDir, 'components', 'button'), { recursive: true }); + await writeFileText(path.join(npmDir, 'components', 'button', 'index.js'), 'export const Button = {};'); + }); + + it('should delete the entire directory', async () => { + const options: CleanExecutorSchema = { + targetDirectory: './npm', + mode: 'simple', + }; + + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + + expect(fs.existsSync(npmDir)).toBe(true); + expect(fs.existsSync(path.join(npmDir, 'index.js'))).toBe(true); + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(npmDir)).toBe(false); + }); + + it('should delete all files and subdirectories recursively', async () => { + const options: CleanExecutorSchema = { + targetDirectory: './npm', + mode: 'simple', + }; + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const npmDir = path.join(projectDir, 'npm'); + + expect(fs.existsSync(path.join(npmDir, 'esm', 'index.js'))).toBe(true); + expect(fs.existsSync(path.join(npmDir, 'cjs', 'index.js'))).toBe(true); + expect(fs.existsSync(path.join(npmDir, 'components', 'button', 'index.js'))).toBe(true); + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(npmDir)).toBe(false); + }); + + it('should succeed when directory does not exist', async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const npmDir = path.join(projectDir, 'npm'); + + fs.rmSync(npmDir, { recursive: true, force: true }); + + const options: CleanExecutorSchema = { + targetDirectory: './npm', + mode: 'simple', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + }); + + it('should not affect other directories', async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + + const srcDir = path.join(projectDir, 'src'); + const distDir = path.join(projectDir, 'dist'); + + await writeFileText(path.join(srcDir, 'index.ts'), 'export const foo = "bar";'); + + fs.mkdirSync(distDir); + await writeFileText(path.join(distDir, 'output.js'), 'compiled'); + + const options: CleanExecutorSchema = { + targetDirectory: './npm', + mode: 'simple', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(projectDir, 'npm'))).toBe(false); + + expect(fs.existsSync(path.join(srcDir, 'index.ts'))).toBe(true); + expect(fs.existsSync(path.join(distDir, 'output.js'))).toBe(true); + }); + + it('should use simple mode by default', async () => { + const options: CleanExecutorSchema = { + targetDirectory: './npm', + }; + + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + + expect(fs.existsSync(npmDir)).toBe(true); + + const result = await executor(options, context); + + expect(result.success).toBe(true); + expect(fs.existsSync(npmDir)).toBe(false); + }); + }); + + describe('Recursive mode', () => { + beforeEach(async () => { + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + await writeFileText(path.join(srcDir, 'button.tsx'), 'export const Button = () => {};'); + await writeFileText(path.join(srcDir, 'text-box.tsx'), 'export const TextBox = () => {};'); + await writeFileText(path.join(srcDir, 'index.ts'), 'export * from "./button";'); + + fs.mkdirSync(path.join(srcDir, 'core'), { recursive: true }); + await writeFileText(path.join(srcDir, 'core', 'component.tsx'), 'export class Component {}'); + await writeFileText(path.join(srcDir, 'core', 'config.tsx'), 'export class Config {}'); + + fs.mkdirSync(path.join(srcDir, 'data'), { recursive: true }); + await writeFileText(path.join(srcDir, 'data', 'grid.tsx'), 'export const Grid = () => {};'); + }); + + it('should clean all files in target directory', async () => { + const options: CleanExecutorSchema = { + targetDirectory: './src', + excludePatterns: ['./src/core'], + mode: 'recursive', + }; + + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + expect(fs.existsSync(path.join(srcDir, 'button.tsx'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'text-box.tsx'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'index.ts'))).toBe(true); + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'button.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'text-box.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'index.ts'))).toBe(false); + }); + + it('should preserve excluded directories', async () => { + const options: CleanExecutorSchema = { + targetDirectory: './src', + excludePatterns: ['./src/core'], + mode: 'recursive', + }; + + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'core'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'core', 'component.tsx'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'core', 'config.tsx'))).toBe(true); + }); + + it('should clean nested directories', async () => { + const options: CleanExecutorSchema = { + targetDirectory: './src', + excludePatterns: ['./src/core'], + mode: 'recursive', + }; + + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + expect(fs.existsSync(path.join(srcDir, 'data', 'grid.tsx'))).toBe(true); + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'data'))).toBe(false); + }); + + it('should preserve multiple excluded directories', async () => { + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + fs.mkdirSync(path.join(srcDir, 'common'), { recursive: true }); + await writeFileText(path.join(srcDir, 'common', 'utils.ts'), 'export const utils = {};'); + + fs.mkdirSync(path.join(srcDir, 'types'), { recursive: true }); + await writeFileText(path.join(srcDir, 'types', 'index.d.ts'), 'export type Foo = string;'); + + const options: CleanExecutorSchema = { + targetDirectory: './src', + excludePatterns: ['./src/core', './src/common', './src/types'], + mode: 'recursive', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'core', 'component.tsx'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'common', 'utils.ts'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'types', 'index.d.ts'))).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'button.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'data'))).toBe(false); + }); + + it('should handle nested exclude patterns', async () => { + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + fs.mkdirSync(path.join(srcDir, 'core', 'internal'), { recursive: true }); + await writeFileText(path.join(srcDir, 'core', 'internal', 'impl.tsx'), 'export const impl = {};'); + + const options: CleanExecutorSchema = { + targetDirectory: './src', + excludePatterns: ['./src/core'], + mode: 'recursive', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'core', 'internal', 'impl.tsx'))).toBe(true); + }); + + it('should clean all files when no exclude patterns specified', async () => { + const options: CleanExecutorSchema = { + targetDirectory: './src', + mode: 'recursive', + }; + + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'button.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'core'))).toBe(false); + }); + + it('should handle absolute exclude paths', async () => { + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + const absoluteCorePath = path.join(srcDir, 'core'); + + const options: CleanExecutorSchema = { + targetDirectory: './src', + excludePatterns: [absoluteCorePath], + mode: 'recursive', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'core', 'component.tsx'))).toBe(true); + }); + }); + + describe('Shallow mode', () => { + beforeEach(async () => { + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + await writeFileText(path.join(srcDir, 'button.tsx'), 'export const Button = () => {};'); + await writeFileText(path.join(srcDir, 'text-box.tsx'), 'export const TextBox = () => {};'); + await writeFileText(path.join(srcDir, 'index.ts'), 'export * from "./button";'); + + fs.mkdirSync(path.join(srcDir, 'core'), { recursive: true }); + await writeFileText(path.join(srcDir, 'core', 'component.tsx'), 'export class Component {}'); + await writeFileText(path.join(srcDir, 'core', 'config.tsx'), 'export class Config {}'); + + fs.mkdirSync(path.join(srcDir, 'common'), { recursive: true }); + await writeFileText(path.join(srcDir, 'common', 'utils.ts'), 'export const utils = {};'); + + fs.mkdirSync(path.join(srcDir, 'data'), { recursive: true }); + await writeFileText(path.join(srcDir, 'data', 'grid.tsx'), 'export const Grid = () => {};'); + }); + + it('should remove only first-level items', async () => { + const options: CleanExecutorSchema = { + targetDirectory: './src', + excludePatterns: ['./src/core', './src/common'], + mode: 'shallow', + }; + + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + expect(fs.existsSync(path.join(srcDir, 'button.tsx'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'text-box.tsx'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'index.ts'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'data'))).toBe(true); + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'button.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'text-box.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'index.ts'))).toBe(false); + + expect(fs.existsSync(path.join(srcDir, 'data'))).toBe(false); + + expect(fs.existsSync(path.join(srcDir, 'core'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'core', 'component.tsx'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'core', 'config.tsx'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'common'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'common', 'utils.ts'))).toBe(true); + }); + + it('should preserve specific files at root level', async () => { + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + const indexPath = path.join(srcDir, 'index.ts'); + + const options: CleanExecutorSchema = { + targetDirectory: './src', + excludePatterns: ['./src/core', './src/common', indexPath], + mode: 'shallow', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(indexPath)).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'button.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'text-box.tsx'))).toBe(false); + + expect(fs.existsSync(path.join(srcDir, 'core'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'common'))).toBe(true); + }); + + it('should handle non-existent directory', async () => { + const options: CleanExecutorSchema = { + targetDirectory: './nonexistent', + excludePatterns: [], + mode: 'shallow', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + }); + + it('should remove all items when no exclusions', async () => { + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + const options: CleanExecutorSchema = { + targetDirectory: './src', + mode: 'shallow', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'button.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'core'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'common'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'data'))).toBe(false); + }); + + it('should handle relative exclude paths', async () => { + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + const options: CleanExecutorSchema = { + targetDirectory: './src', + excludePatterns: ['./src/core', './src/common'], + mode: 'shallow', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'core', 'component.tsx'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'common', 'utils.ts'))).toBe(true); + }); + + it('should handle absolute path exclusions', async () => { + const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); + + const coreDir = path.join(srcDir, 'core'); + const commonDir = path.join(srcDir, 'common'); + const indexFile = path.join(srcDir, 'index.ts'); + + const options: CleanExecutorSchema = { + targetDirectory: './src', + excludePatterns: [coreDir, commonDir, indexFile], + mode: 'shallow', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(coreDir)).toBe(true); + expect(fs.existsSync(commonDir)).toBe(true); + expect(fs.existsSync(indexFile)).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'button.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'text-box.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'data'))).toBe(false); + }); + }); +}); diff --git a/packages/nx-infra-plugin/src/executors/clean/executor.ts b/packages/nx-infra-plugin/src/executors/clean/executor.ts new file mode 100644 index 000000000000..8fbbe4480310 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/clean/executor.ts @@ -0,0 +1,131 @@ +import { PromiseExecutor, logger } from '@nx/devkit'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as rimraf from 'rimraf'; +import { glob } from 'glob'; +import { CleanExecutorSchema } from './schema'; +import { resolveProjectPath } from '../../utils/path-resolver'; +import { logError } from '../../utils/error-handler'; + +const CLEAN_MODE_SIMPLE = 'simple'; +const CLEAN_MODE_SHALLOW = 'shallow'; +const CLEAN_MODE_RECURSIVE = 'recursive'; + +const DEFAULT_TARGET_DIR = './src'; +const DEFAULT_CLEAN_MODE = CLEAN_MODE_SIMPLE; + +const GLOB_ALL_FILES = '**/*'; + +function resolveExcludePaths( + patterns: string[], + absoluteProjectRoot: string +): string[] { + return patterns.map(pattern => + path.isAbsolute(pattern) ? pattern : path.join(absoluteProjectRoot, pattern) + ); +} + +function shouldPreservePath( + filePath: string, + excludePaths: string[], + exactMatch: boolean +): boolean { + const normalized = path.normalize(filePath); + + return excludePaths.some(excludePath => { + const normalizedExclude = path.normalize(excludePath); + return exactMatch + ? normalized === normalizedExclude + : normalized.startsWith(normalizedExclude); + }); +} + +function cleanSimple(targetDirectory: string): void { + if (fs.existsSync(targetDirectory)) { + fs.rmSync(targetDirectory, { recursive: true, force: true }); + } +} + +function cleanShallow( + targetDirectory: string, + absoluteExcludePaths: string[] +): void { + if (!fs.existsSync(targetDirectory)) { + return; + } + + const entries = fs.readdirSync(targetDirectory, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(targetDirectory, entry.name); + + if (!shouldPreservePath(fullPath, absoluteExcludePaths, true)) { + fs.rmSync(fullPath, { recursive: true, force: true }); + } + } +} + +async function cleanRecursive( + targetDirectory: string, + absoluteExcludePaths: string[] +): Promise { + const filesToDelete = await glob(GLOB_ALL_FILES, { + cwd: targetDirectory, + dot: true, + absolute: true + }); + + const filteredFiles = filesToDelete.filter(file => + !shouldPreservePath(file, absoluteExcludePaths, false) + ); + + for (const file of filteredFiles) { + rimraf.sync(file); + } +} + +const runExecutor: PromiseExecutor = async ( + options, + context +) => { + const absoluteProjectRoot = resolveProjectPath(context); + const targetDirectory = path.join( + absoluteProjectRoot, + options.targetDirectory || DEFAULT_TARGET_DIR + ); + const mode = options.mode || DEFAULT_CLEAN_MODE; + const excludePatterns = options.excludePatterns || []; + + logger.info(`Cleaning ${targetDirectory} in ${mode} mode...`); + + if (excludePatterns.length > 0) { + logger.info(`Excluding patterns: ${excludePatterns.join(', ')}`); + } + + try { + const absoluteExcludePaths = resolveExcludePaths( + excludePatterns, + absoluteProjectRoot + ); + + switch (mode) { + case CLEAN_MODE_SIMPLE: + cleanSimple(targetDirectory); + break; + case CLEAN_MODE_SHALLOW: + cleanShallow(targetDirectory, absoluteExcludePaths); + break; + case CLEAN_MODE_RECURSIVE: + await cleanRecursive(targetDirectory, absoluteExcludePaths); + break; + } + + logger.info(`Successfully cleaned ${targetDirectory}`); + return { success: true }; + } catch (error) { + logError(`Failed to clean ${targetDirectory}`, error); + return { success: false }; + } +}; + +export default runExecutor; diff --git a/packages/nx-infra-plugin/src/executors/clean/schema.json b/packages/nx-infra-plugin/src/executors/clean/schema.json new file mode 100644 index 000000000000..fc80aabf8b13 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/clean/schema.json @@ -0,0 +1,25 @@ +{ + "type": "object", + "properties": { + "targetDirectory": { + "type": "string", + "description": "Directory to clean", + "default": "./src" + }, + "excludePatterns": { + "type": "array", + "description": "Patterns to exclude (only used with recursive mode)", + "items": { + "type": "string" + }, + "default": [] + }, + "mode": { + "type": "string", + "enum": ["simple", "recursive", "shallow"], + "description": "Cleaning mode: 'simple' removes entire directory, 'recursive' removes contents recursively with exclusions, 'shallow' removes only first-level items with exclusions", + "default": "simple" + } + }, + "required": [] +} diff --git a/packages/nx-infra-plugin/src/executors/clean/schema.ts b/packages/nx-infra-plugin/src/executors/clean/schema.ts new file mode 100644 index 000000000000..b7d600814d9b --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/clean/schema.ts @@ -0,0 +1,5 @@ +export interface CleanExecutorSchema { + targetDirectory?: string; + excludePatterns?: string[]; + mode?: 'simple' | 'recursive' | 'shallow'; +} diff --git a/packages/nx-infra-plugin/src/executors/copy-files/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/copy-files/executor.e2e.spec.ts new file mode 100644 index 000000000000..445a93aa6536 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/copy-files/executor.e2e.spec.ts @@ -0,0 +1,118 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import executor from './executor'; +import { CopyFilesExecutorSchema } from './schema'; +import { + createTempDir, + cleanupTempDir, + createMockContext, +} from '../../utils/test-utils'; +import { writeFileText, writeJson, readFileText } from '../../utils'; + +describe('CopyFilesExecutor E2E', () => { + let tempDir: string; + let context = createMockContext(); + + beforeEach(async () => { + tempDir = createTempDir('nx-copy-e2e-'); + context = createMockContext({ root: tempDir }); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + + fs.mkdirSync(projectDir, { recursive: true }); + await writeFileText(path.join(projectDir, 'README.md'), '# Test Package\n\nThis is a test.'); + await writeFileText(path.join(projectDir, 'LICENSE'), 'MIT License\n\nCopyright...'); + await writeJson( + path.join(projectDir, 'package.json'), + { name: 'test-package', version: '1.0.0' } + ); + + fs.mkdirSync(path.join(projectDir, 'docs'), { recursive: true }); + await writeFileText(path.join(projectDir, 'docs', 'guide.md'), '# Guide\n\nHow to use...'); + }); + + afterEach(() => { + cleanupTempDir(tempDir); + }); + + describe('Basic functionality', () => { + it('should copy multiple files', async () => { + const options: CopyFilesExecutorSchema = { + files: [ + { from: './README.md', to: './npm/README.md' }, + { from: './LICENSE', to: './npm/LICENSE' }, + { from: './package.json', to: './npm/package.json' }, + ], + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const npmDir = path.join(projectDir, 'npm'); + + expect(fs.existsSync(path.join(npmDir, 'README.md'))).toBe(true); + expect(fs.existsSync(path.join(npmDir, 'LICENSE'))).toBe(true); + expect(fs.existsSync(path.join(npmDir, 'package.json'))).toBe(true); + }); + + it('should preserve file content', async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const originalContent = await readFileText(path.join(projectDir, 'README.md')); + + const options: CopyFilesExecutorSchema = { + files: [ + { from: './README.md', to: './dist/README.md' }, + ], + }; + + await executor(options, context); + + const copiedContent = await readFileText(path.join(projectDir, 'dist', 'README.md')); + + expect(copiedContent).toBe(originalContent); + }); + + it('should create destination directories if they do not exist', async () => { + const options: CopyFilesExecutorSchema = { + files: [ + { from: './README.md', to: './output/nested/deep/README.md' }, + ], + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const destPath = path.join(projectDir, 'output', 'nested', 'deep', 'README.md'); + + expect(fs.existsSync(destPath)).toBe(true); + }); + }); + + describe('File overwriting', () => { + it('should overwrite existing destination files', async () => { + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const distDir = path.join(projectDir, 'dist'); + fs.mkdirSync(distDir); + + await writeFileText(path.join(distDir, 'README.md'), 'Old content'); + + const options: CopyFilesExecutorSchema = { + files: [ + { from: './README.md', to: './dist/README.md' }, + ], + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const content = await readFileText(path.join(distDir, 'README.md')); + expect(content).toBe('# Test Package\n\nThis is a test.'); + expect(content).not.toBe('Old content'); + }); + }); +}); diff --git a/packages/nx-infra-plugin/src/executors/copy-files/executor.ts b/packages/nx-infra-plugin/src/executors/copy-files/executor.ts new file mode 100644 index 000000000000..08380c5dbace --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/copy-files/executor.ts @@ -0,0 +1,43 @@ +import { PromiseExecutor, logger } from '@nx/devkit'; +import * as path from 'path'; +import { CopyFilesExecutorSchema } from './schema'; +import { resolveProjectPath } from '../../utils/path-resolver'; +import { logError } from '../../utils/error-handler'; +import { copyFile, exists } from '../../utils/file-operations'; + +const ERROR_FILES_MUST_BE_ARRAY = 'Files option must be an array'; +const ERROR_FAILED_TO_COPY = 'Failed to copy files'; + +const runExecutor: PromiseExecutor = async ( + options, + context +) => { + const projectRoot = resolveProjectPath(context); + + if (!options.files || !Array.isArray(options.files)) { + logger.error(ERROR_FILES_MUST_BE_ARRAY); + return { success: false }; + } + + try { + for (const { from, to } of options.files) { + const sourcePath = path.resolve(projectRoot, from); + const destPath = path.resolve(projectRoot, to); + + if (!await exists(sourcePath)) { + logger.error(`Source file not found: ${sourcePath}`); + return { success: false }; + } + + await copyFile(sourcePath, destPath); + logger.info(`Copied ${sourcePath} -> ${destPath}`); + } + + return { success: true }; + } catch (error) { + logError(ERROR_FAILED_TO_COPY, error); + return { success: false }; + } +}; + +export default runExecutor; diff --git a/packages/nx-infra-plugin/src/executors/copy-files/schema.json b/packages/nx-infra-plugin/src/executors/copy-files/schema.json new file mode 100644 index 000000000000..7c777b705386 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/copy-files/schema.json @@ -0,0 +1,22 @@ +{ + "type": "object", + "properties": { + "files": { + "type": "array", + "description": "Files to copy (array of {from, to})", + "items": { + "type": "object", + "properties": { + "from": { + "type": "string" + }, + "to": { + "type": "string" + } + }, + "required": ["from", "to"] + } + } + }, + "required": ["files"] +} diff --git a/packages/nx-infra-plugin/src/executors/copy-files/schema.ts b/packages/nx-infra-plugin/src/executors/copy-files/schema.ts new file mode 100644 index 000000000000..9d081978ac5a --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/copy-files/schema.ts @@ -0,0 +1,6 @@ +export interface CopyFilesExecutorSchema { + files: Array<{ + from: string; + to: string; + }>; +} diff --git a/packages/nx-infra-plugin/src/executors/generate-react-components/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/generate-react-components/executor.e2e.spec.ts new file mode 100644 index 000000000000..fa743ee7b8e9 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/generate-react-components/executor.e2e.spec.ts @@ -0,0 +1,288 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import executor from './executor'; +import { GenerateReactComponentsExecutorSchema } from './schema'; +import { + createTempDir, + cleanupTempDir, + createMockContext, +} from '../../utils/test-utils'; +import { writeFileText, writeJson } from '../../utils'; + +describe('GenerateReactComponentsExecutor E2E', () => { + let tempDir: string; + let context = createMockContext(); + + beforeEach(async () => { + tempDir = createTempDir('nx-gen-react-e2e-'); + context = createMockContext({ + root: tempDir, + projectName: 'react-wrappers', + projectRoot: 'packages/react-wrappers', + }); + + const projectDir = path.join(tempDir, 'packages', 'react-wrappers'); + const srcDir = path.join(projectDir, 'src'); + + fs.mkdirSync(path.join(srcDir, 'core'), { recursive: true }); + await writeFileText( + path.join(srcDir, 'core', 'component.tsx'), + `export class Component

{\n constructor(public props: P) {}\n}\n` + ); + await writeFileText( + path.join(srcDir, 'core', 'extension-component.tsx'), + `export class ExtensionComponent {}\n` + ); + await writeFileText( + path.join(srcDir, 'core', 'nested-option.ts'), + `export class NestedOption {}\n` + ); + + const metadataDir = path.join(tempDir, 'packages', 'metadata', 'dist'); + fs.mkdirSync(metadataDir, { recursive: true }); + await writeJson( + path.join(metadataDir, 'integration-data.json'), + { + Widgets: { + dxButton: { + name: 'Button', + module: 'ui/button', + properties: [ + { name: 'text', type: 'String' }, + { name: 'type', type: 'String' }, + { name: 'onClick', type: 'Function' }, + ], + }, + dxTextBox: { + name: 'TextBox', + module: 'ui/text_box', + properties: [ + { name: 'value', type: 'String' }, + { name: 'placeholder', type: 'String' }, + ], + }, + }, + } + ); + }); + + afterEach(() => { + cleanupTempDir(tempDir); + }); + + describe('Basic generation workflow', () => { + it('should generate component wrappers from metadata', async () => { + const mockGenerator = jest.fn(async (config) => { + const outDir = config.out.componentsDir; + const indexFile = config.out.indexFileName; + + await writeFileText( + path.join(outDir, 'button.tsx'), + `export const Button = () =>

Button
;` + ); + await writeFileText( + path.join(outDir, 'text-box.tsx'), + `export const TextBox = () =>
TextBox
;` + ); + + await writeFileText( + indexFile, + `export { Button } from "./button";\nexport { TextBox } from "./text-box";\n` + ); + }); + + jest.mock('devextreme-internal-tools', () => ({ + generateReactComponents: mockGenerator, + }), { virtual: true }); + + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: '../metadata/dist/integration-data.json', + componentsDir: './src', + indexFileName: './src/index.ts', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const srcDir = path.join(tempDir, 'packages', 'react-wrappers', 'src'); + + expect(fs.existsSync(path.join(srcDir, 'core', 'component.tsx'))).toBe(true); + }); + + it('should handle missing metadata file gracefully', async () => { + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: './nonexistent/metadata.json', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(false); + }); + }); + + describe('Cleaning behavior', () => { + it('should clean old generated files before generation', async () => { + const srcDir = path.join(tempDir, 'packages', 'react-wrappers', 'src'); + + await writeFileText(path.join(srcDir, 'old-component.tsx'), 'old content'); + await writeFileText(path.join(srcDir, 'legacy-file.tsx'), 'legacy content'); + + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: '../metadata/dist/integration-data.json', + }; + + await executor(options, context); + + expect(fs.existsSync(path.join(srcDir, 'old-component.tsx'))).toBe(false); + expect(fs.existsSync(path.join(srcDir, 'legacy-file.tsx'))).toBe(false); + }); + + it('should preserve core directory during cleaning', async () => { + const srcDir = path.join(tempDir, 'packages', 'react-wrappers', 'src'); + + await writeFileText(path.join(srcDir, 'core', 'custom.tsx'), 'custom core file'); + await writeFileText(path.join(srcDir, 'temp-generated.tsx'), 'temp'); + + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: '../metadata/dist/integration-data.json', + }; + + await executor(options, context); + + expect(fs.existsSync(path.join(srcDir, 'core', 'component.tsx'))).toBe(true); + expect(fs.existsSync(path.join(srcDir, 'core', 'custom.tsx'))).toBe(true); + + expect(fs.existsSync(path.join(srcDir, 'temp-generated.tsx'))).toBe(false); + }); + + it('should preserve common directory during cleaning', async () => { + const srcDir = path.join(tempDir, 'packages', 'react-wrappers', 'src'); + + fs.mkdirSync(path.join(srcDir, 'common')); + await writeFileText(path.join(srcDir, 'common', 'utils.ts'), 'utils'); + + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: '../metadata/dist/integration-data.json', + }; + + await executor(options, context); + + expect(fs.existsSync(path.join(srcDir, 'common', 'utils.ts'))).toBe(true); + }); + }); + + describe('Path resolution', () => { + it('should resolve metadata path relative to project', async () => { + const projectDir = path.join(tempDir, 'packages', 'react-wrappers'); + + await writeJson( + path.join(projectDir, 'metadata.json'), + { Widgets: {} } + ); + + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: './metadata.json', + }; + + const result = await executor(options, context); + + expect(result).toHaveProperty('success'); + }); + + it('should resolve ../ paths correctly', async () => { + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: '../metadata/dist/integration-data.json', + }; + + const result = await executor(options, context); + + expect(result).toHaveProperty('success'); + }); + }); + + describe('Configuration options', () => { + it('should accept custom component paths', async () => { + const srcDir = path.join(tempDir, 'packages', 'react-wrappers', 'src'); + + fs.mkdirSync(path.join(srcDir, 'templates'), { recursive: true }); + await writeFileText(path.join(srcDir, 'templates', 'base.tsx'), 'base'); + + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: '../metadata/dist/integration-data.json', + baseComponent: './templates/base', + extensionComponent: './templates/extension', + configComponent: './templates/config', + }; + + const result = await executor(options, context); + + expect(result).toHaveProperty('success'); + }); + + it('should accept custom output paths', async () => { + const projectDir = path.join(tempDir, 'packages', 'react-wrappers'); + + fs.mkdirSync(path.join(projectDir, 'generated'), { recursive: true }); + + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: '../metadata/dist/integration-data.json', + componentsDir: './generated', + indexFileName: './generated/index.ts', + }; + + const result = await executor(options, context); + + expect(result).toHaveProperty('success'); + }); + }); + + describe('Multiple runs', () => { + it('should handle repeated generation cleanly', async () => { + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: '../metadata/dist/integration-data.json', + }; + + const result1 = await executor(options, context); + expect(result1).toHaveProperty('success'); + + const result2 = await executor(options, context); + expect(result2).toHaveProperty('success'); + + const srcDir = path.join(tempDir, 'packages', 'react-wrappers', 'src'); + + expect(fs.existsSync(path.join(srcDir, 'core', 'component.tsx'))).toBe(true); + }); + }); + + describe('Error scenarios', () => { + it('should handle corrupted metadata gracefully', async () => { + const metadataPath = path.join(tempDir, 'packages', 'metadata', 'dist', 'integration-data.json'); + + await writeFileText(metadataPath, 'not valid json {{{'); + + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: '../metadata/dist/integration-data.json', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(false); + }); + + it('should handle missing core templates', async () => { + const srcDir = path.join(tempDir, 'packages', 'react-wrappers', 'src'); + + fs.rmSync(path.join(srcDir, 'core'), { recursive: true, force: true }); + + const options: GenerateReactComponentsExecutorSchema = { + metadataPath: '../metadata/dist/integration-data.json', + }; + + const result = await executor(options, context); + + expect(result).toHaveProperty('success'); + expect(typeof result.success).toBe('boolean'); + }); + }); +}); diff --git a/packages/nx-infra-plugin/src/executors/generate-react-components/executor.ts b/packages/nx-infra-plugin/src/executors/generate-react-components/executor.ts new file mode 100644 index 000000000000..6d1fc975fe67 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/generate-react-components/executor.ts @@ -0,0 +1,279 @@ +import { PromiseExecutor, logger, ExecutorContext } from '@nx/devkit'; +import * as fs from 'fs'; +import * as path from 'path'; +import { GenerateReactComponentsExecutorSchema } from './schema'; +import { resolveProjectPath } from '../../utils/path-resolver'; +import { logError, getErrorMessage } from '../../utils/error-handler'; +import cleanExecutor from '../clean/executor'; +import { CleanExecutorSchema } from '../clean/schema'; + +const DEFAULT_COMPONENTS_DIR = './src'; +const DEFAULT_INDEX_FILE_NAME = './src/index.ts'; +const CORE_DIR = 'core'; +const COMMON_DIR = 'common'; + +const TOOLS_DIR = 'tools'; +const GENERATORS_CONFIG_FILE = 'generators-config.js'; +const METADATA_PACKAGE = 'devextreme-metadata'; +const METADATA_FILE = 'integration-data.json'; +const INTERNAL_TOOLS_PACKAGE = 'devextreme-internal-tools'; +const GENERATION_FUNCTION = 'generateReactComponents'; + +const DEFAULT_BASE_COMPONENT = './core/component'; +const DEFAULT_EXTENSION_COMPONENT = './core/extension-component'; +const DEFAULT_CONFIG_COMPONENT = './core/nested-option'; + +const WIDGETS_PACKAGE = 'devextreme'; + +const CLEAN_MODE = 'shallow'; + +const MSG_CLEANING = '๐Ÿงน Cleaning generated components'; +const MSG_CLEANED = 'โœ“ Successfully cleaned components directory'; +const MSG_LOADING_METADATA = '๐Ÿ“‹ Loading metadata'; +const MSG_GENERATORS_CONFIG_NOT_FOUND = 'โš ๏ธ generators-config.js not found, proceeding without unifiedConfig'; +const MSG_LOADED_REACT_CONFIG = 'โœ“ Loaded React configuration from generators-config.js'; +const MSG_GENERATING = 'โš™๏ธ Generating React components'; +const MSG_GENERATION_COMPLETED = 'โœ“ Component generation completed'; +const MSG_GENERATION_SUCCESS = 'โœจ React component generation successful!'; +const MSG_STARTING = '๐Ÿ”ง Starting React component generation'; +const MSG_GENERATION_FAILED = 'โŒ Component generation failed'; + +const ERROR_METADATA_NOT_FOUND = 'Could not find devextreme-metadata/integration-data.json. Please ensure devextreme-metadata is installed or provide a metadataPath option.'; +const ERROR_CLEAN_FAILED = 'Failed to clean components directory'; + +const PARENT_DIR_PREFIX = '../'; +const DOT_SLASH_PREFIX = './'; + +const ENCODING_UTF8 = 'utf-8'; + +const GENERATE_REEXPORTS = 'generateReexports'; +const GENERATE_CUSTOM_TYPES = 'generateCustomTypes'; +const QUOTES_DOUBLE = 'double'; +const EXPLICIT_INDEX_IN_IMPORTS = 'excplicitIndexInImports'; + +const EXPORT_PATTERN = /export \{/g; + +async function cleanComponentsDirectory( + absoluteComponentsDir: string, + preservePaths: string[], + context: ExecutorContext +): Promise { + logger.info(MSG_CLEANING); + + const absoluteProjectRoot = resolveProjectPath(context); + + const relativeComponentsDir = path.relative(absoluteProjectRoot, absoluteComponentsDir); + + const cleanOptions: CleanExecutorSchema = { + targetDirectory: DOT_SLASH_PREFIX + relativeComponentsDir, + excludePatterns: preservePaths.map(currentPath => { + if (path.isAbsolute(currentPath)) { + const relative = path.relative(absoluteProjectRoot, currentPath); + return DOT_SLASH_PREFIX + relative; + } + return currentPath; + }), + mode: CLEAN_MODE, + }; + + const result = await cleanExecutor(cleanOptions, context); + + if (result.success) { + logger.info(MSG_CLEANED); + } else { + throw new Error(ERROR_CLEAN_FAILED); + } +} + +function resolveMetadataPath( + options: GenerateReactComponentsExecutorSchema, + absoluteProjectRoot: string, + workspaceRoot: string +): string { + if (options.metadataPath) { + return resolveCustomMetadataPath( + options.metadataPath, + absoluteProjectRoot, + workspaceRoot + ); + } + + return resolveDefaultMetadataPath(); +} + +function resolveCustomMetadataPath( + metadataPath: string, + absoluteProjectRoot: string, + workspaceRoot: string +): string { + const relativeToProject = path.resolve(absoluteProjectRoot, metadataPath); + if (fs.existsSync(relativeToProject)) { + return relativeToProject; + } + + const relativeToWorkspace = path.resolve(workspaceRoot, metadataPath); + if (fs.existsSync(relativeToWorkspace)) { + return relativeToWorkspace; + } + + if (metadataPath.startsWith(PARENT_DIR_PREFIX)) { + return path.resolve(workspaceRoot, metadataPath); + } + + return relativeToProject; +} + +function resolveDefaultMetadataPath(): string { + try { + return require.resolve(`${METADATA_PACKAGE}/${METADATA_FILE}`); + } catch (error) { + throw new Error(ERROR_METADATA_NOT_FOUND); + } +} + +function loadMetadata(metadataPath: string): any { + logger.info(MSG_LOADING_METADATA); + logger.info(` Path: ${metadataPath}`); + + if (!fs.existsSync(metadataPath)) { + throw new Error(`Metadata file not found: ${metadataPath}`); + } + + const metadataContent = fs.readFileSync(metadataPath, ENCODING_UTF8); + const metaData = JSON.parse(metadataContent); + + const widgetCount = Object.keys(metaData.Widgets || {}).length; + logger.info(`โœ“ Loaded ${widgetCount} widget definitions`); + + return metaData; +} + +function loadReactConfig(workspaceRoot: string): any { + const generatorsConfigPath = path.join(workspaceRoot, TOOLS_DIR, GENERATORS_CONFIG_FILE); + + if (!fs.existsSync(generatorsConfigPath)) { + logger.warn(MSG_GENERATORS_CONFIG_NOT_FOUND); + return undefined; + } + + try { + const generatorsConfig = require(generatorsConfigPath); + logger.info(MSG_LOADED_REACT_CONFIG); + return generatorsConfig.reactConfig; + } catch (error) { + logger.warn(`โš ๏ธ Could not load generators-config.js: ${getErrorMessage(error)}`); + return undefined; + } +} + +function loadGenerationFunction(): any { + try { + const internalTools = require(INTERNAL_TOOLS_PACKAGE); + return internalTools[GENERATION_FUNCTION]; + } catch (error) { + throw new Error(`Could not load devextreme-internal-tools. Please ensure devextreme-internal-tools is installed as a dependency. Error: ${getErrorMessage(error)}`); + } +} + +function buildGenerationConfig( + options: GenerateReactComponentsExecutorSchema, + componentsDir: string, + indexFileName: string, + reactConfig: any +): any { + return { + metaData: undefined, + components: { + baseComponent: options.baseComponent || DEFAULT_BASE_COMPONENT, + extensionComponent: options.extensionComponent || DEFAULT_EXTENSION_COMPONENT, + configComponent: options.configComponent || DEFAULT_CONFIG_COMPONENT, + }, + out: { + componentsDir, + indexFileName, + }, + widgetsPackage: WIDGETS_PACKAGE, + typeGenerationOptions: { + [GENERATE_REEXPORTS]: true, + [GENERATE_CUSTOM_TYPES]: true, + }, + templatingOptions: { + quotes: QUOTES_DOUBLE, + [EXPLICIT_INDEX_IN_IMPORTS]: true, + }, + unifiedConfig: reactConfig, + }; +} + +async function executeGeneration( + generateReactComponents: any, + config: any, + metaData: any, + componentsDir: string, + indexFileName: string +): Promise { + logger.info(MSG_GENERATING); + + config.metaData = metaData; + await generateReactComponents(config); + + logger.info(MSG_GENERATION_COMPLETED); + + if (fs.existsSync(indexFileName)) { + const indexContent = fs.readFileSync(indexFileName, ENCODING_UTF8); + const exportCount = (indexContent.match(EXPORT_PATTERN) || []).length; + logger.info(` Exports: ${exportCount}`); + } + + if (fs.existsSync(componentsDir)) { + const dirCount = fs.readdirSync(componentsDir, { withFileTypes: true }) + .filter(entry => entry.isDirectory() && entry.name !== CORE_DIR) + .length; + logger.info(` Component Directories: ${dirCount}`); + } + + logger.info(MSG_GENERATION_SUCCESS); +} + +const runExecutor: PromiseExecutor< + GenerateReactComponentsExecutorSchema +> = async (options, context) => { + const absoluteProjectRoot = resolveProjectPath(context); + const workspaceRoot = context.root; + + logger.info(MSG_STARTING); + const projectRelativePath = path.relative(workspaceRoot, absoluteProjectRoot) || DOT_SLASH_PREFIX; + logger.info(` Project root: ${projectRelativePath}`); + + try { + const componentsDir = path.resolve( + absoluteProjectRoot, + options.componentsDir || DEFAULT_COMPONENTS_DIR + ); + const indexFileName = path.resolve( + absoluteProjectRoot, + options.indexFileName || DEFAULT_INDEX_FILE_NAME + ); + + const coreDir = path.join(componentsDir, CORE_DIR); + const commonDir = path.join(componentsDir, COMMON_DIR); + await cleanComponentsDirectory(componentsDir, [coreDir, commonDir, indexFileName], context); + + const metadataPath = resolveMetadataPath(options, absoluteProjectRoot, workspaceRoot); + const metaData = loadMetadata(metadataPath); + + const reactConfig = loadReactConfig(workspaceRoot); + + const generateReactComponents = loadGenerationFunction(); + + const config = buildGenerationConfig(options, componentsDir, indexFileName, reactConfig); + await executeGeneration(generateReactComponents, config, metaData, componentsDir, indexFileName); + + return { success: true }; + } catch (error) { + logError(MSG_GENERATION_FAILED, error); + return { success: false }; + } +}; + +export default runExecutor; diff --git a/packages/nx-infra-plugin/src/executors/generate-react-components/schema.d.ts b/packages/nx-infra-plugin/src/executors/generate-react-components/schema.d.ts new file mode 100644 index 000000000000..1811b30b598b --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/generate-react-components/schema.d.ts @@ -0,0 +1,8 @@ +export interface GenerateReactComponentsExecutorSchema { + metadataPath?: string; + componentsDir?: string; + indexFileName?: string; + baseComponent?: string; + extensionComponent?: string; + configComponent?: string; +} diff --git a/packages/nx-infra-plugin/src/executors/generate-react-components/schema.json b/packages/nx-infra-plugin/src/executors/generate-react-components/schema.json new file mode 100644 index 000000000000..5c48579dd30c --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/generate-react-components/schema.json @@ -0,0 +1,35 @@ +{ + "type": "object", + "properties": { + "metadataPath": { + "type": "string", + "description": "Path to metadata JSON file" + }, + "componentsDir": { + "type": "string", + "description": "Output directory for generated components", + "default": "./src" + }, + "indexFileName": { + "type": "string", + "description": "Index file name", + "default": "./src/index.ts" + }, + "baseComponent": { + "type": "string", + "description": "Base component path", + "default": "./core/component" + }, + "extensionComponent": { + "type": "string", + "description": "Extension component path", + "default": "./core/extension-component" + }, + "configComponent": { + "type": "string", + "description": "Config component path", + "default": "./core/nested-option" + } + }, + "required": ["metadataPath"] +} diff --git a/packages/nx-infra-plugin/src/executors/generate-react-components/schema.ts b/packages/nx-infra-plugin/src/executors/generate-react-components/schema.ts new file mode 100644 index 000000000000..ec07683905ed --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/generate-react-components/schema.ts @@ -0,0 +1,8 @@ +export interface GenerateReactComponentsExecutorSchema { + metadataPath: string; + componentsDir?: string; + indexFileName?: string; + baseComponent?: string; + extensionComponent?: string; + configComponent?: string; +} diff --git a/packages/nx-infra-plugin/src/executors/pack-npm/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/pack-npm/executor.e2e.spec.ts new file mode 100644 index 000000000000..889ef9b7cb08 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/pack-npm/executor.e2e.spec.ts @@ -0,0 +1,127 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { execSync } from 'child_process'; +import executor from './executor'; +import { PackNpmExecutorSchema } from './schema'; +import { + createTempDir, + cleanupTempDir, + createMockContext, +} from '../../utils/test-utils'; +import { writeFileText, writeJson } from '../../utils'; + +const PACKAGE_NAME = 'test-package'; +const PACKAGE_VERSION = '1.0.0'; +const EXPECTED_TARBALL_NAME = `${PACKAGE_NAME}-${PACKAGE_VERSION}.tgz`; +const NPM_DIR_NAME = 'npm'; +const PROJECT_NAME = 'test-lib'; +const PACKAGES_DIR = 'packages'; + +describe('PackNpmExecutor E2E', () => { + let tempDir: string; + let context = createMockContext(); + let pnpmAvailable: boolean; + + beforeAll(() => { + try { + execSync('pnpm --version', { stdio: 'ignore' }); + pnpmAvailable = true; + } catch { + pnpmAvailable = false; + } + }); + + beforeEach(async () => { + if (!pnpmAvailable) { + return; + } + + tempDir = createTempDir('nx-pack-e2e-'); + + await writeFileText( + path.join(tempDir, 'pnpm-workspace.yaml'), + `packages:\n - '${PACKAGES_DIR}/*'\n` + ); + + await writeJson( + path.join(tempDir, 'package.json'), + { + name: 'test-workspace', + version: '1.0.0', + private: true, + } + ); + + const projectDir = path.join(tempDir, PACKAGES_DIR, PROJECT_NAME); + const npmDir = path.join(projectDir, NPM_DIR_NAME); + + fs.mkdirSync(npmDir, { recursive: true }); + + await writeJson( + path.join(projectDir, 'package.json'), + { + name: PACKAGE_NAME, + version: PACKAGE_VERSION, + description: 'Test package for pnpm pack', + main: './npm/index.js', + } + ); + + await writeJson( + path.join(npmDir, 'package.json'), + { + name: PACKAGE_NAME, + version: PACKAGE_VERSION, + description: 'Test package for pnpm pack', + main: './index.js', + } + ); + + await writeFileText( + path.join(npmDir, 'index.js'), + 'module.exports = { test: true };' + ); + + context = createMockContext({ + root: tempDir, + projectName: PROJECT_NAME, + projectRoot: path.join(PACKAGES_DIR, PROJECT_NAME), + }); + }); + + afterEach(() => { + if (!pnpmAvailable || !tempDir) { + return; + } + + cleanupTempDir(tempDir); + }); + + it('should create tarball inside npm directory', async () => { + if (!pnpmAvailable) { + console.log('Skipping test: pnpm not available'); + return; + } + + const options: PackNpmExecutorSchema = { + workingDirectory: `./${NPM_DIR_NAME}`, + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const projectDir = path.join(tempDir, PACKAGES_DIR, PROJECT_NAME); + const expectedTarballPath = path.join(projectDir, EXPECTED_TARBALL_NAME); + + console.log('projectDir:', projectDir); + console.log('Files in projectDir:', fs.readdirSync(projectDir)); + console.log('Expected tarball:', expectedTarballPath); + + expect(fs.existsSync(expectedTarballPath)).toBe(true); + + const tarballStat = fs.statSync(expectedTarballPath); + expect(tarballStat.isFile()).toBe(true); + expect(tarballStat.size).toBeGreaterThan(0); + }); +}); diff --git a/packages/nx-infra-plugin/src/executors/pack-npm/executor.ts b/packages/nx-infra-plugin/src/executors/pack-npm/executor.ts new file mode 100644 index 000000000000..1407f3f8963f --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/pack-npm/executor.ts @@ -0,0 +1,44 @@ +import { PromiseExecutor, logger } from '@nx/devkit'; +import { execSync } from 'child_process'; +import path from 'path'; +import { PackNpmExecutorSchema } from './schema'; +import { resolveProjectPath } from '../../utils/path-resolver'; +import { logError } from '../../utils/error-handler'; + +const DEFAULT_DIST_DIR = './npm'; + +const MSG_PACK_SUCCESS = 'pnpm pack completed successfully'; +const MSG_PACK_FAILED = 'Failed to run pnpm pack'; + +const runExecutor: PromiseExecutor = async ( + options, + context +) => { + const absoluteProjectRoot = resolveProjectPath(context); + const distDirectory = options.workingDirectory || DEFAULT_DIST_DIR; + const workspaceRoot = context.root; + + if (!context.projectName) { + logError(MSG_PACK_FAILED, 'Project name is not defined in context'); + return { success: false }; + } + + try { + logger.info(`Running pnpm pack from ${absoluteProjectRoot} (packaging ${distDirectory})...`); + + const projectPath = path.join(workspaceRoot, 'packages', context.projectName); + + execSync(`pnpm pack`, { + cwd: projectPath, + stdio: 'inherit', + }); + + logger.info(MSG_PACK_SUCCESS); + return { success: true }; + } catch (error) { + logError(MSG_PACK_FAILED, error); + return { success: false }; + } +}; + +export default runExecutor; diff --git a/packages/nx-infra-plugin/src/executors/pack-npm/schema.json b/packages/nx-infra-plugin/src/executors/pack-npm/schema.json new file mode 100644 index 000000000000..888e8312ae4f --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/pack-npm/schema.json @@ -0,0 +1,11 @@ +{ + "type": "object", + "properties": { + "workingDirectory": { + "type": "string", + "description": "Working directory for pnpm pack", + "default": "./" + } + }, + "required": [] +} diff --git a/packages/nx-infra-plugin/src/executors/pack-npm/schema.ts b/packages/nx-infra-plugin/src/executors/pack-npm/schema.ts new file mode 100644 index 000000000000..4b7a44f69ae6 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/pack-npm/schema.ts @@ -0,0 +1,3 @@ +export interface PackNpmExecutorSchema { + workingDirectory?: string; +} diff --git a/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.e2e.spec.ts new file mode 100644 index 000000000000..3049a5602f5a --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.e2e.spec.ts @@ -0,0 +1,110 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import executor from './executor'; +import { NpmPackageExecutorSchema } from './schema'; +import { + createTempDir, + cleanupTempDir, + createMockContext, +} from '../../utils/test-utils'; +import { writeJson, readFileText } from '../../utils'; + +describe('PreparePackageJsonExecutor E2E', () => { + let tempDir: string; + let context = createMockContext(); + + beforeEach(async () => { + tempDir = createTempDir('nx-prepare-pkg-e2e-'); + context = createMockContext({ root: tempDir }); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + + fs.mkdirSync(projectDir, { recursive: true }); + + await writeJson( + path.join(projectDir, 'package.json'), + { + name: '@devexpress/test-package', + version: '1.0.0', + description: 'Test package for prepare-package-json', + main: './index.js', + module: './esm/index.js', + types: './index.d.ts', + scripts: { + build: 'tsc', + test: 'jest', + }, + publishConfig: { + access: 'public', + directory: 'npm', + registry: 'https://registry.npmjs.org/', + }, + dependencies: { + react: '^18.0.0', + }, + devDependencies: { + typescript: '^4.9.0', + jest: '^29.0.0', + }, + keywords: ['test', 'package'], + license: 'MIT', + author: 'Test Author', + } + ); + }); + + afterEach(() => { + cleanupTempDir(tempDir); + }); + + describe('publishConfig removal', () => { + it('should remove publishConfig from package.json', async () => { + const options: NpmPackageExecutorSchema = { + distDirectory: './npm', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const distPackageJson = path.join(projectDir, 'npm', 'package.json'); + const distPackage = JSON.parse(await readFileText(distPackageJson)); + + expect(distPackage.publishConfig).toBeUndefined(); + }); + + it('should preserve all other fields when removing publishConfig', async () => { + const options: NpmPackageExecutorSchema = { + distDirectory: './npm', + }; + + await executor(options, context); + + const projectDir = path.join(tempDir, 'packages', 'test-lib'); + const distPackageJson = path.join(projectDir, 'npm', 'package.json'); + const distPackage = JSON.parse(await readFileText(distPackageJson)); + + expect(distPackage.name).toBe('@devexpress/test-package'); + expect(distPackage.version).toBe('1.0.0'); + expect(distPackage.description).toBe('Test package for prepare-package-json'); + expect(distPackage.main).toBe('./index.js'); + expect(distPackage.module).toBe('./esm/index.js'); + expect(distPackage.types).toBe('./index.d.ts'); + expect(distPackage.scripts).toEqual({ + build: 'tsc', + test: 'jest', + }); + expect(distPackage.dependencies).toEqual({ + react: '^18.0.0', + }); + expect(distPackage.devDependencies).toEqual({ + typescript: '^4.9.0', + jest: '^29.0.0', + }); + expect(distPackage.keywords).toEqual(['test', 'package']); + expect(distPackage.license).toBe('MIT'); + expect(distPackage.author).toBe('Test Author'); + }); + }); +}); diff --git a/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.ts b/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.ts new file mode 100644 index 000000000000..91bb0a797070 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.ts @@ -0,0 +1,50 @@ +import { PromiseExecutor, logger } from '@nx/devkit'; +import * as path from 'path'; +import { NpmPackageExecutorSchema } from './schema'; +import { resolveProjectPath } from '../../utils/path-resolver'; +import { logError } from '../../utils/error-handler'; +import { ensureDir, readJson, writeJson } from '../../utils/file-operations'; + +const DEFAULT_SOURCE_PACKAGE_JSON = './package.json'; +const DEFAULT_DIST_DIR = './npm'; + +const PACKAGE_JSON_FILE = 'package.json'; +const PUBLISH_CONFIG_FIELD = 'publishConfig'; + +const JSON_INDENT = 2; + +const ERROR_PREPARE_PACKAGE_JSON = 'Failed to prepare package.json'; + +const runExecutor: PromiseExecutor = async ( + options, + context +) => { + const absoluteProjectRoot = resolveProjectPath(context); + const sourcePackageJson = path.join( + absoluteProjectRoot, + options.sourcePackageJson || DEFAULT_SOURCE_PACKAGE_JSON + ); + const distDirectory = path.join( + absoluteProjectRoot, + options.distDirectory || DEFAULT_DIST_DIR + ); + + try { + await ensureDir(distDirectory); + + const pkg = await readJson>(sourcePackageJson); + delete pkg[PUBLISH_CONFIG_FIELD]; + + const distPackageJson = path.join(distDirectory, PACKAGE_JSON_FILE); + await writeJson(distPackageJson, pkg, JSON_INDENT); + + logger.info(`Created ${distPackageJson}`); + + return { success: true }; + } catch (error) { + logError(ERROR_PREPARE_PACKAGE_JSON, error); + return { success: false }; + } +}; + +export default runExecutor; diff --git a/packages/nx-infra-plugin/src/executors/prepare-package-json/schema.json b/packages/nx-infra-plugin/src/executors/prepare-package-json/schema.json new file mode 100644 index 000000000000..d555d19c5d7f --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/prepare-package-json/schema.json @@ -0,0 +1,16 @@ +{ + "type": "object", + "properties": { + "sourcePackageJson": { + "type": "string", + "description": "Path to source package.json", + "default": "./package.json" + }, + "distDirectory": { + "type": "string", + "description": "Distribution directory", + "default": "./npm" + } + }, + "required": [] +} diff --git a/packages/nx-infra-plugin/src/executors/prepare-package-json/schema.ts b/packages/nx-infra-plugin/src/executors/prepare-package-json/schema.ts new file mode 100644 index 000000000000..8e294d1d6300 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/prepare-package-json/schema.ts @@ -0,0 +1,4 @@ +export interface NpmPackageExecutorSchema { + sourcePackageJson?: string; + distDirectory?: string; +} diff --git a/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts new file mode 100644 index 000000000000..4de675211054 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts @@ -0,0 +1,221 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import executor from './executor'; +import { PrepareSubmodulesExecutorSchema } from './schema'; +import { + createTempDir, + cleanupTempDir, + createMockContext, +} from '../../utils/test-utils'; +import { writeFileText, readFileText } from '../../utils'; + +describe('PrepareSubmodulesExecutor E2E', () => { + let tempDir: string; + let context = createMockContext(); + + beforeEach(async () => { + tempDir = createTempDir('nx-prepare-submodules-e2e-'); + context = createMockContext({ + root: tempDir, + projectName: 'test-package', + projectRoot: 'packages/test-package', + }); + + const projectDir = path.join(tempDir, 'packages', 'test-package'); + const npmDir = path.join(projectDir, 'npm'); + + fs.mkdirSync(path.join(npmDir, 'esm'), { recursive: true }); + fs.mkdirSync(path.join(npmDir, 'cjs'), { recursive: true }); + + await writeFileText( + path.join(npmDir, 'esm', 'index.js'), + `export { Button } from "./button";\nexport { Grid } from "./data/grid";\nexport { Chart } from "./viz/chart";` + ); + + await writeFileText(path.join(npmDir, 'esm', 'button.js'), 'export const Button = () => {};'); + fs.mkdirSync(path.join(npmDir, 'esm', 'data'), { recursive: true }); + await writeFileText(path.join(npmDir, 'esm', 'data', 'grid.js'), 'export const Grid = () => {};'); + fs.mkdirSync(path.join(npmDir, 'esm', 'viz'), { recursive: true }); + await writeFileText(path.join(npmDir, 'esm', 'viz', 'chart.js'), 'export const Chart = () => {};'); + + await writeFileText(path.join(npmDir, 'cjs', 'index.js'), 'module.exports = {};'); + await writeFileText(path.join(npmDir, 'cjs', 'button.js'), 'module.exports = {};'); + fs.mkdirSync(path.join(npmDir, 'cjs', 'data'), { recursive: true }); + await writeFileText(path.join(npmDir, 'cjs', 'data', 'grid.js'), 'module.exports = {};'); + fs.mkdirSync(path.join(npmDir, 'cjs', 'viz'), { recursive: true }); + await writeFileText(path.join(npmDir, 'cjs', 'viz', 'chart.js'), 'module.exports = {};'); + }); + + afterEach(() => { + cleanupTempDir(tempDir); + }); + + describe('Basic functionality', () => { + it('should generate package.json files for discovered modules', async () => { + const options: PrepareSubmodulesExecutorSchema = { + distDirectory: './npm', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); + + const buttonPkgPath = path.join(npmDir, 'button', 'package.json'); + expect(fs.existsSync(buttonPkgPath)).toBe(true); + + const buttonPkg = JSON.parse(await readFileText(buttonPkgPath)); + expect(buttonPkg).toMatchObject({ + sideEffects: false, + main: expect.stringContaining('cjs/button.js'), + module: expect.stringContaining('esm/button.js'), + typings: expect.stringContaining('cjs/button.d.ts'), + }); + }); + + it('should handle nested module structures', async () => { + const options: PrepareSubmodulesExecutorSchema = { + distDirectory: './npm', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); + + const gridPkgPath = path.join(npmDir, 'grid', 'package.json'); + expect(fs.existsSync(gridPkgPath)).toBe(true); + + const gridPkg = JSON.parse(await readFileText(gridPkgPath)); + expect(gridPkg.module).toContain('esm/data/grid.js'); + }); + + it('should work with custom submodule files', async () => { + const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); + + await writeFileText(path.join(npmDir, 'esm', 'custom.js'), 'export const Custom = {};'); + await writeFileText(path.join(npmDir, 'cjs', 'custom.js'), 'module.exports = {};'); + + const esmIndex = await readFileText(path.join(npmDir, 'esm', 'index.js')); + await writeFileText( + path.join(npmDir, 'esm', 'index.js'), + esmIndex + '\nexport { Custom } from "./custom";' + ); + + const options: PrepareSubmodulesExecutorSchema = { + distDirectory: './npm', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + const customPkgPath = path.join(npmDir, 'custom', 'package.json'); + expect(fs.existsSync(customPkgPath)).toBe(true); + + const customPkg = JSON.parse(await readFileText(customPkgPath)); + expect(customPkg.module).toBe('../esm/custom.js'); + }); + + it('should handle devextreme-react-like structure', async () => { + const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); + + fs.mkdirSync(path.join(npmDir, 'esm', 'common'), { recursive: true }); + await writeFileText(path.join(npmDir, 'esm', 'common', 'index.js'), 'export * from "./core";'); + fs.mkdirSync(path.join(npmDir, 'esm', 'common', 'core'), { recursive: true }); + await writeFileText(path.join(npmDir, 'esm', 'common', 'core', 'index.js'), 'export class Component {}'); + + fs.mkdirSync(path.join(npmDir, 'cjs', 'common'), { recursive: true }); + await writeFileText(path.join(npmDir, 'cjs', 'common', 'index.js'), 'module.exports = {};'); + fs.mkdirSync(path.join(npmDir, 'cjs', 'common', 'core'), { recursive: true }); + await writeFileText(path.join(npmDir, 'cjs', 'common', 'core', 'index.js'), 'module.exports = {};'); + + const options: PrepareSubmodulesExecutorSchema = { + distDirectory: './npm', + submoduleFolders: [ + ['common'], + ['common/core'], + ], + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + + expect(fs.existsSync(path.join(npmDir, 'common', 'package.json'))).toBe(true); + expect(fs.existsSync(path.join(npmDir, 'common', 'core', 'package.json'))).toBe(true); + }); + }); + + describe('Package.json content validation', () => { + it('should generate correct relative paths for top-level modules', async () => { + const options: PrepareSubmodulesExecutorSchema = { + distDirectory: './npm', + }; + + await executor(options, context); + + const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); + const buttonPkg = JSON.parse( + await readFileText(path.join(npmDir, 'button', 'package.json')) + ); + + expect(buttonPkg.main).toBe('../cjs/button.js'); + expect(buttonPkg.module).toBe('../esm/button.js'); + expect(buttonPkg.typings).toBe('../cjs/button.d.ts'); + }); + }); + + describe('Error handling', () => { + it('should handle missing dist directory gracefully', async () => { + const options: PrepareSubmodulesExecutorSchema = { + distDirectory: './nonexistent', + }; + + const result = await executor(options, context); + + expect(result).toHaveProperty('success'); + expect(typeof result.success).toBe('boolean'); + }); + + it('should handle empty ESM index file', async () => { + const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); + await writeFileText(path.join(npmDir, 'esm', 'index.js'), ''); + + const options: PrepareSubmodulesExecutorSchema = { + distDirectory: './npm', + }; + + const result = await executor(options, context); + + expect(result.success).toBe(true); + }); + }); + + describe('Integration scenarios', () => { + it('should handle multiple runs idempotently', async () => { + const options: PrepareSubmodulesExecutorSchema = { + distDirectory: './npm', + }; + + const result1 = await executor(options, context); + expect(result1.success).toBe(true); + + const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); + const firstPkg = JSON.parse( + await readFileText(path.join(npmDir, 'button', 'package.json')) + ); + + const result2 = await executor(options, context); + expect(result2.success).toBe(true); + + const secondPkg = JSON.parse( + await readFileText(path.join(npmDir, 'button', 'package.json')) + ); + + expect(secondPkg).toEqual(firstPkg); + }); + }); +}); diff --git a/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts new file mode 100644 index 000000000000..470f724d16c1 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts @@ -0,0 +1,174 @@ +import { PromiseExecutor, logger } from '@nx/devkit'; +import * as fs from 'fs/promises'; +import * as fsSync from 'fs'; +import type { Dirent } from 'fs'; +import * as path from 'path'; +import { PrepareSubmodulesExecutorSchema } from './schema'; +import { PackParam } from '../../utils/types'; +import { resolveProjectPath } from '../../utils/path-resolver'; +import { logError, getErrorMessage } from '../../utils/error-handler'; +import { ensureDir, writeJson } from '../../utils/file-operations'; + +const DEFAULT_DIST_DIR = './npm'; +const ESM_DIR = 'esm'; +const CJS_DIR = 'cjs'; + +const ENCODING_UTF8 = 'utf8'; + +const JS_EXTENSION = '.js'; +const DTS_EXTENSION = '.d.ts'; + +const REGEX_IMPORTS = /from "\.\/([^;]+)";/g; +const REGEX_PARSE_MODULE = /((.*)\/)?([^/]+$)/; + +const MSG_PREPARING = '๐Ÿ“ฆ Preparing submodules'; +const MSG_SUCCESS = 'โœ“ Submodules prepared successfully'; +const ERROR_PREPARE_SUBMODULES = 'Failed to prepare submodules'; + +const INDEX_FILE_NAME = 'index.js'; +const PACKAGE_JSON_FILE = 'package.json'; + +const PATH_SLASH = '/'; +const RELATIVE_DIR_PREFIX = '../'; + +const DEFAULT_SUBMODULE_FOLDERS: PackParam[] = [ + ['common'], + ['core', ['template', 'config', 'nested-option', 'component', 'extension-component']], + ['common/core'], + ['common/data'], + ['common/export'], +]; + +const runExecutor: PromiseExecutor = async ( + options, + context +) => { + const absoluteProjectRoot = resolveProjectPath(context); + const distDirectory = path.join( + absoluteProjectRoot, + options.distDirectory || DEFAULT_DIST_DIR + ); + + try { + logger.info(MSG_PREPARING); + + const packParamsForFolders = options.submoduleFolders || DEFAULT_SUBMODULE_FOLDERS; + + const esmIndexPath = path.join(distDirectory, ESM_DIR, 'index.js'); + let modulesImportsFromIndex = ''; + + if (fsSync.existsSync(esmIndexPath)) { + modulesImportsFromIndex = await fs.readFile(esmIndexPath, ENCODING_UTF8); + } + + const modulesPaths = modulesImportsFromIndex.matchAll(REGEX_IMPORTS); + const packParamsForModules: PackParam[] = Array.from(modulesPaths).map( + ([, modulePath]) => { + const match = modulePath.match(REGEX_PARSE_MODULE) || []; + const moduleFilePath = match[2] as string | undefined; + const moduleFileName = match[3] as string | undefined; + + return ['', moduleFileName ? [moduleFileName] : undefined, moduleFilePath]; + } + ); + + const allModuleParams: PackParam[] = [...packParamsForModules, ...packParamsForFolders]; + + logger.info(`Processing ${allModuleParams.length} submodules...`); + + await Promise.all( + allModuleParams.map(([folder, moduleFileNames, moduleFilePath]) => + makeModule(distDirectory, folder, moduleFileNames, moduleFilePath) + ) + ); + + logger.info(MSG_SUCCESS); + return { success: true }; + } catch (error) { + logError(ERROR_PREPARE_SUBMODULES, error); + return { success: false }; + } +}; + +async function makeModule( + distFolder: string, + folder: string, + moduleFileNames?: string[], + moduleFilePath?: string +): Promise { + const distModuleFolder = path.join(distFolder, folder); + const distEsmFolder = path.join(distFolder, ESM_DIR, folder); + const moduleNames = moduleFileNames || (await findJsModuleFileNamesInFolder(distEsmFolder)); + + try { + await ensureDir(distModuleFolder); + + if (folder && fsSync.existsSync(path.join(distEsmFolder, 'index.js'))) { + await generatePackageJsonFile(distFolder, folder); + } + + await Promise.all( + moduleNames.map(async (moduleFileName) => { + const moduleDir = path.join(distModuleFolder, moduleFileName); + await ensureDir(moduleDir); + + await generatePackageJsonFile( + distFolder, + folder, + moduleFileName, + moduleFilePath || folder + ); + }) + ); + } catch (error) { + throw new Error(`Exception while makeModule(${folder}): ${getErrorMessage(error)}`); + } +} + +async function generatePackageJsonFile( + distFolder: string, + folder: string, + moduleFileName?: string, + filePath?: string +): Promise { + const moduleName = moduleFileName || ''; + const absoluteModulePath = path.join(distFolder, folder, moduleName); + const moduleFilePathResolved = + (filePath ? filePath + PATH_SLASH : '') + (moduleName || 'index'); + const esmFilePath = path.join( + distFolder, + ESM_DIR, + moduleFilePathResolved + JS_EXTENSION + ); + const relativePath = path.relative(absoluteModulePath, esmFilePath); + + const relativeBase = RELATIVE_DIR_PREFIX.repeat(relativePath.split('..').length - 1); + + const packageJson = { + sideEffects: false, + main: `${relativeBase}${CJS_DIR}/${moduleFilePathResolved}${JS_EXTENSION}`, + module: `${relativeBase}${ESM_DIR}/${moduleFilePathResolved}${JS_EXTENSION}`, + typings: `${relativeBase}${CJS_DIR}/${moduleFilePathResolved}${DTS_EXTENSION}`, + }; + + await ensureDir(absoluteModulePath); + await writeJson(path.join(absoluteModulePath, PACKAGE_JSON_FILE), packageJson); +} + +async function findJsModuleFileNamesInFolder(dir: string): Promise { + if (!fsSync.existsSync(dir)) { + return []; + } + + const entries = await fs.readdir(dir, { withFileTypes: true }); + + return entries + .filter(isJsModule) + .map((entry) => path.parse(entry.name).name); +} + +function isJsModule(entry: Dirent): boolean { + return !entry.isDirectory() && entry.name.endsWith(JS_EXTENSION) && entry.name !== INDEX_FILE_NAME; +} + +export default runExecutor; diff --git a/packages/nx-infra-plugin/src/executors/prepare-submodules/schema.json b/packages/nx-infra-plugin/src/executors/prepare-submodules/schema.json new file mode 100644 index 000000000000..e84a530524f9 --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/prepare-submodules/schema.json @@ -0,0 +1,18 @@ +{ + "type": "object", + "properties": { + "distDirectory": { + "type": "string", + "description": "Distribution directory containing ESM and CJS builds. This directory will be scanned to generate submodule package.json files.", + "default": "./npm" + }, + "submoduleFolders": { + "type": "array", + "description": "Custom submodule folder configurations. Each entry is [folder, moduleFileNames?, moduleFilePath?].", + "items": { + "type": "array" + } + } + }, + "required": [] +} diff --git a/packages/nx-infra-plugin/src/executors/prepare-submodules/schema.ts b/packages/nx-infra-plugin/src/executors/prepare-submodules/schema.ts new file mode 100644 index 000000000000..3b7170e9be1a --- /dev/null +++ b/packages/nx-infra-plugin/src/executors/prepare-submodules/schema.ts @@ -0,0 +1,6 @@ +import { PackParam } from '../../utils/types'; + +export interface PrepareSubmodulesExecutorSchema { + distDirectory?: string; + submoduleFolders?: PackParam[]; +} diff --git a/packages/nx-infra-plugin/src/index.ts b/packages/nx-infra-plugin/src/index.ts new file mode 100644 index 000000000000..b38bf27b3619 --- /dev/null +++ b/packages/nx-infra-plugin/src/index.ts @@ -0,0 +1,5 @@ +export default function () { + return { + name: 'nx-infra-plugin', + }; +} diff --git a/packages/nx-infra-plugin/src/utils/error-handler.ts b/packages/nx-infra-plugin/src/utils/error-handler.ts new file mode 100644 index 000000000000..6049e107c436 --- /dev/null +++ b/packages/nx-infra-plugin/src/utils/error-handler.ts @@ -0,0 +1,17 @@ +import { logger } from '@nx/devkit'; + +export function getErrorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +export function getErrorStack(error: unknown): string | undefined { + return error instanceof Error ? error.stack : undefined; +} + +export function logError(message: string, error: unknown): void { + logger.error(`${message}: ${getErrorMessage(error)}`); + const stack = getErrorStack(error); + if (stack) { + logger.error(stack); + } +} diff --git a/packages/nx-infra-plugin/src/utils/file-operations.ts b/packages/nx-infra-plugin/src/utils/file-operations.ts new file mode 100644 index 000000000000..a938829733dc --- /dev/null +++ b/packages/nx-infra-plugin/src/utils/file-operations.ts @@ -0,0 +1,72 @@ +import * as fs from 'fs/promises'; +import * as path from 'path'; +import { glob } from 'glob'; + +const ENCODING_UTF8 = 'utf-8'; +const ERROR_CODE_EXIST = 'EEXIST'; + +export async function ensureDir(dirPath: string): Promise { + try { + await fs.mkdir(dirPath, { recursive: true }); + } catch (error: unknown) { + if (error instanceof Error && 'code' in error && error.code === ERROR_CODE_EXIST) { + return; + } + throw error; + } +} + +export async function readJson(filePath: string): Promise { + const content = await fs.readFile(filePath, ENCODING_UTF8); + return JSON.parse(content) as T; +} + +export async function writeJson( + filePath: string, + data: unknown, + spaces: number = 2 +): Promise { + const content = JSON.stringify(data, null, spaces); + await fs.writeFile(filePath, content, ENCODING_UTF8); +} + +export async function processFiles( + pattern: string, + processor: (filePath: string) => Promise, + options: { ignore?: string[] } = {} +): Promise { + const files = await glob(pattern, { + absolute: true, + nodir: true, + ignore: options.ignore, + }); + + await Promise.all(files.map(processor)); + return files.length; +} + +export async function exists(filePath: string): Promise { + try { + await fs.access(filePath); + return true; + } catch { + return false; + } +} + +export async function copyFile(from: string, to: string): Promise { + await ensureDir(path.dirname(to)); + await fs.copyFile(from, to); +} + +export async function readFileText(filePath: string): Promise { + return fs.readFile(filePath, ENCODING_UTF8); +} + +export async function writeFileText( + filePath: string, + content: string +): Promise { + await ensureDir(path.dirname(filePath)); + await fs.writeFile(filePath, content, ENCODING_UTF8); +} diff --git a/packages/nx-infra-plugin/src/utils/index.ts b/packages/nx-infra-plugin/src/utils/index.ts new file mode 100644 index 000000000000..81ead4bb9a44 --- /dev/null +++ b/packages/nx-infra-plugin/src/utils/index.ts @@ -0,0 +1,4 @@ +export * from './types'; +export * from './path-resolver'; +export * from './error-handler'; +export * from './file-operations'; diff --git a/packages/nx-infra-plugin/src/utils/path-resolver.ts b/packages/nx-infra-plugin/src/utils/path-resolver.ts new file mode 100644 index 000000000000..17049d3a9e67 --- /dev/null +++ b/packages/nx-infra-plugin/src/utils/path-resolver.ts @@ -0,0 +1,38 @@ +import { ExecutorContext } from '@nx/devkit'; +import * as path from 'path'; + +const ERROR_CONFIGURATIONS_NOT_FOUND = 'Project configurations not found in executor context'; +const ERROR_PROJECT_NAME_NOT_FOUND = 'Project name not found in executor context'; +const ERROR_PROJECT_NOT_FOUND = 'Project "{0}" not found in workspace'; + +export function resolveProjectPath(context: ExecutorContext): string { + if (!context.projectsConfigurations) { + throw new Error(ERROR_CONFIGURATIONS_NOT_FOUND); + } + + if (!context.projectName) { + throw new Error(ERROR_PROJECT_NAME_NOT_FOUND); + } + + const project = context.projectsConfigurations.projects[context.projectName]; + if (!project) { + throw new Error(ERROR_PROJECT_NOT_FOUND.replace('{0}', context.projectName)); + } + + return path.resolve(context.root, project.root); +} + +export function resolveFromProject( + context: ExecutorContext, + relativePath: string +): string { + const projectRoot = resolveProjectPath(context); + return path.join(projectRoot, relativePath); +} + +export function resolveFromWorkspace( + context: ExecutorContext, + relativePath: string +): string { + return path.join(context.root, relativePath); +} diff --git a/packages/nx-infra-plugin/src/utils/test-utils.ts b/packages/nx-infra-plugin/src/utils/test-utils.ts new file mode 100644 index 000000000000..7d536890e96b --- /dev/null +++ b/packages/nx-infra-plugin/src/utils/test-utils.ts @@ -0,0 +1,44 @@ +import { ExecutorContext } from '@nx/devkit'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; + +export function createTempDir(prefix: string): string { + return fs.mkdtempSync(path.join(os.tmpdir(), prefix)); +} + +export function cleanupTempDir(dirPath: string): void { + if (fs.existsSync(dirPath)) { + fs.rmSync(dirPath, { recursive: true, force: true }); + } +} + + +export interface MockContextOptions { + root?: string; + projectName?: string; + projectRoot?: string; + isVerbose?: boolean; +} + +export function createMockContext(options: MockContextOptions = {}): ExecutorContext { + const { + root = '/tmp/test', + projectName = 'test-lib', + projectRoot = 'packages/test-lib', + isVerbose = false, + } = options; + + return { + root, + cwd: root, + isVerbose, + projectName, + projectsConfigurations: { + projects: { + [projectName]: { root: projectRoot }, + }, + version: 2, + }, + }; +} diff --git a/packages/nx-infra-plugin/src/utils/types.ts b/packages/nx-infra-plugin/src/utils/types.ts new file mode 100644 index 000000000000..c0a6c14e6e85 --- /dev/null +++ b/packages/nx-infra-plugin/src/utils/types.ts @@ -0,0 +1,51 @@ +export interface TsConfig { + compilerOptions?: CompilerOptions; + extends?: string; + include?: string[]; + exclude?: string[]; + files?: string[]; + references?: Array<{ path: string }>; +} + +export interface CompilerOptions { + target?: string; + module?: string; + lib?: string[]; + outDir?: string; + rootDir?: string; + declaration?: boolean; + declarationMap?: boolean; + sourceMap?: boolean; + strict?: boolean; + esModuleInterop?: boolean; + skipLibCheck?: boolean; + forceConsistentCasingInFileNames?: boolean; + resolveJsonModule?: boolean; + jsx?: string; + paths?: Record; + [key: string]: any; +} + +export type PackParam = [string, string[]?, string?]; + +export interface TemplateData { + pkg: { + name: string; + version: string; + [key: string]: any; + }; + date: string; + year: number; + [key: string]: any; +} + +export interface FileCopyOperation { + from: string; + to: string; +} + +export interface SubmoduleConfig { + folder: string; + moduleFileNames?: string[]; + moduleFilePath?: string; +} diff --git a/packages/nx-infra-plugin/tsconfig.json b/packages/nx-infra-plugin/tsconfig.json new file mode 100644 index 000000000000..f3ee56d7c006 --- /dev/null +++ b/packages/nx-infra-plugin/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "module": "commonjs" + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/nx-infra-plugin/tsconfig.lib.json b/packages/nx-infra-plugin/tsconfig.lib.json new file mode 100644 index 000000000000..ff6f64480938 --- /dev/null +++ b/packages/nx-infra-plugin/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "./prod", + "declaration": true, + "types": ["node"], + "skipLibCheck": true + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/nx-infra-plugin/tsconfig.spec.json b/packages/nx-infra-plugin/tsconfig.spec.json new file mode 100644 index 000000000000..d8fd5f2f8c31 --- /dev/null +++ b/packages/nx-infra-plugin/tsconfig.spec.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4cd29416dd36..7dce5c595289 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -268,7 +268,7 @@ importers: dependencies: '@angular-devkit/build-angular': specifier: 17.3.11 - version: 17.3.11(onoajuib57qxkrthdu6q7z3554) + version: 17.3.11(knttvfyutxltnyggdtp5kkscoe) '@angular/cli': specifier: 17.3.11 version: 17.3.11(chokidar@3.6.0) @@ -626,7 +626,7 @@ importers: version: 1.1.4 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@20.12.8)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)) + version: 29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)) jest-environment-node: specifier: 29.7.0 version: 29.7.0 @@ -674,7 +674,7 @@ importers: version: 3.7.2 ts-node: specifier: 10.9.2 - version: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5) + version: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5) vue-tsc: specifier: ^3.0.6 version: 3.0.8(typescript@5.4.5) @@ -2191,6 +2191,22 @@ importers: specifier: 'catalog:' version: 2.13.0 + packages/nx-infra-plugin: + dependencies: + glob: + specifier: 10.4.5 + version: 10.4.5 + rimraf: + specifier: 3.0.2 + version: 3.0.2 + devDependencies: + '@types/node': + specifier: ^18.0.0 + version: 18.19.64 + typescript: + specifier: 4.9.5 + version: 4.9.5 + packages/testcafe-models: dependencies: testcafe: @@ -19540,7 +19556,7 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@17.3.11(onoajuib57qxkrthdu6q7z3554)': + '@angular-devkit/build-angular@17.3.11(knttvfyutxltnyggdtp5kkscoe)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.1703.11(chokidar@3.6.0) @@ -19558,7 +19574,7 @@ snapshots: '@babel/runtime': 7.24.0 '@discoveryjs/json-ext': 0.5.7 '@ngtools/webpack': 17.3.11(@angular/compiler-cli@17.3.12(@angular/compiler@17.3.12(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.20.1)) - '@vitejs/plugin-basic-ssl': 1.1.0(vite@5.1.8(@types/node@20.12.8)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1)) + '@vitejs/plugin-basic-ssl': 1.1.0(vite@5.1.8(@types/node@18.19.64)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1)) ansi-colors: 4.1.3 autoprefixer: 10.4.18(postcss@8.4.35) babel-loader: 9.1.3(@babel/core@7.24.0)(webpack@5.94.0(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.20.1)) @@ -19600,7 +19616,7 @@ snapshots: tslib: 2.6.2 typescript: 5.4.5 undici: 6.11.1 - vite: 5.1.8(@types/node@20.12.8)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1) + vite: 5.1.8(@types/node@18.19.64)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1) watchpack: 2.4.0 webpack: 5.94.0(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.20.1) webpack-dev-middleware: 6.1.2(webpack@5.94.0(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.20.1)) @@ -19610,7 +19626,7 @@ snapshots: optionalDependencies: '@angular/platform-server': 17.3.12(@angular/animations@17.3.12(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@17.3.12(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/compiler@17.3.12(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10))(@angular/platform-browser@17.3.12(@angular/animations@17.3.12(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@17.3.12(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10))) esbuild: 0.20.1 - jest: 29.7.0(@types/node@20.12.8)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)) + jest: 29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)) jest-environment-jsdom: 29.7.0 karma: 6.4.4 ng-packagr: 17.3.0(@angular/compiler-cli@17.3.12(@angular/compiler@17.3.12(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tslib@2.8.1)(typescript@5.4.5) @@ -23696,27 +23712,27 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5))': + '@jest/core@29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0(node-notifier@9.0.1) '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) + jest-config: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -23739,21 +23755,21 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5))': + '@jest/core@29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0(node-notifier@9.0.1) '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -23775,23 +23791,22 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true - '@jest/core@29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5))': + '@jest/core@29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0(node-notifier@9.0.1) '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -23813,6 +23828,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true '@jest/core@29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2))': dependencies: @@ -23821,14 +23837,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + jest-config: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -23858,14 +23874,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.14.5)(typescript@5.9.2)) + jest-config: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.14.5)(typescript@5.9.2)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -23893,7 +23909,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -23911,7 +23927,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.12.8 + '@types/node': 18.19.64 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -23933,7 +23949,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 20.12.8 + '@types/node': 18.19.64 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -24004,7 +24020,7 @@ snapshots: dependencies: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/yargs': 16.0.9 chalk: 4.1.2 @@ -24013,7 +24029,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/yargs': 17.0.32 chalk: 4.1.2 @@ -24692,7 +24708,7 @@ snapshots: '@parcel/source-map': 2.1.1 '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) abortcontroller-polyfill: 1.7.6 base-x: 3.0.10 browserslist: 4.25.3 @@ -24720,7 +24736,7 @@ snapshots: '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/utils': 2.12.0 '@parcel/watcher': 2.5.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) transitivePeerDependencies: - '@swc/helpers' @@ -24794,7 +24810,7 @@ snapshots: '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@parcel/rust': 2.12.0 '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@parcel/optimizer-svgo@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))': dependencies: @@ -24826,7 +24842,7 @@ snapshots: '@parcel/node-resolver-core': 3.3.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@swc/core': 1.9.2(@swc/helpers@0.5.15) semver: 7.7.2 transitivePeerDependencies: @@ -25015,7 +25031,7 @@ snapshots: '@parcel/core': 2.12.0(@swc/helpers@0.5.15) '@parcel/plugin': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) nullthrows: 1.1.1 '@parcel/transformer-js@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))': @@ -25026,7 +25042,7 @@ snapshots: '@parcel/rust': 2.12.0 '@parcel/source-map': 2.1.1 '@parcel/utils': 2.12.0 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@swc/helpers': 0.5.15 browserslist: 4.25.3 nullthrows: 1.1.1 @@ -25099,7 +25115,7 @@ snapshots: '@parcel/fs': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/package-manager': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/source-map': 2.1.1 - '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) + '@parcel/workers': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) utility-types: 3.11.0 transitivePeerDependencies: - '@parcel/core' @@ -25176,7 +25192,7 @@ snapshots: '@parcel/watcher-win32-ia32': 2.5.0 '@parcel/watcher-win32-x64': 2.5.0 - '@parcel/workers@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)': + '@parcel/workers@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))': dependencies: '@parcel/core': 2.12.0(@swc/helpers@0.5.15) '@parcel/diagnostic': 2.12.0 @@ -25185,8 +25201,6 @@ snapshots: '@parcel/types': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/utils': 2.12.0 nullthrows: 1.1.1 - transitivePeerDependencies: - - '@swc/helpers' '@phenomnomnominal/tsquery@5.0.1(typescript@5.9.2)': dependencies: @@ -26801,17 +26815,17 @@ snapshots: '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/bonjour@3.5.13': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/chai@4.3.20': {} '@types/cheerio@0.22.35': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/clean-css@4.2.11': dependencies: @@ -26821,21 +26835,21 @@ snapshots: '@types/connect-history-api-fallback@1.5.4': dependencies: '@types/express-serve-static-core': 5.0.1 - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/connect@3.4.38': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/cookie@0.4.1': {} '@types/cors@2.8.17': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/cross-spawn@6.0.6': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/debug@4.1.12': dependencies: @@ -26896,14 +26910,14 @@ snapshots: '@types/express-serve-static-core@4.19.6': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/qs': 6.9.17 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 '@types/express-serve-static-core@5.0.1': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/qs': 6.9.17 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -26936,11 +26950,11 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/hast@2.3.10': dependencies: @@ -26952,7 +26966,7 @@ snapshots: '@types/http-proxy@1.17.15': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/istanbul-lib-coverage@2.0.6': {} @@ -26979,7 +26993,7 @@ snapshots: '@types/jsdom@20.0.1': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/tough-cookie': 4.0.5 parse5: 7.2.1 @@ -26989,7 +27003,7 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/lodash@4.17.13': {} @@ -27013,12 +27027,12 @@ snapshots: '@types/node-fetch@2.6.12': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 form-data: 4.0.1 '@types/node-forge@1.3.11': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/node@12.20.55': {} @@ -27103,7 +27117,7 @@ snapshots: '@types/resolve@1.17.1': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/resolve@1.20.2': {} @@ -27120,7 +27134,7 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/serve-index@1.9.4': dependencies: @@ -27129,30 +27143,30 @@ snapshots: '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/send': 0.17.4 '@types/shelljs@0.8.15': dependencies: '@types/glob': 7.2.0 - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/sizzle@2.3.9': {} '@types/sockjs@0.3.36': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/stack-utils@2.0.3': {} '@types/tar-fs@2.0.4': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/tar-stream': 3.1.3 '@types/tar-stream@3.1.3': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/tough-cookie@4.0.5': {} @@ -27170,11 +27184,11 @@ snapshots: '@types/vinyl@2.0.12': dependencies: '@types/expect': 1.20.4 - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/ws@8.5.13': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 '@types/yargs-parser@21.0.3': {} @@ -27188,7 +27202,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 optional: true '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.18.0(jiti@1.21.6))(typescript@5.4.5))(eslint@9.18.0(jiti@1.21.6))(typescript@5.4.5)': @@ -27762,13 +27776,13 @@ snapshots: '@typescript-eslint/types': 8.25.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.8(@types/node@20.11.17)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1))': + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.8(@types/node@18.19.64)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1))': dependencies: - vite: 5.1.8(@types/node@20.11.17)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1) + vite: 5.1.8(@types/node@18.19.64)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1) - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.8(@types/node@20.12.8)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1))': + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.8(@types/node@20.11.17)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1))': dependencies: - vite: 5.1.8(@types/node@20.12.8)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1) + vite: 5.1.8(@types/node@20.11.17)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1) '@vitejs/plugin-basic-ssl@1.2.0(vite@6.2.7(@types/node@20.14.5)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.1)(sass-embedded@1.66.0)(sass@1.85.0)(terser@5.39.0)(yaml@2.5.0))': dependencies: @@ -30463,13 +30477,13 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 - create-jest@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): + create-jest@29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) + jest-config: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -30478,13 +30492,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)): + create-jest@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -30492,15 +30506,14 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true - create-jest@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): + create-jest@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -30510,13 +30523,13 @@ snapshots: - ts-node optional: true - create-jest@29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)): + create-jest@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -30524,6 +30537,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true create-jest@29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): dependencies: @@ -31454,7 +31468,7 @@ snapshots: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 - '@types/node': 20.12.8 + '@types/node': 18.19.64 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.7.2 @@ -35601,7 +35615,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.3 @@ -35621,16 +35635,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): + jest-cli@29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)): dependencies: - '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) + '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) + create-jest: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) + jest-config: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -35642,16 +35656,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)): + jest-cli@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): dependencies: - '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) + '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) + create-jest: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -35662,18 +35676,17 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true - jest-cli@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): + jest-cli@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)): dependencies: - '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + create-jest: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -35686,16 +35699,16 @@ snapshots: - ts-node optional: true - jest-cli@29.7.0(@types/node@20.12.8)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)): + jest-cli@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): dependencies: - '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)) + '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)) + create-jest: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)) + jest-config: 29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -35706,6 +35719,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true jest-cli@29.7.0(@types/node@20.12.8)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): dependencies: @@ -35771,7 +35785,7 @@ snapshots: - ts-node optional: true - jest-config@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): + jest-config@29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)): dependencies: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 @@ -35796,13 +35810,44 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.11.17 + '@types/node': 18.19.64 + ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): + dependencies: + '@babel/core': 7.23.9 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.23.9) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 18.19.64 ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)): dependencies: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 @@ -35827,14 +35872,14 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.11.17 + '@types/node': 18.19.64 ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color optional: true - jest-config@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): + jest-config@29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): dependencies: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 @@ -35859,14 +35904,13 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.11.17 + '@types/node': 18.19.64 ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2) transitivePeerDependencies: - babel-plugin-macros - supports-color - optional: true - jest-config@29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): + jest-config@29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.14.5)(typescript@5.9.2)): dependencies: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 @@ -35891,13 +35935,14 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.12.8 - ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5) + '@types/node': 18.19.64 + ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.14.5)(typescript@5.9.2) transitivePeerDependencies: - babel-plugin-macros - supports-color + optional: true - jest-config@29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): dependencies: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 @@ -35922,14 +35967,13 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.12.8 - ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5) + '@types/node': 20.11.17 + ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5) transitivePeerDependencies: - babel-plugin-macros - supports-color - optional: true - jest-config@29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)): + jest-config@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)): dependencies: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 @@ -35954,13 +35998,14 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.12.8 - ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5) + '@types/node': 20.11.17 + ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5) transitivePeerDependencies: - babel-plugin-macros - supports-color + optional: true - jest-config@29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): + jest-config@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): dependencies: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 @@ -35985,13 +36030,14 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.12.8 + '@types/node': 20.11.17 ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2) transitivePeerDependencies: - babel-plugin-macros - supports-color + optional: true - jest-config@29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.14.5)(typescript@5.9.2)): + jest-config@29.7.0(@types/node@20.12.8)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): dependencies: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 @@ -36017,11 +36063,10 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.12.8 - ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.14.5)(typescript@5.9.2) + ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2) transitivePeerDependencies: - babel-plugin-macros - supports-color - optional: true jest-config@29.7.0(@types/node@20.14.5)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): dependencies: @@ -36135,7 +36180,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.12.8 + '@types/node': 18.19.64 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -36174,12 +36219,12 @@ snapshots: jest-mock@27.5.1: dependencies: '@jest/types': 27.5.1 - '@types/node': 20.12.8 + '@types/node': 18.19.64 jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -36214,7 +36259,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -36242,7 +36287,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 chalk: 4.1.2 cjs-module-lexer: 1.4.1 collect-v8-coverage: 1.0.2 @@ -36288,7 +36333,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -36307,7 +36352,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 18.19.64 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -36316,23 +36361,23 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 20.12.8 + '@types/node': 18.19.64 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): + jest@29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)): dependencies: - '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) + '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) + jest-cli: 29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5)) optionalDependencies: node-notifier: 9.0.1 transitivePeerDependencies: @@ -36341,12 +36386,12 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)): + jest@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): dependencies: - '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) + '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) + jest-cli: 29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) optionalDependencies: node-notifier: 9.0.1 transitivePeerDependencies: @@ -36354,14 +36399,13 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true - jest@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): + jest@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)): dependencies: - '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + jest-cli: 29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5)) optionalDependencies: node-notifier: 9.0.1 transitivePeerDependencies: @@ -36371,12 +36415,12 @@ snapshots: - ts-node optional: true - jest@29.7.0(@types/node@20.12.8)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)): + jest@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): dependencies: - '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)) + '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.12.8)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5)) + jest-cli: 29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) optionalDependencies: node-notifier: 9.0.1 transitivePeerDependencies: @@ -36384,6 +36428,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true jest@29.7.0(@types/node@20.12.8)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): dependencies: @@ -40196,7 +40241,7 @@ snapshots: rollup@0.58.2: dependencies: '@types/estree': 0.0.38 - '@types/node': 20.12.8 + '@types/node': 18.19.64 rollup@4.22.4: dependencies: @@ -42752,27 +42797,27 @@ snapshots: optionalDependencies: '@swc/core': 1.9.2(@swc/helpers@0.5.15) - ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5): + ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@18.19.64)(typescript@5.4.5): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.11.17 + '@types/node': 18.19.64 acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.9.5 + typescript: 5.4.5 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: '@swc/core': 1.9.2(@swc/helpers@0.5.15) - ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5): + ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -42786,20 +42831,20 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.4.5 + typescript: 4.9.5 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: '@swc/core': 1.9.2(@swc/helpers@0.5.15) - ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.4.5): + ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@5.4.5): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.12.8 + '@types/node': 20.11.17 acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 @@ -43580,26 +43625,26 @@ snapshots: replace-ext: 2.0.0 teex: 1.0.1 - vite@5.1.8(@types/node@20.11.17)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1): + vite@5.1.8(@types/node@18.19.64)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1): dependencies: esbuild: 0.19.3 postcss: 8.4.38 rollup: 4.22.4 optionalDependencies: - '@types/node': 20.11.17 + '@types/node': 18.19.64 fsevents: 2.3.3 less: 4.2.0 lightningcss: 1.28.1 sass: 1.71.1 terser: 5.29.1 - vite@5.1.8(@types/node@20.12.8)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1): + vite@5.1.8(@types/node@20.11.17)(less@4.2.0)(lightningcss@1.28.1)(sass@1.71.1)(terser@5.29.1): dependencies: esbuild: 0.19.3 postcss: 8.4.38 rollup: 4.22.4 optionalDependencies: - '@types/node': 20.12.8 + '@types/node': 20.11.17 fsevents: 2.3.3 less: 4.2.0 lightningcss: 1.28.1 diff --git a/tools/scripts/build-all.ts b/tools/scripts/build-all.ts index 59bf1664d73d..18ae0dc483fc 100644 --- a/tools/scripts/build-all.ts +++ b/tools/scripts/build-all.ts @@ -78,7 +78,7 @@ sh.cp([path.join(BOOTSTRAP_DIR, 'css', 'bootstrap.css'), path.join(BOOTSTRAP_DIR sh.exec('pnpm run all:pack-and-copy'); -sh.exec('pnpx nx pack devextreme-react', { silent: true }); +sh.exec('pnpx nx pack devextreme-react', { silent: false }); sh.exec('pnpx nx pack devextreme-vue', { silent: true }); sh.exec(`pnpx nx pack devextreme-angular${devMode ? '' : ' --with-descriptions'}`, { silent: true }); From e912ee4d94640d03bcb34521002be94a164d14f2 Mon Sep 17 00:00:00 2001 From: Adel Khamatov Date: Mon, 27 Oct 2025 09:31:36 +0200 Subject: [PATCH 3/9] chore: add prettier --- packages/nx-infra-plugin/.prettierignore | 3 + packages/nx-infra-plugin/.prettierrc.yaml | 12 +++ packages/nx-infra-plugin/package.json | 10 +- packages/nx-infra-plugin/prod/package.json | 4 +- packages/nx-infra-plugin/project.json | 5 +- .../add-license-headers/executor.e2e.spec.ts | 50 ++++------ .../executors/add-license-headers/executor.ts | 22 +++-- .../build-typescript/executor.e2e.spec.ts | 82 +++++++--------- .../executors/build-typescript/executor.ts | 47 +++------ .../src/executors/clean/executor.e2e.spec.ts | 16 ++-- .../src/executors/clean/executor.ts | 42 +++----- .../executors/copy-files/executor.e2e.spec.ts | 26 ++--- .../src/executors/copy-files/executor.ts | 7 +- .../executor.e2e.spec.ts | 84 ++++++++-------- .../generate-react-components/executor.ts | 55 ++++++----- .../executors/pack-npm/executor.e2e.spec.ts | 56 ++++------- .../src/executors/pack-npm/executor.ts | 5 +- .../prepare-package-json/executor.e2e.spec.ts | 63 ++++++------ .../prepare-package-json/executor.ts | 12 +-- .../prepare-submodules/executor.e2e.spec.ts | 52 +++++----- .../executors/prepare-submodules/executor.ts | 60 ++++-------- .../src/utils/file-operations.ts | 9 +- .../src/utils/path-resolver.ts | 10 +- .../nx-infra-plugin/src/utils/test-utils.ts | 1 - pnpm-lock.yaml | 95 +++++++++++++++++-- 25 files changed, 405 insertions(+), 423 deletions(-) create mode 100644 packages/nx-infra-plugin/.prettierignore create mode 100644 packages/nx-infra-plugin/.prettierrc.yaml diff --git a/packages/nx-infra-plugin/.prettierignore b/packages/nx-infra-plugin/.prettierignore new file mode 100644 index 000000000000..9bead4ff939e --- /dev/null +++ b/packages/nx-infra-plugin/.prettierignore @@ -0,0 +1,3 @@ +/prod/ +/pnpm-lock.yaml +*.json diff --git a/packages/nx-infra-plugin/.prettierrc.yaml b/packages/nx-infra-plugin/.prettierrc.yaml new file mode 100644 index 000000000000..08e20ffc0b60 --- /dev/null +++ b/packages/nx-infra-plugin/.prettierrc.yaml @@ -0,0 +1,12 @@ +arrowParens: always +bracketSameLine: true +bracketSpacing: true +endOfLine: lf +experimentalOperatorPosition: start +objectWrap: preserve +printWidth: 100 +quoteProps: preserve +semi: true +singleQuote: true +tabWidth: 2 +trailingComma: all diff --git a/packages/nx-infra-plugin/package.json b/packages/nx-infra-plugin/package.json index de7196a6522a..4fcc6b4bba2a 100644 --- a/packages/nx-infra-plugin/package.json +++ b/packages/nx-infra-plugin/package.json @@ -17,10 +17,16 @@ }, "devDependencies": { "@types/node": "^18.0.0", - "typescript": "4.9.5" + "typescript": "4.9.5", + "prettier": "catalog:tools", + "@types/jest": "29.5.12", + "ts-jest": "29.1.3" }, "scripts": { + "format:check": "prettier --check .", + "format": "prettier --write .", "build": "nx build nx-infra-plugin", - "test": "nx test nx-infra-plugin" + "test": "nx test nx-infra-plugin", + "lint": "pnpm run format:check" } } diff --git a/packages/nx-infra-plugin/prod/package.json b/packages/nx-infra-plugin/prod/package.json index 2a3cd48002c0..07141427ba33 100644 --- a/packages/nx-infra-plugin/prod/package.json +++ b/packages/nx-infra-plugin/prod/package.json @@ -18,7 +18,9 @@ "devDependencies": { "@types/node": "^18.0.0", "typescript": "4.9.5", - "prettier": "catalog:tools" + "prettier": "catalog:tools", + "@types/jest": "29.5.12", + "ts-jest": "29.1.3" }, "scripts": { "format:check": "prettier --check .", diff --git a/packages/nx-infra-plugin/project.json b/packages/nx-infra-plugin/project.json index eadd60ed20ac..51fe2e7a78a1 100644 --- a/packages/nx-infra-plugin/project.json +++ b/packages/nx-infra-plugin/project.json @@ -34,7 +34,10 @@ } }, "lint": { - "executor": "@nx/eslint:lint" + "executor": "nx:run-script", + "options": { + "script": "lint" + } }, "test": { "executor": "@nx/jest:jest", diff --git a/packages/nx-infra-plugin/src/executors/add-license-headers/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/add-license-headers/executor.e2e.spec.ts index 098f4c4d492e..ed47947b1e36 100644 --- a/packages/nx-infra-plugin/src/executors/add-license-headers/executor.e2e.spec.ts +++ b/packages/nx-infra-plugin/src/executors/add-license-headers/executor.e2e.spec.ts @@ -2,11 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import executor from './executor'; import { AddLicenseHeadersExecutorSchema } from './schema'; -import { - createTempDir, - cleanupTempDir, - createMockContext, -} from '../../utils/test-utils'; +import { createTempDir, cleanupTempDir, createMockContext } from '../../utils/test-utils'; import { writeFileText, writeJson, readFileText } from '../../utils'; describe('AddLicenseHeadersExecutor E2E', () => { @@ -29,23 +25,20 @@ describe('AddLicenseHeadersExecutor E2E', () => { await writeFileText( path.join(npmDir, 'index.js'), - `export function hello() {\n return 'Hello';\n}\n` + `export function hello() {\n return 'Hello';\n}\n`, ); - await writeFileText( - path.join(npmDir, 'utils.js'), - `export const add = (a, b) => a + b;\n` - ); + await writeFileText(path.join(npmDir, 'utils.js'), `export const add = (a, b) => a + b;\n`); fs.mkdirSync(path.join(npmDir, 'components'), { recursive: true }); await writeFileText( path.join(npmDir, 'components', 'button.js'), - `export const Button = () => {};\n` + `export const Button = () => {};\n`, ); await writeFileText( path.join(npmDir, 'types.ts'), - `export interface Config { name: string; }\n` + `export interface Config { name: string; }\n`, ); }); @@ -90,9 +83,7 @@ describe('AddLicenseHeadersExecutor E2E', () => { expect(result.success).toBe(true); const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); - const buttonContent = await readFileText( - path.join(npmDir, 'components', 'button.js') - ); + const buttonContent = await readFileText(path.join(npmDir, 'components', 'button.js')); expect(buttonContent).toMatch(/^\/\*!/); expect(buttonContent).toContain('test-package'); @@ -148,7 +139,7 @@ describe('AddLicenseHeadersExecutor E2E', () => { await writeFileText( path.join(npmDir, 'with-header.js'), - `/*!\n * Existing header\n */\nexport const foo = 'bar';\n` + `/*!\n * Existing header\n */\nexport const foo = 'bar';\n`, ); const options: AddLicenseHeadersExecutorSchema = { @@ -241,10 +232,7 @@ describe('AddLicenseHeadersExecutor E2E', () => { it('should fail gracefully with invalid package.json', async () => { const projectDir = path.join(tempDir, 'packages', 'test-lib'); - await writeFileText( - path.join(projectDir, 'package.json'), - 'not valid json {{{}' - ); + await writeFileText(path.join(projectDir, 'package.json'), 'not valid json {{{}'); const options: AddLicenseHeadersExecutorSchema = { targetDirectory: './npm', @@ -278,10 +266,7 @@ describe('AddLicenseHeadersExecutor E2E', () => { const customDir = path.join(projectDir, 'dist'); fs.mkdirSync(customDir, { recursive: true }); - await writeFileText( - path.join(customDir, 'custom.js'), - `export const custom = true;\n` - ); + await writeFileText(path.join(customDir, 'custom.js'), `export const custom = true;\n`); const options: AddLicenseHeadersExecutorSchema = { targetDirectory: './dist', @@ -300,13 +285,10 @@ describe('AddLicenseHeadersExecutor E2E', () => { it('should work with custom package.json path', async () => { const projectDir = path.join(tempDir, 'packages', 'test-lib'); - await writeJson( - path.join(projectDir, 'custom-package.json'), - { - name: 'custom-package-name', - version: '2.0.0', - } - ); + await writeJson(path.join(projectDir, 'custom-package.json'), { + name: 'custom-package-name', + version: '2.0.0', + }); const options: AddLicenseHeadersExecutorSchema = { targetDirectory: './npm', @@ -325,10 +307,10 @@ describe('AddLicenseHeadersExecutor E2E', () => { }); }); - it('should preserve formatting and whitespace', async () => { - const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); + it('should preserve formatting and whitespace', async () => { + const npmDir = path.join(tempDir, 'packages', 'test-lib', 'npm'); - const originalContent = `export function complex() { + const originalContent = `export function complex() { if (true) { return 'formatted'; } diff --git a/packages/nx-infra-plugin/src/executors/add-license-headers/executor.ts b/packages/nx-infra-plugin/src/executors/add-license-headers/executor.ts index 1b2fda35895b..bbf6db8f0bbd 100644 --- a/packages/nx-infra-plugin/src/executors/add-license-headers/executor.ts +++ b/packages/nx-infra-plugin/src/executors/add-license-headers/executor.ts @@ -19,29 +19,31 @@ const EMPTY_LINE = ''; const GITHUB_URL = 'https://github.com/DevExpress/devextreme-react'; -const COPYRIGHT_START = ' * Copyright (c) 2012 - <%= year %> Developer Express Inc. ALL RIGHTS RESERVED'; +const COPYRIGHT_START = + ' * Copyright (c) 2012 - <%= year %> Developer Express Inc. ALL RIGHTS RESERVED'; const BANNER_PKG_NAME = COMMENT_PREFIX + ' ' + '<%= pkg.name %>'; const BANNER_VERSION = COMMENT_PREFIX + ' ' + 'Version: <%= pkg.version %>'; const BANNER_BUILD_DATE = COMMENT_PREFIX + ' ' + 'Build date: <%= date %>'; -const BANNER_LICENSE_LINE1 = COMMENT_PREFIX + ' ' + 'This software may be modified and distributed under the terms'; -const BANNER_LICENSE_LINE2 = COMMENT_PREFIX + ' ' + 'of the MIT license. See the LICENSE file in the root of the project for details.'; +const BANNER_LICENSE_LINE1 = + COMMENT_PREFIX + ' ' + 'This software may be modified and distributed under the terms'; +const BANNER_LICENSE_LINE2 = + COMMENT_PREFIX + + ' ' + + 'of the MIT license. See the LICENSE file in the root of the project for details.'; const BANNER_GITHUB = COMMENT_PREFIX + ' ' + GITHUB_URL; const TEMPLATE_REGEX = /<%=\s*(\w+(?:\.\w+)*)\s*%>/g; -const runExecutor: PromiseExecutor = async ( - options, - context -) => { +const runExecutor: PromiseExecutor = async (options, context) => { const absoluteProjectRoot = resolveProjectPath(context); const targetDirectory = path.join( absoluteProjectRoot, - options.targetDirectory || DEFAULT_TARGET_DIR + options.targetDirectory || DEFAULT_TARGET_DIR, ); const packageJsonPath = path.join( absoluteProjectRoot, - options.packageJsonPath || DEFAULT_PACKAGE_JSON + options.packageJsonPath || DEFAULT_PACKAGE_JSON, ); let pkg; @@ -92,7 +94,7 @@ const runExecutor: PromiseExecutor = async ( } await writeFileText(file, banner + NEWLINE + content); - }) + }), ); logger.info('License headers added successfully'); diff --git a/packages/nx-infra-plugin/src/executors/build-typescript/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/build-typescript/executor.e2e.spec.ts index 47a66ebe1417..b19b4a0ba8b1 100644 --- a/packages/nx-infra-plugin/src/executors/build-typescript/executor.e2e.spec.ts +++ b/packages/nx-infra-plugin/src/executors/build-typescript/executor.e2e.spec.ts @@ -2,11 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import executor from './executor'; import { BuildTypescriptExecutorSchema } from './schema'; -import { - createTempDir, - cleanupTempDir, - createMockContext, -} from '../../utils/test-utils'; +import { createTempDir, cleanupTempDir, createMockContext } from '../../utils/test-utils'; import { writeFileText, writeJson, readFileText } from '../../utils'; describe('BuildTypescriptExecutor E2E', () => { @@ -24,59 +20,53 @@ describe('BuildTypescriptExecutor E2E', () => { await writeFileText( path.join(srcDir, 'index.ts'), - `export function hello(name: string): string {\n return \`Hello, \${name}!\`;\n}\n` + `export function hello(name: string): string {\n return \`Hello, \${name}!\`;\n}\n`, ); await writeFileText( path.join(srcDir, 'utils.ts'), - `export const add = (a: number, b: number): number => a + b;\n` + `export const add = (a: number, b: number): number => a + b;\n`, ); fs.mkdirSync(path.join(srcDir, '__tests__'), { recursive: true }); await writeFileText( path.join(srcDir, '__tests__', 'index.spec.ts'), - `import { hello } from '../index';\ntest('hello', () => {});\n` + `import { hello } from '../index';\ntest('hello', () => {});\n`, ); - await writeJson( - path.join(projectDir, 'tsconfig.esm.json'), - { - compilerOptions: { - target: 'ES2020', - module: 'ESNext', - declaration: true, - declarationMap: true, - sourceMap: true, - outDir: './npm/esm', - rootDir: './src', - strict: true, - esModuleInterop: true, - skipLibCheck: true, - }, - include: ['src/**/*'], - exclude: ['**/*.spec.ts', '**/__tests__/**'], - } - ); + await writeJson(path.join(projectDir, 'tsconfig.esm.json'), { + compilerOptions: { + target: 'ES2020', + module: 'ESNext', + declaration: true, + declarationMap: true, + sourceMap: true, + outDir: './npm/esm', + rootDir: './src', + strict: true, + esModuleInterop: true, + skipLibCheck: true, + }, + include: ['src/**/*'], + exclude: ['**/*.spec.ts', '**/__tests__/**'], + }); - await writeJson( - path.join(projectDir, 'tsconfig.json'), - { - compilerOptions: { - target: 'ES2020', - module: 'CommonJS', - declaration: true, - declarationMap: true, - sourceMap: true, - outDir: './npm/cjs', - rootDir: './src', - strict: true, - esModuleInterop: true, - skipLibCheck: true, - }, - include: ['src/**/*'], - exclude: ['**/*.spec.ts', '**/__tests__/**'], - } - ); + await writeJson(path.join(projectDir, 'tsconfig.json'), { + compilerOptions: { + target: 'ES2020', + module: 'CommonJS', + declaration: true, + declarationMap: true, + sourceMap: true, + outDir: './npm/cjs', + rootDir: './src', + strict: true, + esModuleInterop: true, + skipLibCheck: true, + }, + include: ['src/**/*'], + exclude: ['**/*.spec.ts', '**/__tests__/**'], + }); }); afterEach(() => { diff --git a/packages/nx-infra-plugin/src/executors/build-typescript/executor.ts b/packages/nx-infra-plugin/src/executors/build-typescript/executor.ts index 696b10ac6450..128daa7fd02f 100644 --- a/packages/nx-infra-plugin/src/executors/build-typescript/executor.ts +++ b/packages/nx-infra-plugin/src/executors/build-typescript/executor.ts @@ -23,9 +23,9 @@ const ERROR_COMPILATION_FAILED = 'Compilation failed'; const NEWLINE_CHAR = '\n'; async function loadTsConfig( - tsconfigPath: string + tsconfigPath: string, ): Promise<{ content: TsConfig; compilerOptions: CompilerOptions }> { - if (!await exists(tsconfigPath)) { + if (!(await exists(tsconfigPath))) { throw new Error(`TypeScript config file not found: ${tsconfigPath}`); } @@ -37,48 +37,31 @@ async function loadTsConfig( }; } -function formatDiagnostics( - diagnostics: ts.Diagnostic[] -): string[] { +function formatDiagnostics(diagnostics: ts.Diagnostic[]): string[] { return diagnostics.map((diagnostic) => { if (diagnostic.file) { - const { line, character } = - diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!); - const message = ts.flattenDiagnosticMessageText( - diagnostic.messageText, - NEWLINE_CHAR - ); + const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!); + const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, NEWLINE_CHAR); return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`; } return ts.flattenDiagnosticMessageText(diagnostic.messageText, NEWLINE_CHAR); }); } -function compile( - sourceFiles: string[], - compilerOptions: ts.CompilerOptions -): ts.Program { +function compile(sourceFiles: string[], compilerOptions: ts.CompilerOptions): ts.Program { return ts.createProgram(sourceFiles, compilerOptions); } -const runExecutor: PromiseExecutor = async ( - options, - context -) => { +const runExecutor: PromiseExecutor = async (options, context) => { const absoluteProjectRoot = resolveProjectPath(context); const module = options.module || DEFAULT_MODULE_TYPE; - const defaultTsconfigPath = module === MODULE_TYPE_CJS ? DEFAULT_TSCONFIG_CJS : DEFAULT_TSCONFIG_ESM; - const tsconfigPath = path.join( - absoluteProjectRoot, - options.tsconfig || defaultTsconfigPath - ); + const defaultTsconfigPath = + module === MODULE_TYPE_CJS ? DEFAULT_TSCONFIG_CJS : DEFAULT_TSCONFIG_ESM; + const tsconfigPath = path.join(absoluteProjectRoot, options.tsconfig || defaultTsconfigPath); const defaultOutDir = module === MODULE_TYPE_CJS ? DEFAULT_OUT_DIR_CJS : DEFAULT_OUT_DIR_ESM; - const outDir = path.join( - absoluteProjectRoot, - options.outDir || defaultOutDir - ); + const outDir = path.join(absoluteProjectRoot, options.outDir || defaultOutDir); try { const { content: tsconfigContent, compilerOptions } = await loadTsConfig(tsconfigPath); @@ -106,7 +89,7 @@ const runExecutor: PromiseExecutor = async ( const parsedConfig = ts.parseJsonConfigFileContent( tsconfigContent, ts.sys, - path.dirname(tsconfigPath) + path.dirname(tsconfigPath), ); const finalCompilerOptions: ts.CompilerOptions = { @@ -120,11 +103,9 @@ const runExecutor: PromiseExecutor = async ( if (result.emitSkipped) { logger.error(ERROR_COMPILATION_FAILED); - const diagnostics = ts - .getPreEmitDiagnostics(program) - .concat(result.diagnostics); + const diagnostics = ts.getPreEmitDiagnostics(program).concat(result.diagnostics); - formatDiagnostics(diagnostics).forEach(msg => logger.error(msg)); + formatDiagnostics(diagnostics).forEach((msg) => logger.error(msg)); return { success: false }; } diff --git a/packages/nx-infra-plugin/src/executors/clean/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/clean/executor.e2e.spec.ts index 28285c31464f..561689c07d6e 100644 --- a/packages/nx-infra-plugin/src/executors/clean/executor.e2e.spec.ts +++ b/packages/nx-infra-plugin/src/executors/clean/executor.e2e.spec.ts @@ -2,11 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import executor from './executor'; import { CleanExecutorSchema } from './schema'; -import { - createTempDir, - cleanupTempDir, - createMockContext, -} from '../../utils/test-utils'; +import { createTempDir, cleanupTempDir, createMockContext } from '../../utils/test-utils'; import { writeFileText } from '../../utils'; describe('CleanExecutor E2E', () => { @@ -45,7 +41,10 @@ describe('CleanExecutor E2E', () => { await writeFileText(path.join(npmDir, 'cjs', 'index.js'), 'module.exports = {};'); fs.mkdirSync(path.join(npmDir, 'components', 'button'), { recursive: true }); - await writeFileText(path.join(npmDir, 'components', 'button', 'index.js'), 'export const Button = {};'); + await writeFileText( + path.join(npmDir, 'components', 'button', 'index.js'), + 'export const Button = {};', + ); }); it('should delete the entire directory', async () => { @@ -249,7 +248,10 @@ describe('CleanExecutor E2E', () => { const srcDir = path.join(tempDir, 'packages', 'test-lib', 'src'); fs.mkdirSync(path.join(srcDir, 'core', 'internal'), { recursive: true }); - await writeFileText(path.join(srcDir, 'core', 'internal', 'impl.tsx'), 'export const impl = {};'); + await writeFileText( + path.join(srcDir, 'core', 'internal', 'impl.tsx'), + 'export const impl = {};', + ); const options: CleanExecutorSchema = { targetDirectory: './src', diff --git a/packages/nx-infra-plugin/src/executors/clean/executor.ts b/packages/nx-infra-plugin/src/executors/clean/executor.ts index 8fbbe4480310..b2e56debb2f8 100644 --- a/packages/nx-infra-plugin/src/executors/clean/executor.ts +++ b/packages/nx-infra-plugin/src/executors/clean/executor.ts @@ -16,27 +16,22 @@ const DEFAULT_CLEAN_MODE = CLEAN_MODE_SIMPLE; const GLOB_ALL_FILES = '**/*'; -function resolveExcludePaths( - patterns: string[], - absoluteProjectRoot: string -): string[] { - return patterns.map(pattern => - path.isAbsolute(pattern) ? pattern : path.join(absoluteProjectRoot, pattern) +function resolveExcludePaths(patterns: string[], absoluteProjectRoot: string): string[] { + return patterns.map((pattern) => + path.isAbsolute(pattern) ? pattern : path.join(absoluteProjectRoot, pattern), ); } function shouldPreservePath( filePath: string, excludePaths: string[], - exactMatch: boolean + exactMatch: boolean, ): boolean { const normalized = path.normalize(filePath); - return excludePaths.some(excludePath => { + return excludePaths.some((excludePath) => { const normalizedExclude = path.normalize(excludePath); - return exactMatch - ? normalized === normalizedExclude - : normalized.startsWith(normalizedExclude); + return exactMatch ? normalized === normalizedExclude : normalized.startsWith(normalizedExclude); }); } @@ -46,10 +41,7 @@ function cleanSimple(targetDirectory: string): void { } } -function cleanShallow( - targetDirectory: string, - absoluteExcludePaths: string[] -): void { +function cleanShallow(targetDirectory: string, absoluteExcludePaths: string[]): void { if (!fs.existsSync(targetDirectory)) { return; } @@ -67,16 +59,16 @@ function cleanShallow( async function cleanRecursive( targetDirectory: string, - absoluteExcludePaths: string[] + absoluteExcludePaths: string[], ): Promise { const filesToDelete = await glob(GLOB_ALL_FILES, { cwd: targetDirectory, dot: true, - absolute: true + absolute: true, }); - const filteredFiles = filesToDelete.filter(file => - !shouldPreservePath(file, absoluteExcludePaths, false) + const filteredFiles = filesToDelete.filter( + (file) => !shouldPreservePath(file, absoluteExcludePaths, false), ); for (const file of filteredFiles) { @@ -84,14 +76,11 @@ async function cleanRecursive( } } -const runExecutor: PromiseExecutor = async ( - options, - context -) => { +const runExecutor: PromiseExecutor = async (options, context) => { const absoluteProjectRoot = resolveProjectPath(context); const targetDirectory = path.join( absoluteProjectRoot, - options.targetDirectory || DEFAULT_TARGET_DIR + options.targetDirectory || DEFAULT_TARGET_DIR, ); const mode = options.mode || DEFAULT_CLEAN_MODE; const excludePatterns = options.excludePatterns || []; @@ -103,10 +92,7 @@ const runExecutor: PromiseExecutor = async ( } try { - const absoluteExcludePaths = resolveExcludePaths( - excludePatterns, - absoluteProjectRoot - ); + const absoluteExcludePaths = resolveExcludePaths(excludePatterns, absoluteProjectRoot); switch (mode) { case CLEAN_MODE_SIMPLE: diff --git a/packages/nx-infra-plugin/src/executors/copy-files/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/copy-files/executor.e2e.spec.ts index 445a93aa6536..72a266c51719 100644 --- a/packages/nx-infra-plugin/src/executors/copy-files/executor.e2e.spec.ts +++ b/packages/nx-infra-plugin/src/executors/copy-files/executor.e2e.spec.ts @@ -2,11 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import executor from './executor'; import { CopyFilesExecutorSchema } from './schema'; -import { - createTempDir, - cleanupTempDir, - createMockContext, -} from '../../utils/test-utils'; +import { createTempDir, cleanupTempDir, createMockContext } from '../../utils/test-utils'; import { writeFileText, writeJson, readFileText } from '../../utils'; describe('CopyFilesExecutor E2E', () => { @@ -22,10 +18,10 @@ describe('CopyFilesExecutor E2E', () => { fs.mkdirSync(projectDir, { recursive: true }); await writeFileText(path.join(projectDir, 'README.md'), '# Test Package\n\nThis is a test.'); await writeFileText(path.join(projectDir, 'LICENSE'), 'MIT License\n\nCopyright...'); - await writeJson( - path.join(projectDir, 'package.json'), - { name: 'test-package', version: '1.0.0' } - ); + await writeJson(path.join(projectDir, 'package.json'), { + name: 'test-package', + version: '1.0.0', + }); fs.mkdirSync(path.join(projectDir, 'docs'), { recursive: true }); await writeFileText(path.join(projectDir, 'docs', 'guide.md'), '# Guide\n\nHow to use...'); @@ -62,9 +58,7 @@ describe('CopyFilesExecutor E2E', () => { const originalContent = await readFileText(path.join(projectDir, 'README.md')); const options: CopyFilesExecutorSchema = { - files: [ - { from: './README.md', to: './dist/README.md' }, - ], + files: [{ from: './README.md', to: './dist/README.md' }], }; await executor(options, context); @@ -76,9 +70,7 @@ describe('CopyFilesExecutor E2E', () => { it('should create destination directories if they do not exist', async () => { const options: CopyFilesExecutorSchema = { - files: [ - { from: './README.md', to: './output/nested/deep/README.md' }, - ], + files: [{ from: './README.md', to: './output/nested/deep/README.md' }], }; const result = await executor(options, context); @@ -101,9 +93,7 @@ describe('CopyFilesExecutor E2E', () => { await writeFileText(path.join(distDir, 'README.md'), 'Old content'); const options: CopyFilesExecutorSchema = { - files: [ - { from: './README.md', to: './dist/README.md' }, - ], + files: [{ from: './README.md', to: './dist/README.md' }], }; const result = await executor(options, context); diff --git a/packages/nx-infra-plugin/src/executors/copy-files/executor.ts b/packages/nx-infra-plugin/src/executors/copy-files/executor.ts index 08380c5dbace..23077da36f1a 100644 --- a/packages/nx-infra-plugin/src/executors/copy-files/executor.ts +++ b/packages/nx-infra-plugin/src/executors/copy-files/executor.ts @@ -8,10 +8,7 @@ import { copyFile, exists } from '../../utils/file-operations'; const ERROR_FILES_MUST_BE_ARRAY = 'Files option must be an array'; const ERROR_FAILED_TO_COPY = 'Failed to copy files'; -const runExecutor: PromiseExecutor = async ( - options, - context -) => { +const runExecutor: PromiseExecutor = async (options, context) => { const projectRoot = resolveProjectPath(context); if (!options.files || !Array.isArray(options.files)) { @@ -24,7 +21,7 @@ const runExecutor: PromiseExecutor = async ( const sourcePath = path.resolve(projectRoot, from); const destPath = path.resolve(projectRoot, to); - if (!await exists(sourcePath)) { + if (!(await exists(sourcePath))) { logger.error(`Source file not found: ${sourcePath}`); return { success: false }; } diff --git a/packages/nx-infra-plugin/src/executors/generate-react-components/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/generate-react-components/executor.e2e.spec.ts index fa743ee7b8e9..42a33fb8b487 100644 --- a/packages/nx-infra-plugin/src/executors/generate-react-components/executor.e2e.spec.ts +++ b/packages/nx-infra-plugin/src/executors/generate-react-components/executor.e2e.spec.ts @@ -2,11 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import executor from './executor'; import { GenerateReactComponentsExecutorSchema } from './schema'; -import { - createTempDir, - cleanupTempDir, - createMockContext, -} from '../../utils/test-utils'; +import { createTempDir, cleanupTempDir, createMockContext } from '../../utils/test-utils'; import { writeFileText, writeJson } from '../../utils'; describe('GenerateReactComponentsExecutor E2E', () => { @@ -27,43 +23,40 @@ describe('GenerateReactComponentsExecutor E2E', () => { fs.mkdirSync(path.join(srcDir, 'core'), { recursive: true }); await writeFileText( path.join(srcDir, 'core', 'component.tsx'), - `export class Component

{\n constructor(public props: P) {}\n}\n` + `export class Component

{\n constructor(public props: P) {}\n}\n`, ); await writeFileText( path.join(srcDir, 'core', 'extension-component.tsx'), - `export class ExtensionComponent {}\n` + `export class ExtensionComponent {}\n`, ); await writeFileText( path.join(srcDir, 'core', 'nested-option.ts'), - `export class NestedOption {}\n` + `export class NestedOption {}\n`, ); const metadataDir = path.join(tempDir, 'packages', 'metadata', 'dist'); fs.mkdirSync(metadataDir, { recursive: true }); - await writeJson( - path.join(metadataDir, 'integration-data.json'), - { - Widgets: { - dxButton: { - name: 'Button', - module: 'ui/button', - properties: [ - { name: 'text', type: 'String' }, - { name: 'type', type: 'String' }, - { name: 'onClick', type: 'Function' }, - ], - }, - dxTextBox: { - name: 'TextBox', - module: 'ui/text_box', - properties: [ - { name: 'value', type: 'String' }, - { name: 'placeholder', type: 'String' }, - ], - }, + await writeJson(path.join(metadataDir, 'integration-data.json'), { + Widgets: { + dxButton: { + name: 'Button', + module: 'ui/button', + properties: [ + { name: 'text', type: 'String' }, + { name: 'type', type: 'String' }, + { name: 'onClick', type: 'Function' }, + ], }, - } - ); + dxTextBox: { + name: 'TextBox', + module: 'ui/text_box', + properties: [ + { name: 'value', type: 'String' }, + { name: 'placeholder', type: 'String' }, + ], + }, + }, + }); }); afterEach(() => { @@ -78,22 +71,26 @@ describe('GenerateReactComponentsExecutor E2E', () => { await writeFileText( path.join(outDir, 'button.tsx'), - `export const Button = () =>

Button
;` + `export const Button = () =>
Button
;`, ); await writeFileText( path.join(outDir, 'text-box.tsx'), - `export const TextBox = () =>
TextBox
;` + `export const TextBox = () =>
TextBox
;`, ); await writeFileText( indexFile, - `export { Button } from "./button";\nexport { TextBox } from "./text-box";\n` + `export { Button } from "./button";\nexport { TextBox } from "./text-box";\n`, ); }); - jest.mock('devextreme-internal-tools', () => ({ - generateReactComponents: mockGenerator, - }), { virtual: true }); + jest.mock( + 'devextreme-internal-tools', + () => ({ + generateReactComponents: mockGenerator, + }), + { virtual: true }, + ); const options: GenerateReactComponentsExecutorSchema = { metadataPath: '../metadata/dist/integration-data.json', @@ -176,10 +173,7 @@ describe('GenerateReactComponentsExecutor E2E', () => { it('should resolve metadata path relative to project', async () => { const projectDir = path.join(tempDir, 'packages', 'react-wrappers'); - await writeJson( - path.join(projectDir, 'metadata.json'), - { Widgets: {} } - ); + await writeJson(path.join(projectDir, 'metadata.json'), { Widgets: {} }); const options: GenerateReactComponentsExecutorSchema = { metadataPath: './metadata.json', @@ -257,7 +251,13 @@ describe('GenerateReactComponentsExecutor E2E', () => { describe('Error scenarios', () => { it('should handle corrupted metadata gracefully', async () => { - const metadataPath = path.join(tempDir, 'packages', 'metadata', 'dist', 'integration-data.json'); + const metadataPath = path.join( + tempDir, + 'packages', + 'metadata', + 'dist', + 'integration-data.json', + ); await writeFileText(metadataPath, 'not valid json {{{'); diff --git a/packages/nx-infra-plugin/src/executors/generate-react-components/executor.ts b/packages/nx-infra-plugin/src/executors/generate-react-components/executor.ts index 6d1fc975fe67..7d5448bdf920 100644 --- a/packages/nx-infra-plugin/src/executors/generate-react-components/executor.ts +++ b/packages/nx-infra-plugin/src/executors/generate-react-components/executor.ts @@ -30,7 +30,8 @@ const CLEAN_MODE = 'shallow'; const MSG_CLEANING = '๐Ÿงน Cleaning generated components'; const MSG_CLEANED = 'โœ“ Successfully cleaned components directory'; const MSG_LOADING_METADATA = '๐Ÿ“‹ Loading metadata'; -const MSG_GENERATORS_CONFIG_NOT_FOUND = 'โš ๏ธ generators-config.js not found, proceeding without unifiedConfig'; +const MSG_GENERATORS_CONFIG_NOT_FOUND = + 'โš ๏ธ generators-config.js not found, proceeding without unifiedConfig'; const MSG_LOADED_REACT_CONFIG = 'โœ“ Loaded React configuration from generators-config.js'; const MSG_GENERATING = 'โš™๏ธ Generating React components'; const MSG_GENERATION_COMPLETED = 'โœ“ Component generation completed'; @@ -38,7 +39,8 @@ const MSG_GENERATION_SUCCESS = 'โœจ React component generation successful!'; const MSG_STARTING = '๐Ÿ”ง Starting React component generation'; const MSG_GENERATION_FAILED = 'โŒ Component generation failed'; -const ERROR_METADATA_NOT_FOUND = 'Could not find devextreme-metadata/integration-data.json. Please ensure devextreme-metadata is installed or provide a metadataPath option.'; +const ERROR_METADATA_NOT_FOUND = + 'Could not find devextreme-metadata/integration-data.json. Please ensure devextreme-metadata is installed or provide a metadataPath option.'; const ERROR_CLEAN_FAILED = 'Failed to clean components directory'; const PARENT_DIR_PREFIX = '../'; @@ -56,7 +58,7 @@ const EXPORT_PATTERN = /export \{/g; async function cleanComponentsDirectory( absoluteComponentsDir: string, preservePaths: string[], - context: ExecutorContext + context: ExecutorContext, ): Promise { logger.info(MSG_CLEANING); @@ -66,7 +68,7 @@ async function cleanComponentsDirectory( const cleanOptions: CleanExecutorSchema = { targetDirectory: DOT_SLASH_PREFIX + relativeComponentsDir, - excludePatterns: preservePaths.map(currentPath => { + excludePatterns: preservePaths.map((currentPath) => { if (path.isAbsolute(currentPath)) { const relative = path.relative(absoluteProjectRoot, currentPath); return DOT_SLASH_PREFIX + relative; @@ -88,14 +90,10 @@ async function cleanComponentsDirectory( function resolveMetadataPath( options: GenerateReactComponentsExecutorSchema, absoluteProjectRoot: string, - workspaceRoot: string + workspaceRoot: string, ): string { if (options.metadataPath) { - return resolveCustomMetadataPath( - options.metadataPath, - absoluteProjectRoot, - workspaceRoot - ); + return resolveCustomMetadataPath(options.metadataPath, absoluteProjectRoot, workspaceRoot); } return resolveDefaultMetadataPath(); @@ -104,7 +102,7 @@ function resolveMetadataPath( function resolveCustomMetadataPath( metadataPath: string, absoluteProjectRoot: string, - workspaceRoot: string + workspaceRoot: string, ): string { const relativeToProject = path.resolve(absoluteProjectRoot, metadataPath); if (fs.existsSync(relativeToProject)) { @@ -171,7 +169,11 @@ function loadGenerationFunction(): any { const internalTools = require(INTERNAL_TOOLS_PACKAGE); return internalTools[GENERATION_FUNCTION]; } catch (error) { - throw new Error(`Could not load devextreme-internal-tools. Please ensure devextreme-internal-tools is installed as a dependency. Error: ${getErrorMessage(error)}`); + throw new Error( + `Could not load devextreme-internal-tools. Please ensure devextreme-internal-tools is installed as a dependency. Error: ${getErrorMessage( + error, + )}`, + ); } } @@ -179,7 +181,7 @@ function buildGenerationConfig( options: GenerateReactComponentsExecutorSchema, componentsDir: string, indexFileName: string, - reactConfig: any + reactConfig: any, ): any { return { metaData: undefined, @@ -210,7 +212,7 @@ async function executeGeneration( config: any, metaData: any, componentsDir: string, - indexFileName: string + indexFileName: string, ): Promise { logger.info(MSG_GENERATING); @@ -226,18 +228,19 @@ async function executeGeneration( } if (fs.existsSync(componentsDir)) { - const dirCount = fs.readdirSync(componentsDir, { withFileTypes: true }) - .filter(entry => entry.isDirectory() && entry.name !== CORE_DIR) - .length; + const dirCount = fs + .readdirSync(componentsDir, { withFileTypes: true }) + .filter((entry) => entry.isDirectory() && entry.name !== CORE_DIR).length; logger.info(` Component Directories: ${dirCount}`); } logger.info(MSG_GENERATION_SUCCESS); } -const runExecutor: PromiseExecutor< - GenerateReactComponentsExecutorSchema -> = async (options, context) => { +const runExecutor: PromiseExecutor = async ( + options, + context, +) => { const absoluteProjectRoot = resolveProjectPath(context); const workspaceRoot = context.root; @@ -248,11 +251,11 @@ const runExecutor: PromiseExecutor< try { const componentsDir = path.resolve( absoluteProjectRoot, - options.componentsDir || DEFAULT_COMPONENTS_DIR + options.componentsDir || DEFAULT_COMPONENTS_DIR, ); const indexFileName = path.resolve( absoluteProjectRoot, - options.indexFileName || DEFAULT_INDEX_FILE_NAME + options.indexFileName || DEFAULT_INDEX_FILE_NAME, ); const coreDir = path.join(componentsDir, CORE_DIR); @@ -267,7 +270,13 @@ const runExecutor: PromiseExecutor< const generateReactComponents = loadGenerationFunction(); const config = buildGenerationConfig(options, componentsDir, indexFileName, reactConfig); - await executeGeneration(generateReactComponents, config, metaData, componentsDir, indexFileName); + await executeGeneration( + generateReactComponents, + config, + metaData, + componentsDir, + indexFileName, + ); return { success: true }; } catch (error) { diff --git a/packages/nx-infra-plugin/src/executors/pack-npm/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/pack-npm/executor.e2e.spec.ts index 889ef9b7cb08..0d9b1423aeba 100644 --- a/packages/nx-infra-plugin/src/executors/pack-npm/executor.e2e.spec.ts +++ b/packages/nx-infra-plugin/src/executors/pack-npm/executor.e2e.spec.ts @@ -3,11 +3,7 @@ import * as path from 'path'; import { execSync } from 'child_process'; import executor from './executor'; import { PackNpmExecutorSchema } from './schema'; -import { - createTempDir, - cleanupTempDir, - createMockContext, -} from '../../utils/test-utils'; +import { createTempDir, cleanupTempDir, createMockContext } from '../../utils/test-utils'; import { writeFileText, writeJson } from '../../utils'; const PACKAGE_NAME = 'test-package'; @@ -40,47 +36,35 @@ describe('PackNpmExecutor E2E', () => { await writeFileText( path.join(tempDir, 'pnpm-workspace.yaml'), - `packages:\n - '${PACKAGES_DIR}/*'\n` + `packages:\n - '${PACKAGES_DIR}/*'\n`, ); - await writeJson( - path.join(tempDir, 'package.json'), - { - name: 'test-workspace', - version: '1.0.0', - private: true, - } - ); + await writeJson(path.join(tempDir, 'package.json'), { + name: 'test-workspace', + version: '1.0.0', + private: true, + }); const projectDir = path.join(tempDir, PACKAGES_DIR, PROJECT_NAME); const npmDir = path.join(projectDir, NPM_DIR_NAME); fs.mkdirSync(npmDir, { recursive: true }); - await writeJson( - path.join(projectDir, 'package.json'), - { - name: PACKAGE_NAME, - version: PACKAGE_VERSION, - description: 'Test package for pnpm pack', - main: './npm/index.js', - } - ); + await writeJson(path.join(projectDir, 'package.json'), { + name: PACKAGE_NAME, + version: PACKAGE_VERSION, + description: 'Test package for pnpm pack', + main: './npm/index.js', + }); - await writeJson( - path.join(npmDir, 'package.json'), - { - name: PACKAGE_NAME, - version: PACKAGE_VERSION, - description: 'Test package for pnpm pack', - main: './index.js', - } - ); + await writeJson(path.join(npmDir, 'package.json'), { + name: PACKAGE_NAME, + version: PACKAGE_VERSION, + description: 'Test package for pnpm pack', + main: './index.js', + }); - await writeFileText( - path.join(npmDir, 'index.js'), - 'module.exports = { test: true };' - ); + await writeFileText(path.join(npmDir, 'index.js'), 'module.exports = { test: true };'); context = createMockContext({ root: tempDir, diff --git a/packages/nx-infra-plugin/src/executors/pack-npm/executor.ts b/packages/nx-infra-plugin/src/executors/pack-npm/executor.ts index 1407f3f8963f..25b5edc84ec3 100644 --- a/packages/nx-infra-plugin/src/executors/pack-npm/executor.ts +++ b/packages/nx-infra-plugin/src/executors/pack-npm/executor.ts @@ -10,10 +10,7 @@ const DEFAULT_DIST_DIR = './npm'; const MSG_PACK_SUCCESS = 'pnpm pack completed successfully'; const MSG_PACK_FAILED = 'Failed to run pnpm pack'; -const runExecutor: PromiseExecutor = async ( - options, - context -) => { +const runExecutor: PromiseExecutor = async (options, context) => { const absoluteProjectRoot = resolveProjectPath(context); const distDirectory = options.workingDirectory || DEFAULT_DIST_DIR; const workspaceRoot = context.root; diff --git a/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.e2e.spec.ts index 3049a5602f5a..d11d2c288583 100644 --- a/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.e2e.spec.ts +++ b/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.e2e.spec.ts @@ -2,11 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import executor from './executor'; import { NpmPackageExecutorSchema } from './schema'; -import { - createTempDir, - cleanupTempDir, - createMockContext, -} from '../../utils/test-utils'; +import { createTempDir, cleanupTempDir, createMockContext } from '../../utils/test-utils'; import { writeJson, readFileText } from '../../utils'; describe('PreparePackageJsonExecutor E2E', () => { @@ -21,36 +17,33 @@ describe('PreparePackageJsonExecutor E2E', () => { fs.mkdirSync(projectDir, { recursive: true }); - await writeJson( - path.join(projectDir, 'package.json'), - { - name: '@devexpress/test-package', - version: '1.0.0', - description: 'Test package for prepare-package-json', - main: './index.js', - module: './esm/index.js', - types: './index.d.ts', - scripts: { - build: 'tsc', - test: 'jest', - }, - publishConfig: { - access: 'public', - directory: 'npm', - registry: 'https://registry.npmjs.org/', - }, - dependencies: { - react: '^18.0.0', - }, - devDependencies: { - typescript: '^4.9.0', - jest: '^29.0.0', - }, - keywords: ['test', 'package'], - license: 'MIT', - author: 'Test Author', - } - ); + await writeJson(path.join(projectDir, 'package.json'), { + name: '@devexpress/test-package', + version: '1.0.0', + description: 'Test package for prepare-package-json', + main: './index.js', + module: './esm/index.js', + types: './index.d.ts', + scripts: { + build: 'tsc', + test: 'jest', + }, + publishConfig: { + access: 'public', + directory: 'npm', + registry: 'https://registry.npmjs.org/', + }, + dependencies: { + react: '^18.0.0', + }, + devDependencies: { + typescript: '^4.9.0', + jest: '^29.0.0', + }, + keywords: ['test', 'package'], + license: 'MIT', + author: 'Test Author', + }); }); afterEach(() => { diff --git a/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.ts b/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.ts index 91bb0a797070..8315a808e821 100644 --- a/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.ts +++ b/packages/nx-infra-plugin/src/executors/prepare-package-json/executor.ts @@ -15,19 +15,13 @@ const JSON_INDENT = 2; const ERROR_PREPARE_PACKAGE_JSON = 'Failed to prepare package.json'; -const runExecutor: PromiseExecutor = async ( - options, - context -) => { +const runExecutor: PromiseExecutor = async (options, context) => { const absoluteProjectRoot = resolveProjectPath(context); const sourcePackageJson = path.join( absoluteProjectRoot, - options.sourcePackageJson || DEFAULT_SOURCE_PACKAGE_JSON - ); - const distDirectory = path.join( - absoluteProjectRoot, - options.distDirectory || DEFAULT_DIST_DIR + options.sourcePackageJson || DEFAULT_SOURCE_PACKAGE_JSON, ); + const distDirectory = path.join(absoluteProjectRoot, options.distDirectory || DEFAULT_DIST_DIR); try { await ensureDir(distDirectory); diff --git a/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts index 4de675211054..17ad49603e36 100644 --- a/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts +++ b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts @@ -2,11 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import executor from './executor'; import { PrepareSubmodulesExecutorSchema } from './schema'; -import { - createTempDir, - cleanupTempDir, - createMockContext, -} from '../../utils/test-utils'; +import { createTempDir, cleanupTempDir, createMockContext } from '../../utils/test-utils'; import { writeFileText, readFileText } from '../../utils'; describe('PrepareSubmodulesExecutor E2E', () => { @@ -29,14 +25,20 @@ describe('PrepareSubmodulesExecutor E2E', () => { await writeFileText( path.join(npmDir, 'esm', 'index.js'), - `export { Button } from "./button";\nexport { Grid } from "./data/grid";\nexport { Chart } from "./viz/chart";` + `export { Button } from "./button";\nexport { Grid } from "./data/grid";\nexport { Chart } from "./viz/chart";`, ); await writeFileText(path.join(npmDir, 'esm', 'button.js'), 'export const Button = () => {};'); fs.mkdirSync(path.join(npmDir, 'esm', 'data'), { recursive: true }); - await writeFileText(path.join(npmDir, 'esm', 'data', 'grid.js'), 'export const Grid = () => {};'); + await writeFileText( + path.join(npmDir, 'esm', 'data', 'grid.js'), + 'export const Grid = () => {};', + ); fs.mkdirSync(path.join(npmDir, 'esm', 'viz'), { recursive: true }); - await writeFileText(path.join(npmDir, 'esm', 'viz', 'chart.js'), 'export const Chart = () => {};'); + await writeFileText( + path.join(npmDir, 'esm', 'viz', 'chart.js'), + 'export const Chart = () => {};', + ); await writeFileText(path.join(npmDir, 'cjs', 'index.js'), 'module.exports = {};'); await writeFileText(path.join(npmDir, 'cjs', 'button.js'), 'module.exports = {};'); @@ -101,7 +103,7 @@ describe('PrepareSubmodulesExecutor E2E', () => { const esmIndex = await readFileText(path.join(npmDir, 'esm', 'index.js')); await writeFileText( path.join(npmDir, 'esm', 'index.js'), - esmIndex + '\nexport { Custom } from "./custom";' + esmIndex + '\nexport { Custom } from "./custom";', ); const options: PrepareSubmodulesExecutorSchema = { @@ -123,21 +125,27 @@ describe('PrepareSubmodulesExecutor E2E', () => { const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); fs.mkdirSync(path.join(npmDir, 'esm', 'common'), { recursive: true }); - await writeFileText(path.join(npmDir, 'esm', 'common', 'index.js'), 'export * from "./core";'); + await writeFileText( + path.join(npmDir, 'esm', 'common', 'index.js'), + 'export * from "./core";', + ); fs.mkdirSync(path.join(npmDir, 'esm', 'common', 'core'), { recursive: true }); - await writeFileText(path.join(npmDir, 'esm', 'common', 'core', 'index.js'), 'export class Component {}'); + await writeFileText( + path.join(npmDir, 'esm', 'common', 'core', 'index.js'), + 'export class Component {}', + ); fs.mkdirSync(path.join(npmDir, 'cjs', 'common'), { recursive: true }); await writeFileText(path.join(npmDir, 'cjs', 'common', 'index.js'), 'module.exports = {};'); fs.mkdirSync(path.join(npmDir, 'cjs', 'common', 'core'), { recursive: true }); - await writeFileText(path.join(npmDir, 'cjs', 'common', 'core', 'index.js'), 'module.exports = {};'); + await writeFileText( + path.join(npmDir, 'cjs', 'common', 'core', 'index.js'), + 'module.exports = {};', + ); const options: PrepareSubmodulesExecutorSchema = { distDirectory: './npm', - submoduleFolders: [ - ['common'], - ['common/core'], - ], + submoduleFolders: [['common'], ['common/core']], }; const result = await executor(options, context); @@ -158,9 +166,7 @@ describe('PrepareSubmodulesExecutor E2E', () => { await executor(options, context); const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); - const buttonPkg = JSON.parse( - await readFileText(path.join(npmDir, 'button', 'package.json')) - ); + const buttonPkg = JSON.parse(await readFileText(path.join(npmDir, 'button', 'package.json'))); expect(buttonPkg.main).toBe('../cjs/button.js'); expect(buttonPkg.module).toBe('../esm/button.js'); @@ -204,16 +210,12 @@ describe('PrepareSubmodulesExecutor E2E', () => { expect(result1.success).toBe(true); const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); - const firstPkg = JSON.parse( - await readFileText(path.join(npmDir, 'button', 'package.json')) - ); + const firstPkg = JSON.parse(await readFileText(path.join(npmDir, 'button', 'package.json'))); const result2 = await executor(options, context); expect(result2.success).toBe(true); - const secondPkg = JSON.parse( - await readFileText(path.join(npmDir, 'button', 'package.json')) - ); + const secondPkg = JSON.parse(await readFileText(path.join(npmDir, 'button', 'package.json'))); expect(secondPkg).toEqual(firstPkg); }); diff --git a/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts index 470f724d16c1..c52431404106 100644 --- a/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts +++ b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts @@ -39,15 +39,9 @@ const DEFAULT_SUBMODULE_FOLDERS: PackParam[] = [ ['common/export'], ]; -const runExecutor: PromiseExecutor = async ( - options, - context -) => { +const runExecutor: PromiseExecutor = async (options, context) => { const absoluteProjectRoot = resolveProjectPath(context); - const distDirectory = path.join( - absoluteProjectRoot, - options.distDirectory || DEFAULT_DIST_DIR - ); + const distDirectory = path.join(absoluteProjectRoot, options.distDirectory || DEFAULT_DIST_DIR); try { logger.info(MSG_PREPARING); @@ -62,15 +56,13 @@ const runExecutor: PromiseExecutor = async ( } const modulesPaths = modulesImportsFromIndex.matchAll(REGEX_IMPORTS); - const packParamsForModules: PackParam[] = Array.from(modulesPaths).map( - ([, modulePath]) => { - const match = modulePath.match(REGEX_PARSE_MODULE) || []; - const moduleFilePath = match[2] as string | undefined; - const moduleFileName = match[3] as string | undefined; - - return ['', moduleFileName ? [moduleFileName] : undefined, moduleFilePath]; - } - ); + const packParamsForModules: PackParam[] = Array.from(modulesPaths).map(([, modulePath]) => { + const match = modulePath.match(REGEX_PARSE_MODULE) || []; + const moduleFilePath = match[2] as string | undefined; + const moduleFileName = match[3] as string | undefined; + + return ['', moduleFileName ? [moduleFileName] : undefined, moduleFilePath]; + }); const allModuleParams: PackParam[] = [...packParamsForModules, ...packParamsForFolders]; @@ -78,8 +70,8 @@ const runExecutor: PromiseExecutor = async ( await Promise.all( allModuleParams.map(([folder, moduleFileNames, moduleFilePath]) => - makeModule(distDirectory, folder, moduleFileNames, moduleFilePath) - ) + makeModule(distDirectory, folder, moduleFileNames, moduleFilePath), + ), ); logger.info(MSG_SUCCESS); @@ -94,7 +86,7 @@ async function makeModule( distFolder: string, folder: string, moduleFileNames?: string[], - moduleFilePath?: string + moduleFilePath?: string, ): Promise { const distModuleFolder = path.join(distFolder, folder); const distEsmFolder = path.join(distFolder, ESM_DIR, folder); @@ -112,13 +104,8 @@ async function makeModule( const moduleDir = path.join(distModuleFolder, moduleFileName); await ensureDir(moduleDir); - await generatePackageJsonFile( - distFolder, - folder, - moduleFileName, - moduleFilePath || folder - ); - }) + await generatePackageJsonFile(distFolder, folder, moduleFileName, moduleFilePath || folder); + }), ); } catch (error) { throw new Error(`Exception while makeModule(${folder}): ${getErrorMessage(error)}`); @@ -129,17 +116,12 @@ async function generatePackageJsonFile( distFolder: string, folder: string, moduleFileName?: string, - filePath?: string + filePath?: string, ): Promise { const moduleName = moduleFileName || ''; const absoluteModulePath = path.join(distFolder, folder, moduleName); - const moduleFilePathResolved = - (filePath ? filePath + PATH_SLASH : '') + (moduleName || 'index'); - const esmFilePath = path.join( - distFolder, - ESM_DIR, - moduleFilePathResolved + JS_EXTENSION - ); + const moduleFilePathResolved = (filePath ? filePath + PATH_SLASH : '') + (moduleName || 'index'); + const esmFilePath = path.join(distFolder, ESM_DIR, moduleFilePathResolved + JS_EXTENSION); const relativePath = path.relative(absoluteModulePath, esmFilePath); const relativeBase = RELATIVE_DIR_PREFIX.repeat(relativePath.split('..').length - 1); @@ -162,13 +144,13 @@ async function findJsModuleFileNamesInFolder(dir: string): Promise { const entries = await fs.readdir(dir, { withFileTypes: true }); - return entries - .filter(isJsModule) - .map((entry) => path.parse(entry.name).name); + return entries.filter(isJsModule).map((entry) => path.parse(entry.name).name); } function isJsModule(entry: Dirent): boolean { - return !entry.isDirectory() && entry.name.endsWith(JS_EXTENSION) && entry.name !== INDEX_FILE_NAME; + return ( + !entry.isDirectory() && entry.name.endsWith(JS_EXTENSION) && entry.name !== INDEX_FILE_NAME + ); } export default runExecutor; diff --git a/packages/nx-infra-plugin/src/utils/file-operations.ts b/packages/nx-infra-plugin/src/utils/file-operations.ts index a938829733dc..ca15a61e1464 100644 --- a/packages/nx-infra-plugin/src/utils/file-operations.ts +++ b/packages/nx-infra-plugin/src/utils/file-operations.ts @@ -24,7 +24,7 @@ export async function readJson(filePath: string): Promise { export async function writeJson( filePath: string, data: unknown, - spaces: number = 2 + spaces: number = 2, ): Promise { const content = JSON.stringify(data, null, spaces); await fs.writeFile(filePath, content, ENCODING_UTF8); @@ -33,7 +33,7 @@ export async function writeJson( export async function processFiles( pattern: string, processor: (filePath: string) => Promise, - options: { ignore?: string[] } = {} + options: { ignore?: string[] } = {}, ): Promise { const files = await glob(pattern, { absolute: true, @@ -63,10 +63,7 @@ export async function readFileText(filePath: string): Promise { return fs.readFile(filePath, ENCODING_UTF8); } -export async function writeFileText( - filePath: string, - content: string -): Promise { +export async function writeFileText(filePath: string, content: string): Promise { await ensureDir(path.dirname(filePath)); await fs.writeFile(filePath, content, ENCODING_UTF8); } diff --git a/packages/nx-infra-plugin/src/utils/path-resolver.ts b/packages/nx-infra-plugin/src/utils/path-resolver.ts index 17049d3a9e67..78293541c62a 100644 --- a/packages/nx-infra-plugin/src/utils/path-resolver.ts +++ b/packages/nx-infra-plugin/src/utils/path-resolver.ts @@ -22,17 +22,11 @@ export function resolveProjectPath(context: ExecutorContext): string { return path.resolve(context.root, project.root); } -export function resolveFromProject( - context: ExecutorContext, - relativePath: string -): string { +export function resolveFromProject(context: ExecutorContext, relativePath: string): string { const projectRoot = resolveProjectPath(context); return path.join(projectRoot, relativePath); } -export function resolveFromWorkspace( - context: ExecutorContext, - relativePath: string -): string { +export function resolveFromWorkspace(context: ExecutorContext, relativePath: string): string { return path.join(context.root, relativePath); } diff --git a/packages/nx-infra-plugin/src/utils/test-utils.ts b/packages/nx-infra-plugin/src/utils/test-utils.ts index 7d536890e96b..98694687b197 100644 --- a/packages/nx-infra-plugin/src/utils/test-utils.ts +++ b/packages/nx-infra-plugin/src/utils/test-utils.ts @@ -13,7 +13,6 @@ export function cleanupTempDir(dirPath: string): void { } } - export interface MockContextOptions { root?: string; projectName?: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7dce5c595289..2d4c9941c4cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2200,9 +2200,18 @@ importers: specifier: 3.0.2 version: 3.0.2 devDependencies: + '@types/jest': + specifier: 29.5.12 + version: 29.5.12 '@types/node': specifier: ^18.0.0 version: 18.19.64 + prettier: + specifier: catalog:tools + version: 3.5.3 + ts-jest: + specifier: 29.1.3 + version: 29.1.3(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)))(typescript@4.9.5) typescript: specifier: 4.9.5 version: 4.9.5 @@ -24627,15 +24636,13 @@ snapshots: transitivePeerDependencies: - '@parcel/core' - '@parcel/cache@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)': + '@parcel/cache@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))': dependencies: '@parcel/core': 2.12.0(@swc/helpers@0.5.15) '@parcel/fs': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/logger': 2.12.0 '@parcel/utils': 2.12.0 lmdb: 2.8.5 - transitivePeerDependencies: - - '@swc/helpers' '@parcel/codeframe@2.12.0': dependencies: @@ -24695,7 +24702,7 @@ snapshots: '@parcel/core@2.12.0(@swc/helpers@0.5.15)': dependencies: '@mischnic/json-sourcemap': 0.1.1 - '@parcel/cache': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) + '@parcel/cache': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@parcel/diagnostic': 2.12.0 '@parcel/events': 2.12.0 '@parcel/fs': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) @@ -25110,7 +25117,7 @@ snapshots: '@parcel/types@2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)': dependencies: - '@parcel/cache': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) + '@parcel/cache': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15)) '@parcel/diagnostic': 2.12.0 '@parcel/fs': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) '@parcel/package-manager': 2.12.0(@parcel/core@2.12.0(@swc/helpers@0.5.15))(@swc/helpers@0.5.15) @@ -30492,6 +30499,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-jest@29.7.0(@types/node@20.11.17)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): dependencies: '@jest/types': 29.6.3 @@ -35656,6 +35678,27 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): + dependencies: + '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@18.19.64)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + optionalDependencies: + node-notifier: 9.0.1 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-cli@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): dependencies: '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) @@ -36386,6 +36429,20 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)): + dependencies: + '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + optionalDependencies: + node-notifier: 9.0.1 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest@29.7.0(@types/node@20.11.17)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)): dependencies: '@jest/core': 29.7.0(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.11.17)(typescript@4.9.5)) @@ -42674,7 +42731,7 @@ snapshots: json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.1 + semver: 7.7.2 typescript: 4.9.5 yargs-parser: 21.1.1 optionalDependencies: @@ -42691,7 +42748,7 @@ snapshots: json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.1 + semver: 7.7.2 typescript: 4.9.5 yargs-parser: 21.1.1 optionalDependencies: @@ -42708,7 +42765,7 @@ snapshots: json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.1 + semver: 7.7.2 typescript: 5.9.2 yargs-parser: 21.1.1 optionalDependencies: @@ -42716,6 +42773,24 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.10) + ts-jest@29.1.3(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)))(typescript@4.9.5): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@18.19.64)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.2 + typescript: 4.9.5 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.26.10 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.10) + ts-jest@29.1.3(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.14.5)(node-notifier@9.0.1)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.12.8)(typescript@5.9.2)))(typescript@4.9.5): dependencies: bs-logger: 0.2.6 @@ -42725,7 +42800,7 @@ snapshots: json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.1 + semver: 7.7.2 typescript: 4.9.5 yargs-parser: 21.1.1 optionalDependencies: @@ -42743,7 +42818,7 @@ snapshots: json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.1 + semver: 7.7.2 typescript: 5.9.2 yargs-parser: 21.1.1 optionalDependencies: From bf17449d0998834b47327189f1aff1f57cccb0a6 Mon Sep 17 00:00:00 2001 From: Adel Khamatov Date: Wed, 29 Oct 2025 11:04:33 +0200 Subject: [PATCH 4/9] chore: return `silent: false` --- tools/scripts/build-all.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/scripts/build-all.ts b/tools/scripts/build-all.ts index 18ae0dc483fc..59bf1664d73d 100644 --- a/tools/scripts/build-all.ts +++ b/tools/scripts/build-all.ts @@ -78,7 +78,7 @@ sh.cp([path.join(BOOTSTRAP_DIR, 'css', 'bootstrap.css'), path.join(BOOTSTRAP_DIR sh.exec('pnpm run all:pack-and-copy'); -sh.exec('pnpx nx pack devextreme-react', { silent: false }); +sh.exec('pnpx nx pack devextreme-react', { silent: true }); sh.exec('pnpx nx pack devextreme-vue', { silent: true }); sh.exec(`pnpx nx pack devextreme-angular${devMode ? '' : ' --with-descriptions'}`, { silent: true }); From 3822b5e62073303e80f81188666cf1ccf0ca083a Mon Sep 17 00:00:00 2001 From: Adel Khamatov Date: Thu, 30 Oct 2025 12:43:51 +0200 Subject: [PATCH 5/9] fix(nx-infra-plugin): correct nested submodule paths --- .../executors/prepare-submodules/executor.js | 2 +- .../prepare-submodules/executor.e2e.spec.ts | 35 +++++++++++++++++++ .../executors/prepare-submodules/executor.ts | 2 +- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js index 45ff62be8670..e3550bd204cd 100644 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js +++ b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js @@ -88,7 +88,7 @@ async function makeModule(distFolder, folder, moduleFileNames, moduleFilePath) { try { await (0, file_operations_1.ensureDir)(distModuleFolder); if (folder && fsSync.existsSync(path.join(distEsmFolder, 'index.js'))) { - await generatePackageJsonFile(distFolder, folder); + await generatePackageJsonFile(distFolder, folder, undefined, folder); } await Promise.all(moduleNames.map(async (moduleFileName) => { const moduleDir = path.join(distModuleFolder, moduleFileName); diff --git a/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts index 17ad49603e36..d6a088b184b5 100644 --- a/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts +++ b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.e2e.spec.ts @@ -172,6 +172,41 @@ describe('PrepareSubmodulesExecutor E2E', () => { expect(buttonPkg.module).toBe('../esm/button.js'); expect(buttonPkg.typings).toBe('../cjs/button.d.ts'); }); + + it('should generate correct paths for nested folder modules with index.js', async () => { + const npmDir = path.join(tempDir, 'packages', 'test-package', 'npm'); + + fs.mkdirSync(path.join(npmDir, 'esm', 'common', 'core'), { recursive: true }); + await writeFileText( + path.join(npmDir, 'esm', 'common', 'core', 'index.js'), + 'export class Component {}', + ); + fs.mkdirSync(path.join(npmDir, 'cjs', 'common', 'core'), { recursive: true }); + await writeFileText( + path.join(npmDir, 'cjs', 'common', 'core', 'index.js'), + 'module.exports = {};', + ); + + const options: PrepareSubmodulesExecutorSchema = { + distDirectory: './npm', + submoduleFolders: [['common/core']], + }; + + const result = await executor(options, context); + expect(result.success).toBe(true); + + const commonCorePkg = JSON.parse( + await readFileText(path.join(npmDir, 'common', 'core', 'package.json')), + ); + + expect(commonCorePkg.main).toBe('../../cjs/common/core/index.js'); + expect(commonCorePkg.module).toBe('../../esm/common/core/index.js'); + expect(commonCorePkg.typings).toBe('../../cjs/common/core/index.d.ts'); + + expect(commonCorePkg.main).not.toBe('../../cjs/index.js'); + expect(commonCorePkg.module).not.toBe('../../esm/index.js'); + expect(commonCorePkg.typings).not.toBe('../../cjs/index.d.ts'); + }); }); describe('Error handling', () => { diff --git a/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts index c52431404106..f024153b04af 100644 --- a/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts +++ b/packages/nx-infra-plugin/src/executors/prepare-submodules/executor.ts @@ -96,7 +96,7 @@ async function makeModule( await ensureDir(distModuleFolder); if (folder && fsSync.existsSync(path.join(distEsmFolder, 'index.js'))) { - await generatePackageJsonFile(distFolder, folder); + await generatePackageJsonFile(distFolder, folder, undefined, folder); } await Promise.all( From 9a2387a4ec3b4030b22b2294703d026e9d22810c Mon Sep 17 00:00:00 2001 From: Adel Khamatov Date: Thu, 30 Oct 2025 13:10:02 +0200 Subject: [PATCH 6/9] fix(nx-infra-plugin): package scripts --- packages/nx-infra-plugin/package.json | 4 ++-- packages/nx-infra-plugin/prod/package.json | 4 ++-- packages/nx-infra-plugin/project.json | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/nx-infra-plugin/package.json b/packages/nx-infra-plugin/package.json index 4fcc6b4bba2a..335fac3ddc52 100644 --- a/packages/nx-infra-plugin/package.json +++ b/packages/nx-infra-plugin/package.json @@ -25,8 +25,8 @@ "scripts": { "format:check": "prettier --check .", "format": "prettier --write .", - "build": "nx build nx-infra-plugin", - "test": "nx test nx-infra-plugin", + "build": "pnpm --workspace-root nx build devextreme-nx-infra-plugin", + "test": "pnpm --workspace-root nx test devextreme-nx-infra-plugin", "lint": "pnpm run format:check" } } diff --git a/packages/nx-infra-plugin/prod/package.json b/packages/nx-infra-plugin/prod/package.json index 07141427ba33..93d472a7b816 100644 --- a/packages/nx-infra-plugin/prod/package.json +++ b/packages/nx-infra-plugin/prod/package.json @@ -25,8 +25,8 @@ "scripts": { "format:check": "prettier --check .", "format": "prettier --write .", - "build": "nx build nx-infra-plugin", - "test": "nx test nx-infra-plugin", + "build": "pnpm --workspace-root nx build devextreme-nx-infra-plugin", + "test": "pnpm --workspace-root nx test devextreme-nx-infra-plugin", "lint": "pnpm run format:check" }, "main": "./src/index.js" diff --git a/packages/nx-infra-plugin/project.json b/packages/nx-infra-plugin/project.json index 51fe2e7a78a1..d4cdb493cb4e 100644 --- a/packages/nx-infra-plugin/project.json +++ b/packages/nx-infra-plugin/project.json @@ -11,22 +11,22 @@ "options": { "outputPath": "{projectRoot}/prod", "main": "{projectRoot}/src/index.ts", - "tsConfig": "packages/nx-infra-plugin/tsconfig.lib.json", + "tsConfig": "{projectRoot}/tsconfig.lib.json", "generateExportsField": true, "assets": [ - "packages/nx-infra-plugin/*.md", + "{projectRoot}/*.md", { - "input": "./packages/nx-infra-plugin/src", + "input": "{projectRoot}/src", "glob": "**/!(*.ts)", "output": "./src" }, { - "input": "./packages/nx-infra-plugin/src", + "input": "{projectRoot}/src", "glob": "**/*.d.ts", "output": "./src" }, { - "input": "./packages/nx-infra-plugin", + "input": "{projectRoot}", "glob": "executors.json", "output": "." } @@ -43,7 +43,7 @@ "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { - "jestConfig": "packages/nx-infra-plugin/jest.config.ts" + "jestConfig": "{projectRoot}/jest.config.ts" } } } From 0453bcb99ef2b5b4a6f912eb73aad1ddc19d9b9b Mon Sep 17 00:00:00 2001 From: Adel Khamatov Date: Thu, 30 Oct 2025 13:12:23 +0200 Subject: [PATCH 7/9] fix(devextreme-react): package scripts --- packages/devextreme-react/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/devextreme-react/package.json b/packages/devextreme-react/package.json index 5bedd1a7cc21..0c600499663c 100644 --- a/packages/devextreme-react/package.json +++ b/packages/devextreme-react/package.json @@ -13,9 +13,9 @@ "types": "./cjs/index.d.ts", "scripts": { "clean": "nx clean devextreme-react", - "regenerate": "nx regenerate devextreme-react", + "regenerate": "pnpm --workspace-root nx regenerate devextreme-react", "lint": "eslint src/core", - "pack": "nx pack devextreme-react", + "pack": "pnpm --workspace-root nx pack devextreme-react", "test": "jest" }, "keywords": [ @@ -87,4 +87,4 @@ "directory": "npm", "linkDirectory": true } -} \ No newline at end of file +} From 8252d46402ff6e0d9c10711720b4082fd0756b72 Mon Sep 17 00:00:00 2001 From: Adel Khamatov Date: Thu, 30 Oct 2025 13:21:34 +0200 Subject: [PATCH 8/9] chore(nx-infra): build plugin on postinstall --- nx.json | 2 +- packages/devextreme-react/package.json | 1 + packages/nx-infra-plugin/.prettierignore | 2 +- packages/nx-infra-plugin/package.json | 7 +- packages/nx-infra-plugin/prod/executors.json | 44 ---- packages/nx-infra-plugin/prod/package.json | 33 --- .../add-license-headers/executor.d.ts | 4 - .../executors/add-license-headers/executor.js | 119 --------- .../executors/add-license-headers/schema.d.ts | 4 - .../executors/add-license-headers/schema.js | 2 - .../executors/add-license-headers/schema.json | 16 -- .../executors/build-typescript/executor.d.ts | 4 - .../executors/build-typescript/executor.js | 114 --------- .../executors/build-typescript/schema.d.ts | 7 - .../src/executors/build-typescript/schema.js | 2 - .../executors/build-typescript/schema.json | 33 --- .../prod/src/executors/clean/executor.d.ts | 4 - .../prod/src/executors/clean/executor.js | 107 --------- .../prod/src/executors/clean/schema.d.ts | 5 - .../prod/src/executors/clean/schema.js | 2 - .../prod/src/executors/clean/schema.json | 25 -- .../src/executors/copy-files/executor.d.ts | 4 - .../prod/src/executors/copy-files/executor.js | 57 ----- .../prod/src/executors/copy-files/schema.d.ts | 6 - .../prod/src/executors/copy-files/schema.js | 2 - .../prod/src/executors/copy-files/schema.json | 22 -- .../generate-react-components/executor.d.ts | 4 - .../generate-react-components/executor.js | 225 ------------------ .../generate-react-components/schema.d.ts | 8 - .../generate-react-components/schema.js | 2 - .../generate-react-components/schema.json | 35 --- .../prod/src/executors/pack-npm/executor.d.ts | 4 - .../prod/src/executors/pack-npm/executor.js | 37 --- .../prod/src/executors/pack-npm/schema.d.ts | 3 - .../prod/src/executors/pack-npm/schema.js | 2 - .../prod/src/executors/pack-npm/schema.json | 11 - .../prepare-package-json/executor.d.ts | 4 - .../prepare-package-json/executor.js | 55 ----- .../prepare-package-json/schema.d.ts | 4 - .../executors/prepare-package-json/schema.js | 2 - .../prepare-package-json/schema.json | 16 -- .../prepare-submodules/executor.d.ts | 4 - .../executors/prepare-submodules/executor.js | 129 ---------- .../executors/prepare-submodules/schema.d.ts | 5 - .../executors/prepare-submodules/schema.js | 2 - .../executors/prepare-submodules/schema.json | 18 -- packages/nx-infra-plugin/prod/src/index.d.ts | 3 - packages/nx-infra-plugin/prod/src/index.js | 8 - .../prod/src/utils/error-handler.d.ts | 3 - .../prod/src/utils/error-handler.js | 20 -- .../prod/src/utils/file-operations.d.ts | 10 - .../prod/src/utils/file-operations.js | 87 ------- .../nx-infra-plugin/prod/src/utils/index.d.ts | 4 - .../nx-infra-plugin/prod/src/utils/index.js | 20 -- .../prod/src/utils/path-resolver.d.ts | 4 - .../prod/src/utils/path-resolver.js | 53 ----- .../prod/src/utils/test-utils.d.ts | 10 - .../prod/src/utils/test-utils.js | 55 ----- .../nx-infra-plugin/prod/src/utils/types.d.ts | 48 ---- .../nx-infra-plugin/prod/src/utils/types.js | 2 - packages/nx-infra-plugin/project.json | 2 +- packages/nx-infra-plugin/tsconfig.lib.json | 2 +- pnpm-lock.yaml | 3 + 63 files changed, 12 insertions(+), 1520 deletions(-) delete mode 100644 packages/nx-infra-plugin/prod/executors.json delete mode 100644 packages/nx-infra-plugin/prod/package.json delete mode 100644 packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.json delete mode 100644 packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.json delete mode 100644 packages/nx-infra-plugin/prod/src/executors/clean/executor.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/clean/executor.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/clean/schema.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/clean/schema.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/clean/schema.json delete mode 100644 packages/nx-infra-plugin/prod/src/executors/copy-files/executor.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/copy-files/executor.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/copy-files/schema.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/copy-files/schema.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/copy-files/schema.json delete mode 100644 packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.json delete mode 100644 packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.json delete mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.json delete mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.js delete mode 100644 packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.json delete mode 100644 packages/nx-infra-plugin/prod/src/index.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/index.js delete mode 100644 packages/nx-infra-plugin/prod/src/utils/error-handler.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/utils/error-handler.js delete mode 100644 packages/nx-infra-plugin/prod/src/utils/file-operations.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/utils/file-operations.js delete mode 100644 packages/nx-infra-plugin/prod/src/utils/index.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/utils/index.js delete mode 100644 packages/nx-infra-plugin/prod/src/utils/path-resolver.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/utils/path-resolver.js delete mode 100644 packages/nx-infra-plugin/prod/src/utils/test-utils.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/utils/test-utils.js delete mode 100644 packages/nx-infra-plugin/prod/src/utils/types.d.ts delete mode 100644 packages/nx-infra-plugin/prod/src/utils/types.js diff --git a/nx.json b/nx.json index 67daac063585..f32039a35ff6 100644 --- a/nx.json +++ b/nx.json @@ -2,7 +2,7 @@ "extends": "nx/presets/npm.json", "$schema": "./node_modules/nx/schemas/nx-schema.json", "nxCloudAccessToken": "ZDFmMzkyZTYtZmU5MC00MDMyLWI3NDktYjhhYWUxZWM4YTg3fHJlYWQ=", - "plugins": ["./packages/nx-infra-plugin/prod"], + "plugins": ["./packages/nx-infra-plugin/dist"], "namedInputs": { "metadataToolsCommonInputs": [ "{projectRoot}/**/*.ts", diff --git a/packages/devextreme-react/package.json b/packages/devextreme-react/package.json index 0c600499663c..afade306aa16 100644 --- a/packages/devextreme-react/package.json +++ b/packages/devextreme-react/package.json @@ -70,6 +70,7 @@ "@types/react": "~18.0.0", "@types/react-dom": "~18.0.0", "devextreme-metadata": "workspace:*", + "devextreme-nx-infra-plugin": "workspace:*", "jest-environment-jsdom": "29.7.0", "react": "18.0.0", "react-dom": "18.0.0", diff --git a/packages/nx-infra-plugin/.prettierignore b/packages/nx-infra-plugin/.prettierignore index 9bead4ff939e..ee306f539069 100644 --- a/packages/nx-infra-plugin/.prettierignore +++ b/packages/nx-infra-plugin/.prettierignore @@ -1,3 +1,3 @@ -/prod/ +/dist/ /pnpm-lock.yaml *.json diff --git a/packages/nx-infra-plugin/package.json b/packages/nx-infra-plugin/package.json index 335fac3ddc52..4aeb83662425 100644 --- a/packages/nx-infra-plugin/package.json +++ b/packages/nx-infra-plugin/package.json @@ -3,11 +3,11 @@ "version": "0.0.1", "type": "commonjs", "private": true, - "executors": "./prod/executors.json", + "executors": "./dist/executors.json", "exports": { ".": { - "require": "./prod/src/index.js", - "types": "./prod/src/index.d.ts" + "require": "./dist/src/index.js", + "types": "./dist/src/index.d.ts" }, "./package.json": "./package.json" }, @@ -23,6 +23,7 @@ "ts-jest": "29.1.3" }, "scripts": { + "postinstall": "pnpm run build", "format:check": "prettier --check .", "format": "prettier --write .", "build": "pnpm --workspace-root nx build devextreme-nx-infra-plugin", diff --git a/packages/nx-infra-plugin/prod/executors.json b/packages/nx-infra-plugin/prod/executors.json deleted file mode 100644 index b429a50f06a6..000000000000 --- a/packages/nx-infra-plugin/prod/executors.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "executors": { - "generate-react-components": { - "implementation": "./src/executors/generate-react-components/executor", - "schema": "./src/executors/generate-react-components/schema.json", - "description": "Generate React components from DevExtreme metadata" - }, - "clean": { - "implementation": "./src/executors/clean/executor", - "schema": "./src/executors/clean/schema.json", - "description": "Clean directories with support for simple or recursive mode" - }, - "add-license-headers": { - "implementation": "./src/executors/add-license-headers/executor", - "schema": "./src/executors/add-license-headers/schema.json", - "description": "Add license headers to compiled files" - }, - "prepare-submodules": { - "implementation": "./src/executors/prepare-submodules/executor", - "schema": "./src/executors/prepare-submodules/schema.json", - "description": "Prepare submodule entry points with package.json files" - }, - "copy-files": { - "implementation": "./src/executors/copy-files/executor", - "schema": "./src/executors/copy-files/schema.json", - "description": "Copy files to destination" - }, - "build-typescript": { - "implementation": "./src/executors/build-typescript/executor", - "schema": "./src/executors/build-typescript/schema.json", - "description": "Build TypeScript modules (CJS or ESM) with configurable output format" - }, - "prepare-package-json": { - "implementation": "./src/executors/prepare-package-json/executor", - "schema": "./src/executors/prepare-package-json/schema.json", - "description": "Create npm distribution package.json" - }, - "pack-npm": { - "implementation": "./src/executors/pack-npm/executor", - "schema": "./src/executors/pack-npm/schema.json", - "description": "Run pnpm pack for npm distribution" - } - } -} diff --git a/packages/nx-infra-plugin/prod/package.json b/packages/nx-infra-plugin/prod/package.json deleted file mode 100644 index 93d472a7b816..000000000000 --- a/packages/nx-infra-plugin/prod/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "devextreme-nx-infra-plugin", - "version": "0.0.1", - "type": "commonjs", - "private": true, - "executors": "./prod/executors.json", - "exports": { - ".": { - "require": "./prod/src/index.js", - "types": "./prod/src/index.d.ts" - }, - "./package.json": "./package.json" - }, - "dependencies": { - "glob": "10.4.5", - "rimraf": "3.0.2" - }, - "devDependencies": { - "@types/node": "^18.0.0", - "typescript": "4.9.5", - "prettier": "catalog:tools", - "@types/jest": "29.5.12", - "ts-jest": "29.1.3" - }, - "scripts": { - "format:check": "prettier --check .", - "format": "prettier --write .", - "build": "pnpm --workspace-root nx build devextreme-nx-infra-plugin", - "test": "pnpm --workspace-root nx test devextreme-nx-infra-plugin", - "lint": "pnpm run format:check" - }, - "main": "./src/index.js" -} \ No newline at end of file diff --git a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.d.ts deleted file mode 100644 index 2ac1ee9ab623..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PromiseExecutor } from '@nx/devkit'; -import { AddLicenseHeadersExecutorSchema } from './schema'; -declare const runExecutor: PromiseExecutor; -export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.js b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.js deleted file mode 100644 index 11b511be6977..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/executor.js +++ /dev/null @@ -1,119 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const devkit_1 = require("@nx/devkit"); -const path = __importStar(require("path")); -const glob_1 = require("glob"); -const path_resolver_1 = require("../../utils/path-resolver"); -const error_handler_1 = require("../../utils/error-handler"); -const file_operations_1 = require("../../utils/file-operations"); -const DEFAULT_TARGET_DIR = './npm'; -const DEFAULT_PACKAGE_JSON = './package.json'; -const GLOB_PATTERN = '**/*.{ts,js}'; -const LICENSE_MARKER = '/*!'; -const COMMENT_END = ' */'; -const COMMENT_PREFIX = ' *'; -const NEWLINE = '\n'; -const EMPTY_LINE = ''; -const GITHUB_URL = 'https://github.com/DevExpress/devextreme-react'; -const COPYRIGHT_START = ' * Copyright (c) 2012 - <%= year %> Developer Express Inc. ALL RIGHTS RESERVED'; -const BANNER_PKG_NAME = COMMENT_PREFIX + ' ' + '<%= pkg.name %>'; -const BANNER_VERSION = COMMENT_PREFIX + ' ' + 'Version: <%= pkg.version %>'; -const BANNER_BUILD_DATE = COMMENT_PREFIX + ' ' + 'Build date: <%= date %>'; -const BANNER_LICENSE_LINE1 = COMMENT_PREFIX + ' ' + 'This software may be modified and distributed under the terms'; -const BANNER_LICENSE_LINE2 = COMMENT_PREFIX - + ' ' - + 'of the MIT license. See the LICENSE file in the root of the project for details.'; -const BANNER_GITHUB = COMMENT_PREFIX + ' ' + GITHUB_URL; -const TEMPLATE_REGEX = /<%=\s*(\w+(?:\.\w+)*)\s*%>/g; -const runExecutor = async (options, context) => { - const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); - const targetDirectory = path.join(absoluteProjectRoot, options.targetDirectory || DEFAULT_TARGET_DIR); - const packageJsonPath = path.join(absoluteProjectRoot, options.packageJsonPath || DEFAULT_PACKAGE_JSON); - let pkg; - try { - pkg = await (0, file_operations_1.readJson)(packageJsonPath); - } - catch (error) { - (0, error_handler_1.logError)('Failed to read package.json', error); - return { success: false }; - } - const now = new Date(); - const data = { - pkg, - date: now.toDateString(), - year: now.getFullYear(), - }; - const bannerTemplate = [ - LICENSE_MARKER, - BANNER_PKG_NAME, - BANNER_VERSION, - BANNER_BUILD_DATE, - COMMENT_PREFIX, - COPYRIGHT_START, - COMMENT_PREFIX, - BANNER_LICENSE_LINE1, - BANNER_LICENSE_LINE2, - COMMENT_PREFIX, - BANNER_GITHUB, - COMMENT_END, - EMPTY_LINE, - ].join(NEWLINE); - const banner = renderTemplate(bannerTemplate, data); - try { - const pattern = path.join(targetDirectory, GLOB_PATTERN); - const files = await (0, glob_1.glob)(pattern); - devkit_1.logger.info(`Adding license headers to ${files.length} files...`); - await Promise.all(files.map(async (file) => { - const content = await (0, file_operations_1.readFileText)(file); - if (content.startsWith(LICENSE_MARKER)) { - return; - } - await (0, file_operations_1.writeFileText)(file, banner + NEWLINE + content); - })); - devkit_1.logger.info('License headers added successfully'); - return { success: true }; - } - catch (error) { - (0, error_handler_1.logError)('Failed to add license headers', error); - return { success: false }; - } -}; -function renderTemplate(template, data) { - return template.replace(TEMPLATE_REGEX, (_match, key) => { - const keys = key.split('.'); - let value = data; - for (const k of keys) { - if (value && typeof value === 'object' && k in value) { - value = value[k]; - } - else { - return ''; - } - } - return String(value); - }); -} -exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.d.ts deleted file mode 100644 index 7f04a8d2d9e4..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface AddLicenseHeadersExecutorSchema { - targetDirectory?: string; - packageJsonPath?: string; -} diff --git a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.js b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.js deleted file mode 100644 index c8ad2e549bdc..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.json b/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.json deleted file mode 100644 index d9c56f52207b..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/add-license-headers/schema.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "type": "object", - "properties": { - "targetDirectory": { - "type": "string", - "description": "Directory containing files to add headers to", - "default": "./npm" - }, - "packageJsonPath": { - "type": "string", - "description": "Path to package.json for version info", - "default": "./package.json" - } - }, - "required": [] -} diff --git a/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.d.ts deleted file mode 100644 index 504ea8d892fb..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PromiseExecutor } from '@nx/devkit'; -import { BuildTypescriptExecutorSchema } from './schema'; -declare const runExecutor: PromiseExecutor; -export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.js b/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.js deleted file mode 100644 index f8fd96aaf834..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/build-typescript/executor.js +++ /dev/null @@ -1,114 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const devkit_1 = require("@nx/devkit"); -const ts = __importStar(require("typescript")); -const path = __importStar(require("path")); -const glob_1 = require("glob"); -const path_resolver_1 = require("../../utils/path-resolver"); -const error_handler_1 = require("../../utils/error-handler"); -const file_operations_1 = require("../../utils/file-operations"); -const MODULE_TYPE_ESM = 'esm'; -const MODULE_TYPE_CJS = 'cjs'; -const DEFAULT_MODULE_TYPE = MODULE_TYPE_ESM; -const DEFAULT_TSCONFIG_CJS = './tsconfig.json'; -const DEFAULT_TSCONFIG_ESM = './tsconfig.esm.json'; -const DEFAULT_OUT_DIR_CJS = './npm/cjs'; -const DEFAULT_OUT_DIR_ESM = './npm/esm'; -const DEFAULT_SRC_PATTERN = './src/**/*.{ts,tsx}'; -const ERROR_COMPILATION_FAILED = 'Compilation failed'; -const NEWLINE_CHAR = '\n'; -async function loadTsConfig(tsconfigPath) { - if (!(await (0, file_operations_1.exists)(tsconfigPath))) { - throw new Error(`TypeScript config file not found: ${tsconfigPath}`); - } - const tsconfigContentRaw = await (0, file_operations_1.readFileText)(tsconfigPath); - const content = JSON.parse(tsconfigContentRaw); - return { - content, - compilerOptions: content.compilerOptions || {}, - }; -} -function formatDiagnostics(diagnostics) { - return diagnostics.map((diagnostic) => { - if (diagnostic.file) { - const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); - const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, NEWLINE_CHAR); - return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`; - } - return ts.flattenDiagnosticMessageText(diagnostic.messageText, NEWLINE_CHAR); - }); -} -function compile(sourceFiles, compilerOptions) { - return ts.createProgram(sourceFiles, compilerOptions); -} -const runExecutor = async (options, context) => { - const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); - const module = options.module || DEFAULT_MODULE_TYPE; - const defaultTsconfigPath = module === MODULE_TYPE_CJS ? DEFAULT_TSCONFIG_CJS : DEFAULT_TSCONFIG_ESM; - const tsconfigPath = path.join(absoluteProjectRoot, options.tsconfig || defaultTsconfigPath); - const defaultOutDir = module === MODULE_TYPE_CJS ? DEFAULT_OUT_DIR_CJS : DEFAULT_OUT_DIR_ESM; - const outDir = path.join(absoluteProjectRoot, options.outDir || defaultOutDir); - try { - const { content: tsconfigContent, compilerOptions } = await loadTsConfig(tsconfigPath); - compilerOptions.outDir = outDir; - await (0, file_operations_1.ensureDir)(outDir); - const srcPattern = options.srcPattern || DEFAULT_SRC_PATTERN; - const globPattern = path.join(absoluteProjectRoot, srcPattern); - const excludePattern = options.excludePattern - ? path.join(absoluteProjectRoot, options.excludePattern) - : undefined; - const sourceFiles = await (0, glob_1.glob)(globPattern, { - absolute: true, - nodir: true, - ignore: excludePattern ? [excludePattern] : [], - }); - devkit_1.logger.info(`Building ${module.toUpperCase()} for ${sourceFiles.length} source files...`); - if (sourceFiles.length === 0) { - devkit_1.logger.warn(`No source files matched pattern: ${srcPattern}`); - } - const parsedConfig = ts.parseJsonConfigFileContent(tsconfigContent, ts.sys, path.dirname(tsconfigPath)); - const finalCompilerOptions = { - ...parsedConfig.options, - outDir: compilerOptions.outDir, - paths: {}, - }; - const program = compile(sourceFiles, finalCompilerOptions); - const result = program.emit(); - if (result.emitSkipped) { - devkit_1.logger.error(ERROR_COMPILATION_FAILED); - const diagnostics = ts.getPreEmitDiagnostics(program).concat(result.diagnostics); - formatDiagnostics(diagnostics).forEach((msg) => devkit_1.logger.error(msg)); - return { success: false }; - } - devkit_1.logger.info(`โœ“ ${module.toUpperCase()} build completed successfully`); - return { success: true }; - } - catch (error) { - (0, error_handler_1.logError)(`Failed to build ${module.toUpperCase()}`, error); - return { success: false }; - } -}; -exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.d.ts deleted file mode 100644 index 9b219138da34..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface BuildTypescriptExecutorSchema { - module?: 'cjs' | 'esm'; - srcPattern?: string; - excludePattern?: string; - tsconfig?: string; - outDir?: string; -} diff --git a/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.js b/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.js deleted file mode 100644 index c8ad2e549bdc..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.json b/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.json deleted file mode 100644 index 838ad534df45..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/build-typescript/schema.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema", - "type": "object", - "title": "Build TypeScript Executor", - "description": "Compile TypeScript code to CommonJS or ESM modules", - "properties": { - "module": { - "type": "string", - "description": "Target module format. 'esm' generates ES modules with import/export statements, 'cjs' generates CommonJS with require/module.exports. This affects output file structure, TypeScript compiler module settings, and determines the default tsconfig and output directory.", - "enum": ["cjs", "esm"], - "default": "esm" - }, - "srcPattern": { - "type": "string", - "description": "Glob pattern for source files to include in compilation. Supports standard glob syntax with wildcards. Default pattern includes all .ts and .tsx files in src directory recursively.", - "default": "./src/**/*.{ts,tsx}" - }, - "excludePattern": { - "type": "string", - "description": "Glob pattern for files to exclude from compilation (e.g., test files, stories). Files matching this pattern will be ignored even if they match srcPattern. Commonly used to exclude __tests__, __mocks__, or *.spec.ts files." - }, - "tsconfig": { - "type": "string", - "description": "Path to TypeScript configuration file relative to project root. If not specified, defaults to './tsconfig.json' for CJS builds or './tsconfig.esm.json' for ESM builds. The tsconfig should contain appropriate module and target settings for the desired output format." - }, - "outDir": { - "type": "string", - "description": "Output directory path relative to project root where compiled JavaScript and declaration files will be written. If not specified, defaults to './npm/cjs' for CJS builds or './npm/esm' for ESM builds. Directory will be created if it doesn't exist." - } - }, - "required": [], - "additionalProperties": false -} diff --git a/packages/nx-infra-plugin/prod/src/executors/clean/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/clean/executor.d.ts deleted file mode 100644 index 24881bef85fb..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/clean/executor.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PromiseExecutor } from '@nx/devkit'; -import { CleanExecutorSchema } from './schema'; -declare const runExecutor: PromiseExecutor; -export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/clean/executor.js b/packages/nx-infra-plugin/prod/src/executors/clean/executor.js deleted file mode 100644 index 30bd1b315c74..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/clean/executor.js +++ /dev/null @@ -1,107 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const devkit_1 = require("@nx/devkit"); -const fs = __importStar(require("fs")); -const path = __importStar(require("path")); -const rimraf = __importStar(require("rimraf")); -const glob_1 = require("glob"); -const path_resolver_1 = require("../../utils/path-resolver"); -const error_handler_1 = require("../../utils/error-handler"); -const CLEAN_MODE_SIMPLE = 'simple'; -const CLEAN_MODE_SHALLOW = 'shallow'; -const CLEAN_MODE_RECURSIVE = 'recursive'; -const DEFAULT_TARGET_DIR = './src'; -const DEFAULT_CLEAN_MODE = CLEAN_MODE_SIMPLE; -const GLOB_ALL_FILES = '**/*'; -function resolveExcludePaths(patterns, absoluteProjectRoot) { - return patterns.map((pattern) => path.isAbsolute(pattern) ? pattern : path.join(absoluteProjectRoot, pattern)); -} -function shouldPreservePath(filePath, excludePaths, exactMatch) { - const normalized = path.normalize(filePath); - return excludePaths.some((excludePath) => { - const normalizedExclude = path.normalize(excludePath); - return exactMatch ? normalized === normalizedExclude : normalized.startsWith(normalizedExclude); - }); -} -function cleanSimple(targetDirectory) { - if (fs.existsSync(targetDirectory)) { - fs.rmSync(targetDirectory, { recursive: true, force: true }); - } -} -function cleanShallow(targetDirectory, absoluteExcludePaths) { - if (!fs.existsSync(targetDirectory)) { - return; - } - const entries = fs.readdirSync(targetDirectory, { withFileTypes: true }); - for (const entry of entries) { - const fullPath = path.join(targetDirectory, entry.name); - if (!shouldPreservePath(fullPath, absoluteExcludePaths, true)) { - fs.rmSync(fullPath, { recursive: true, force: true }); - } - } -} -async function cleanRecursive(targetDirectory, absoluteExcludePaths) { - const filesToDelete = await (0, glob_1.glob)(GLOB_ALL_FILES, { - cwd: targetDirectory, - dot: true, - absolute: true, - }); - const filteredFiles = filesToDelete.filter((file) => !shouldPreservePath(file, absoluteExcludePaths, false)); - for (const file of filteredFiles) { - rimraf.sync(file); - } -} -const runExecutor = async (options, context) => { - const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); - const targetDirectory = path.join(absoluteProjectRoot, options.targetDirectory || DEFAULT_TARGET_DIR); - const mode = options.mode || DEFAULT_CLEAN_MODE; - const excludePatterns = options.excludePatterns || []; - devkit_1.logger.info(`Cleaning ${targetDirectory} in ${mode} mode...`); - if (excludePatterns.length > 0) { - devkit_1.logger.info(`Excluding patterns: ${excludePatterns.join(', ')}`); - } - try { - const absoluteExcludePaths = resolveExcludePaths(excludePatterns, absoluteProjectRoot); - switch (mode) { - case CLEAN_MODE_SIMPLE: - cleanSimple(targetDirectory); - break; - case CLEAN_MODE_SHALLOW: - cleanShallow(targetDirectory, absoluteExcludePaths); - break; - case CLEAN_MODE_RECURSIVE: - await cleanRecursive(targetDirectory, absoluteExcludePaths); - break; - } - devkit_1.logger.info(`Successfully cleaned ${targetDirectory}`); - return { success: true }; - } - catch (error) { - (0, error_handler_1.logError)(`Failed to clean ${targetDirectory}`, error); - return { success: false }; - } -}; -exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/clean/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/clean/schema.d.ts deleted file mode 100644 index fc3426a2ac4d..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/clean/schema.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface CleanExecutorSchema { - targetDirectory?: string; - excludePatterns?: string[]; - mode?: 'simple' | 'recursive' | 'shallow'; -} diff --git a/packages/nx-infra-plugin/prod/src/executors/clean/schema.js b/packages/nx-infra-plugin/prod/src/executors/clean/schema.js deleted file mode 100644 index c8ad2e549bdc..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/clean/schema.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/clean/schema.json b/packages/nx-infra-plugin/prod/src/executors/clean/schema.json deleted file mode 100644 index fc80aabf8b13..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/clean/schema.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "type": "object", - "properties": { - "targetDirectory": { - "type": "string", - "description": "Directory to clean", - "default": "./src" - }, - "excludePatterns": { - "type": "array", - "description": "Patterns to exclude (only used with recursive mode)", - "items": { - "type": "string" - }, - "default": [] - }, - "mode": { - "type": "string", - "enum": ["simple", "recursive", "shallow"], - "description": "Cleaning mode: 'simple' removes entire directory, 'recursive' removes contents recursively with exclusions, 'shallow' removes only first-level items with exclusions", - "default": "simple" - } - }, - "required": [] -} diff --git a/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.d.ts deleted file mode 100644 index b3b6ac66eaa2..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PromiseExecutor } from '@nx/devkit'; -import { CopyFilesExecutorSchema } from './schema'; -declare const runExecutor: PromiseExecutor; -export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.js b/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.js deleted file mode 100644 index 7218b487784e..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/copy-files/executor.js +++ /dev/null @@ -1,57 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const devkit_1 = require("@nx/devkit"); -const path = __importStar(require("path")); -const path_resolver_1 = require("../../utils/path-resolver"); -const error_handler_1 = require("../../utils/error-handler"); -const file_operations_1 = require("../../utils/file-operations"); -const ERROR_FILES_MUST_BE_ARRAY = 'Files option must be an array'; -const ERROR_FAILED_TO_COPY = 'Failed to copy files'; -const runExecutor = async (options, context) => { - const projectRoot = (0, path_resolver_1.resolveProjectPath)(context); - if (!options.files || !Array.isArray(options.files)) { - devkit_1.logger.error(ERROR_FILES_MUST_BE_ARRAY); - return { success: false }; - } - try { - for (const { from, to } of options.files) { - const sourcePath = path.resolve(projectRoot, from); - const destPath = path.resolve(projectRoot, to); - if (!(await (0, file_operations_1.exists)(sourcePath))) { - devkit_1.logger.error(`Source file not found: ${sourcePath}`); - return { success: false }; - } - await (0, file_operations_1.copyFile)(sourcePath, destPath); - devkit_1.logger.info(`Copied ${sourcePath} -> ${destPath}`); - } - return { success: true }; - } - catch (error) { - (0, error_handler_1.logError)(ERROR_FAILED_TO_COPY, error); - return { success: false }; - } -}; -exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.d.ts deleted file mode 100644 index 490d39c9b14d..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface CopyFilesExecutorSchema { - files: Array<{ - from: string; - to: string; - }>; -} diff --git a/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.js b/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.js deleted file mode 100644 index c8ad2e549bdc..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.json b/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.json deleted file mode 100644 index 7c777b705386..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/copy-files/schema.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "type": "object", - "properties": { - "files": { - "type": "array", - "description": "Files to copy (array of {from, to})", - "items": { - "type": "object", - "properties": { - "from": { - "type": "string" - }, - "to": { - "type": "string" - } - }, - "required": ["from", "to"] - } - } - }, - "required": ["files"] -} diff --git a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.d.ts deleted file mode 100644 index 39fa2d52b464..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PromiseExecutor } from '@nx/devkit'; -import { GenerateReactComponentsExecutorSchema } from './schema'; -declare const runExecutor: PromiseExecutor; -export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.js b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.js deleted file mode 100644 index 0c094ace1ac0..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/executor.js +++ /dev/null @@ -1,225 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const devkit_1 = require("@nx/devkit"); -const fs = __importStar(require("fs")); -const path = __importStar(require("path")); -const path_resolver_1 = require("../../utils/path-resolver"); -const error_handler_1 = require("../../utils/error-handler"); -const executor_1 = __importDefault(require("../clean/executor")); -const DEFAULT_COMPONENTS_DIR = './src'; -const DEFAULT_INDEX_FILE_NAME = './src/index.ts'; -const CORE_DIR = 'core'; -const COMMON_DIR = 'common'; -const TOOLS_DIR = 'tools'; -const GENERATORS_CONFIG_FILE = 'generators-config.js'; -const METADATA_PACKAGE = 'devextreme-metadata'; -const METADATA_FILE = 'integration-data.json'; -const INTERNAL_TOOLS_PACKAGE = 'devextreme-internal-tools'; -const GENERATION_FUNCTION = 'generateReactComponents'; -const DEFAULT_BASE_COMPONENT = './core/component'; -const DEFAULT_EXTENSION_COMPONENT = './core/extension-component'; -const DEFAULT_CONFIG_COMPONENT = './core/nested-option'; -const WIDGETS_PACKAGE = 'devextreme'; -const CLEAN_MODE = 'shallow'; -const MSG_CLEANING = '๐Ÿงน Cleaning generated components'; -const MSG_CLEANED = 'โœ“ Successfully cleaned components directory'; -const MSG_LOADING_METADATA = '๐Ÿ“‹ Loading metadata'; -const MSG_GENERATORS_CONFIG_NOT_FOUND = 'โš ๏ธ generators-config.js not found, proceeding without unifiedConfig'; -const MSG_LOADED_REACT_CONFIG = 'โœ“ Loaded React configuration from generators-config.js'; -const MSG_GENERATING = 'โš™๏ธ Generating React components'; -const MSG_GENERATION_COMPLETED = 'โœ“ Component generation completed'; -const MSG_GENERATION_SUCCESS = 'โœจ React component generation successful!'; -const MSG_STARTING = '๐Ÿ”ง Starting React component generation'; -const MSG_GENERATION_FAILED = 'โŒ Component generation failed'; -const ERROR_METADATA_NOT_FOUND = 'Could not find devextreme-metadata/integration-data.json. Please ensure devextreme-metadata is installed or provide a metadataPath option.'; -const ERROR_CLEAN_FAILED = 'Failed to clean components directory'; -const PARENT_DIR_PREFIX = '../'; -const DOT_SLASH_PREFIX = './'; -const ENCODING_UTF8 = 'utf-8'; -const GENERATE_REEXPORTS = 'generateReexports'; -const GENERATE_CUSTOM_TYPES = 'generateCustomTypes'; -const QUOTES_DOUBLE = 'double'; -const EXPLICIT_INDEX_IN_IMPORTS = 'excplicitIndexInImports'; -const EXPORT_PATTERN = /export \{/g; -async function cleanComponentsDirectory(absoluteComponentsDir, preservePaths, context) { - devkit_1.logger.info(MSG_CLEANING); - const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); - const relativeComponentsDir = path.relative(absoluteProjectRoot, absoluteComponentsDir); - const cleanOptions = { - targetDirectory: DOT_SLASH_PREFIX + relativeComponentsDir, - excludePatterns: preservePaths.map((currentPath) => { - if (path.isAbsolute(currentPath)) { - const relative = path.relative(absoluteProjectRoot, currentPath); - return DOT_SLASH_PREFIX + relative; - } - return currentPath; - }), - mode: CLEAN_MODE, - }; - const result = await (0, executor_1.default)(cleanOptions, context); - if (result.success) { - devkit_1.logger.info(MSG_CLEANED); - } - else { - throw new Error(ERROR_CLEAN_FAILED); - } -} -function resolveMetadataPath(options, absoluteProjectRoot, workspaceRoot) { - if (options.metadataPath) { - return resolveCustomMetadataPath(options.metadataPath, absoluteProjectRoot, workspaceRoot); - } - return resolveDefaultMetadataPath(); -} -function resolveCustomMetadataPath(metadataPath, absoluteProjectRoot, workspaceRoot) { - const relativeToProject = path.resolve(absoluteProjectRoot, metadataPath); - if (fs.existsSync(relativeToProject)) { - return relativeToProject; - } - const relativeToWorkspace = path.resolve(workspaceRoot, metadataPath); - if (fs.existsSync(relativeToWorkspace)) { - return relativeToWorkspace; - } - if (metadataPath.startsWith(PARENT_DIR_PREFIX)) { - return path.resolve(workspaceRoot, metadataPath); - } - return relativeToProject; -} -function resolveDefaultMetadataPath() { - try { - return require.resolve(`${METADATA_PACKAGE}/${METADATA_FILE}`); - } - catch (error) { - throw new Error(ERROR_METADATA_NOT_FOUND); - } -} -function loadMetadata(metadataPath) { - devkit_1.logger.info(MSG_LOADING_METADATA); - devkit_1.logger.info(` Path: ${metadataPath}`); - if (!fs.existsSync(metadataPath)) { - throw new Error(`Metadata file not found: ${metadataPath}`); - } - const metadataContent = fs.readFileSync(metadataPath, ENCODING_UTF8); - const metaData = JSON.parse(metadataContent); - const widgetCount = Object.keys(metaData.Widgets || {}).length; - devkit_1.logger.info(`โœ“ Loaded ${widgetCount} widget definitions`); - return metaData; -} -function loadReactConfig(workspaceRoot) { - const generatorsConfigPath = path.join(workspaceRoot, TOOLS_DIR, GENERATORS_CONFIG_FILE); - if (!fs.existsSync(generatorsConfigPath)) { - devkit_1.logger.warn(MSG_GENERATORS_CONFIG_NOT_FOUND); - return undefined; - } - try { - const generatorsConfig = require(generatorsConfigPath); - devkit_1.logger.info(MSG_LOADED_REACT_CONFIG); - return generatorsConfig.reactConfig; - } - catch (error) { - devkit_1.logger.warn(`โš ๏ธ Could not load generators-config.js: ${(0, error_handler_1.getErrorMessage)(error)}`); - return undefined; - } -} -function loadGenerationFunction() { - try { - const internalTools = require(INTERNAL_TOOLS_PACKAGE); - return internalTools[GENERATION_FUNCTION]; - } - catch (error) { - throw new Error(`Could not load devextreme-internal-tools. Please ensure devextreme-internal-tools is installed as a dependency. Error: ${(0, error_handler_1.getErrorMessage)(error)}`); - } -} -function buildGenerationConfig(options, componentsDir, indexFileName, reactConfig) { - return { - metaData: undefined, - components: { - baseComponent: options.baseComponent || DEFAULT_BASE_COMPONENT, - extensionComponent: options.extensionComponent || DEFAULT_EXTENSION_COMPONENT, - configComponent: options.configComponent || DEFAULT_CONFIG_COMPONENT, - }, - out: { - componentsDir, - indexFileName, - }, - widgetsPackage: WIDGETS_PACKAGE, - typeGenerationOptions: { - [GENERATE_REEXPORTS]: true, - [GENERATE_CUSTOM_TYPES]: true, - }, - templatingOptions: { - quotes: QUOTES_DOUBLE, - [EXPLICIT_INDEX_IN_IMPORTS]: true, - }, - unifiedConfig: reactConfig, - }; -} -async function executeGeneration(generateReactComponents, config, metaData, componentsDir, indexFileName) { - devkit_1.logger.info(MSG_GENERATING); - config.metaData = metaData; - await generateReactComponents(config); - devkit_1.logger.info(MSG_GENERATION_COMPLETED); - if (fs.existsSync(indexFileName)) { - const indexContent = fs.readFileSync(indexFileName, ENCODING_UTF8); - const exportCount = (indexContent.match(EXPORT_PATTERN) || []).length; - devkit_1.logger.info(` Exports: ${exportCount}`); - } - if (fs.existsSync(componentsDir)) { - const dirCount = fs - .readdirSync(componentsDir, { withFileTypes: true }) - .filter((entry) => entry.isDirectory() && entry.name !== CORE_DIR).length; - devkit_1.logger.info(` Component Directories: ${dirCount}`); - } - devkit_1.logger.info(MSG_GENERATION_SUCCESS); -} -const runExecutor = async (options, context) => { - const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); - const workspaceRoot = context.root; - devkit_1.logger.info(MSG_STARTING); - const projectRelativePath = path.relative(workspaceRoot, absoluteProjectRoot) || DOT_SLASH_PREFIX; - devkit_1.logger.info(` Project root: ${projectRelativePath}`); - try { - const componentsDir = path.resolve(absoluteProjectRoot, options.componentsDir || DEFAULT_COMPONENTS_DIR); - const indexFileName = path.resolve(absoluteProjectRoot, options.indexFileName || DEFAULT_INDEX_FILE_NAME); - const coreDir = path.join(componentsDir, CORE_DIR); - const commonDir = path.join(componentsDir, COMMON_DIR); - await cleanComponentsDirectory(componentsDir, [coreDir, commonDir, indexFileName], context); - const metadataPath = resolveMetadataPath(options, absoluteProjectRoot, workspaceRoot); - const metaData = loadMetadata(metadataPath); - const reactConfig = loadReactConfig(workspaceRoot); - const generateReactComponents = loadGenerationFunction(); - const config = buildGenerationConfig(options, componentsDir, indexFileName, reactConfig); - await executeGeneration(generateReactComponents, config, metaData, componentsDir, indexFileName); - return { success: true }; - } - catch (error) { - (0, error_handler_1.logError)(MSG_GENERATION_FAILED, error); - return { success: false }; - } -}; -exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.d.ts deleted file mode 100644 index 1811b30b598b..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface GenerateReactComponentsExecutorSchema { - metadataPath?: string; - componentsDir?: string; - indexFileName?: string; - baseComponent?: string; - extensionComponent?: string; - configComponent?: string; -} diff --git a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.js b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.js deleted file mode 100644 index c8ad2e549bdc..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.json b/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.json deleted file mode 100644 index 5c48579dd30c..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/generate-react-components/schema.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "type": "object", - "properties": { - "metadataPath": { - "type": "string", - "description": "Path to metadata JSON file" - }, - "componentsDir": { - "type": "string", - "description": "Output directory for generated components", - "default": "./src" - }, - "indexFileName": { - "type": "string", - "description": "Index file name", - "default": "./src/index.ts" - }, - "baseComponent": { - "type": "string", - "description": "Base component path", - "default": "./core/component" - }, - "extensionComponent": { - "type": "string", - "description": "Extension component path", - "default": "./core/extension-component" - }, - "configComponent": { - "type": "string", - "description": "Config component path", - "default": "./core/nested-option" - } - }, - "required": ["metadataPath"] -} diff --git a/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.d.ts deleted file mode 100644 index 15a2f65bff94..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PromiseExecutor } from '@nx/devkit'; -import { PackNpmExecutorSchema } from './schema'; -declare const runExecutor: PromiseExecutor; -export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.js b/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.js deleted file mode 100644 index cba2fa542969..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/pack-npm/executor.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const devkit_1 = require("@nx/devkit"); -const child_process_1 = require("child_process"); -const path_1 = __importDefault(require("path")); -const path_resolver_1 = require("../../utils/path-resolver"); -const error_handler_1 = require("../../utils/error-handler"); -const DEFAULT_DIST_DIR = './npm'; -const MSG_PACK_SUCCESS = 'pnpm pack completed successfully'; -const MSG_PACK_FAILED = 'Failed to run pnpm pack'; -const runExecutor = async (options, context) => { - const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); - const distDirectory = options.workingDirectory || DEFAULT_DIST_DIR; - const workspaceRoot = context.root; - if (!context.projectName) { - (0, error_handler_1.logError)(MSG_PACK_FAILED, 'Project name is not defined in context'); - return { success: false }; - } - try { - devkit_1.logger.info(`Running pnpm pack from ${absoluteProjectRoot} (packaging ${distDirectory})...`); - const projectPath = path_1.default.join(workspaceRoot, 'packages', context.projectName); - (0, child_process_1.execSync)(`pnpm pack`, { - cwd: projectPath, - stdio: 'inherit', - }); - devkit_1.logger.info(MSG_PACK_SUCCESS); - return { success: true }; - } - catch (error) { - (0, error_handler_1.logError)(MSG_PACK_FAILED, error); - return { success: false }; - } -}; -exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.d.ts deleted file mode 100644 index c979e6541f3c..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface PackNpmExecutorSchema { - workingDirectory?: string; -} diff --git a/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.js b/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.js deleted file mode 100644 index c8ad2e549bdc..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.json b/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.json deleted file mode 100644 index 888e8312ae4f..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/pack-npm/schema.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "object", - "properties": { - "workingDirectory": { - "type": "string", - "description": "Working directory for pnpm pack", - "default": "./" - } - }, - "required": [] -} diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.d.ts deleted file mode 100644 index 975c85d0e9ba..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PromiseExecutor } from '@nx/devkit'; -import { NpmPackageExecutorSchema } from './schema'; -declare const runExecutor: PromiseExecutor; -export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.js b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.js deleted file mode 100644 index 1eeb97e4eca2..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/executor.js +++ /dev/null @@ -1,55 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const devkit_1 = require("@nx/devkit"); -const path = __importStar(require("path")); -const path_resolver_1 = require("../../utils/path-resolver"); -const error_handler_1 = require("../../utils/error-handler"); -const file_operations_1 = require("../../utils/file-operations"); -const DEFAULT_SOURCE_PACKAGE_JSON = './package.json'; -const DEFAULT_DIST_DIR = './npm'; -const PACKAGE_JSON_FILE = 'package.json'; -const PUBLISH_CONFIG_FIELD = 'publishConfig'; -const JSON_INDENT = 2; -const ERROR_PREPARE_PACKAGE_JSON = 'Failed to prepare package.json'; -const runExecutor = async (options, context) => { - const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); - const sourcePackageJson = path.join(absoluteProjectRoot, options.sourcePackageJson || DEFAULT_SOURCE_PACKAGE_JSON); - const distDirectory = path.join(absoluteProjectRoot, options.distDirectory || DEFAULT_DIST_DIR); - try { - await (0, file_operations_1.ensureDir)(distDirectory); - const pkg = await (0, file_operations_1.readJson)(sourcePackageJson); - delete pkg[PUBLISH_CONFIG_FIELD]; - const distPackageJson = path.join(distDirectory, PACKAGE_JSON_FILE); - await (0, file_operations_1.writeJson)(distPackageJson, pkg, JSON_INDENT); - devkit_1.logger.info(`Created ${distPackageJson}`); - return { success: true }; - } - catch (error) { - (0, error_handler_1.logError)(ERROR_PREPARE_PACKAGE_JSON, error); - return { success: false }; - } -}; -exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.d.ts deleted file mode 100644 index 5b20a50c39ac..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface NpmPackageExecutorSchema { - sourcePackageJson?: string; - distDirectory?: string; -} diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.js b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.js deleted file mode 100644 index c8ad2e549bdc..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.json b/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.json deleted file mode 100644 index d555d19c5d7f..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-package-json/schema.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "type": "object", - "properties": { - "sourcePackageJson": { - "type": "string", - "description": "Path to source package.json", - "default": "./package.json" - }, - "distDirectory": { - "type": "string", - "description": "Distribution directory", - "default": "./npm" - } - }, - "required": [] -} diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.d.ts b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.d.ts deleted file mode 100644 index f16c9e5cddb8..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PromiseExecutor } from '@nx/devkit'; -import { PrepareSubmodulesExecutorSchema } from './schema'; -declare const runExecutor: PromiseExecutor; -export default runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js deleted file mode 100644 index e3550bd204cd..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/executor.js +++ /dev/null @@ -1,129 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const devkit_1 = require("@nx/devkit"); -const fs = __importStar(require("fs/promises")); -const fsSync = __importStar(require("fs")); -const path = __importStar(require("path")); -const path_resolver_1 = require("../../utils/path-resolver"); -const error_handler_1 = require("../../utils/error-handler"); -const file_operations_1 = require("../../utils/file-operations"); -const DEFAULT_DIST_DIR = './npm'; -const ESM_DIR = 'esm'; -const CJS_DIR = 'cjs'; -const ENCODING_UTF8 = 'utf8'; -const JS_EXTENSION = '.js'; -const DTS_EXTENSION = '.d.ts'; -const REGEX_IMPORTS = /from "\.\/([^;]+)";/g; -const REGEX_PARSE_MODULE = /((.*)\/)?([^/]+$)/; -const MSG_PREPARING = '๐Ÿ“ฆ Preparing submodules'; -const MSG_SUCCESS = 'โœ“ Submodules prepared successfully'; -const ERROR_PREPARE_SUBMODULES = 'Failed to prepare submodules'; -const INDEX_FILE_NAME = 'index.js'; -const PACKAGE_JSON_FILE = 'package.json'; -const PATH_SLASH = '/'; -const RELATIVE_DIR_PREFIX = '../'; -const DEFAULT_SUBMODULE_FOLDERS = [ - ['common'], - ['core', ['template', 'config', 'nested-option', 'component', 'extension-component']], - ['common/core'], - ['common/data'], - ['common/export'], -]; -const runExecutor = async (options, context) => { - const absoluteProjectRoot = (0, path_resolver_1.resolveProjectPath)(context); - const distDirectory = path.join(absoluteProjectRoot, options.distDirectory || DEFAULT_DIST_DIR); - try { - devkit_1.logger.info(MSG_PREPARING); - const packParamsForFolders = options.submoduleFolders || DEFAULT_SUBMODULE_FOLDERS; - const esmIndexPath = path.join(distDirectory, ESM_DIR, 'index.js'); - let modulesImportsFromIndex = ''; - if (fsSync.existsSync(esmIndexPath)) { - modulesImportsFromIndex = await fs.readFile(esmIndexPath, ENCODING_UTF8); - } - const modulesPaths = modulesImportsFromIndex.matchAll(REGEX_IMPORTS); - const packParamsForModules = Array.from(modulesPaths).map(([, modulePath]) => { - const match = modulePath.match(REGEX_PARSE_MODULE) || []; - const moduleFilePath = match[2]; - const moduleFileName = match[3]; - return ['', moduleFileName ? [moduleFileName] : undefined, moduleFilePath]; - }); - const allModuleParams = [...packParamsForModules, ...packParamsForFolders]; - devkit_1.logger.info(`Processing ${allModuleParams.length} submodules...`); - await Promise.all(allModuleParams.map(([folder, moduleFileNames, moduleFilePath]) => makeModule(distDirectory, folder, moduleFileNames, moduleFilePath))); - devkit_1.logger.info(MSG_SUCCESS); - return { success: true }; - } - catch (error) { - (0, error_handler_1.logError)(ERROR_PREPARE_SUBMODULES, error); - return { success: false }; - } -}; -async function makeModule(distFolder, folder, moduleFileNames, moduleFilePath) { - const distModuleFolder = path.join(distFolder, folder); - const distEsmFolder = path.join(distFolder, ESM_DIR, folder); - const moduleNames = moduleFileNames || (await findJsModuleFileNamesInFolder(distEsmFolder)); - try { - await (0, file_operations_1.ensureDir)(distModuleFolder); - if (folder && fsSync.existsSync(path.join(distEsmFolder, 'index.js'))) { - await generatePackageJsonFile(distFolder, folder, undefined, folder); - } - await Promise.all(moduleNames.map(async (moduleFileName) => { - const moduleDir = path.join(distModuleFolder, moduleFileName); - await (0, file_operations_1.ensureDir)(moduleDir); - await generatePackageJsonFile(distFolder, folder, moduleFileName, moduleFilePath || folder); - })); - } - catch (error) { - throw new Error(`Exception while makeModule(${folder}): ${(0, error_handler_1.getErrorMessage)(error)}`); - } -} -async function generatePackageJsonFile(distFolder, folder, moduleFileName, filePath) { - const moduleName = moduleFileName || ''; - const absoluteModulePath = path.join(distFolder, folder, moduleName); - const moduleFilePathResolved = (filePath ? filePath + PATH_SLASH : '') + (moduleName || 'index'); - const esmFilePath = path.join(distFolder, ESM_DIR, moduleFilePathResolved + JS_EXTENSION); - const relativePath = path.relative(absoluteModulePath, esmFilePath); - const relativeBase = RELATIVE_DIR_PREFIX.repeat(relativePath.split('..').length - 1); - const packageJson = { - sideEffects: false, - main: `${relativeBase}${CJS_DIR}/${moduleFilePathResolved}${JS_EXTENSION}`, - module: `${relativeBase}${ESM_DIR}/${moduleFilePathResolved}${JS_EXTENSION}`, - typings: `${relativeBase}${CJS_DIR}/${moduleFilePathResolved}${DTS_EXTENSION}`, - }; - await (0, file_operations_1.ensureDir)(absoluteModulePath); - await (0, file_operations_1.writeJson)(path.join(absoluteModulePath, PACKAGE_JSON_FILE), packageJson); -} -async function findJsModuleFileNamesInFolder(dir) { - if (!fsSync.existsSync(dir)) { - return []; - } - const entries = await fs.readdir(dir, { withFileTypes: true }); - return entries.filter(isJsModule).map((entry) => path.parse(entry.name).name); -} -function isJsModule(entry) { - return (!entry.isDirectory() && entry.name.endsWith(JS_EXTENSION) && entry.name !== INDEX_FILE_NAME); -} -exports.default = runExecutor; diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.d.ts b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.d.ts deleted file mode 100644 index 6e0bd8674257..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { PackParam } from '../../utils/types'; -export interface PrepareSubmodulesExecutorSchema { - distDirectory?: string; - submoduleFolders?: PackParam[]; -} diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.js b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.js deleted file mode 100644 index c8ad2e549bdc..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.json b/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.json deleted file mode 100644 index e84a530524f9..000000000000 --- a/packages/nx-infra-plugin/prod/src/executors/prepare-submodules/schema.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "object", - "properties": { - "distDirectory": { - "type": "string", - "description": "Distribution directory containing ESM and CJS builds. This directory will be scanned to generate submodule package.json files.", - "default": "./npm" - }, - "submoduleFolders": { - "type": "array", - "description": "Custom submodule folder configurations. Each entry is [folder, moduleFileNames?, moduleFilePath?].", - "items": { - "type": "array" - } - } - }, - "required": [] -} diff --git a/packages/nx-infra-plugin/prod/src/index.d.ts b/packages/nx-infra-plugin/prod/src/index.d.ts deleted file mode 100644 index 98e4ca30c454..000000000000 --- a/packages/nx-infra-plugin/prod/src/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default function (): { - name: string; -}; diff --git a/packages/nx-infra-plugin/prod/src/index.js b/packages/nx-infra-plugin/prod/src/index.js deleted file mode 100644 index 6d2abf23dcef..000000000000 --- a/packages/nx-infra-plugin/prod/src/index.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -function default_1() { - return { - name: 'nx-infra-plugin', - }; -} -exports.default = default_1; diff --git a/packages/nx-infra-plugin/prod/src/utils/error-handler.d.ts b/packages/nx-infra-plugin/prod/src/utils/error-handler.d.ts deleted file mode 100644 index 120f5dd81af8..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/error-handler.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export declare function getErrorMessage(error: unknown): string; -export declare function getErrorStack(error: unknown): string | undefined; -export declare function logError(message: string, error: unknown): void; diff --git a/packages/nx-infra-plugin/prod/src/utils/error-handler.js b/packages/nx-infra-plugin/prod/src/utils/error-handler.js deleted file mode 100644 index 5a274aea1353..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/error-handler.js +++ /dev/null @@ -1,20 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.logError = exports.getErrorStack = exports.getErrorMessage = void 0; -const devkit_1 = require("@nx/devkit"); -function getErrorMessage(error) { - return error instanceof Error ? error.message : String(error); -} -exports.getErrorMessage = getErrorMessage; -function getErrorStack(error) { - return error instanceof Error ? error.stack : undefined; -} -exports.getErrorStack = getErrorStack; -function logError(message, error) { - devkit_1.logger.error(`${message}: ${getErrorMessage(error)}`); - const stack = getErrorStack(error); - if (stack) { - devkit_1.logger.error(stack); - } -} -exports.logError = logError; diff --git a/packages/nx-infra-plugin/prod/src/utils/file-operations.d.ts b/packages/nx-infra-plugin/prod/src/utils/file-operations.d.ts deleted file mode 100644 index 1a51021909d1..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/file-operations.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -export declare function ensureDir(dirPath: string): Promise; -export declare function readJson(filePath: string): Promise; -export declare function writeJson(filePath: string, data: unknown, spaces?: number): Promise; -export declare function processFiles(pattern: string, processor: (filePath: string) => Promise, options?: { - ignore?: string[]; -}): Promise; -export declare function exists(filePath: string): Promise; -export declare function copyFile(from: string, to: string): Promise; -export declare function readFileText(filePath: string): Promise; -export declare function writeFileText(filePath: string, content: string): Promise; diff --git a/packages/nx-infra-plugin/prod/src/utils/file-operations.js b/packages/nx-infra-plugin/prod/src/utils/file-operations.js deleted file mode 100644 index 01c2b2ba142d..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/file-operations.js +++ /dev/null @@ -1,87 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.writeFileText = exports.readFileText = exports.copyFile = exports.exists = exports.processFiles = exports.writeJson = exports.readJson = exports.ensureDir = void 0; -const fs = __importStar(require("fs/promises")); -const path = __importStar(require("path")); -const glob_1 = require("glob"); -const ENCODING_UTF8 = 'utf-8'; -const ERROR_CODE_EXIST = 'EEXIST'; -async function ensureDir(dirPath) { - try { - await fs.mkdir(dirPath, { recursive: true }); - } - catch (error) { - if (error instanceof Error && 'code' in error && error.code === ERROR_CODE_EXIST) { - return; - } - throw error; - } -} -exports.ensureDir = ensureDir; -async function readJson(filePath) { - const content = await fs.readFile(filePath, ENCODING_UTF8); - return JSON.parse(content); -} -exports.readJson = readJson; -async function writeJson(filePath, data, spaces = 2) { - const content = JSON.stringify(data, null, spaces); - await fs.writeFile(filePath, content, ENCODING_UTF8); -} -exports.writeJson = writeJson; -async function processFiles(pattern, processor, options = {}) { - const files = await (0, glob_1.glob)(pattern, { - absolute: true, - nodir: true, - ignore: options.ignore, - }); - await Promise.all(files.map(processor)); - return files.length; -} -exports.processFiles = processFiles; -async function exists(filePath) { - try { - await fs.access(filePath); - return true; - } - catch { - return false; - } -} -exports.exists = exists; -async function copyFile(from, to) { - await ensureDir(path.dirname(to)); - await fs.copyFile(from, to); -} -exports.copyFile = copyFile; -async function readFileText(filePath) { - return fs.readFile(filePath, ENCODING_UTF8); -} -exports.readFileText = readFileText; -async function writeFileText(filePath, content) { - await ensureDir(path.dirname(filePath)); - await fs.writeFile(filePath, content, ENCODING_UTF8); -} -exports.writeFileText = writeFileText; diff --git a/packages/nx-infra-plugin/prod/src/utils/index.d.ts b/packages/nx-infra-plugin/prod/src/utils/index.d.ts deleted file mode 100644 index 81ead4bb9a44..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './types'; -export * from './path-resolver'; -export * from './error-handler'; -export * from './file-operations'; diff --git a/packages/nx-infra-plugin/prod/src/utils/index.js b/packages/nx-infra-plugin/prod/src/utils/index.js deleted file mode 100644 index fe88aab75ab6..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/index.js +++ /dev/null @@ -1,20 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __exportStar = (this && this.__exportStar) || function(m, exports) { - for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -__exportStar(require("./types"), exports); -__exportStar(require("./path-resolver"), exports); -__exportStar(require("./error-handler"), exports); -__exportStar(require("./file-operations"), exports); diff --git a/packages/nx-infra-plugin/prod/src/utils/path-resolver.d.ts b/packages/nx-infra-plugin/prod/src/utils/path-resolver.d.ts deleted file mode 100644 index cd99c66b2e7c..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/path-resolver.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { ExecutorContext } from '@nx/devkit'; -export declare function resolveProjectPath(context: ExecutorContext): string; -export declare function resolveFromProject(context: ExecutorContext, relativePath: string): string; -export declare function resolveFromWorkspace(context: ExecutorContext, relativePath: string): string; diff --git a/packages/nx-infra-plugin/prod/src/utils/path-resolver.js b/packages/nx-infra-plugin/prod/src/utils/path-resolver.js deleted file mode 100644 index e089f9628593..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/path-resolver.js +++ /dev/null @@ -1,53 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.resolveFromWorkspace = exports.resolveFromProject = exports.resolveProjectPath = void 0; -const path = __importStar(require("path")); -const ERROR_CONFIGURATIONS_NOT_FOUND = 'Project configurations not found in executor context'; -const ERROR_PROJECT_NAME_NOT_FOUND = 'Project name not found in executor context'; -const ERROR_PROJECT_NOT_FOUND = 'Project "{0}" not found in workspace'; -function resolveProjectPath(context) { - if (!context.projectsConfigurations) { - throw new Error(ERROR_CONFIGURATIONS_NOT_FOUND); - } - if (!context.projectName) { - throw new Error(ERROR_PROJECT_NAME_NOT_FOUND); - } - const project = context.projectsConfigurations.projects[context.projectName]; - if (!project) { - throw new Error(ERROR_PROJECT_NOT_FOUND.replace('{0}', context.projectName)); - } - return path.resolve(context.root, project.root); -} -exports.resolveProjectPath = resolveProjectPath; -function resolveFromProject(context, relativePath) { - const projectRoot = resolveProjectPath(context); - return path.join(projectRoot, relativePath); -} -exports.resolveFromProject = resolveFromProject; -function resolveFromWorkspace(context, relativePath) { - return path.join(context.root, relativePath); -} -exports.resolveFromWorkspace = resolveFromWorkspace; diff --git a/packages/nx-infra-plugin/prod/src/utils/test-utils.d.ts b/packages/nx-infra-plugin/prod/src/utils/test-utils.d.ts deleted file mode 100644 index cb50f3362eee..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/test-utils.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ExecutorContext } from '@nx/devkit'; -export declare function createTempDir(prefix: string): string; -export declare function cleanupTempDir(dirPath: string): void; -export interface MockContextOptions { - root?: string; - projectName?: string; - projectRoot?: string; - isVerbose?: boolean; -} -export declare function createMockContext(options?: MockContextOptions): ExecutorContext; diff --git a/packages/nx-infra-plugin/prod/src/utils/test-utils.js b/packages/nx-infra-plugin/prod/src/utils/test-utils.js deleted file mode 100644 index 8394daac9cdb..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/test-utils.js +++ /dev/null @@ -1,55 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createMockContext = exports.cleanupTempDir = exports.createTempDir = void 0; -const fs = __importStar(require("fs")); -const path = __importStar(require("path")); -const os = __importStar(require("os")); -function createTempDir(prefix) { - return fs.mkdtempSync(path.join(os.tmpdir(), prefix)); -} -exports.createTempDir = createTempDir; -function cleanupTempDir(dirPath) { - if (fs.existsSync(dirPath)) { - fs.rmSync(dirPath, { recursive: true, force: true }); - } -} -exports.cleanupTempDir = cleanupTempDir; -function createMockContext(options = {}) { - const { root = '/tmp/test', projectName = 'test-lib', projectRoot = 'packages/test-lib', isVerbose = false, } = options; - return { - root, - cwd: root, - isVerbose, - projectName, - projectsConfigurations: { - projects: { - [projectName]: { root: projectRoot }, - }, - version: 2, - }, - }; -} -exports.createMockContext = createMockContext; diff --git a/packages/nx-infra-plugin/prod/src/utils/types.d.ts b/packages/nx-infra-plugin/prod/src/utils/types.d.ts deleted file mode 100644 index 8529556b628d..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/types.d.ts +++ /dev/null @@ -1,48 +0,0 @@ -export interface TsConfig { - compilerOptions?: CompilerOptions; - extends?: string; - include?: string[]; - exclude?: string[]; - files?: string[]; - references?: Array<{ - path: string; - }>; -} -export interface CompilerOptions { - target?: string; - module?: string; - lib?: string[]; - outDir?: string; - rootDir?: string; - declaration?: boolean; - declarationMap?: boolean; - sourceMap?: boolean; - strict?: boolean; - esModuleInterop?: boolean; - skipLibCheck?: boolean; - forceConsistentCasingInFileNames?: boolean; - resolveJsonModule?: boolean; - jsx?: string; - paths?: Record; - [key: string]: any; -} -export type PackParam = [string, string[]?, string?]; -export interface TemplateData { - pkg: { - name: string; - version: string; - [key: string]: any; - }; - date: string; - year: number; - [key: string]: any; -} -export interface FileCopyOperation { - from: string; - to: string; -} -export interface SubmoduleConfig { - folder: string; - moduleFileNames?: string[]; - moduleFilePath?: string; -} diff --git a/packages/nx-infra-plugin/prod/src/utils/types.js b/packages/nx-infra-plugin/prod/src/utils/types.js deleted file mode 100644 index c8ad2e549bdc..000000000000 --- a/packages/nx-infra-plugin/prod/src/utils/types.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/packages/nx-infra-plugin/project.json b/packages/nx-infra-plugin/project.json index d4cdb493cb4e..0ae30207e750 100644 --- a/packages/nx-infra-plugin/project.json +++ b/packages/nx-infra-plugin/project.json @@ -9,7 +9,7 @@ "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], "options": { - "outputPath": "{projectRoot}/prod", + "outputPath": "{projectRoot}/dist", "main": "{projectRoot}/src/index.ts", "tsConfig": "{projectRoot}/tsconfig.lib.json", "generateExportsField": true, diff --git a/packages/nx-infra-plugin/tsconfig.lib.json b/packages/nx-infra-plugin/tsconfig.lib.json index ff6f64480938..1a46f829ba6b 100644 --- a/packages/nx-infra-plugin/tsconfig.lib.json +++ b/packages/nx-infra-plugin/tsconfig.lib.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.json", "compilerOptions": { "baseUrl": ".", - "outDir": "./prod", + "outDir": "./dist", "declaration": true, "types": ["node"], "skipLibCheck": true diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d4c9941c4cb..cd645c21b251 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1932,6 +1932,9 @@ importers: devextreme-metadata: specifier: workspace:* version: link:../devextreme-metadata + devextreme-nx-infra-plugin: + specifier: workspace:* + version: link:../nx-infra-plugin eslint: specifier: 'catalog:' version: 9.18.0(jiti@1.21.6) From 3bade7da96ea8fdf549fd4dcd502e8eb4c5db31a Mon Sep 17 00:00:00 2001 From: Adel Khamatov Date: Thu, 30 Oct 2025 13:35:39 +0200 Subject: [PATCH 9/9] chore(nx-infra-plugin): add custom build script for `nx-infra-plugin` to use postinstall hook --- package.json | 1 + packages/nx-infra-plugin/package.json | 7 +- packages/nx-infra-plugin/project.json | 27 +--- tools/scripts/build-nx-plugin.ts | 211 ++++++++++++++++++++++++++ 4 files changed, 218 insertions(+), 28 deletions(-) create mode 100644 tools/scripts/build-nx-plugin.ts diff --git a/package.json b/package.json index 153a7172f5b6..270341893a3b 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "license": "MIT", "author": "Developer Express Inc.", "scripts": { + "postinstall": "npx ts-node tools/scripts/build-nx-plugin.ts || true", "devextreme:inject-descriptions-to-bundle": "dx-tools inject-descriptions --target-path ./packages/devextreme/ts/dx.all.d.ts --artifacts ./node_modules/devextreme-metadata/dist", "devextreme:inject-descriptions-to-modules": "dx-tools inject-descriptions --collapse-tags --sources ./packages/devextreme/js --artifacts ./node_modules/devextreme-metadata/dist", "devextreme:inject-descriptions": "npm run devextreme:inject-descriptions-to-bundle && npm run devextreme:inject-descriptions-to-modules", diff --git a/packages/nx-infra-plugin/package.json b/packages/nx-infra-plugin/package.json index 4aeb83662425..bf1a106ada12 100644 --- a/packages/nx-infra-plugin/package.json +++ b/packages/nx-infra-plugin/package.json @@ -6,8 +6,8 @@ "executors": "./dist/executors.json", "exports": { ".": { - "require": "./dist/src/index.js", - "types": "./dist/src/index.d.ts" + "require": "./dist/index.js", + "types": "./dist/index.d.ts" }, "./package.json": "./package.json" }, @@ -23,10 +23,9 @@ "ts-jest": "29.1.3" }, "scripts": { - "postinstall": "pnpm run build", "format:check": "prettier --check .", "format": "prettier --write .", - "build": "pnpm --workspace-root nx build devextreme-nx-infra-plugin", + "build": "npx ts-node ../../tools/scripts/build-nx-plugin.ts --force", "test": "pnpm --workspace-root nx test devextreme-nx-infra-plugin", "lint": "pnpm run format:check" } diff --git a/packages/nx-infra-plugin/project.json b/packages/nx-infra-plugin/project.json index 0ae30207e750..1c0103ee6907 100644 --- a/packages/nx-infra-plugin/project.json +++ b/packages/nx-infra-plugin/project.json @@ -6,31 +6,10 @@ "tags": [], "targets": { "build": { - "executor": "@nx/js:tsc", - "outputs": ["{options.outputPath}"], + "executor": "nx:run-script", + "outputs": ["{projectRoot}/dist"], "options": { - "outputPath": "{projectRoot}/dist", - "main": "{projectRoot}/src/index.ts", - "tsConfig": "{projectRoot}/tsconfig.lib.json", - "generateExportsField": true, - "assets": [ - "{projectRoot}/*.md", - { - "input": "{projectRoot}/src", - "glob": "**/!(*.ts)", - "output": "./src" - }, - { - "input": "{projectRoot}/src", - "glob": "**/*.d.ts", - "output": "./src" - }, - { - "input": "{projectRoot}", - "glob": "executors.json", - "output": "." - } - ] + "script": "build" } }, "lint": { diff --git a/tools/scripts/build-nx-plugin.ts b/tools/scripts/build-nx-plugin.ts new file mode 100644 index 000000000000..82bbbd7f8ed7 --- /dev/null +++ b/tools/scripts/build-nx-plugin.ts @@ -0,0 +1,211 @@ +import { execSync } from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; + +const PLUGIN_DIR_NAME = 'nx-infra-plugin'; +const DIST_DIR_NAME = 'dist'; +const SRC_DIR_NAME = 'src'; +const TEMP_TSCONFIG_NAME = 'tsconfig.bootstrap.json'; +const TSCONFIG_LIB_NAME = 'tsconfig.lib.json'; +const EXECUTORS_JSON_NAME = 'executors.json'; +const JSON_EXTENSION = '.json'; +const TSCONFIG_PREFIX = 'tsconfig'; + +interface PathConfig { + pluginDir: string; + distDir: string; + srcDir: string; + tsconfig: string; +} + +interface TsConfig { + extends?: string; + compilerOptions?: Record; + include?: string[]; + exclude?: string[]; +} + +interface CompilationResult { + success: boolean; + error?: string; +} + +interface AssetCopyResult { + filesCopied: number; +} + +const buildPathConfig = (rootDir: string): PathConfig => { + const pluginDir = path.join(rootDir, '../../packages', PLUGIN_DIR_NAME); + return { + pluginDir, + distDir: path.join(pluginDir, DIST_DIR_NAME), + srcDir: path.join(pluginDir, SRC_DIR_NAME), + tsconfig: path.join(pluginDir, TSCONFIG_LIB_NAME) + }; +}; + +const checkDistExists = (distPath: string): boolean => { + if (!fs.existsSync(distPath)) return false; + const files = fs.readdirSync(distPath); + return files.length > 0; +}; + +const readTsConfig = (configPath: string): TsConfig => { + const content = fs.readFileSync(configPath, 'utf8'); + return JSON.parse(content); +}; + +const createBootstrapConfig = (original: TsConfig): TsConfig => ({ + ...original, + compilerOptions: { + ...original.compilerOptions, + rootDir: undefined, + outDir: `./${DIST_DIR_NAME}` + } +}); + +const writeTsConfig = (configPath: string, config: TsConfig): void => { + fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); +}; + +const compileTypeScript = (pluginDir: string, configPath: string): CompilationResult => { + try { + execSync( + `npx tsc -p ${configPath}`, + { + cwd: pluginDir, + stdio: 'inherit', + env: { ...process.env, NODE_ENV: 'production' } + } + ); + return { success: true }; + } catch (error) { + return { + success: false, + error: (error as Error).message + }; + } +}; + +const isJsonAsset = (filename: string): boolean => + filename.endsWith(JSON_EXTENSION) && !filename.includes(TSCONFIG_PREFIX); + +const copyJsonAssets = (srcDir: string, destDir: string): AssetCopyResult => { + if (!fs.existsSync(srcDir)) { + return { filesCopied: 0 }; + } + + let filesCopied = 0; + const entries = fs.readdirSync(srcDir, { withFileTypes: true }); + + for (const entry of entries) { + const srcPath = path.join(srcDir, entry.name); + const destPath = path.join(destDir, entry.name); + + if (entry.isDirectory()) { + if (!fs.existsSync(destPath)) { + fs.mkdirSync(destPath, { recursive: true }); + } + const result = copyJsonAssets(srcPath, destPath); + filesCopied += result.filesCopied; + } else if (isJsonAsset(entry.name)) { + fs.copyFileSync(srcPath, destPath); + filesCopied++; + } + } + + return { filesCopied }; +}; + +const updateExecutorPaths = (config: Record): Record => { + const executors = config.executors as Record; + + const updated = Object.entries(executors).reduce((acc, [key, value]) => { + acc[key] = { + ...value, + implementation: value.implementation.replace('./src/', './'), + schema: value.schema.replace('./src/', './') + }; + return acc; + }, {} as Record); + + return { ...config, executors: updated }; +}; + +const copyExecutorsJson = (pluginDir: string, distDir: string): boolean => { + const sourcePath = path.join(pluginDir, EXECUTORS_JSON_NAME); + if (!fs.existsSync(sourcePath)) return false; + + const content = fs.readFileSync(sourcePath, 'utf8'); + const config = JSON.parse(content); + const updatedConfig = updateExecutorPaths(config); + + const destPath = path.join(distDir, EXECUTORS_JSON_NAME); + fs.writeFileSync(destPath, JSON.stringify(updatedConfig, null, 2)); + return true; +}; + +const cleanupTempConfig = (configPath: string): void => { + if (fs.existsSync(configPath)) { + fs.unlinkSync(configPath); + } +}; + +const shouldSkipBuild = (distPath: string, forceRebuild: boolean): boolean => { + if (forceRebuild) return false; + return checkDistExists(distPath); +}; + +const buildPlugin = (paths: PathConfig, forceRebuild = false): void => { + if (shouldSkipBuild(paths.distDir, forceRebuild)) { + console.log('โœ“ Plugin already built, skipping...'); + process.exit(0); + } + + console.log(' Compiling TypeScript...'); + + const tempConfigPath = path.join(paths.pluginDir, TEMP_TSCONFIG_NAME); + const originalConfig = readTsConfig(paths.tsconfig); + const bootstrapConfig = createBootstrapConfig(originalConfig); + + writeTsConfig(tempConfigPath, bootstrapConfig); + + try { + const result = compileTypeScript(paths.pluginDir, tempConfigPath); + if (!result.success) { + throw new Error(result.error); + } + + console.log(' Copying assets...'); + copyJsonAssets(paths.srcDir, paths.distDir); + + copyExecutorsJson(paths.pluginDir, paths.distDir); + + console.log('โœ“ Plugin built successfully!'); + } finally { + cleanupTempConfig(tempConfigPath); + } +}; + +const parseArgs = (): { forceRebuild: boolean } => { + const args = process.argv.slice(2); + return { + forceRebuild: args.includes('--force') || args.includes('-f') + }; +}; + +const main = (): void => { + console.log('๐Ÿ”จ Building nx-infra-plugin...'); + + try { + const { forceRebuild } = parseArgs(); + const paths = buildPathConfig(__dirname); + buildPlugin(paths, forceRebuild); + } catch (error) { + console.error('โš  Failed to build plugin:', (error as Error).message); + console.error(' The plugin will be built on first use by NX'); + process.exit(0); + } +}; + +main();