@rxap/plugin-angular 20.0.1-dev.10 → 20.0.1-dev.11

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 (80) hide show
  1. package/.eslintignore +6 -0
  2. package/.eslintrc.json +44 -0
  3. package/CHANGELOG.md +4 -0
  4. package/LICENSE +621 -0
  5. package/README.md.handlebars +115 -0
  6. package/jest.config.ts +11 -0
  7. package/package.json +2 -15
  8. package/project.json +68 -0
  9. package/schematics.yaml +6 -0
  10. package/src/application.ts +124 -0
  11. package/src/executors/check-ng-package/executor.ts +33 -0
  12. package/src/executors/config/executor.ts +74 -0
  13. package/src/executors/i18n/executor.ts +198 -0
  14. package/src/executors/tailwind/executor.ts +34 -0
  15. package/src/generators/convert-to-buildable-library/generator.ts +110 -0
  16. package/src/generators/fix-schematic/generator.ts +103 -0
  17. package/src/generators/fix-schematic/index.ts +5 -0
  18. package/src/generators/init/coerce-nx-json.ts +72 -0
  19. package/src/generators/init/generator.ts +28 -0
  20. package/src/generators/init/index.ts +5 -0
  21. package/src/generators/init/init-workspace.ts +84 -0
  22. package/src/generators/init-application/assert-main-statements.ts +74 -0
  23. package/src/generators/init-application/cleanup.ts +127 -0
  24. package/src/generators/init-application/coerce-app-config.ts +147 -0
  25. package/src/generators/init-application/coerce-environment-files.ts +105 -0
  26. package/src/generators/init-application/coerce-localazy-config-file.ts +26 -0
  27. package/src/generators/init-application/coerce-project.ts +128 -0
  28. package/src/generators/init-application/generate-authentication.ts +122 -0
  29. package/src/generators/init-application/generate-monolithic.spec.ts +45 -0
  30. package/src/generators/init-application/generate-monolithic.ts +57 -0
  31. package/src/generators/init-application/generator.ts +356 -0
  32. package/src/generators/init-application/index.ts +5 -0
  33. package/src/generators/init-application/link-mfe-remote-with-host.ts +60 -0
  34. package/src/generators/init-application/project-i18n-configuration.ts +4 -0
  35. package/src/generators/init-application/update-git-ignore.ts +22 -0
  36. package/src/generators/init-application/update-main-file.ts +118 -0
  37. package/src/generators/init-application/update-project-targets.ts +229 -0
  38. package/src/generators/init-application/update-tags.ts +30 -0
  39. package/src/generators/init-application/update-target-defaults.ts +43 -0
  40. package/src/generators/init-application/update-ts-config.ts +31 -0
  41. package/src/generators/init-component/generator.ts +147 -0
  42. package/src/generators/init-component/index.ts +5 -0
  43. package/src/generators/init-feature/generator.ts +77 -0
  44. package/src/generators/init-feature/index.ts +5 -0
  45. package/src/generators/init-feature-library/generator.ts +82 -0
  46. package/src/generators/init-feature-library/index.ts +5 -0
  47. package/src/generators/init-feature-library/init-project.ts +53 -0
  48. package/src/generators/init-feature-library/init-workspace.ts +10 -0
  49. package/src/generators/init-library/check-if-secondary-entrypoint-include-in-the-ts-config.ts +46 -0
  50. package/src/generators/init-library/cleanup.ts +22 -0
  51. package/src/generators/init-library/coerce-projects.ts +118 -0
  52. package/src/generators/init-library/coerce-tailwind-theme-scss.ts +27 -0
  53. package/src/generators/init-library/extend-angular-specific-eslint.ts +37 -0
  54. package/src/generators/init-library/generator.ts +87 -0
  55. package/src/generators/init-library/has-index-scss.ts +14 -0
  56. package/src/generators/init-library/has-tailwind-config.ts +9 -0
  57. package/src/generators/init-library/index.ts +5 -0
  58. package/src/generators/init-library/init-project.ts +46 -0
  59. package/src/generators/init-library/init-workspace.ts +26 -0
  60. package/src/generators/init-library/is-ng-packagr-project.ts +9 -0
  61. package/src/generators/init-library/ng-package-json.ts +23 -0
  62. package/src/generators/init-library/set-general-target-defaults.ts +36 -0
  63. package/src/generators/init-library/update-package-json.ts +26 -0
  64. package/src/generators/init-library/update-project-ng-package-configuration.ts +51 -0
  65. package/src/generators/init-library/update-ts-config.ts +24 -0
  66. package/src/generators/schematic/generator.ts +179 -0
  67. package/src/generators/schematic/index.ts +5 -0
  68. package/src/i18n.ts +130 -0
  69. package/src/index.ts +3 -0
  70. package/src/lib/angular-version.ts +1 -0
  71. package/src/lib/coerce-cypress-component-testing.ts +113 -0
  72. package/src/lib/coerce-test-setup.ts +60 -0
  73. package/src/library.ts +153 -0
  74. package/src/migrations/update-19-0-0/add-m2-prefix-to-material-scss-functions.ts +32 -0
  75. package/src/migrations/update-19-0-0/migration.ts +283 -0
  76. package/src/test-setup.ts +24 -0
  77. package/tsconfig.json +20 -0
  78. package/tsconfig.lib.json +10 -0
  79. package/tsconfig.spec.json +15 -0
  80. package/tsconfig.typedoc.json +5 -0
