diff --git a/libs/ddd/package.json b/libs/ddd/package.json index 8930d71..7c5def0 100644 --- a/libs/ddd/package.json +++ b/libs/ddd/package.json @@ -1,6 +1,6 @@ { "name": "@angular-architects/ddd", - "version": "19.0.4", + "version": "19.0.6", "license": "MIT", "author": "Manfred Steyer", "description": "Nx plugin for structuring a monorepo with domain driven design", diff --git a/libs/ddd/src/generators/api/index.ts b/libs/ddd/src/generators/api/index.ts index 49a27bb..d37aa31 100644 --- a/libs/ddd/src/generators/api/index.ts +++ b/libs/ddd/src/generators/api/index.ts @@ -4,12 +4,19 @@ import { ApiOptions } from './schema'; import { strings } from '@angular-devkit/core'; import { validateInputs } from '../utils/validate-inputs'; import { deleteDefaultComponent } from '../utils/delete-default-component'; +import { getWorkspaceScope } from '../utils/get-workspace-scope'; export default async function (tree: Tree, options: ApiOptions) { validateInputs(options); - const libName = options.name ? `api-${strings.dasherize(options.name)}` : 'api'; - const libDirectory = options.directory ? strings.dasherize(options.directory) : libName; + const workspaceName = getWorkspaceScope(tree); + + const libName = options.name + ? `api-${strings.dasherize(options.name)}` + : 'api'; + const libDirectory = options.directory + ? strings.dasherize(options.directory) + : libName; const domainName = options.shared ? 'shared' : options.domain; const isPublishableLib = options.type === 'publishable'; @@ -17,22 +24,21 @@ export default async function (tree: Tree, options: ApiOptions) { const finalName = domainName + '-' + libName; const finalDirectory = `libs/${domainName}/${libDirectory}`; + const prefix = strings.dasherize(finalName).split('/').join('-'); + const importPath = `${workspaceName}/${domainName}/${libDirectory}`; + await libraryGenerator(tree, { name: finalName, - prefix: finalName, + prefix: prefix, directory: finalDirectory, tags: `domain:${domainName},domain:${domainName}/${libName},type:api`, publishable: isPublishableLib, buildable: options.type === 'buildable', - importPath: options.importPath, + importPath: options.importPath ?? importPath, standalone: options.standalone, }); - deleteDefaultComponent( - tree, - finalDirectory, - finalName - ); + deleteDefaultComponent(tree, finalDirectory, finalName); console.info( `\nHINT: Don\'t forget to extend the rules in your "eslint.config.js" to allow selected domains to access this API.\nFor this, add the tag domain:${domainName}/${libName} to the respective domains' rule sets.\n ` diff --git a/libs/ddd/src/generators/domain/index.ts b/libs/ddd/src/generators/domain/index.ts index e99d303..68b55b9 100644 --- a/libs/ddd/src/generators/domain/index.ts +++ b/libs/ddd/src/generators/domain/index.ts @@ -52,6 +52,8 @@ function convertToStandaloneApp( } export default async function (tree: Tree, options: DomainOptions) { + const npmScope = getNpmScope(tree); + const appName = strings.dasherize(options.name); const appNameAndDirectory = options.appDirectory ? `apps/${options.appDirectory}/${appName}` @@ -82,14 +84,21 @@ export default async function (tree: Tree, options: DomainOptions) { ); }*/ + const prefix = strings + .dasherize(finalName) + .split('/') + .join('-'); + + const importPath = `${npmScope}/${domainNameAndDirectory}/domain`; + await libraryGenerator(tree, { name: finalName, - prefix: finalName, + prefix: prefix, directory: finalDirectory, tags: `domain:${domainName},type:domain-logic`, publishable: options.type === 'publishable', buildable: options.type === 'buildable', - importPath: options.importPath, + importPath: options.importPath ?? importPath, standalone: options.standalone, }); @@ -122,7 +131,6 @@ export default async function (tree: Tree, options: DomainOptions) { } const wsConfig = readNxJson(tree); - const npmScope = getNpmScope(tree); // const wsConfig = readWorkspaceConfiguration(tree); if (options.addApp && options.standalone) { diff --git a/libs/ddd/src/generators/feature/files/forFeature/__name@dasherize__.component.ts__tmpl__ b/libs/ddd/src/generators/feature/files/forFeature/__name@dasherize__.component.ts__tmpl__ index d0a86b9..7d63fb2 100644 --- a/libs/ddd/src/generators/feature/files/forFeature/__name@dasherize__.component.ts__tmpl__ +++ b/libs/ddd/src/generators/feature/files/forFeature/__name@dasherize__.component.ts__tmpl__ @@ -5,7 +5,7 @@ import { CommonModule } from '@angular/common'; @Component({ <% if (standalone) { %> standalone: true, imports: [CommonModule], - <% } %>selector: '<%=dasherize(domain)%>-<%=dasherize(name)%>', + <% } %>selector: '<%=dasherize(flatDomain)%>-feature-<%=dasherize(name)%>', templateUrl: './<%=dasherize(name)%>.component.html', styleUrls: ['./<%=dasherize(name)%>.component.scss'] }) diff --git a/libs/ddd/src/generators/feature/files/forFeatureWithNgrx/__name@dasherize__.component.ts__tmpl__ b/libs/ddd/src/generators/feature/files/forFeatureWithNgrx/__name@dasherize__.component.ts__tmpl__ index 28a3e9b..65c7756 100644 --- a/libs/ddd/src/generators/feature/files/forFeatureWithNgrx/__name@dasherize__.component.ts__tmpl__ +++ b/libs/ddd/src/generators/feature/files/forFeatureWithNgrx/__name@dasherize__.component.ts__tmpl__ @@ -5,7 +5,7 @@ import { CommonModule } from '@angular/common'; @Component({ <% if (standalone) { %> standalone: true, imports: [CommonModule], - <% } %>selector: '<%=dasherize(domain)%>-<%=dasherize(name)%>', + <% } %>selector: '<%=dasherize(flatDomain)%>-feature-<%=dasherize(name)%>', templateUrl: './<%=dasherize(name)%>.component.html', styleUrls: ['./<%=dasherize(name)%>.component.scss'] }) diff --git a/libs/ddd/src/generators/feature/index.ts b/libs/ddd/src/generators/feature/index.ts index 95b15c0..bbd3ed8 100644 --- a/libs/ddd/src/generators/feature/index.ts +++ b/libs/ddd/src/generators/feature/index.ts @@ -108,14 +108,21 @@ export default async function (tree: Tree, options: FeatureOptions) { ? `libs/${domainNameAndDirectory}/${featureDirectory}` : `libs/${domainNameAndDirectory}/${featureFolderName}`; + const prefix = strings + .dasherize(finalName) + .split('/') + .join('-'); + + const importPath = `${workspaceName}/${domainNameAndDirectory}/${featureFolderName}`; + await libraryGenerator(tree, { name: finalName, - prefix: finalName, + prefix: prefix, directory: finalDirectory, tags: `domain:${domainName},type:feature`, publishable: options.type === 'publishable', buildable: options.type === 'buildable', - importPath: options.importPath, + importPath: options.importPath ?? importPath, standalone: options.standalone, }); @@ -279,6 +286,9 @@ function generate( featureLibFolderPath: string; } ) { + + const flatDomain = strings.dasherize(options.domain).split('/').join('-'); + const tmpl = ''; const params = { ...strings, @@ -290,6 +300,7 @@ function generate( domainLibFolderPath, featureLibFolderPath, tmpl, + flatDomain }; if (options.ngrx && entityName) { diff --git a/libs/ddd/src/generators/init/index.ts b/libs/ddd/src/generators/init/index.ts index e263279..aa4083a 100644 --- a/libs/ddd/src/generators/init/index.ts +++ b/libs/ddd/src/generators/init/index.ts @@ -1,4 +1,4 @@ -import { Tree } from '@nx/devkit'; +import { formatFiles, Tree } from '@nx/devkit'; import { updateDepConst } from '../utils/update-dep-const'; export default async function (tree: Tree, schema: any) { @@ -53,4 +53,6 @@ export default async function (tree: Tree, schema: any) { onlyDependOnLibsWithTags: ['domain:shared'], }); }); + + await formatFiles(tree); } diff --git a/libs/ddd/src/generators/ui/index.ts b/libs/ddd/src/generators/ui/index.ts index 6021ede..1cff700 100644 --- a/libs/ddd/src/generators/ui/index.ts +++ b/libs/ddd/src/generators/ui/index.ts @@ -4,10 +4,13 @@ import { UiOptions } from './schema'; import { strings } from '@angular-devkit/core'; import { validateInputs } from '../utils/validate-inputs'; import { deleteDefaultComponent } from '../utils/delete-default-component'; +import { getWorkspaceScope } from '../utils/get-workspace-scope'; export default async function (tree: Tree, options: UiOptions) { validateInputs(options); + const workspaceName = getWorkspaceScope(tree); + const libName = `ui-${strings.dasherize(options.name)}`; const libDirectory = options.directory ? strings.dasherize(options.directory) : libName; const domainName = options.shared ? 'shared' : options.domain; @@ -17,14 +20,17 @@ export default async function (tree: Tree, options: UiOptions) { const finalName = domainName + '-' + libName; const finalDirectory = `libs/${domainName}/${libDirectory}`; + const prefix = strings.dasherize(finalName).split('/').join('-'); + const importPath = `${workspaceName}/${domainName}/${libDirectory}`; + await libraryGenerator(tree, { name: finalName, - prefix: finalName, + prefix: prefix, directory: finalDirectory, tags: `domain:${domainName},type:ui`, publishable: isPublishableLib, buildable: options.type === 'buildable', - importPath: options.importPath, + importPath: options.importPath ?? importPath, standalone: options.standalone, }); diff --git a/libs/ddd/src/generators/util/index.ts b/libs/ddd/src/generators/util/index.ts index 694c0f8..395e6bb 100644 --- a/libs/ddd/src/generators/util/index.ts +++ b/libs/ddd/src/generators/util/index.ts @@ -4,10 +4,13 @@ import { UtilOptions } from './schema'; import { strings } from '@angular-devkit/core'; import { validateInputs } from '../utils/validate-inputs'; import { deleteDefaultComponent } from '../utils/delete-default-component'; +import { getWorkspaceScope } from '../utils/get-workspace-scope'; export default async function (tree: Tree, options: UtilOptions) { validateInputs(options); + const workspaceName = getWorkspaceScope(tree); + const libName = `util-${strings.dasherize(options.name)}`; const libDirectory = options.directory ? strings.dasherize(options.directory) : libName; const domainName = options.shared ? 'shared' : options.domain; @@ -17,14 +20,17 @@ export default async function (tree: Tree, options: UtilOptions) { const finalName = domainName + '-' + libName; const finalDirectory = `libs/${domainName}/${libDirectory}`; + const prefix = strings.dasherize(finalName).split('/').join('-'); + const importPath = `${workspaceName}/${domainName}/${libDirectory}`; + await libraryGenerator(tree, { name: finalName, - prefix: finalName, + prefix: prefix, directory: finalDirectory, tags: `domain:${domainName},type:util`, publishable: isPublishableLib, buildable: options.type === 'buildable', - importPath: options.importPath, + importPath: options.importPath ?? importPath, standalone: options.standalone, }); diff --git a/libs/ddd/src/generators/utils/update-dep-const.ts b/libs/ddd/src/generators/utils/update-dep-const.ts index 526e909..c3961b4 100644 --- a/libs/ddd/src/generators/utils/update-dep-const.ts +++ b/libs/ddd/src/generators/utils/update-dep-const.ts @@ -1,22 +1,34 @@ import { Tree } from '@nx/devkit'; import { checkRuleExists } from './check-rule-exists'; +const allowAll = /\s*\{\s*sourceTag:\s*'\*',\s*onlyDependOnLibsWithTags:\s*\['\*'\],?\s*\}\s*,?/; +const depConstraints = /depConstraints:\s*\[\s*/; + + export function updateDepConst( host: Tree, update: (depConst: Array) => void ) { let filePath = 'tslint.json'; - let rule = 'nx-enforce-module-boundaries'; + const rule = 'nx-enforce-module-boundaries'; + let isJson = true; + let newText = ''; if (!host.exists('tslint.json')) { if (host.exists('.eslintrc.json')) { filePath = '.eslintrc.json'; - rule = '@nx/enforce-module-boundaries'; console.info('Found .eslintrc.json'); } else if (host.exists('.eslintrc')) { filePath = '.eslintrc'; - rule = '@nx/enforce-module-boundaries'; - console.info('Did not find .eslintrc.json but found .eslintrc'); + console.info('Found .eslintrc'); + } else if (host.exists('eslint.config.cjs')) { + filePath = 'eslint.config.cjs'; + console.info('Found .eslintrc'); + isJson = false; + } else if (host.exists('eslint.config.mjs')) { + filePath = 'eslint.config.mjs'; + console.info('Found .eslintrc'); + isJson = false; } else { console.info( 'Cannot add linting rules: linting config file does not exist' @@ -26,20 +38,44 @@ export function updateDepConst( } const text = host.read(filePath).toString(); - const json = JSON.parse(text); - let rules = json; - if (rules['overrides']) { - const overrides = rules['overrides']; - rules = overrides.find( - (e) => e.rules && e.rules['@nx/enforce-module-boundaries'] - ); - } - if (!checkRuleExists(filePath, rule, rules)) return; + if (isJson) { + const json = JSON.parse(text); + let rules = json; + if (rules['overrides']) { + const overrides = rules['overrides']; + rules = overrides.find( + (e) => e.rules && e.rules['@nx/enforce-module-boundaries'] + ); + } + + if (!checkRuleExists(filePath, rule, rules)) return; - const depConst = rules['rules'][rule][1]['depConstraints'] as Array; - update(depConst); + const depConst = rules['rules'][rule][1]['depConstraints'] as Array; + update(depConst); + newText = JSON.stringify(json, undefined, 2); + + } + else { + const rules = new Array(); + update(rules); + const code = trim(JSON.stringify(rules, null, 2)) + ','; + newText = text.replace(allowAll, ''); + newText = newText.replace(depConstraints, 'depConstraints: [\n' + code); + } - const newText = JSON.stringify(json, undefined, 2); host.write(filePath, newText); } + +function trim(str: string) { + + if (str.startsWith('[')) { + str = str.substring(1); + } + + if (str.endsWith(']')) { + str = str.substring(0, str.length-1); + } + + return str.trim(); +} diff --git a/update.sh b/update.sh new file mode 100644 index 0000000..bc4beb7 --- /dev/null +++ b/update.sh @@ -0,0 +1,3 @@ +npx nx build ddd +npm unpublish @angular-architects/ddd@19.0.6 -f --registry http://localhost:4873 +npm publish dist/libs/ddd --registry http://localhost:4873