@impactor/nx-manager 2.0.2 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/index.d.ts +11 -0
  2. package/index.js +16 -0
  3. package/nx.json +174 -0
  4. package/package.json +17 -14
  5. package/src/executors/universal-builder/builders/angular.d.ts +16 -0
  6. package/src/executors/universal-builder/builders/angular.js +123 -0
  7. package/src/executors/universal-builder/builders/esbuild.d.ts +45 -0
  8. package/src/executors/universal-builder/builders/esbuild.js +63 -0
  9. package/src/executors/universal-builder/builders/nest.d.ts +6 -0
  10. package/src/executors/universal-builder/builders/nest.js +54 -0
  11. package/src/executors/universal-builder/post-build.d.ts +2 -0
  12. package/src/executors/universal-builder/post-build.js +95 -0
  13. package/src/executors/universal-builder/schema.d.js +0 -0
  14. package/src/executors/universal-builder/types/builder-options.d.ts +44 -0
  15. package/src/executors/universal-builder/types/builder-options.js +0 -0
  16. package/src/executors/universal-builder/types/builder.d.ts +1 -0
  17. package/src/executors/universal-builder/types/builder.js +0 -0
  18. package/src/executors/universal-builder/types/package.d.ts +64 -0
  19. package/src/executors/universal-builder/types/package.js +0 -0
  20. package/src/executors/universal-builder/universal-builder.d.ts +6 -0
  21. package/src/executors/universal-builder/universal-builder.js +119 -0
  22. package/src/executors/universal-builder/universal-builder.spec.js +23 -0
  23. package/src/executors/universal-builder/utils/detect-project-type.d.ts +7 -0
  24. package/src/executors/universal-builder/utils/detect-project-type.js +21 -0
  25. package/src/executors/universal-builder/utils/exec.d.ts +1 -0
  26. package/src/executors/universal-builder/utils/exec.js +22 -0
  27. package/src/executors/universal-builder/utils/fs.d.ts +5 -0
  28. package/src/executors/universal-builder/utils/fs.js +92 -0
  29. package/src/executors/universal-builder/utils/get-tsconfig-file.d.ts +2 -0
  30. package/src/executors/universal-builder/utils/get-tsconfig-file.js +12 -0