@@ -0,0 +1,229 @@
1
+ import {
2
+ ProjectConfiguration,
3
+ Tree,
4
+ } from '@nx/devkit';
5
+ import {
6
+ DeleteEmptyProperties,
7
+ unique,
8
+ } from '@rxap/utilities';
9
+ import {
10
+ CoerceAssets,
11
+ CoerceTarget,
12
+ GetProjectSourceRoot,
13
+ Strategy,
14
+ } from '@rxap/workspace-utilities';
15
+ import { join } from 'path';
16
+ import { ProjectI18nConfiguration } from './project-i18n-configuration';
17
+ import { InitApplicationGeneratorSchema } from './schema';
18
+
19
+ /**
20
+ * Compare two budget strings
21
+ *
22
+ * @param a
23
+ * @param b
24
+ * @returns -1 if a < b, 0 if a === b, 1 if a > b
25
+ */
26
+ function compareBudget(a: string, b: string): -1 | 0 | 1 {
27
+ const aUnit = a.slice(-2);
28
+ const bUnit = b.slice(-2);
29
+ const aNumber = Number(a.slice(0, -2));
30
+ const bNumber = Number(b.slice(0, -2));
31
+ if (aUnit === bUnit) {
32
+ return aNumber < bNumber ? -1 : aNumber > bNumber ? 1 : 0;
33
+ }
34
+ if (aUnit === 'kb') {
35
+ return bUnit === 'mb' ? -1 : 1;
36
+ }
37
+ if (aUnit === 'mb') {
38
+ return bUnit === 'kb' ? 1 : -1;
39
+ }
40
+ return 0;
41
+ }
42
+
43
+ export function updateProjectTargets(
44
+ tree: Tree,
45
+ projectName: string,
46
+ project: ProjectConfiguration & { i18n?: ProjectI18nConfiguration },
47
+ options: InitApplicationGeneratorSchema,
48
+ ) {
49
+ const projectSourceRoot = GetProjectSourceRoot(tree, projectName);
50
+
51
+ project.targets ??= {};
52
+
53
+ if (!project.targets['build']) {
54
+ throw new Error(`The project '${ project.name }' has no build target`);
55
+ }
56
+
57
+ if (!options.skipDocker) {
58
+ if (project.targets['docker']) {
59
+ project.targets['docker'].options ??= {};
60
+ project.targets['docker'].options.dockerfile ??= options.moduleFederation === 'remote' ?
61
+ join(project.sourceRoot!, 'Dockerfile') :
62
+ 'shared/angular/Dockerfile';
63
+ }
64
+ }
65
+
66
+ CoerceTarget(project, 'serve', {
67
+ options: {
68
+ proxyConfig: 'shared/angular/proxy.conf.json',
69
+ },
70
+ }, Strategy.OVERWRITE);
71
+
72
+ if (project.targets['extract-i18n']) {
73
+ if (options.i18n) {
74
+ options.languages ??= [];
75
+ if (options.languages.length === 0) {
76
+ options.languages.push('en');
77
+ }
78
+ project.targets['build'].configurations ??= {};
79
+ if (options.overwrite) {
80
+ project.targets['build'].configurations.production.localize = options.languages;
81
+ } else {
82
+ if (typeof project.targets['build'].configurations.production.localize === 'boolean') {
83
+ project.targets['build'].configurations.production.localize = options.languages;
84
+ }
85
+ project.targets['build'].configurations.production.localize ??= [];
86
+ project.targets['build'].configurations.production.localize.push(...options.languages);
87
+ project.targets['build'].configurations.production.localize
88
+ = project.targets['build'].configurations.production.localize.filter(unique());
89
+ }
90
+ project.i18n ??= {};
91
+ project.i18n.sourceLocale ??= 'en-US';
92
+ project.i18n.locales ??= {};
93
+ for (const language of options.languages) {
94
+ project.i18n.locales[language] ??= {
95
+ translation: `${ project.sourceRoot }/i18n/${ language }.xlf`,
96
+ baseHref: `${ language }/`,
97
+ };
98
+ }
99
+ }
100
+ if (!project.sourceRoot) {
101
+ throw new Error(`The project ${ project.name } has no source root`);
102
+ }
103
+ project.targets['extract-i18n'].options ??= {};
104
+ project.targets['extract-i18n'].options.format = 'xliff2';
105
+ project.targets['extract-i18n'].options.outputPath = join(project.sourceRoot, 'i18n');
106
+ if (options.localazy && options.localazyReadKey) {
107
+ project.targets['localazy-download'] ??= {
108
+ options: DeleteEmptyProperties({
109
+ readKey: options.localazyReadKey,
110
+ }),
111
+ };
112
+ }
113
+ }
114
+ CoerceTarget(project, 'build', {
115
+ options: {
116
+ sourceMap: true,
117
+ },
118
+ configurations: {
119
+ production: {
120
+ fileReplacements: [
121
+ {
122
+ replace: `${ project.sourceRoot }/environments/environment.ts`,
123
+ with: `${ project.sourceRoot }/environments/environment.prod.ts`,
124
+ },
125
+ ],
126
+ },
127
+ },
128
+ }, Strategy.OVERWRITE);
129
+ project.targets['build'].options ??= {};
130
+ project.targets['build'].options.sourceMap = true;
131
+ project.targets['build'].options.assets ??= [];
132
+ project.targets['build'].options.scripts ??= [];
133
+ if (options.moduleFederation !== 'remote') {
134
+ if (!project.targets['build'].options.scripts.includes('node_modules/marked/marked.min.js')) {
135
+ project.targets['build'].options.scripts.push('node_modules/marked/marked.min.js');
136
+ }
137
+ }
138
+ CoerceAssets(project.targets['build'].options.assets, [
139
+ `${projectSourceRoot}/assets`,
140
+ {
141
+ glob: '*',
142
+ input: 'shared/angular/assets/',
143
+ output: '.',
144
+ },
145
+ {
146
+ glob: 'mdi.svg',
147
+ input: './node_modules/@mdi/angular-material',
148
+ output: '.',
149
+ },
150
+ ]);
151
+ // ensure the property polyfills are defined
152
+ project.targets['build'].options.polyfills ??= [];
153
+ if (!Array.isArray(project.targets['build'].options.polyfills)) {
154
+ // ensure the property is an array
155
+ project.targets['build'].options.polyfills = [ 'zone.js' ];
156
+ }
157
+ // always add the localize init polyfill as some rxap components use the i18n directive
158
+ CoerceAssets(project.targets['build'].options.polyfills, [ '@angular/localize/init' ]);
159
+ if (options.serviceWorker) {
160
+ if (!project.sourceRoot) {
161
+ throw new Error(`The project ${ project.name } has no source root`);
162
+ }
163
+ CoerceAssets(project.targets['build'].options.assets, [
164
+ join(project.sourceRoot, 'manifest.webmanifest'),
165
+ ]);
166
+ project.targets['build'].configurations ??= {};
167
+ project.targets['build'].configurations.production ??= {};
168
+ project.targets['build'].configurations.production.serviceWorker = true;
169
+ project.targets['build'].configurations.production.ngswConfigPath ??= 'shared/angular/ngsw-config.json';
170
+ }
171
+ project.targets['build'].configurations ??= {};
172
+ project.targets['build'].configurations.production ??= {};
173
+ project.targets['build'].configurations.production.budgets ??= [];
174
+ const budget = project.targets['build'].configurations.production.budgets.find((b: any) => b.type === 'initial');
175
+ const defaultWarning = '2mb';
176
+ const defaultError = '5mb';
177
+ if (!budget) {
178
+ project.targets['build'].configurations.production.budgets.push({
179
+ type: 'initial',
180
+ maximumWarning: defaultWarning,
181
+ maximumError: defaultError,
182
+ });
183
+ } else {
184
+ if (options.overwrite) {
185
+ budget.maximumWarning = defaultWarning;
186
+ budget.maximumError = defaultError;
187
+ } else {
188
+ if (compareBudget(budget.maximumWarning, defaultWarning) === -1) {
189
+ budget.maximumWarning = defaultWarning;
190
+ }
191
+ if (compareBudget(budget.maximumError, defaultError) === -1) {
192
+ budget.maximumError = defaultError;
193
+ }
194
+ }
195
+ }
196
+
197
+ if (options.incrementalBuild) {
198
+ project.targets['build'].executor = '@nx/angular:webpack-browser';
199
+ project.targets['build'].options.buildLibsFromSource = false;
200
+ CoerceTarget(project, 'serve-static', {
201
+ executor: '@nx/web:file-server',
202
+ options: {
203
+ proxyUrl: 'https://127-0-0-1.nip.io:8443',
204
+ },
205
+ configurations: {
206
+ production: {
207
+ buildTarget: `${ projectName }:build:production`,
208
+ },
209
+ development: {
210
+ buildTarget: `${ projectName }:build:development`,
211
+ },
212
+ },
213
+ });
214
+ }
215
+
216
+ if (options.deploy) {
217
+ switch (options.deploy) {
218
+ case 'web3-storage':
219
+ if (options.i18n) {
220
+ CoerceTarget(project, 'i18n-index-html', {});
221
+ }
222
+ CoerceTarget(project, 'deploy', {
223
+ executor: '@rxap/plugin-web3-storage:deploy',
224
+ outputs: [ 'dist/{projectRoot}/ipfs-cid.txt' ],
225
+ }, Strategy.OVERWRITE);
226
+ break;
227
+ }
228
+ }
229
+ }
@@ -0,0 +1,30 @@
1
+ import { ProjectConfiguration } from '@nx/devkit';
2
+ import { CoerceProjectTags } from '@rxap/workspace-utilities';
3
+ import { InitApplicationGeneratorSchema } from './schema';
4
+
5
+ export function updateTags(project: ProjectConfiguration, options: InitApplicationGeneratorSchema) {
6
+ const tags = [ 'frontend', 'user-interface' ];
7
+
8
+ if (options.i18n) {
9
+ tags.push('i18n');
10
+ }
11
+
12
+ if (options.localazy) {
13
+ tags.push('localazy');
14
+ }
15
+
16
+ if (options.serviceWorker) {
17
+ tags.push('service-worker');
18
+ }
19
+
20
+ if (options.sentry) {
21
+ tags.push('sentry');
22
+ }
23
+
24
+ if (options.moduleFederation) {
25
+ tags.push('module-federation');
26
+ tags.push(`mfe:${ options.moduleFederation }`);
27
+ }
28
+
29
+ CoerceProjectTags(project, tags);
30
+ }
@@ -0,0 +1,43 @@
1
+ import {
2
+ readNxJson,
3
+ Tree,
4
+ updateNxJson,
5
+ } from '@nx/devkit';
6
+ import {
7
+ CoerceTarget,
8
+ CoerceTargetDefaults,
9
+ CoerceTargetDefaultsDependency,
10
+ CoerceTargetDefaultsInput,
11
+ Strategy,
12
+ } from '@rxap/workspace-utilities';
13
+ import { InitApplicationGeneratorSchema } from './schema';
14
+
15
+ export function updateTargetDefaults(tree: Tree, options: InitApplicationGeneratorSchema) {
16
+ const nxJson = readNxJson(tree);
17
+
18
+ if (!nxJson) {
19
+ throw new Error('NxJson not found');
20
+ }
21
+
22
+ CoerceTargetDefaults(nxJson, '@angular-devkit/build-angular:browser', {
23
+ cache: true,
24
+ dependsOn: [ '^index-export', 'index-export', '^build', 'localazy-download' ],
25
+ inputs: [ 'production', '^production' ],
26
+ }, Strategy.OVERWRITE);
27
+
28
+ CoerceTargetDefaults(nxJson, '@nx/angular:webpack-browser', {
29
+ cache: true,
30
+ dependsOn: [ '^index-export', 'index-export', '^build', 'localazy-download' ],
31
+ inputs: [
32
+ 'production',
33
+ '^production',
34
+ {
35
+ 'env': 'NX_MF_DEV_SERVER_STATIC_REMOTES',
36
+ },
37
+ ],
38
+ }, Strategy.OVERWRITE);
39
+
40
+ CoerceTargetDefaultsDependency(nxJson, 'deploy', 'i18n-index-html');
41
+
42
+ updateNxJson(tree, nxJson);
43
+ }
@@ -0,0 +1,31 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import { CoerceArrayItems } from '@rxap/utilities';
3
+ import {
4
+ GetProjectRoot,
5
+ UpdateTsConfigJson,
6
+ } from '@rxap/workspace-utilities';
7
+
8
+ export function updateTsConfig(tree: Tree, projectName: string) {
9
+
10
+ const projectRoot = GetProjectRoot(tree, projectName);
11
+ for (const tsConfigName of [ 'app', 'editor', 'spec' ]) {
12
+ UpdateTsConfigJson(tree, tsConfig => {
13
+ tsConfig.compilerOptions ??= {};
14
+ tsConfig.compilerOptions.types ??= [];
15
+ if (!tsConfig.compilerOptions.types.includes('@angular/localize')) {
16
+ tsConfig.compilerOptions.types.push('@angular/localize');
17
+ }
18
+ if ([ 'app', 'spec' ].includes(tsConfigName)) {
19
+ tsConfig.exclude ??= [];
20
+ CoerceArrayItems(tsConfig.exclude, [
21
+ 'src/**/*.stories.ts',
22
+ 'src/**/*.cy.ts',
23
+ ]);
24
+ }
25
+ }, {
26
+ infix: tsConfigName,
27
+ basePath: projectRoot,
28
+ });
29
+ }
30
+
31
+ }
@@ -0,0 +1,147 @@
1
+ import {
2
+ cypressComponentConfiguration,
3
+ componentGenerator,
4
+ componentStoryGenerator,
5
+ componentTestGenerator,
6
+ } from '@nx/angular/generators';
7
+ import { Tree } from '@nx/devkit';
8
+ import { CoerceDefaultClassExport } from '@rxap/ts-morph';
9
+ import {
10
+ classify,
11
+ dasherize,
12
+ } from '@rxap/utilities';
13
+ import { TsMorphAngularProjectTransform } from '@rxap/workspace-ts-morph';
14
+ import {
15
+ GenerateSerializedSchematicFile,
16
+ GetDefaultGeneratorOptions,
17
+ GetProject,
18
+ GetProjectRoot,
19
+ GetProjectSourceRoot,
20
+ HasTarget,
21
+ IsLibraryProject,
22
+ } from '@rxap/workspace-utilities';
23
+ import {
24
+ join,
25
+ relative,
26
+ } from 'path';
27
+ import { InitComponentGeneratorSchema } from './schema';
28
+ import 'colors';
29
+
30
+ function buildComponentDirectory(tree: Tree, options: InitComponentGeneratorSchema) {
31
+ let directory = GetProjectSourceRoot(tree, options.project);
32
+ if (IsLibraryProject(GetProject(tree, options.project))) {
33
+ directory = join(directory, 'lib');
34
+ } else if (options.feature) {
35
+ directory = join(directory, 'feature', dasherize(options.feature));
36
+ } else {
37
+ directory = join(directory, 'app');
38
+ }
39
+ if (!options.flat) {
40
+ directory = join(directory, dasherize(options.name));
41
+ }
42
+ return directory;
43
+ }
44
+
45
+ function buildRelativePath(tree: Tree, options: InitComponentGeneratorSchema, directory: string) {
46
+ const projectSourceRoot = GetProjectSourceRoot(tree, options.project);
47
+ let relativePath = relative(projectSourceRoot, directory);
48
+ if (IsLibraryProject(GetProject(tree, options.project))) {
49
+ relativePath = relative('lib', relativePath);
50
+ } else if (options.feature) {
51
+ relativePath = relative(join('feature', dasherize(options.feature)), relativePath);
52
+ } else {
53
+ relativePath = relative('app', relativePath);
54
+ }
55
+ return relativePath;
56
+ }
57
+
58
+ export async function initComponentGenerator(
59
+ tree: Tree,
60
+ options: InitComponentGeneratorSchema
61
+ ) {
62
+
63
+ const projectRoot = GetProjectRoot(tree, options.project);
64
+
65
+ const directory = options.directory ?? buildComponentDirectory(tree, options);
66
+ const componentPath = relative(projectRoot, directory);
67
+
68
+ GenerateSerializedSchematicFile(
69
+ tree,
70
+ directory,
71
+ '@rxap/plugin-angular',
72
+ 'init-component',
73
+ options,
74
+ );
75
+
76
+ const defaultOptions = GetDefaultGeneratorOptions(tree, '@nx/angular: component');
77
+ const componentOptions = {
78
+ ...defaultOptions,
79
+ ...options,
80
+ };
81
+
82
+ componentOptions.displayBlock ??= false;
83
+ componentOptions.inlineStyle ??= false;
84
+ componentOptions.standalone ??= true;
85
+ componentOptions.changeDetection ??= 'OnPush';
86
+ componentOptions.skipTests ??= false;
87
+ componentOptions.flat ??= false;
88
+ componentOptions.skipImport ??= false;
89
+ componentOptions.skipSelector ??= false;
90
+ componentOptions.type ??= 'component';
91
+ componentOptions.export ??= false;
92
+ componentOptions.skipFormat ??= false;
93
+ componentOptions.style ??= 'scss';
94
+
95
+ const componentName = classify(componentOptions.name) + 'Component';
96
+ const componentFileName = dasherize(componentOptions.name) + '.component';
97
+
98
+ console.log('Generate component'.cyan);
99
+ console.log('componentName: ' + componentName.magenta);
100
+ console.log('componentFileName: ' + componentFileName.magenta);
101
+ console.log('componentPath: ' + componentPath.magenta);
102
+ console.log('directory: ' + directory.magenta);
103
+
104
+ if (!tree.exists(join(directory, componentFileName + '.ts'))) {
105
+ await componentGenerator(tree, {
106
+ ...componentOptions,
107
+ path: directory,
108
+ });
109
+ }
110
+
111
+ if (!tree.exists(join(directory, componentFileName + '.stories.ts')) && HasTarget(tree, options.project, 'storybook')) {
112
+ console.log('Generate component story'.blue);
113
+ await componentStoryGenerator(tree, {
114
+ projectPath: projectRoot,
115
+ interactionTests: componentOptions.interactionTests,
116
+ componentName,
117
+ componentPath,
118
+ componentFileName,
119
+ skipFormat: componentOptions.skipFormat,
120
+ });
121
+
122
+ }
123
+
124
+ if (!tree.exists(join(directory, componentFileName + '.cy.ts')) && HasTarget(tree, options.project, 'component-test')) {
125
+ console.log('Generate component test'.blue);
126
+ await componentTestGenerator(tree, {
127
+ project: options.project,
128
+ componentName,
129
+ componentDir: componentPath,
130
+ componentFileName,
131
+ skipFormat: componentOptions.skipFormat
132
+ });
133
+ }
134
+
135
+ if (options.defaultExport) {
136
+ TsMorphAngularProjectTransform(tree, {
137
+ project: options.project,
138
+ feature: options.feature,
139
+ directory: buildRelativePath(tree, options, directory),
140
+ }, (_, [sourceFile]) => {
141
+ CoerceDefaultClassExport(sourceFile);
142
+ }, [`${dasherize(options.name)}.component.ts`]);
143
+ }
144
+
145
+ }
146
+
147
+ export default initComponentGenerator;
@@ -0,0 +1,5 @@
1
+ import { convertNxGenerator } from '@nx/devkit';
2
+ import generator from './generator';
3
+
4
+ const schematic = convertNxGenerator(generator);
5
+ export default schematic;
@@ -0,0 +1,77 @@
1
+ import {
2
+ formatFiles,
3
+ Tree,
4
+ } from '@nx/devkit';
5
+ import {
6
+ CoerceAppNavigation,
7
+ CoerceLayoutRoutes,
8
+ CoerceRoutes,
9
+ } from '@rxap/ts-morph';
10
+ import {
11
+ dasherize,
12
+ DeleteProperties,
13
+ } from '@rxap/utilities';
14
+ import { TsMorphAngularProjectTransform } from '@rxap/workspace-ts-morph';
15
+ import {
16
+ GenerateSerializedSchematicFile,
17
+ GetProjectRoot,
18
+ GetProjectSourceRoot,
19
+ } from '@rxap/workspace-utilities';
20
+ import { join } from 'path';
21
+ import { InitFeatureGeneratorSchema } from './schema';
22
+
23
+ export async function initFeatureGenerator(
24
+ tree: Tree,
25
+ options: InitFeatureGeneratorSchema,
26
+ ) {
27
+ options.name = dasherize(options.name);
28
+ console.log('angular init feature generator:', options);
29
+ const projectSourceRoot = GetProjectSourceRoot(tree, options.project);
30
+
31
+ if (!projectSourceRoot) {
32
+ throw new Error(`Project source root not found for project ${ options.project }`);
33
+ }
34
+
35
+ GenerateSerializedSchematicFile(
36
+ tree,
37
+ join(GetProjectRoot(tree, options.project), 'feature', options.name),
38
+ '@rxap/plugin-angular',
39
+ 'init-feature',
40
+ DeleteProperties(options, [ 'project', 'overwrite' ]),
41
+ );
42
+
43
+ TsMorphAngularProjectTransform(tree, {
44
+ project: options.project,
45
+ }, (_, [ layoutSourceFile, featureSourceFile, navigationSourceFile ]) => {
46
+ CoerceRoutes(featureSourceFile);
47
+ CoerceLayoutRoutes(layoutSourceFile, {
48
+ itemList: [
49
+ {
50
+ route: {
51
+ path: options.name,
52
+ loadChildren: '../feature/' + options.name + '/routes',
53
+ },
54
+ component: 'LayoutComponent'
55
+ }
56
+ ],
57
+ withStatusCheckGuard: options.apiStatusCheck,
58
+ });
59
+ if (options.navigation) {
60
+ CoerceAppNavigation(navigationSourceFile, {
61
+ itemList: [{
62
+ routerLink: [ '/', options.name ],
63
+ label: options.navigation.label,
64
+ icon: options.navigation.icon
65
+ }],
66
+ overwrite: options.overwrite,
67
+ });
68
+ }
69
+ }, [ 'app/layout.routes.ts?', `feature/${dasherize(options.name)}/routes.ts?`, 'app/app.navigation.ts?' ]);
70
+
71
+ if (!options.skipFormat) {
72
+ await formatFiles(tree);
73
+ }
74
+
75
+ }
76
+
77
+ export default initFeatureGenerator;
@@ -0,0 +1,5 @@
1
+ import { convertNxGenerator } from '@nx/devkit';
2
+ import generator from './generator';
3
+
4
+ const schematic = convertNxGenerator(generator);
5
+ export default schematic;
@@ -0,0 +1,82 @@
1
+ import {
2
+ formatFiles,
3
+ getProjects,
4
+ ProjectConfiguration,
5
+ Tree,
6
+ } from '@nx/devkit';
7
+ import { CoerceArrayItems } from '@rxap/utilities';
8
+ import {
9
+ GenerateSerializedSchematicFile,
10
+ GetProjectRoot,
11
+ SkipNonAngularProject,
12
+ SkipNonLibraryProject,
13
+ } from '@rxap/workspace-utilities';
14
+ import { initProject } from './init-project';
15
+ import { initWorkspace } from './init-workspace';
16
+ import { InitFeatureLibraryGeneratorSchema } from './schema';
17
+
18
+ function skipProject(tree: Tree, options: InitFeatureLibraryGeneratorSchema, project: ProjectConfiguration, projectName: string) {
19
+
20
+ if (options.project === projectName) {
21
+ return false;
22
+ }
23
+
24
+ if (SkipNonAngularProject(tree, options, project, projectName)) {
25
+ return true;
26
+ }
27
+
28
+ if (SkipNonLibraryProject(tree, options, project, projectName)) {
29
+ return true;
30
+ }
31
+
32
+ if (!project.tags?.includes('feature')) {
33
+ return true;
34
+ }
35
+
36
+ return false;
37
+
38
+ }
39
+
40
+ export async function initFeatureLibraryGenerator(
41
+ tree: Tree,
42
+ options: InitFeatureLibraryGeneratorSchema
43
+ ) {options.project ??= undefined;
44
+ options.projects ??= [];
45
+ if (options.project) {
46
+ CoerceArrayItems(options.projects, [options.project]);
47
+ }
48
+ console.log('angular feature library init generator:', options);
49
+
50
+ await initWorkspace(tree, options);
51
+
52
+ if (!options.skipProjects) {
53
+
54
+ for (const [ projectName, project ] of getProjects(tree).entries()) {
55
+
56
+ if (skipProject(tree, options, project, projectName)) {
57
+ continue;
58
+ }
59
+
60
+ GenerateSerializedSchematicFile(
61
+ tree,
62
+ GetProjectRoot(tree, projectName),
63
+ '@rxap/plugin-angular',
64
+ 'init-feature-library',
65
+ options,
66
+ );
67
+
68
+ await initProject(tree, projectName, project, options);
69
+
70
+ }
71
+
72
+
73
+
74
+ }
75
+
76
+ if (!options.skipFormat) {
77
+ await formatFiles(tree);
78
+ }
79
+
80
+ }
81
+
82
+ export default initFeatureLibraryGenerator;
@@ -0,0 +1,5 @@
1
+ import { convertNxGenerator } from '@nx/devkit';
2
+ import generator from './generator';
3
+
4
+ const schematic = convertNxGenerator(generator);
5
+ export default schematic;