package/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ export { default as ngBuilder } from './src/executors/universal-builder/builders/angular.js';
2
+ export { default as esBuilder } from './src/executors/universal-builder/builders/esbuild.js';
3
+ export { default as nestBuilder } from './src/executors/universal-builder/builders/nest.js';
4
+ export * from './src/executors/universal-builder/post-build.js';
5
+ export * from './src/executors/universal-builder/types/builder.js';
6
+ export * from './src/executors/universal-builder/types/builder-options.js';
7
+ export * from './src/executors/universal-builder/types/package.js';
8
+ export * from './src/executors/universal-builder/universal-builder.js';
9
+ export * from './src/executors/universal-builder/utils/detect-project-type.js';
10
+ export * from './src/executors/universal-builder/utils/exec.js';
11
+ export * from './src/executors/universal-builder/utils/get-tsconfig-file.js';
package/index.js ADDED
@@ -0,0 +1,16 @@
1
+ import { default as default2 } from "./src/executors/universal-builder/builders/angular.js";
2
+ import { default as default3 } from "./src/executors/universal-builder/builders/esbuild.js";
3
+ import { default as default4 } from "./src/executors/universal-builder/builders/nest.js";
4
+ export * from "./src/executors/universal-builder/post-build.js";
5
+ export * from "./src/executors/universal-builder/types/builder.js";
6
+ export * from "./src/executors/universal-builder/types/builder-options.js";
7
+ export * from "./src/executors/universal-builder/types/package.js";
8
+ export * from "./src/executors/universal-builder/universal-builder.js";
9
+ export * from "./src/executors/universal-builder/utils/detect-project-type.js";
10
+ export * from "./src/executors/universal-builder/utils/exec.js";
11
+ export * from "./src/executors/universal-builder/utils/get-tsconfig-file.js";
12
+ export {
13
+ default3 as esBuilder,
14
+ default4 as nestBuilder,
15
+ default2 as ngBuilder
16
+ };
package/nx.json ADDED
@@ -0,0 +1,174 @@
1
+ {
2
+ "$schema": "./node_modules/nx/schemas/nx-schema.json",
3
+ "targetDefaults": {
4
+ "build": {
5
+ "executor": "@impactor/nx-manager:universal-builder",
6
+ "dependsOn": ["typecheck", "prebuild", "^build"],
7
+ "cache": true,
8
+ "inputs": ["default", "^default"],
9
+ "outputs": ["{projectRoot}/dist"],
10
+ "options": {
11
+ "forceRnDefaultPostBuild": true
12
+ }
13
+ },
14
+ "serve": {
15
+ "executor": "nx:run-commands",
16
+ "dependsOn": ["build", "preserve"],
17
+ "continuous": true,
18
+ "options": {
19
+ "cwd": "{projectRoot}",
20
+ "command": "NODE_ENV=development pnpm tsx --env-file-if-exists=.env --env-file-if-exists=.env.local dist/main.js"
21
+ },
22
+ "configurations": {
23
+ "production": {
24
+ "command": "NODE_ENV=production pnpm tsx --env-file-if-exists=.env --env-file-if-exists=.env.local --env-file-if-exists=.env.production --env-file-if-exists=.env.production.local dist/main.js"
25
+ }
26
+ }
27
+ },
28
+ "nx-release-publish": {
29
+ "options": {
30
+ "packageRoot": "{projectRoot}/dist"
31
+ }
32
+ },
33
+ "test": {
34
+ "inputs": ["test"],
35
+ "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
36
+ "dependsOn": ["^build", "pretest"],
37
+ "configurations": {
38
+ "unit": {
39
+ "args": [
40
+ "--testPathIgnorePatterns '.*\\.e2e\\.spec\\.ts$'",
41
+ "--testPathIgnorePatterns '/.*-e2e/'",
42
+ "--testPathIgnorePatterns '/.*-e2e/'"
43
+ ]
44
+ },
45
+ "e2e": {
46
+ "args": [
47
+ "--testMatch '**/*-e2e/**/*.{spec,test}.[mc]?[jt]s?(x)'",
48
+ "--testMatch '**/e2e/**/*.{spec,test}.[mc]?[jt]s?(x)'",
49
+ "--testMatch '**/*.e2e.(spec|test).?([mc])[jt]s?(x)'"
50
+ ]
51
+ }
52
+ }
53
+ },
54
+ "@angular/build:application": {
55
+ "cache": true,
56
+ "dependsOn": ["prebuild", "^build"],
57
+ "inputs": ["default", "^default"]
58
+ },
59
+ "@nx/angular:package": {
60
+ "cache": true,
61
+ "dependsOn": ["^build"],
62
+ "inputs": ["default", "^default"],
63
+ "outputs": ["{projectRoot}/dist"],
64
+ "options": {
65
+ "project": "{projectRoot}/ng-package.json",
66
+ "tsConfig": "{projectRoot}/tsconfig.lib.json"
67
+ }
68
+ },
69
+ "@nx/js:tsc": {
70
+ "cache": true,
71
+ "dependsOn": ["^build"],
72
+ "inputs": ["default", "^default"]
73
+ }
74
+ },
75
+ "namedInputs": {
76
+ "default": [
77
+ "{projectRoot}/src/**/*",
78
+ "!{projectRoot}/**/*.(spec|test)(.e2e)?.[tj]sx?",
79
+ "!{projectRoot}/**/e2e/**/*",
80
+ "{projectRoot}/.env(.*)?",
81
+ "{workspaceRoot}/tasks/(post-)?build.ts",
82
+ "{projectRoot}/(project|package|tsconfig)(.+)?.json",
83
+ "{workspaceRoot}/tsconfig.base.json",
84
+ {
85
+ "runtime": "node --version"
86
+ },
87
+ {
88
+ "env": "NODE_ENV"
89
+ }
90
+ ],
91
+ "test": [
92
+ "default",
93
+ "{projectRoot}/tsconfig.spec.json",
94
+ "{projectRoot}/jest.config.[jt]s",
95
+ "{workspaceRoot}/jest.config.[jt]s",
96
+ "{projectRoot}/**/*.(spec|test)(.e2e)?.[jt]sx?",
97
+ "{projectRoot}/**/e2e/**/*.[jt]sx?",
98
+ {
99
+ "externalDependencies": ["jest"]
100
+ }
101
+ ]
102
+ },
103
+ "plugins": [
104
+ {
105
+ "plugin": "@nx/js/typescript",
106
+ "options": {
107
+ "typecheck": {
108
+ "targetName": "typecheck"
109
+ },
110
+ "build": false
111
+ }
112
+ },
113
+ {
114
+ "plugin": "@nx/jest/plugin",
115
+ "options": {
116
+ "targetName": "test",
117
+ "ciTargetName": "test-ci"
118
+ }
119
+ }
120
+ ],
121
+ "tasksRunnerOptions": {
122
+ "default": {
123
+ "options": {
124
+ "useDaemonProcess": false
125
+ }
126
+ }
127
+ },
128
+ "generators": {
129
+ "@nx/angular:library": {
130
+ "linter": "eslint",
131
+ "unitTestRunner": "jest"
132
+ },
133
+ "@nx/angular:component": {
134
+ "style": "scss"
135
+ }
136
+ },
137
+ "release": {
138
+ "groups": {
139
+ "libs": {
140
+ "projects": ["libs/*"]
141
+ },
142
+ "apps": {
143
+ "projects": ["apps/*"],
144
+ "changelog": {
145
+ "projectChangelogs": {
146
+ "createRelease": "github"
147
+ }
148
+ }
149
+ }
150
+ },
151
+ "projectsRelationship": "independent",
152
+ "version": {
153
+ "conventionalCommits": true,
154
+ "updateDependents": "always",
155
+ "preVersionCommand": "pnpm nx run-many -t build",
156
+ "manifestRootsToUpdate": [
157
+ "{projectRoot}",
158
+ {
159
+ "path": "{projectRoot}/dist",
160
+ "preserveLocalDependencyProtocols": false
161
+ }
162
+ ]
163
+ },
164
+ "releaseTag": {
165
+ "pattern": "{projectName}@{version}"
166
+ },
167
+ "changelog": {
168
+ "projectChangelogs": true
169
+ }
170
+ },
171
+ "sync": {
172
+ "applyChanges": false
173
+ }
174
+ }
package/package.json CHANGED
@@ -1,40 +1,43 @@
1
1
  {
2
2
  "name": "@impactor/nx-manager",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "NX generators and executors",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "publishConfig": {
8
- "access": "public"
8
+ "access": "public",
9
+ "linkDirectory": false
9
10
  },
10
11
  "nx": {
11
12
  "projectType": "library",
12
13
  "targets": {
13
- "build": {},
14
- "semantic-release": {}
14
+ "build": {}
15
15
  }
16
16
  },
17
+ "imports": {
18
+ "#*": "./src/*"
19
+ },
17
20
  "exports": {
18
21
  ".": {
19
22
  "types": "./index.d.js",
20
23
  "default": "./index.js"
21
24
  },
25
+ "./*": {
26
+ "types": "./src/*",
27
+ "default": "./src/*"
28
+ },
22
29
  "./package.json": {
23
30
  "default": "./package.json"
24
31
  },
25
- "./*": "./src/*"
32
+ "./executors.json": "./executors.json"
26
33
  },
27
- "files": [
28
- "dist",
29
- "!**/*.tsbuildinfo",
30
- "executors.json"
31
- ],
34
+ "types": "./index.d.ts",
35
+ "main": "./index.js",
32
36
  "dependencies": {
33
37
  "@nx/angular": "22.3.3",
34
- "@nx/devkit": "22.3.3",
35
- "@nx/esbuild": "22.3.3",
36
- "tslib": "^2.8.1",
37
- "@impactor/nodejs": "3.0.2"
38
+ "@nx/devkit": "22.4.5",
39
+ "@nx/esbuild": "22.4.5",
40
+ "tslib": "^2.8.1"
38
41
  },
39
42
  "executors": "./executors.json",
40
43
  "devDependencies": {
@@ -0,0 +1,16 @@
1
+ import { type ExecutorContext } from '@nx/devkit';
2
+ import type { IBuildAngularAppOptions, IBuildAngularLibraryOptions, IBuildAngularNormalizedOptions, IBuildAngularOptions } from '../types/builder-options.js';
3
+ export default function build(options: IBuildAngularOptions, ctx: ExecutorContext): Promise<{
4
+ success: boolean;
5
+ }>;
6
+ export declare function buildAngularLibrary(options: IBuildAngularNormalizedOptions, ctx: ExecutorContext): Promise<{
7
+ success: boolean;
8
+ }>;
9
+ export declare function buildAngularApp(options: IBuildAngularNormalizedOptions, ctx: ExecutorContext): Promise<{
10
+ success: boolean;
11
+ }>;
12
+ export declare function getOptions(options: IBuildAngularOptions, _ctx: ExecutorContext): Promise<IBuildAngularNormalizedOptions>;
13
+ export declare function getLibraryOptions(options: IBuildAngularNormalizedOptions, _ctx: ExecutorContext): IBuildAngularLibraryOptions;
14
+ export declare function getAppOptions(options: IBuildAngularNormalizedOptions, _ctx: ExecutorContext): IBuildAngularAppOptions & {
15
+ tsConfig: string;
16
+ };
@@ -0,0 +1,123 @@
1
+ import { packageExecutor } from "@nx/angular/src/executors/package/package.impl";
2
+ import applicationExecutor from "@nx/angular/src/executors/application/application.impl";
3
+ import { getTsConfigFile } from "../utils/get-tsconfig-file";
4
+ import { relative } from "node:path";
5
+ import { readJSON } from "../utils/fs";
6
+ async function build(options, ctx) {
7
+ let opts = await getOptions(options, ctx);
8
+ if (opts.projectType === "library") return buildAngularLibrary(opts, ctx);
9
+ if (opts.projectType === "application") return buildAngularApp(opts, ctx);
10
+ return { success: false };
11
+ }
12
+ async function buildAngularLibrary(options, ctx) {
13
+ let opts = getLibraryOptions(options, ctx);
14
+ let results = await packageExecutor(opts, ctx);
15
+ for await (let result of results) {
16
+ if (!result.success) return { success: false };
17
+ }
18
+ return { success: true };
19
+ }
20
+ async function buildAngularApp(options, ctx) {
21
+ let opts = getAppOptions(options, ctx);
22
+ if (opts.outputMode) {
23
+ console.warn(
24
+ `The option outputMode is currently not supported, it will be ignored`
25
+ );
26
+ delete opts.outputMode;
27
+ }
28
+ if (opts.ssr && typeof opts.ssr !== "boolean") {
29
+ console.warn(
30
+ `The option ssr curently support boolean values only, it'll considered as true`
31
+ );
32
+ opts.ssr = true;
33
+ }
34
+ let results = await applicationExecutor(opts, ctx);
35
+ for await (let result of results) {
36
+ if (!result.success) return { success: false };
37
+ }
38
+ return { success: true };
39
+ }
40
+ async function getOptions(options, _ctx) {
41
+ let opts = { ...options };
42
+ if (!opts.angularConfigs) {
43
+ opts.angularConfigs = readJSON(
44
+ `${opts.projectPath}/angular.json`
45
+ );
46
+ }
47
+ opts.projectType = opts.projectType || opts.projectConfig.projectType || // todo: remove the scope part from the projectName i.e. @scope/name -> name
48
+ // @ts-ignore
49
+ opts.angularConfigs?.projects?.[opts.projectName]?.projectType;
50
+ if (!opts.projectType) {
51
+ throw new Error(`projectType is not provided`);
52
+ }
53
+ if (!["library", "application"].includes(opts.projectType)) {
54
+ throw new Error(
55
+ `projectType ${opts.projectType} is not supported. supported values are "library","application"`
56
+ );
57
+ }
58
+ let tsConfig = (
59
+ // todo: remove `./`
60
+ opts.tsConfig || opts.angularConfigs?.projects?.[opts.projectName]?.tsConfig || getTsConfigFile(opts)
61
+ );
62
+ let relativeProjectPath = relative(opts.root, opts.projectPath);
63
+ opts.tsConfig = `${relativeProjectPath}/${tsConfig}`;
64
+ let buildOptions = (
65
+ // @ts-ignore
66
+ opts.angularConfigs?.projects?.[opts.projectName]?.architect?.build?.options
67
+ );
68
+ if (buildOptions) {
69
+ let properties = [
70
+ "root",
71
+ "sourceRoot",
72
+ "index",
73
+ "browser",
74
+ "assets",
75
+ "styles",
76
+ "scripts",
77
+ "server",
78
+ "serviceWorker",
79
+ "outputPath",
80
+ "tsConfig"
81
+ // 'serviceWorker',
82
+ ];
83
+ for (let prop of properties) {
84
+ if (typeof buildOptions[prop] === "string") {
85
+ buildOptions[prop] = `${relativeProjectPath}/${buildOptions[prop]}`;
86
+ } else if (Array.isArray(buildOptions[prop])) {
87
+ buildOptions[prop] = buildOptions[prop]?.map(
88
+ (el) => {
89
+ return typeof el === "string" ? `${relativeProjectPath}/${el}` : { ...el, input: `${relativeProjectPath}/${el.input}` };
90
+ }
91
+ );
92
+ }
93
+ }
94
+ if (buildOptions.ssr?.entry) {
95
+ buildOptions.ssr.entry = `${relativeProjectPath}/${buildOptions.ssr.entry}`;
96
+ }
97
+ }
98
+ opts = {
99
+ ...buildOptions,
100
+ ...opts
101
+ };
102
+ return opts;
103
+ }
104
+ function getLibraryOptions(options, _ctx) {
105
+ let opts = {
106
+ // todo: only if exists
107
+ project: `${options.projectPath}/ng-package.json`,
108
+ ...options
109
+ };
110
+ return opts;
111
+ }
112
+ function getAppOptions(options, _ctx) {
113
+ let opts = { ...options };
114
+ return opts;
115
+ }
116
+ export {
117
+ buildAngularApp,
118
+ buildAngularLibrary,
119
+ build as default,
120
+ getAppOptions,
121
+ getLibraryOptions,
122
+ getOptions
123
+ };
@@ -0,0 +1,45 @@
1
+ import { type EsBuildExecutorOptions } from '@nx/esbuild/src/executors/esbuild/schema.js';
2
+ import { type IBuildEsbuildOptions } from '../types/builder-options.js';
3
+ import { type ExecutorContext } from '@nx/devkit';
4
+ export default function build(options: IBuildEsbuildOptions, ctx: ExecutorContext): Promise<{
5
+ success: boolean;
6
+ }>;
7
+ export declare function getTargetOptions(opts: IBuildEsbuildOptions, ctx: ExecutorContext): Promise<{
8
+ tsConfig?: EsBuildExecutorOptions["tsConfig"];
9
+ esbuildConfigFile?: string;
10
+ esbuildOptions?: import("~~node_modules/esbuild/lib/main.js").BuildOptions;
11
+ builder: import("../types/builder.js").Builder;
12
+ projectName: string;
13
+ projectPath: string;
14
+ projectConfig: import("@nx/devkit").ProjectConfiguration;
15
+ flags: string[];
16
+ root: string;
17
+ outDir?: string;
18
+ postBuild?: boolean | string;
19
+ forceRnDefaultPostBuild?: true;
20
+ mode?: "development" | "production";
21
+ cwd?: string;
22
+ additionalEntryPoints?: string[] | undefined;
23
+ assets: (import("~~node_modules/@nx/js/src/utils/assets/assets.js").AssetGlob | string)[];
24
+ bundle?: boolean | undefined;
25
+ declaration?: boolean | undefined;
26
+ declarationRootDir?: string | undefined;
27
+ deleteOutputPath?: boolean | undefined;
28
+ esbuildConfig?: string | undefined;
29
+ external?: string[] | undefined;
30
+ excludeFromExternal?: string[] | undefined;
31
+ format?: Array<"esm" | "cjs"> | undefined;
32
+ generatePackageJson?: boolean | undefined;
33
+ main?: string | undefined;
34
+ metafile?: boolean | undefined;
35
+ minify?: boolean | undefined;
36
+ outputFileName?: string | undefined;
37
+ outputHashing?: "none" | "all" | undefined;
38
+ outputPath?: string | undefined;
39
+ platform?: "node" | "browser" | "neutral" | undefined;
40
+ sourcemap?: boolean | "linked" | "inline" | "external" | "both" | undefined;
41
+ skipTypeCheck?: boolean | undefined;
42
+ target?: string | undefined;
43
+ thirdParty?: boolean | undefined;
44
+ watch?: boolean | undefined;
45
+ }>;
@@ -0,0 +1,63 @@
1
+ import { esbuildExecutor } from "@nx/esbuild/src/executors/esbuild/esbuild.impl.js";
2
+ import { existsSync } from "node:fs";
3
+ import { getTsConfigFile } from "../utils/get-tsconfig-file";
4
+ async function build(options, ctx) {
5
+ let opts = await getTargetOptions(options, ctx);
6
+ ctx.target = ctx.target || {};
7
+ ctx.target.options.outputPath = opts.outputPath;
8
+ let results = esbuildExecutor(opts, ctx);
9
+ for await (let result of results) {
10
+ if (!result.success) return { success: false };
11
+ }
12
+ return { success: true };
13
+ }
14
+ async function getTargetOptions(opts, ctx) {
15
+ if (!opts.esbuildOptions && !opts.esbuildConfig) {
16
+ if (!opts.esbuildConfigFile) {
17
+ if (existsSync(`${opts.projectPath}/esbuild.config.ts`)) {
18
+ opts.esbuildConfigFile = `${opts.projectPath}/esbuild.config.ts`;
19
+ } else if (existsSync(`${ctx.root}/esbuild.config.ts`)) {
20
+ opts.esbuildConfigFile = `${ctx.root}/esbuild.config.ts`;
21
+ }
22
+ }
23
+ if (!opts.tsConfig) {
24
+ opts.tsConfig = `${getTsConfigFile(opts)}`;
25
+ }
26
+ if (opts.esbuildConfigFile) {
27
+ opts.esbuildOptions = await import(opts.esbuildConfigFile).then(
28
+ (m) => m.default({
29
+ projectRoot: opts.projectPath,
30
+ tsconfig: `${opts.projectPath}/${opts.tsConfig}`
31
+ })
32
+ );
33
+ }
34
+ }
35
+ if (!opts.outputPath) {
36
+ opts.outputPath = opts.esbuildOptions?.outdir || "dist";
37
+ }
38
+ if (!opts.main) {
39
+ if (Array.isArray(opts.esbuildOptions?.entryPoints) && opts.esbuildOptions.entryPoints.length > 0 && opts.esbuildOptions.entryPoints.every((el) => typeof el === "string")) {
40
+ [opts.main, ...opts.additionalEntryPoints] = opts.esbuildOptions.entryPoints;
41
+ } else if (existsSync(`${opts.projectPath}/index.ts`)) {
42
+ opts.main = `${opts.projectPath}/index.ts`;
43
+ } else if (existsSync(`${opts.projectPath}/src/index.ts`)) {
44
+ opts.main = `${opts.projectPath}/src/index.ts`;
45
+ } else {
46
+ throw new Error(
47
+ `[universal-builder] No entry point found for esbuild. specify options.esbuildOptions.entrypoint or create index.ts or src/index.ts in the project's root dir`
48
+ );
49
+ }
50
+ }
51
+ if (!opts.format) {
52
+ if (opts.esbuildOptions?.format && opts.esbuildOptions.format !== "iife") {
53
+ opts.format = [opts.esbuildOptions.format];
54
+ } else {
55
+ opts.format = ["esm"];
56
+ }
57
+ }
58
+ return { assets: [], ...opts };
59
+ }
60
+ export {
61
+ build as default,
62
+ getTargetOptions
63
+ };
@@ -0,0 +1,6 @@
1
+ import { type ExecutorContext } from '@nx/devkit';
2
+ import type { IBuilderNestOptions } from '../types/builder-options.js';
3
+ export default function build(options: IBuilderNestOptions, ctx: ExecutorContext): Promise<{
4
+ success: boolean;
5
+ }>;
6
+ export declare function getOptions(options: IBuilderNestOptions, _ctx: ExecutorContext): IBuilderNestOptions;
@@ -0,0 +1,54 @@
1
+ import { existsSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { exec } from "../utils/exec";
4
+ async function build(options, ctx) {
5
+ let opts = getOptions(options, ctx);
6
+ let flags = ["@nestjs/cli", "build", ...opts.flags];
7
+ if (!flags.includes("--path") && !flags.includes("-p") && opts.tsConfig) {
8
+ flags.push("-p", opts.tsConfig);
9
+ }
10
+ if (opts.bundler) {
11
+ if (["tsc", "webpack"].includes(opts.bundler) && !flags.includes(`--${opts.bundler}`)) {
12
+ flags.push(`--${opts.bundler}`);
13
+ } else if (!flags.includes("--builder") && !flags.includes("-b")) {
14
+ flags.push("-b", opts.bundler);
15
+ }
16
+ }
17
+ if (!flags.includes("--config") && !flags.includes("-c") && opts.configFile) {
18
+ flags.push("-c", opts.configFile);
19
+ }
20
+ if (opts.typeCheck) {
21
+ flags.push("--type-check");
22
+ }
23
+ if (opts.watch && !flags.includes("--watch") && !flags.includes("-w")) {
24
+ flags.push("-w");
25
+ }
26
+ if (opts.watch && !flags.includes("--watchAssets")) {
27
+ flags.push("--watchAssets");
28
+ }
29
+ if (opts.webpackPath && !flags.includes("--webpackPath")) {
30
+ flags.push("--webpackPath", opts.webpackPath);
31
+ }
32
+ if (opts.webpackPath && !flags.includes("--preserveWatchOutput")) {
33
+ flags.push("--preserveWatchOutput", opts.webpackPath);
34
+ }
35
+ await exec("npx", flags, opts.projectPath);
36
+ return { success: true };
37
+ }
38
+ function getOptions(options, _ctx) {
39
+ let opts = { ...options };
40
+ if (!opts.bundler && !opts.flags.includes("--builder") && !opts.flags.includes("-b") && existsSync(resolve(`${opts.projectPath}/.swcrc`))) {
41
+ console.info(
42
+ `[universal-builder] SWC config file is detected, building using SWC`
43
+ );
44
+ opts.bundler = "swc";
45
+ if (!opts.configFile && !opts.flags.includes("--config") && !opts.flags.includes("-c")) {
46
+ opts.configFile = ".swcrc";
47
+ }
48
+ }
49
+ return opts;
50
+ }
51
+ export {
52
+ build as default,
53
+ getOptions
54
+ };
@@ -0,0 +1,2 @@
1
+ import { IBuilderBaseOptions } from './types/builder-options.js';
2
+ export default function postBuild(options: IBuilderBaseOptions): void;
@@ -0,0 +1,95 @@
1
+ import { copyFileSync, existsSync, readdirSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { readJSON, writeJSON } from "./utils/fs";
4
+ function postBuild(options) {
5
+ console.info(
6
+ `[universal-builder] running the default post-build script. to skip use options.postBuild=false`
7
+ );
8
+ let opts = {
9
+ ...options
10
+ };
11
+ let pkg = readJSON(`${opts.projectPath}/package.json`) || {}, distPkg = existsSync(`${opts.projectPath}/dist/package.json`) ? readJSON(`${opts.projectPath}/dist/package.json`) : pkg, rootPkg = readJSON(`${opts.root}/package.json`) || {}, dist = `${opts.projectPath}/${opts.outDir || "dist"}`;
12
+ if (!existsSync(dist)) {
13
+ throw new Error(
14
+ `[universal-builder] "${dist}" doesn't exist, be sure the app is built. if you're using a custom output dir, provide options.outDir`
15
+ );
16
+ }
17
+ for (let property of [
18
+ "engines",
19
+ "packageManager",
20
+ "repository",
21
+ "author",
22
+ "homepage",
23
+ "bugs",
24
+ "license",
25
+ "contributors",
26
+ "funding",
27
+ // `add pnpm.overrides` to override deps when installing in the server
28
+ "pnpm"
29
+ ]) {
30
+ if (!distPkg[property]) {
31
+ if (pkg[property]) distPkg[property] = pkg[property];
32
+ else if (rootPkg[property]) distPkg[property] = rootPkg[property];
33
+ }
34
+ }
35
+ if (!distPkg.exports) {
36
+ distPkg.exports = {};
37
+ }
38
+ if (!distPkg.exports["./package.json"]) {
39
+ distPkg.exports["./package.json"] = "./package.json";
40
+ }
41
+ if (distPkg.exports["."]) {
42
+ if (typeof distPkg.exports["."] === "string") {
43
+ distPkg.exports["."] = distPkg.exports["."].replace(/\.ts$/, ".js");
44
+ } else {
45
+ for (let key in distPkg.exports["."]) {
46
+ distPkg.exports["."][key] = distPkg.exports["."][key].replace(
47
+ /\.ts$/,
48
+ ".js"
49
+ );
50
+ }
51
+ }
52
+ } else {
53
+ distPkg.exports["."] = {
54
+ types: "./index.d.ts",
55
+ default: "./index.js"
56
+ };
57
+ }
58
+ if (!distPkg.exports["./*"]) {
59
+ distPkg.exports["./*"] = existsSync(`${dist}/src`) ? "./src/*" : "./*";
60
+ }
61
+ writeJSON(`${dist}/package.json`, distPkg);
62
+ ["package-lock.json", "pnpm-lock.yaml", "yarn.lock"].map((el) => {
63
+ let path = resolve(`${opts.root}/${el}`);
64
+ if (existsSync(path)) {
65
+ copyFileSync(path, resolve(`${dist}/${el}`));
66
+ }
67
+ });
68
+ readdirSync(opts.projectPath).filter(
69
+ (el) => (
70
+ // matches `.env` and `.env.*`
71
+ /^\.env($|\..+)/.test(el)
72
+ )
73
+ ).map((el) => copyFileSync(`${opts.projectPath}/${el}`, `${dist}/${el}`));
74
+ ["README.md"].map((file) => {
75
+ if (existsSync(`${opts.projectPath}/${file}`)) {
76
+ copyFileSync(`${opts.projectPath}/${file}`, `${dist}/${file}`);
77
+ }
78
+ });
79
+ if (existsSync(`${opts.projectPath}/project.json`)) {
80
+ copyFileSync(`${opts.projectPath}/project.json`, `${dist}/project.json`);
81
+ }
82
+ if (existsSync(`${opts.root}/nx.json`)) {
83
+ copyFileSync(`${opts.root}/nx.json`, `${dist}/nx.json`);
84
+ }
85
+ if (!existsSync(`${dist}/main.js`)) {
86
+ if (existsSync(`${dist}/server/server.mjs`)) {
87
+ writeFileSync(`${dist}/main.js`, `import "./server/server.mjs"`);
88
+ } else if (existsSync(`${dist}/server/server.js`)) {
89
+ writeFileSync(`${dist}/main.js`, `import "./server/server.js"`);
90
+ }
91
+ }
92
+ }
93
+ export {
94
+ postBuild as default
95
+ };
File without changes
@@ -0,0 +1,44 @@
1
+ import { ProjectConfiguration } from 'nx/src/devkit-exports.js';
2
+ import { UniversalBuilderExecutorSchema } from '../schema.js';
3
+ import { type Builder } from './builder.js';
4
+ import { type BuildOptions } from 'esbuild';
5
+ import type { BuildAngularLibraryExecutorOptions } from '@nx/angular/src/executors/package/schema';
6
+ import type { ApplicationExecutorOptions } from '@nx/angular/src/executors/application/schema';
7
+ import type { EsBuildExecutorOptions } from '@nx/esbuild/src/executors/esbuild/schema.js';
8
+ export type IBuilderOptions = IBuildEsbuildOptions | IBuildAngularOptions | IBuilderNestOptions;
9
+ export interface IBuilderBaseOptions extends UniversalBuilderExecutorSchema {
10
+ builder: Builder;
11
+ projectName: string;
12
+ projectPath: string;
13
+ projectConfig: ProjectConfiguration;
14
+ flags: string[];
15
+ root: string;
16
+ }
17
+ export interface IBuildEsbuildOptions extends IBuilderBaseOptions, Partial<EsBuildExecutorOptions> {
18
+ tsConfig?: EsBuildExecutorOptions['tsConfig'];
19
+ esbuildConfigFile?: string;
20
+ esbuildOptions?: BuildOptions;
21
+ }
22
+ export interface IBuildAngularBaseOptions extends IBuilderBaseOptions {
23
+ projectType?: 'application' | 'library';
24
+ tsConfig?: string;
25
+ angularConfigs?: Record<string, unknown>;
26
+ }
27
+ export interface IBuildAngularLibraryOptions extends IBuildAngularBaseOptions, BuildAngularLibraryExecutorOptions {
28
+ }
29
+ export interface IBuildAngularAppOptions extends IBuildAngularBaseOptions, Omit<ApplicationExecutorOptions, 'tsConfig'> {
30
+ }
31
+ export type IBuildAngularOptions = IBuildAngularLibraryOptions | IBuildAngularAppOptions;
32
+ export type IBuildAngularNormalizedOptions = IBuildAngularOptions & {
33
+ tsConfig: string;
34
+ };
35
+ export interface IBuilderNestOptions extends IBuilderBaseOptions {
36
+ bundler?: 'swc' | 'webpack' | 'tsc';
37
+ configFile?: string;
38
+ typeCheck?: boolean;
39
+ tsConfig?: string;
40
+ watch?: boolean;
41
+ watchAssets?: boolean;
42
+ webpackPath?: string;
43
+ preserveWatchOutput?: boolean;
44
+ }
@@ -0,0 +1 @@
1
+ export type Builder = 'tsc' | 'esbuild' | 'webpack' | 'angular' | 'nest';
@@ -0,0 +1,64 @@
1
+ export interface IPackage {
2
+ name?: string;
3
+ description?: string;
4
+ version?: string;
5
+ type?: 'module' | 'commonjs';
6
+ workspaces?: string[];
7
+ private?: boolean;
8
+ engines: {
9
+ node?: string;
10
+ [key: string]: unknown;
11
+ };
12
+ packageManager?: string;
13
+ scripts?: {
14
+ [key: string]: string;
15
+ };
16
+ imports?: {
17
+ [key: string]: string | {
18
+ [key: string]: string;
19
+ };
20
+ };
21
+ exports?: {
22
+ [key: string]: string | {
23
+ [key: string]: string;
24
+ };
25
+ };
26
+ dependencies?: {
27
+ [key: string]: string;
28
+ };
29
+ devDependencies?: {
30
+ [key: string]: string;
31
+ };
32
+ peerDependencies?: {
33
+ [key: string]: string;
34
+ };
35
+ optionalDependencies?: {
36
+ [key: string]: string;
37
+ };
38
+ keywords?: string[];
39
+ repository: string | {
40
+ type?: string;
41
+ url?: string;
42
+ [key: string]: unknown;
43
+ };
44
+ homepage?: string;
45
+ bugs: {
46
+ url?: string;
47
+ email?: string;
48
+ };
49
+ license?: string;
50
+ author?: string;
51
+ contributors?: string[];
52
+ funding?: [
53
+ {
54
+ type?: string;
55
+ url?: string;
56
+ }
57
+ ];
58
+ pnpm?: {
59
+ overrides?: {
60
+ [key: string]: string;
61
+ };
62
+ };
63
+ [key: string]: unknown;
64
+ }
@@ -0,0 +1,6 @@
1
+ import { type ExecutorContext, type PromiseExecutor } from '@nx/devkit';
2
+ import type { UniversalBuilderExecutorSchema } from './schema.js';
3
+ import type { IBuilderOptions } from './types/builder-options.js';
4
+ declare const run: PromiseExecutor<UniversalBuilderExecutorSchema>;
5
+ export default run;
6
+ export declare function getOptions(options: UniversalBuilderExecutorSchema, ctx: ExecutorContext): IBuilderOptions;
@@ -0,0 +1,119 @@
1
+ import {
2
+ joinPathFragments
3
+ } from "@nx/devkit";
4
+ import {
5
+ detectProjectType
6
+ } from "./utils/detect-project-type";
7
+ import buildESBuild from "./builders/esbuild";
8
+ import buildAngular from "./builders/angular";
9
+ import buildNest from "./builders/nest";
10
+ import { exec } from "./utils/exec";
11
+ import { readFileSync } from "node:fs";
12
+ const run = async (options, ctx) => {
13
+ let opts = getOptions(options, ctx);
14
+ console.info(`[universal-builder] building using builder: ${opts.builder}`);
15
+ let result;
16
+ let originalCwd = process.cwd();
17
+ if (opts.cwd && opts.cwd !== originalCwd) {
18
+ console.info(
19
+ `[universal-builder] changing CWD from ${originalCwd} to ${opts.cwd}`
20
+ );
21
+ process.chdir(opts.cwd);
22
+ }
23
+ if (opts.builder === "angular") {
24
+ result = await buildAngular(opts, ctx);
25
+ } else if (opts.builder === "nest") {
26
+ result = await buildNest(opts, ctx);
27
+ } else if (opts.builder === "esbuild") {
28
+ result = await buildESBuild(opts, ctx);
29
+ } else if (opts.builder === "webpack") {
30
+ throw new Error(
31
+ `[universal-builder] webpack builder has not implemented yet!`
32
+ );
33
+ } else {
34
+ throw new Error(
35
+ `[universal-builder] invalid or not supported builder ${opts.builder}`
36
+ );
37
+ }
38
+ if (!result.success) return result;
39
+ if (opts.postBuild) {
40
+ console.info(`[universal-builder] executing postbuild`, opts.postBuild);
41
+ if (Array.isArray(opts.postBuild)) {
42
+ await exec(opts.postBuild[0], opts.postBuild[1]);
43
+ } else {
44
+ }
45
+ } else if (options.postBuild !== false) {
46
+ if (opts.forceRnDefaultPostBuild) {
47
+ await import("./post-build").then((m) => m.default(opts));
48
+ }
49
+ console.info(
50
+ `[universal-builder] executing the script postbuild (if exists)`
51
+ );
52
+ let pkg = JSON.parse(
53
+ readFileSync(`${opts.projectPath}/package.json`, "utf8")
54
+ );
55
+ if (pkg.scripts?.postbuild) {
56
+ await exec(
57
+ // todo: detect the package manager (may be NX already provide it with opts)
58
+ "pnpm",
59
+ ["run", "postbuild"],
60
+ // the script should be executed from the project root even if opts.cwd is not specified
61
+ opts.projectPath
62
+ );
63
+ } else if (!opts.forceRnDefaultPostBuild) {
64
+ await import("./post-build").then((m) => m.default(opts));
65
+ }
66
+ }
67
+ if (opts.cwd && opts.cwd !== originalCwd) {
68
+ console.info(
69
+ `[universal-builder] resetting CWD from ${opts.cwd} to ${originalCwd}`
70
+ );
71
+ process.chdir(originalCwd);
72
+ }
73
+ console.info(
74
+ `[universal-builder] building ${opts.projectName} finished successfully`
75
+ );
76
+ return {
77
+ success: true
78
+ };
79
+ };
80
+ var universal_builder_default = run;
81
+ function getOptions(options, ctx) {
82
+ let opts = {
83
+ projectName: ctx.projectName,
84
+ flags: [],
85
+ ...options
86
+ };
87
+ if (!opts.projectName) {
88
+ throw new Error("[universal-builder] projectName is not provided");
89
+ }
90
+ let projectConfig = ctx.projectsConfigurations?.projects[opts.projectName];
91
+ if (!projectConfig) {
92
+ throw new Error(
93
+ `[universal-builder] The project ${opts.projectName} is not existing`
94
+ );
95
+ }
96
+ if (!opts.projectPath) {
97
+ opts.projectPath = joinPathFragments(ctx.root, projectConfig.root);
98
+ }
99
+ if (!opts.projectPath) {
100
+ throw new Error("[universal-builder] projectPath is not provided");
101
+ }
102
+ if (!opts.builder) {
103
+ opts.builder = detectProjectType({
104
+ ...opts,
105
+ root: ctx.root
106
+ });
107
+ }
108
+ if (!opts.builder) {
109
+ throw new Error("[universal-builder] builder is not provided");
110
+ }
111
+ if (!opts.mode) {
112
+ opts.mode = process.env.NODE_MODE || ctx.configurationName || "production";
113
+ }
114
+ return { ...opts, root: ctx.root, projectConfig };
115
+ }
116
+ export {
117
+ universal_builder_default as default,
118
+ getOptions
119
+ };
@@ -0,0 +1,23 @@
1
+ import { describe, it, expect } from "@jest/globals";
2
+ import executor from "./universal-builder";
3
+ const options = {};
4
+ const context = {
5
+ root: "",
6
+ cwd: process.cwd(),
7
+ isVerbose: false,
8
+ projectGraph: {
9
+ nodes: {},
10
+ dependencies: {}
11
+ },
12
+ projectsConfigurations: {
13
+ projects: {},
14
+ version: 2
15
+ },
16
+ nxJsonConfiguration: {}
17
+ };
18
+ describe("UniversalBuilder Executor", () => {
19
+ it("can run", async () => {
20
+ const output = await executor(options, context);
21
+ expect(output.success).toBe(true);
22
+ });
23
+ });
@@ -0,0 +1,7 @@
1
+ import { Builder } from '../types/builder.js';
2
+ export interface IDetectProjectTypeOptions {
3
+ projectPath: string;
4
+ projectName?: string;
5
+ root?: string;
6
+ }
7
+ export declare function detectProjectType(options: IDetectProjectTypeOptions): Builder;
@@ -0,0 +1,21 @@
1
+ import { existsSync } from "node:fs";
2
+ function detectProjectType(options) {
3
+ if (existsSync(`${options.projectPath}/nest-cli.json`)) {
4
+ return "nest";
5
+ } else if (existsSync(`${options.projectPath}/angular.json`)) {
6
+ return "angular";
7
+ } else if (["ng-", "ngx-"].some((prefix) => {
8
+ let pkgName = options.projectName?.match(/(?:@.+\/)?(.+)/)?.[1];
9
+ pkgName?.startsWith(prefix);
10
+ })) {
11
+ return "angular";
12
+ } else if (existsSync(`${options.projectPath}/esbuild.config.ts`) || existsSync(`${options.root}/esbuild.config.ts`)) {
13
+ return "esbuild";
14
+ } else if (existsSync(`${options.projectPath}/webpack.config.js`)) {
15
+ return "webpack";
16
+ } else if (existsSync(`${options.projectPath}/tsconfig.json`)) return "tsc";
17
+ else throw new Error(`cannot detect the project type`);
18
+ }
19
+ export {
20
+ detectProjectType
21
+ };
@@ -0,0 +1 @@
1
+ export declare function exec(cmd: string, args?: string[], cwd?: string): Promise<void>;
@@ -0,0 +1,22 @@
1
+ import { spawn } from "node:child_process";
2
+ function exec(cmd, args = [], cwd) {
3
+ console.info(`[universal-builder] cwd: ${cwd || process.cwd()}`);
4
+ console.info(`[universal-builder] > ${cmd} ${args?.join(" ")}`);
5
+ return new Promise((res, rej) => {
6
+ let childProcess = spawn(cmd, args, {
7
+ shell: true,
8
+ cwd,
9
+ stdio: "inherit"
10
+ });
11
+ childProcess.on("error", (error) => {
12
+ rej(error);
13
+ });
14
+ childProcess.on("exit", (exitCode) => {
15
+ if (exitCode === 0) res();
16
+ else rej(`Process exited with code ${exitCode}`);
17
+ });
18
+ });
19
+ }
20
+ export {
21
+ exec
22
+ };
@@ -0,0 +1,5 @@
1
+ import { PathLike } from 'node:fs';
2
+ export declare function readJSON<R extends Record<string, unknown>>(path: PathLike): R;
3
+ export declare function writeJSON(path: PathLike, data: any): void;
4
+ export declare function cleanJson(content: string): string;
5
+ export declare function getEntriesSync(dir?: string | string[], filter?: ((entry: string) => boolean) | RegExp | 'files' | 'dirs', depth?: number, skip?: ((entry: string) => boolean) | RegExp): Array<string>;
@@ -0,0 +1,92 @@
1
+ import {
2
+ lstatSync,
3
+ mkdirSync,
4
+ readdirSync,
5
+ readFileSync,
6
+ writeFileSync
7
+ } from "node:fs";
8
+ import { dirname, join, resolve } from "node:path";
9
+ function readJSON(path) {
10
+ path = resolve(path.toString());
11
+ let data = readFileSync(path, "utf8");
12
+ return JSON.parse(cleanJson(data));
13
+ }
14
+ function writeJSON(path, data) {
15
+ path = resolve(path.toString());
16
+ mkdirSync(dirname(path), { recursive: true });
17
+ let dataString = JSON.stringify(data, null, 2);
18
+ return writeFileSync(path, dataString);
19
+ }
20
+ function cleanJson(content) {
21
+ if (typeof content !== "string") {
22
+ throw new TypeError(`the content must be a string`);
23
+ }
24
+ let isInsideComment = false;
25
+ let isInsideString = false;
26
+ let offset = 0;
27
+ let result = "";
28
+ for (let index = 0; index < content.length; index++) {
29
+ let currentCharacter = content[index], chars = currentCharacter + content[index + 1];
30
+ if (isInsideComment) {
31
+ if (isInsideComment === "single" && chars === "\r\n" || isInsideComment === "multi" && chars === "*/") {
32
+ isInsideComment = false;
33
+ index++;
34
+ offset = ++index;
35
+ } else if (isInsideComment === "single" && ["\r", "\n"].includes(currentCharacter)) {
36
+ isInsideComment = false;
37
+ offset = ++index;
38
+ }
39
+ } else {
40
+ if (currentCharacter === '"' && !isEscaped(content, index)) {
41
+ isInsideString = !isInsideString;
42
+ }
43
+ if (isInsideString) continue;
44
+ else if (["//", "/*"].includes(chars)) {
45
+ isInsideComment = chars === "//" ? "single" : "multi";
46
+ result += content.slice(offset, index);
47
+ index++;
48
+ }
49
+ }
50
+ }
51
+ return result + content.slice(offset);
52
+ }
53
+ function isEscaped(content, charPosition) {
54
+ let index = charPosition - 1;
55
+ let backslashCount = 0;
56
+ while (content[index] === "\\") {
57
+ index--;
58
+ backslashCount++;
59
+ }
60
+ return Boolean(backslashCount % 2);
61
+ }
62
+ function getEntriesSync(dir = ".", filter, depth, skip) {
63
+ if (Array.isArray(dir)) {
64
+ return dir.flatMap((el) => getEntriesSync(el, filter, depth));
65
+ }
66
+ dir = resolve(dir);
67
+ let filterFunction = filter === "files" ? (entry) => lstatSync(entry).isFile() : filter === "dirs" ? (entry) => lstatSync(entry).isDirectory() : filter instanceof RegExp ? (entry) => filter.test(entry) : typeof filter === "function" ? filter : void 0;
68
+ let skipFunction = skip instanceof RegExp ? (entry) => skip.test(entry) : typeof skip === "function" ? skip : (entry) => ["node_modules", "dist"].includes(entry);
69
+ let entries = readdirSync(dir);
70
+ let result = [];
71
+ for (let entry of entries) {
72
+ let fullPath = join(dir, entry);
73
+ if (!filterFunction || filterFunction?.(fullPath)) {
74
+ result.push(fullPath);
75
+ }
76
+ if ((depth === void 0 || depth > 0) && lstatSync(fullPath).isDirectory() && !skipFunction?.(entry)) {
77
+ let subEntries = getEntriesSync(
78
+ fullPath,
79
+ filterFunction,
80
+ depth === void 0 ? void 0 : depth - 1
81
+ );
82
+ result = [...result, ...subEntries];
83
+ }
84
+ }
85
+ return result;
86
+ }
87
+ export {
88
+ cleanJson,
89
+ getEntriesSync,
90
+ readJSON,
91
+ writeJSON
92
+ };
@@ -0,0 +1,2 @@
1
+ import { IBuilderOptions } from '../types/builder-options.js';
2
+ export declare function getTsConfigFile(options: IBuilderOptions): string;
@@ -0,0 +1,12 @@
1
+ import { existsSync } from "node:fs";
2
+ function getTsConfigFile(options) {
3
+ if (options.tsConfig) return options.tsConfig;
4
+ let files = ["tsconfig.lib.json", "tsconfig.app.json", "tsconfig.json"];
5
+ for (let file of files) {
6
+ if (existsSync(`${options.projectPath}/${file}`)) return file;
7
+ }
8
+ throw new Error(`No tsconfig file is found in the project`);
9
+ }
10
+ export {
11
+ getTsConfigFile
12
+ };