From b4d9b51d2ecbff7b8cca662f89e89a43fb057a70 Mon Sep 17 00:00:00 2001 From: Tim Fabian Date: Sun, 20 Apr 2025 18:53:16 +0200 Subject: [PATCH 1/2] Added angular ui library project, made custom type for getPath --- README.md | 1 - package.json | 2 +- src/__testing__/mock/constants.ts | 60 +++++++++---------- src/__testing__/mock/file-mock.utilities.ts | 9 +-- src/angular/angular.utilities.ts | 46 +++++++------- .../add-angular-library.command.ts | 27 ++++++++- .../add/add-loopback/add-loopback.command.ts | 18 +++--- .../add-ts-library/add-ts-library.command.ts | 4 +- src/commands/init/init.command.ts | 14 ++--- src/commands/version/version.command.ts | 5 +- src/db/db.utilities.ts | 20 +++---- src/docker/docker.utilities.ts | 12 ++-- src/encapsulation/fs.utilities.ts | 46 +++++++------- src/env/env-utilities.test.ts | 4 +- src/env/env.utilities.ts | 14 ++--- src/github/github-utilities.test.ts | 4 +- src/github/github.utilities.ts | 6 +- src/loopback/loopback.utilities.ts | 28 ++++----- src/npm/npm.utilities.ts | 15 ++--- src/robots/robots.utilities.ts | 8 +-- src/storybook/storybook.utilities.ts | 7 ++- src/ts/ts.utilities.ts | 17 +++--- src/tsconfig/tsconfig-utilities.test.ts | 4 +- src/tsconfig/tsconfig.utilities.ts | 10 ++-- src/utilities/get-path.function.ts | 15 ++++- src/workspace/workspace.utilities.ts | 6 +- 26 files changed, 220 insertions(+), 182 deletions(-) diff --git a/README.md b/README.md index 73afbea..6bc26bc 100644 --- a/README.md +++ b/README.md @@ -300,7 +300,6 @@ They will give you a nice overview of all monorepos on your machine and their re ## Angular app ## Angular website ## Angular library -WIP ## LoopBack ## Typescript library ## Wordpress diff --git a/package.json b/package.json index 960610a..3fda527 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "monux-cli", - "version": "2.2.0", + "version": "2.2.1", "license": "MIT", "main": "index.js", "engines": { diff --git a/src/__testing__/mock/constants.ts b/src/__testing__/mock/constants.ts index 1404b34..e403382 100644 --- a/src/__testing__/mock/constants.ts +++ b/src/__testing__/mock/constants.ts @@ -1,61 +1,61 @@ import { ANGULAR_JSON_FILE_NAME, ANGULAR_ROUTES_FILE_NAME, APP_CONFIG_FILE_NAME, APPS_DIRECTORY_NAME, DEV_DOCKER_COMPOSE_FILE_NAME, PROD_DOCKER_COMPOSE_FILE_NAME, ENV_FILE_NAME, ENVIRONMENT_MODEL_TS_FILE_NAME, ENVIRONMENT_TS_FILE_NAME, ESLINT_CONFIG_FILE_NAME, GLOBAL_ENVIRONMENT_MODEL_FILE_NAME, LIBS_DIRECTORY_NAME, PACKAGE_JSON_FILE_NAME, LOCAL_DOCKER_COMPOSE_FILE_NAME } from '../../constants'; import { OmitStrict } from '../../types'; -import { getPath } from '../../utilities'; +import { getPath, Path } from '../../utilities'; // eslint-disable-next-line jsdoc/require-jsdoc export type MockConstants = { // eslint-disable-next-line jsdoc/require-jsdoc - readonly PROJECT_DIR: string, + readonly PROJECT_DIR: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly APPS_DIR: string, + readonly APPS_DIR: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly LIBS_DIR: string, + readonly LIBS_DIR: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly DOCKER_COMPOSE_YAML: string, + readonly DOCKER_COMPOSE_YAML: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly DEV_DOCKER_COMPOSE_YAML: string, + readonly DEV_DOCKER_COMPOSE_YAML: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly LOCAL_DOCKER_COMPOSE_YAML: string, + readonly LOCAL_DOCKER_COMPOSE_YAML: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_ESLINT_CONFIG_MJS: string, + readonly ANGULAR_ESLINT_CONFIG_MJS: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_PACKAGE_JSON: string, + readonly ANGULAR_PACKAGE_JSON: Path, // eslint-disable-next-line jsdoc/require-jsdoc readonly ANGULAR_APP_NAME: string, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_APP_DIR: string, + readonly ANGULAR_APP_DIR: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_APP_COMPONENT_TS: string, + readonly ANGULAR_APP_COMPONENT_TS: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_APP_COMPONENT_HTML: string, + readonly ANGULAR_APP_COMPONENT_HTML: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_APP_ROUTES_TS: string, + readonly ANGULAR_APP_ROUTES_TS: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_ROUTES_TS: string, + readonly ANGULAR_ROUTES_TS: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_APP_CONFIG_TS: string, + readonly ANGULAR_APP_CONFIG_TS: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_JSON: string, + readonly ANGULAR_JSON: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_ENVIRONMENT_MODEL: string, + readonly ANGULAR_ENVIRONMENT_MODEL: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ANGULAR_ENVIRONMENT: string, + readonly ANGULAR_ENVIRONMENT: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly TS_LIBRARY_DIR: string, + readonly TS_LIBRARY_DIR: Path, // eslint-disable-next-line jsdoc/require-jsdoc readonly TS_LIBRARY_SCOPE: string, // eslint-disable-next-line jsdoc/require-jsdoc - readonly TS_LIBRARY_PACKAGE_JSON: string, + readonly TS_LIBRARY_PACKAGE_JSON: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ROOT_PACKAGE_JSON: string, + readonly ROOT_PACKAGE_JSON: Path, // eslint-disable-next-line jsdoc/require-jsdoc readonly TS_LIBRARY_NAME: string, // eslint-disable-next-line jsdoc/require-jsdoc - readonly ENV: string, + readonly ENV: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly GLOBAL_ENV_MODEL: string, + readonly GLOBAL_ENV_MODEL: Path, // eslint-disable-next-line jsdoc/require-jsdoc - readonly GITHUB_WORKFLOW_DIR: string + readonly GITHUB_WORKFLOW_DIR: Path }; // eslint-disable-next-line jsdoc/require-jsdoc @@ -79,14 +79,14 @@ export type DirMockConstants = OmitStrict< * @returns Constant values. */ export function getMockConstants(projectName: string): MockConstants { - const TMP_DIR: string = getPath(__dirname, '..', 'tmp'); - const PROJECT_DIR: string = getPath(TMP_DIR, projectName); - const APPS_DIR: string = getPath(PROJECT_DIR, APPS_DIRECTORY_NAME); - const LIBS_DIR: string = getPath(PROJECT_DIR, LIBS_DIRECTORY_NAME); + const TMP_DIR: Path = getPath(__dirname, '..', 'tmp'); + const PROJECT_DIR: Path = getPath(TMP_DIR, projectName); + const APPS_DIR: Path = getPath(PROJECT_DIR, APPS_DIRECTORY_NAME); + const LIBS_DIR: Path = getPath(PROJECT_DIR, LIBS_DIRECTORY_NAME); const ANGULAR_APP_NAME: string = 'angular'; - const ANGULAR_APP_DIR: string = getPath(APPS_DIR, ANGULAR_APP_NAME); + const ANGULAR_APP_DIR: Path = getPath(APPS_DIR, ANGULAR_APP_NAME); const TS_LIBRARY_NAME: string = 'library'; - const TS_LIBRARY_DIR: string = getPath(LIBS_DIR, TS_LIBRARY_NAME); + const TS_LIBRARY_DIR: Path = getPath(LIBS_DIR, TS_LIBRARY_NAME); const mockConstants: MockConstants = { PROJECT_DIR: PROJECT_DIR, diff --git a/src/__testing__/mock/file-mock.utilities.ts b/src/__testing__/mock/file-mock.utilities.ts index b02a34b..f9fe05a 100644 --- a/src/__testing__/mock/file-mock.utilities.ts +++ b/src/__testing__/mock/file-mock.utilities.ts @@ -4,6 +4,7 @@ import { AngularJson } from '../../angular'; import { CPUtilities, FsUtilities, JsonUtilities } from '../../encapsulation'; import { EnvUtilities } from '../../env'; import { WorkspaceUtilities } from '../../workspace'; +import { getPath } from '../../utilities'; export abstract class FileMockUtilities { @@ -35,7 +36,7 @@ export abstract class FileMockUtilities { filesToMock: (keyof FileMockConstants)[] = [], contentOverrides: Partial> = {} ): Promise { - await FsUtilities.rm(mockConstants.PROJECT_DIR); + await FsUtilities.rm(getPath(mockConstants.PROJECT_DIR)); CPUtilities['cwd'] = mockConstants.PROJECT_DIR; await this.mockFolders(mockConstants); await this.mockFiles(filesToMock, contentOverrides, mockConstants); @@ -52,7 +53,7 @@ export abstract class FileMockUtilities { GITHUB_WORKFLOW_DIR: mockConstants.GITHUB_WORKFLOW_DIR }; for (const entry of Object.values(dirMockConstants)) { - await FsUtilities.mkdir(entry, true, false); + await FsUtilities.mkdir(getPath(entry), true, false); } } @@ -77,14 +78,14 @@ export abstract class FileMockUtilities { content: string | string[] | undefined ): Promise { if (hasContentOverride) { - await FsUtilities.createFile(mockConstants[entry], content ?? '', true, false); + await FsUtilities.createFile(getPath(mockConstants[entry]), content ?? '', true, false); return; } await this.mockMethodForFile[entry](mockConstants, entry); } private static async createEmptyFile(mockConstants: MockConstants, entry: keyof MockConstants): Promise { - await FsUtilities.createFile(mockConstants[entry], '', true, false); + await FsUtilities.createFile(getPath(mockConstants[entry]), '', true, false); } private static async createAngularJson(mockConstants: MockConstants): Promise { diff --git a/src/angular/angular.utilities.ts b/src/angular/angular.utilities.ts index 903d7f6..9e1a195 100644 --- a/src/angular/angular.utilities.ts +++ b/src/angular/angular.utilities.ts @@ -11,7 +11,7 @@ import { ANGULAR_APP_COMPONENT_FILE_NAME, ANGULAR_JSON_FILE_NAME, ANGULAR_ROUTES import { DefaultEnvKeys, EnvUtilities } from '../env'; import { DeepPartial } from '../types'; import { AddNavElementConfig } from './add-nav-element-config.model'; -import { getPath, mergeDeep, optionsToCliString } from '../utilities'; +import { getPath, mergeDeep, optionsToCliString, Path } from '../utilities'; import { NavElementTypes } from './nav-element-types.enum'; import { RobotsUtilities } from '../robots'; import { WorkspaceProject, WorkspaceUtilities } from '../workspace'; @@ -132,7 +132,7 @@ export abstract class AngularUtilities { '}' ] ); - const appComponentPath: string = getPath(root, 'src', 'app', ANGULAR_APP_COMPONENT_FILE_NAME); + const appComponentPath: Path = getPath(root, 'src', 'app', ANGULAR_APP_COMPONENT_FILE_NAME); await TsUtilities.addImportStatements( appComponentPath, [{ defaultImport: false, element: 'LoggerService', path: './services/logger.service' }] @@ -187,7 +187,7 @@ export abstract class AngularUtilities { false, getPath('.') ); - const authServicePath: string = getPath(projectRoot, 'src', 'app', 'services', 'auth.service.ts'); + const authServicePath: Path = getPath(projectRoot, 'src', 'app', 'services', 'auth.service.ts'); await FsUtilities.createFile(authServicePath, authServiceContent); await this.addProvider( projectRoot, @@ -205,7 +205,7 @@ export abstract class AngularUtilities { { defaultImport: false, element: 'environment', path: '../environment/environment' } ] ); - const appConfigPath: string = getPath(projectRoot, 'src', 'app', APP_CONFIG_FILE_NAME); + const appConfigPath: Path = getPath(projectRoot, 'src', 'app', APP_CONFIG_FILE_NAME); await TsUtilities.addImportStatements( appConfigPath, [ @@ -249,9 +249,9 @@ export abstract class AngularUtilities { }, domain ); - const pagesPath: string = getPath(projectRoot, 'src', 'app', 'pages'); - const loginPageTs: string = getPath(pagesPath, 'login', 'login.component.ts'); - const loginPageHtml: string = getPath(pagesPath, 'login', 'login.component.html'); + const pagesPath: Path = getPath(projectRoot, 'src', 'app', 'pages'); + const loginPageTs: Path = getPath(pagesPath, 'login', 'login.component.ts'); + const loginPageHtml: Path = getPath(pagesPath, 'login', 'login.component.html'); await this.addComponentImports( loginPageTs, [{ defaultImport: false, element: 'NgxMatAuthLoginComponent', path: NpmPackage.NGX_MATERIAL_AUTH }] @@ -284,9 +284,9 @@ export abstract class AngularUtilities { }, domain ); - const requestResetPasswordPageTs: string = getPath(pagesPath, 'request-reset-password', 'request-reset-password.component.ts'); + const requestResetPasswordPageTs: Path = getPath(pagesPath, 'request-reset-password', 'request-reset-password.component.ts'); - const requestResetPasswordPageHtml: string = getPath(pagesPath, 'request-reset-password', 'request-reset-password.component.html'); + const requestResetPasswordPageHtml: Path = getPath(pagesPath, 'request-reset-password', 'request-reset-password.component.html'); await this.addComponentImports( requestResetPasswordPageTs, [{ defaultImport: false, element: 'NgxMatAuthRequestResetPasswordComponent', path: NpmPackage.NGX_MATERIAL_AUTH }] @@ -317,9 +317,9 @@ export abstract class AngularUtilities { }, domain ); - const confirmResetPasswordPageTs: string = getPath(pagesPath, 'confirm-reset-password', 'confirm-reset-password.component.ts'); + const confirmResetPasswordPageTs: Path = getPath(pagesPath, 'confirm-reset-password', 'confirm-reset-password.component.ts'); - const confirmResetPasswordPageHtml: string = getPath(pagesPath, 'confirm-reset-password', 'confirm-reset-password.component.html'); + const confirmResetPasswordPageHtml: Path = getPath(pagesPath, 'confirm-reset-password', 'confirm-reset-password.component.html'); await this.addComponentImports( confirmResetPasswordPageTs, [{ defaultImport: false, element: 'NgxMatAuthConfirmResetPasswordComponent', path: NpmPackage.NGX_MATERIAL_AUTH }] @@ -358,8 +358,8 @@ export abstract class AngularUtilities { }, domain ); - const adminsPageTs: string = getPath(pagesPath, 'admins', 'admins.component.ts'); - const adminsPageHtml: string = getPath(pagesPath, 'admins', 'admins.component.html'); + const adminsPageTs: Path = getPath(pagesPath, 'admins', 'admins.component.ts'); + const adminsPageHtml: Path = getPath(pagesPath, 'admins', 'admins.component.html'); await FsUtilities.updateFile( adminsPageTs, adminsPageTsContent, @@ -374,7 +374,7 @@ export abstract class AngularUtilities { ], 'replace' ); - const routesTs: string = getPath(projectRoot, 'src', 'app', ANGULAR_ROUTES_FILE_NAME); + const routesTs: Path = getPath(projectRoot, 'src', 'app', ANGULAR_ROUTES_FILE_NAME); await TsUtilities.addImportStatements( routesTs, [ @@ -480,7 +480,7 @@ export abstract class AngularUtilities { provider: Provider | EnvironmentProviders | CustomTsValues, imports: TsImportDefinition[] ): Promise { - const appConfigPath: string = getPath(root, 'src', 'app', APP_CONFIG_FILE_NAME); + const appConfigPath: Path = getPath(root, 'src', 'app', APP_CONFIG_FILE_NAME); const { result, contentString } = await TsUtilities.getArrayStartingWith(appConfigPath, 'providers: ['); @@ -528,7 +528,7 @@ export abstract class AngularUtilities { await this.addNavElement(root, navElement); } - const sitemapPath: string = getPath(root, 'src', SITEMAP_FILE_NAME); + const sitemapPath: Path = getPath(root, 'src', SITEMAP_FILE_NAME); const route: string | undefined = this.resolveInternalRoute(navElement); if ( domain @@ -566,7 +566,7 @@ export abstract class AngularUtilities { } private static async addNavElement(projectPath: string, element: AddNavElementConfig): Promise { - const routesPath: string = getPath(projectPath, 'src', 'app', ANGULAR_ROUTES_FILE_NAME); + const routesPath: Path = getPath(projectPath, 'src', 'app', ANGULAR_ROUTES_FILE_NAME); const startIdentifier: ArrayStartIdentifier = this.getStartIdentifierForAddingNavElement(element); const { result, contentString } = await TsUtilities.getArrayStartingWith(routesPath, startIdentifier); @@ -629,7 +629,7 @@ export abstract class AngularUtilities { '' ]); - const angularJsonPath: string = getPath(root, ANGULAR_JSON_FILE_NAME); + const angularJsonPath: Path = getPath(root, ANGULAR_JSON_FILE_NAME); const currentAngularJson: AngularJson = await FsUtilities.parseFileAs(angularJsonPath); // eslint-disable-next-line stylistic/max-len const currentAssets: AngularJsonAssetPattern[] = currentAngularJson?.projects[projectName]?.architect?.['build'].options?.assets ?? []; @@ -674,7 +674,7 @@ export abstract class AngularUtilities { ], 'append' ); - const appComponentTs: string = getPath(root, 'src', 'app', ANGULAR_APP_COMPONENT_FILE_NAME); + const appComponentTs: Path = getPath(root, 'src', 'app', ANGULAR_APP_COMPONENT_FILE_NAME); await this.addComponentImports( appComponentTs, [ @@ -724,7 +724,7 @@ export abstract class AngularUtilities { } await FsUtilities.updateFile(appComponentTs, tsLines, 'replace'); - const routesTs: string = getPath(root, 'src', 'app', ANGULAR_ROUTES_FILE_NAME); + const routesTs: Path = getPath(root, 'src', 'app', ANGULAR_ROUTES_FILE_NAME); await FsUtilities.rename( getPath(root, 'src', 'app', 'app.routes.ts'), routesTs @@ -825,7 +825,7 @@ export abstract class AngularUtilities { * @param path - The path of the ng-package.json. * @param data - The data to update with. */ - static async updateNgPackageJson(path: string, data: Partial): Promise { + static async updateNgPackageJson(path: Path, data: Partial): Promise { const oldData: NgPackageJson = await FsUtilities.parseFileAs(path); const updatedData: NgPackageJson = mergeDeep(oldData, data); await FsUtilities.updateFile(path, JsonUtilities.stringify(updatedData), 'replace', false); @@ -836,13 +836,13 @@ export abstract class AngularUtilities { * @param path - The path of the angular.json. * @param data - The data to update with. */ - static async updateAngularJson(path: string, data: DeepPartial): Promise { + static async updateAngularJson(path: Path, data: DeepPartial): Promise { const oldData: AngularJson = await FsUtilities.parseFileAs(path); const newData: AngularJson = mergeDeep(oldData, data); await FsUtilities.updateFile(path, JsonUtilities.stringify(newData), 'replace'); } - private static async addComponentImports(componentPath: string, imports: TsImportDefinition[]): Promise { + private static async addComponentImports(componentPath: Path, imports: TsImportDefinition[]): Promise { await TsUtilities.addImportStatements(componentPath, imports); let lines: string[] = await FsUtilities.readFileLines(componentPath); for (const imp of imports) { diff --git a/src/commands/add/add-angular-library/add-angular-library.command.ts b/src/commands/add/add-angular-library/add-angular-library.command.ts index fb7bc11..01a0e69 100644 --- a/src/commands/add/add-angular-library/add-angular-library.command.ts +++ b/src/commands/add/add-angular-library/add-angular-library.command.ts @@ -7,7 +7,7 @@ import { StorybookUtilities } from '../../../storybook'; import { TailwindUtilities } from '../../../tailwind'; import { TsConfig, TsConfigUtilities } from '../../../tsconfig'; import { OmitStrict } from '../../../types'; -import { getPath, mergeDeep } from '../../../utilities'; +import { getPath, mergeDeep, Path } from '../../../utilities'; import { WorkspaceConfig, WorkspaceProject, WorkspaceUtilities } from '../../../workspace'; import { BaseAddCommand } from '../models'; import { AddConfiguration } from '../models/add-configuration.model'; @@ -117,6 +117,27 @@ export class AddAngularLibraryCommand extends BaseAddCommand { - const tsconfigPath: string = getPath(root, 'tsconfig.lib.json'); + const tsconfigPath: Path = getPath(root, 'tsconfig.lib.json'); const oldConfig: TsConfig = await FsUtilities.parseFileAs(tsconfigPath); const config: TsConfig = mergeDeep(oldConfig, { extends: './tsconfig.json', @@ -147,7 +168,7 @@ export class AddAngularLibraryCommand extends BaseAddCommand { - const tsconfigPath: string = getPath(root, 'tsconfig.spec.json'); + const tsconfigPath: Path = getPath(root, 'tsconfig.spec.json'); const oldConfig: TsConfig = await FsUtilities.parseFileAs(tsconfigPath); const config: TsConfig = mergeDeep(oldConfig, { extends: 'tsconfig.json', diff --git a/src/commands/add/add-loopback/add-loopback.command.ts b/src/commands/add/add-loopback/add-loopback.command.ts index 58a41d1..8ab9196 100644 --- a/src/commands/add/add-loopback/add-loopback.command.ts +++ b/src/commands/add/add-loopback/add-loopback.command.ts @@ -9,7 +9,7 @@ import { NpmPackage, NpmUtilities } from '../../../npm'; import { TsUtilities } from '../../../ts'; import { TsConfigUtilities } from '../../../tsconfig'; import { OmitStrict } from '../../../types'; -import { getPath, toKebabCase, toPascalCase } from '../../../utilities'; +import { getPath, Path, toKebabCase, toPascalCase } from '../../../utilities'; import { WorkspaceProject, WorkspaceUtilities } from '../../../workspace'; import { BaseAddCommand } from '../models'; import { AddConfiguration } from '../models/add-configuration.model'; @@ -63,7 +63,9 @@ export class AddLoopbackCommand extends BaseAddCommand type: 'input', message: 'Email of the default user', required: true, - default: async () => (await FsUtilities.readFile(PROD_DOCKER_COMPOSE_FILE_NAME)).split('.acme.email=')[1].split('\n')[0] + default: async () => (await FsUtilities.readFile(getPath(PROD_DOCKER_COMPOSE_FILE_NAME))) + .split('.acme.email=')[1] + .split('\n')[0] }, defaultUserPassword: { type: 'input', @@ -129,7 +131,7 @@ export class AddLoopbackCommand extends BaseAddCommand } private async updateIndexTs(root: string, port: number): Promise { - const indexPath: string = getPath(root, 'src', 'index.ts'); + const indexPath: Path = getPath(root, 'src', 'index.ts'); await FsUtilities.replaceInFile(indexPath, ' console.log(`Try ${url}/ping`);\n', ''); await FsUtilities.replaceInFile( indexPath, @@ -142,14 +144,14 @@ export class AddLoopbackCommand extends BaseAddCommand } private async updateOpenApiSpec(root: string, port: number): Promise { - const openApiPath: string = getPath(root, 'src', 'openapi-spec.ts'); + const openApiPath: Path = getPath(root, 'src', 'openapi-spec.ts'); await FsUtilities.replaceInFile(openApiPath, 'env.PORT', 'env[\'PORT\']'); await FsUtilities.replaceInFile(openApiPath, 'env.HOST', 'env[\'HOST\']'); await FsUtilities.replaceInFile(openApiPath, '?? 3000', `?? ${port}`); } private async updateApplicationTs(root: string): Promise { - const applicationPath: string = getPath(root, 'src', 'application.ts'); + const applicationPath: Path = getPath(root, 'src', 'application.ts'); await FsUtilities.replaceInFile( applicationPath, 'BootMixin(RestApplication)', @@ -179,7 +181,7 @@ export class AddLoopbackCommand extends BaseAddCommand await NpmUtilities.install(projectName, [NpmPackage.LOOPBACK_CONNECTOR_POSTGRES]); await LoopbackUtilities.runCommand(root, `datasource ${databaseName}`, { '--config': lbDatabaseConfig, '--yes': true }); - const dataSourcePath: string = getPath(root, 'src', 'datasources', `${toKebabCase(databaseName)}.datasource.ts`); + const dataSourcePath: Path = getPath(root, 'src', 'datasources', `${toKebabCase(databaseName)}.datasource.ts`); await TsUtilities.addImportStatements( dataSourcePath, [{ defaultImport: false, element: 'environment', path: '../environment/environment' }] @@ -215,7 +217,7 @@ export class AddLoopbackCommand extends BaseAddCommand ` constructor(\n @inject('datasources.config.${databaseName}', {optional: true})\n dsConfig: object = config,\n ) {\n super(dsConfig);\n }`, ' constructor() {\n super(config);\n }' ); - const environmentModel: string = getPath(root, 'src', 'environment', ENVIRONMENT_MODEL_TS_FILE_NAME); + const environmentModel: Path = getPath(root, 'src', 'environment', ENVIRONMENT_MODEL_TS_FILE_NAME); await EnvUtilities.addProjectVariableKey( projectName, @@ -259,7 +261,7 @@ export class AddLoopbackCommand extends BaseAddCommand FsUtilities.rm(getPath(newProject.path, 'src', 'controllers', 'ping.controller.ts')), FsUtilities.updateFile(getPath(newProject.path, 'src', 'controllers', 'index.ts'), '', 'replace') ]); - const indexTs: string = getPath(newProject.path, 'src', 'index.ts'); + const indexTs: Path = getPath(newProject.path, 'src', 'index.ts'); await FsUtilities.replaceInFile( indexTs, 'async function main(options: ApplicationConfig = {})', diff --git a/src/commands/add/add-ts-library/add-ts-library.command.ts b/src/commands/add/add-ts-library/add-ts-library.command.ts index ad63595..a28ab93 100644 --- a/src/commands/add/add-ts-library/add-ts-library.command.ts +++ b/src/commands/add/add-ts-library/add-ts-library.command.ts @@ -23,6 +23,8 @@ type TsLibraryConfiguration = AddConfiguration & { * The command for adding a typescript library to the monorepo. */ export class AddTsLibraryCommand extends BaseAddCommand { + private readonly VITE_VERSION: number = 6; + protected override configQuestions: QuestionsFor> = { scope: { type: 'input', @@ -76,7 +78,7 @@ export class AddTsLibraryCommand extends BaseAddCommand private async createProject(config: TsLibraryConfiguration): Promise { // eslint-disable-next-line no-console console.log('Creates the library'); - CPUtilities.execSync(`cd ${LIBS_DIRECTORY_NAME} && npm create vite@latest ${config.name} -- --template vanilla-ts`); + CPUtilities.execSync(`cd ${LIBS_DIRECTORY_NAME} && npm create vite@${this.VITE_VERSION} ${config.name} -- --template vanilla-ts`); const libraryPath: string = getPath(LIBS_DIRECTORY_NAME, config.name); await FsUtilities.createFile(getPath(libraryPath, 'vite.config.ts'), [ 'import { defineConfig, PluginOption } from \'vite\';', diff --git a/src/commands/init/init.command.ts b/src/commands/init/init.command.ts index a77f92d..fbb3dd5 100644 --- a/src/commands/init/init.command.ts +++ b/src/commands/init/init.command.ts @@ -6,7 +6,7 @@ import { EnvUtilities } from '../../env'; import { GithubUtilities } from '../../github'; import { NpmPackage, NpmUtilities } from '../../npm'; import { TsConfigUtilities } from '../../tsconfig'; -import { exitWithError } from '../../utilities'; +import { exitWithError, getPath } from '../../utilities'; import { WorkspaceConfig, WorkspaceUtilities } from '../../workspace'; import { BaseCommand } from '../base-command.model'; @@ -33,8 +33,8 @@ export class InitCommand extends BaseCommand { this.createEslintConfig(), this.createCspellWords(), DockerUtilities.createComposeFiles(config.email), - FsUtilities.mkdir(APPS_DIRECTORY_NAME), - FsUtilities.mkdir(LIBS_DIRECTORY_NAME), + FsUtilities.mkdir(getPath(APPS_DIRECTORY_NAME)), + FsUtilities.mkdir(getPath(LIBS_DIRECTORY_NAME)), this.createGitIgnore(), this.createTailwindConfig(), this.addNpmWorkspaces() @@ -78,7 +78,7 @@ export class InitCommand extends BaseCommand { } private async createGitIgnore(): Promise { - await FsUtilities.createFile(GIT_IGNORE_FILE_NAME, [ + await FsUtilities.createFile(getPath(GIT_IGNORE_FILE_NAME), [ '# See http://help.github.com/ignore-files/ for more about ignoring files.', ENV_FILE_NAME, ENVIRONMENT_TS_FILE_NAME, @@ -98,11 +98,11 @@ export class InitCommand extends BaseCommand { } private async createCspellWords(): Promise { - await FsUtilities.createFile('cspell.words.txt', ''); + await FsUtilities.createFile(getPath('cspell.words.txt'), ''); } private async createEslintConfig(): Promise { - await FsUtilities.createFile(ESLINT_CONFIG_FILE_NAME, [ + await FsUtilities.createFile(getPath(ESLINT_CONFIG_FILE_NAME), [ `import { configs } from '${NpmPackage.ESLINT_CONFIG_SERVICE_SOFT}';`, '', '// eslint-disable-next-line jsdoc/require-description', @@ -113,7 +113,7 @@ export class InitCommand extends BaseCommand { private async createTailwindConfig(): Promise { await FsUtilities.createFile( - TAILWIND_CONFIG_FILE_NAME, + getPath(TAILWIND_CONFIG_FILE_NAME), [ '// eslint-disable-next-line jsdoc/require-description', '/** @type {import(\'tailwindcss\').Config} */', diff --git a/src/commands/version/version.command.ts b/src/commands/version/version.command.ts index e0fe5d2..b898053 100644 --- a/src/commands/version/version.command.ts +++ b/src/commands/version/version.command.ts @@ -2,7 +2,7 @@ import { PACKAGE_JSON_FILE_NAME } from '../../constants'; import { ChalkUtilities, FsUtilities } from '../../encapsulation'; import { PackageJson } from '../../npm'; -import { getPath, exitWithError } from '../../utilities'; +import { getPath, exitWithError, Path } from '../../utilities'; import { BaseCommand } from '../base-command.model'; /** @@ -10,11 +10,10 @@ import { BaseCommand } from '../base-command.model'; */ export class VersionCommand extends BaseCommand { protected override async run(): Promise { - const packageJsonPath: string = getPath(__dirname, '..', '..', '..', PACKAGE_JSON_FILE_NAME); + const packageJsonPath: Path = getPath(__dirname, '..', '..', '..', PACKAGE_JSON_FILE_NAME); const pkg: PackageJson = await FsUtilities.parseFileAs(packageJsonPath); if (!pkg.version) { exitWithError('Could not determine the currently running version of Monux'); - return; } console.log(ChalkUtilities.boldUnderline('Version:')); console.log(ChalkUtilities.secondary(pkg.version)); diff --git a/src/db/db.utilities.ts b/src/db/db.utilities.ts index e5a734f..0e473fc 100644 --- a/src/db/db.utilities.ts +++ b/src/db/db.utilities.ts @@ -4,7 +4,7 @@ import { DATABASES_DIRECTORY_NAME, DEV_DOCKER_COMPOSE_FILE_NAME, DockerComposeFi import { ComposeService, DockerUtilities } from '../docker'; import { FsUtilities, InquirerUtilities, JsonUtilities, QuestionsFor } from '../encapsulation'; import { DefaultEnvKeys, EnvironmentVariableKey, EnvUtilities } from '../env'; -import { generatePlaceholderPassword, getPath, toKebabCase, toSnakeCase } from '../utilities'; +import { generatePlaceholderPassword, getPath, Path, toKebabCase, toSnakeCase } from '../utilities'; import { DbType } from './db-type.enum'; import { dbTypeQuestion } from './db-type.question'; import { MariaDbConfig, mariaDbConfigQuestions } from './maria-db.questions'; @@ -65,8 +65,8 @@ export abstract class DbUtilities { for (const db of dbs) { const configs: DbInitConfig[] = await this.getInitConfigsForDb(db.name, rootDir); for (let i: number = 0; i < configs.length; i++) { - const initFileSh: string = getPath(rootDir, DATABASES_DIRECTORY_NAME, toKebabCase(db.name), 'init', `${i}.sh`); - const initFileSql: string = getPath(rootDir, DATABASES_DIRECTORY_NAME, toKebabCase(db.name), 'init', `${i}.sql`); + const initFileSh: Path = getPath(rootDir, DATABASES_DIRECTORY_NAME, toKebabCase(db.name), 'init', `${i}.sh`); + const initFileSql: Path = getPath(rootDir, DATABASES_DIRECTORY_NAME, toKebabCase(db.name), 'init', `${i}.sql`); await FsUtilities.rm(initFileSh); await FsUtilities.rm(initFileSql); await this.createInitFile(configs[i], initFileSh, initFileSql, fileName, rootDir); @@ -76,8 +76,8 @@ export abstract class DbUtilities { private static async createInitFile( config: DbInitConfig, - initFileSh: string, - initFileSql: string, + initFileSh: Path, + initFileSql: Path, fileName: DockerComposeFileName, rootDir: string ): Promise { @@ -119,7 +119,7 @@ export abstract class DbUtilities { private static async getInitConfigsForDb(db: string, rootDir: string): Promise { const dbFolder: Dirent[] = await FsUtilities.readdir(getPath(rootDir, DATABASES_DIRECTORY_NAME, toKebabCase(db))); - const configFilePaths: string[] = dbFolder.filter(e => e.name.endsWith('.json')).map(e => getPath(e.parentPath, e.name)); + const configFilePaths: Path[] = dbFolder.filter(e => e.name.endsWith('.json')).map(e => getPath(e.parentPath, e.name)); return await Promise.all(configFilePaths.map(async p => await FsUtilities.parseFileAs(p))); } @@ -217,7 +217,7 @@ export abstract class DbUtilities { let created: boolean = false; let i: number = 0; while (!created) { - const configFile: string = getPath(dbFolder, `${i}.json`); + const configFile: Path = getPath(dbFolder, `${i}.json`); if (await FsUtilities.exists(configFile)) { i++; continue; @@ -313,9 +313,8 @@ export abstract class DbUtilities { } }); - const environmentModelFilePath: string = getPath(GLOBAL_ENVIRONMENT_MODEL_FILE_NAME); await FsUtilities.replaceInFile( - environmentModelFilePath, + getPath(GLOBAL_ENVIRONMENT_MODEL_FILE_NAME), 'DB_SERVICE_NAME_PLACEHOLDER', dbServiceName ); @@ -401,9 +400,8 @@ export abstract class DbUtilities { } }); - const environmentModelFilePath: string = getPath(GLOBAL_ENVIRONMENT_MODEL_FILE_NAME); await FsUtilities.replaceInFile( - environmentModelFilePath, + getPath(GLOBAL_ENVIRONMENT_MODEL_FILE_NAME), 'DB_SERVICE_NAME_PLACEHOLDER', dbServiceName ); diff --git a/src/docker/docker.utilities.ts b/src/docker/docker.utilities.ts index 79f72dd..ea4c471 100644 --- a/src/docker/docker.utilities.ts +++ b/src/docker/docker.utilities.ts @@ -5,7 +5,7 @@ import { FsUtilities } from '../encapsulation'; import { ComposeBuild, ComposeDefinition, ComposePort, ComposeService, ComposeServiceEnvironment, ComposeServiceVolume } from './compose-file.model'; import { DefaultEnvKeys, EnvUtilities } from '../env'; import { OmitStrict } from '../types'; -import { getPath } from '../utilities'; +import { getPath, Path } from '../utilities'; import { DockerTraefikUtilities } from './docker-traefik.utilities'; // eslint-disable-next-line jsdoc/require-jsdoc @@ -187,7 +187,7 @@ export abstract class DockerUtilities { subDomain?: string, composeFileName: DockerComposeFileName = PROD_DOCKER_COMPOSE_FILE_NAME ): Promise { - const composePath: string = getPath(composeFileName); + const composePath: Path = getPath(composeFileName); const definition: ComposeDefinition = await this.yamlToComposeDefinition(composePath); const labels: string[] = []; @@ -302,7 +302,7 @@ export abstract class DockerUtilities { } } - const environmentModelFilePath: string = getPath(GLOBAL_ENVIRONMENT_MODEL_FILE_NAME); + const environmentModelFilePath: Path = getPath(GLOBAL_ENVIRONMENT_MODEL_FILE_NAME); await FsUtilities.replaceAllInFile(environmentModelFilePath, '\'PORT_PLACEHOLDER\'', `env.${DefaultEnvKeys.port(service.name)}`); await FsUtilities.replaceAllInFile( environmentModelFilePath, @@ -322,7 +322,7 @@ export abstract class DockerUtilities { * @returns The parsed services. */ static async getComposeServices(rootDir: string): Promise { - const composePath: string = getPath(rootDir, PROD_DOCKER_COMPOSE_FILE_NAME); + const composePath: Path = getPath(rootDir, PROD_DOCKER_COMPOSE_FILE_NAME); const definition: ComposeDefinition = await this.yamlToComposeDefinition(composePath); return definition.services; } @@ -336,7 +336,7 @@ export abstract class DockerUtilities { volume: string, composeFileName: string = PROD_DOCKER_COMPOSE_FILE_NAME ): Promise { - const composePath: string = getPath(composeFileName); + const composePath: Path = getPath(composeFileName); const definition: ComposeDefinition = await this.yamlToComposeDefinition(composePath); definition.volumes.push(volume); await FsUtilities.updateFile(composePath, this.composeDefinitionToYaml(definition), 'replace'); @@ -473,7 +473,7 @@ export abstract class DockerUtilities { ]; } - private static async yamlToComposeDefinition(composePath: string): Promise { + private static async yamlToComposeDefinition(composePath: Path): Promise { // Load the YAML file const fileContent: string = await FsUtilities.readFile(composePath); const parsedYaml: ParsedDockerCompose | undefined = yaml.load(fileContent) as ParsedDockerCompose | undefined; diff --git a/src/encapsulation/fs.utilities.ts b/src/encapsulation/fs.utilities.ts index b4324e4..8f1a19e 100644 --- a/src/encapsulation/fs.utilities.ts +++ b/src/encapsulation/fs.utilities.ts @@ -3,7 +3,7 @@ import { access, writeFile, mkdir, readFile, readdir, rm, rename, cp } from 'fs/ import { dirname } from 'path'; import { JsonUtilities } from './json.utilities'; -import { getPath } from '../utilities'; +import { getPath, Path } from '../utilities'; /** * Definition for a line in a file. @@ -51,7 +51,7 @@ export abstract class FsUtilities { * @throws When no line could be found. */ static async findLineWithContent( - linesOrPath: string | string[], + linesOrPath: Path | string[], content: string, fromIndex: number = 0, untilIndex?: number @@ -76,7 +76,7 @@ export abstract class FsUtilities { * @param path - The path to check. * @returns True when a file could be accessed and false otherwise. */ - static async exists(path: string): Promise { + static async exists(path: Path): Promise { try { await access(path); return true; @@ -104,7 +104,7 @@ export abstract class FsUtilities { * @param untilIndex - The ending line index (inclusive). Defaults to the end of the file. */ static async replaceAllInFile( - path: string, + path: Path, oldContent: string | RegExp, newContent: string, fromIndex?: number, @@ -122,7 +122,7 @@ export abstract class FsUtilities { * @param untilIndex - The ending line index (inclusive). Defaults to the end of the file. */ static async replaceInFile( - path: string, + path: Path, oldContent: string | RegExp, newContent: string, fromIndex?: number, @@ -132,7 +132,7 @@ export abstract class FsUtilities { } private static async replaceContentInFile( - path: string, + path: Path, oldContent: string | RegExp, newContent: string, all: boolean, @@ -162,12 +162,12 @@ export abstract class FsUtilities { * @param recursive - Whether or not to recursively create the file. * @param log - Whether or not the success of the creation should be logged to the console. */ - static async createFile(path: string, data: string | string[], recursive: boolean = true, log: boolean = true): Promise { + static async createFile(path: Path, data: string | string[], recursive: boolean = true, log: boolean = true): Promise { if (await this.exists(path)) { throw new Error(`File at ${path} already exists. Did you mean to call "updateFile"?`); } data = this.normalizeData(data); - const parentDir: string = dirname(path); + const parentDir: Path = dirname(path) as Path; if (recursive && !await this.exists(parentDir)) { await this.mkdir(parentDir, true, false); } @@ -195,7 +195,7 @@ export abstract class FsUtilities { * @param log - Whether or not the success of the update should be logged to the console. */ static async updateFile( - path: string, + path: Path, data: string | string[], action: 'replace' | 'prepend' | 'append', log: boolean = true @@ -235,7 +235,7 @@ export abstract class FsUtilities { * @param path - The path of the file to read. * @returns The content as a single string. */ - static async readFile(path: string): Promise { + static async readFile(path: Path): Promise { return readFile(path, { encoding: 'utf8' }); } @@ -244,7 +244,7 @@ export abstract class FsUtilities { * @param path - The path of the file to read the lines from. * @returns The content as an array of line strings. */ - static async readFileLines(path: string): Promise { + static async readFileLines(path: Path): Promise { const content: string = await this.readFile(path); return content.split('\n'); } @@ -254,7 +254,7 @@ export abstract class FsUtilities { * @param filePath - The path of the file to parse. * @returns An object of the provided generic. */ - static async parseFileAs(filePath: string): Promise { + static async parseFileAs(filePath: Path): Promise { const fileContent: string = await this.readFile(filePath); return JsonUtilities.parse(fileContent); } @@ -264,7 +264,7 @@ export abstract class FsUtilities { * @param path - The path to remove. * @param recursive - Whether or not subdirectories should be deleted as well. Defaults to true. */ - static async rm(path: string, recursive: boolean = true): Promise { + static async rm(path: Path, recursive: boolean = true): Promise { if (!await this.exists(path)) { return; } @@ -277,7 +277,7 @@ export abstract class FsUtilities { * @param recursive - Whether or not missing directories in the path should be created as well. * @param log - Whether or not the success of the creation should be logged to the console. */ - static async mkdir(path: string, recursive: boolean = true, log: boolean = true): Promise { + static async mkdir(path: Path, recursive: boolean = true, log: boolean = true): Promise { await mkdir(path, { recursive: recursive }); if (log) { // eslint-disable-next-line no-console @@ -290,26 +290,26 @@ export abstract class FsUtilities { * @param path - The path of the directory to get the contents of. * @returns An array of the directory contents. */ - static async readdir(path: string): Promise { + static async readdir(path: Path): Promise { return readdir(path, { withFileTypes: true }); } /** * Moves the contents of the given source inside the given destination. * Overrides any contents that might already exist inside the destination. - * @param source - The source to move the content of. - * @param destination - The destination folder where the content should be moved inside. + * @param sourcePath - The source folder to move the content of. + * @param destinationPath - The destination folder where the content should be moved inside. * @param excludeElements - Optional array of elements which should not be moved. */ - static async moveDirectoryContent(source: string, destination: string, excludeElements: string[] = []): Promise { - const entries: Dirent[] = (await this.readdir(source)).filter(e => !excludeElements.includes(e.name)); - await Promise.all(entries.map(e => this.copyEntry(e, destination))); - await this.rm(source); + static async moveDirectoryContent(sourcePath: Path, destinationPath: Path, excludeElements: string[] = []): Promise { + const entries: Dirent[] = (await this.readdir(sourcePath)).filter(e => !excludeElements.includes(e.name)); + await Promise.all(entries.map(e => this.copyEntry(e, destinationPath))); + await this.rm(sourcePath); } private static async copyEntry(entry: Dirent, destination: string): Promise { - const source: string = getPath(entry.parentPath, entry.name); - const dest: string = getPath(destination, entry.name); + const source: Path = getPath(entry.parentPath, entry.name); + const dest: Path = getPath(destination, entry.name); await cp(source, dest, { recursive: true, errorOnExist: true }); } } \ No newline at end of file diff --git a/src/env/env-utilities.test.ts b/src/env/env-utilities.test.ts index d486b93..9eab12a 100644 --- a/src/env/env-utilities.test.ts +++ b/src/env/env-utilities.test.ts @@ -7,7 +7,7 @@ import { FsUtilities } from '../encapsulation'; import { KeyValue } from '../types'; import { DefaultEnvKeys } from './default-environment-keys'; import { GLOBAL_ENVIRONMENT_MODEL_FILE_NAME } from '../constants'; -import { getPath } from '../utilities'; +import { getPath, Path } from '../utilities'; const mockConstants: MockConstants = getMockConstants('env-utilities'); @@ -93,7 +93,7 @@ describe('EnvUtilities', () => { } ); - const environmentModelFilePath: string = getPath(mockConstants.PROJECT_DIR, GLOBAL_ENVIRONMENT_MODEL_FILE_NAME); + const environmentModelFilePath: Path = getPath(mockConstants.PROJECT_DIR, GLOBAL_ENVIRONMENT_MODEL_FILE_NAME); await FsUtilities.replaceAllInFile(environmentModelFilePath, '\'PORT_PLACEHOLDER\'', `env.${DefaultEnvKeys.port(name)}`); await FsUtilities.replaceAllInFile(environmentModelFilePath, '\'SUB_DOMAIN_PLACEHOLDER\'', `env.${DefaultEnvKeys.subDomain(name)}`); await FsUtilities.replaceAllInFile(environmentModelFilePath, '\'PROD_ROOT_DOMAIN_PLACEHOLDER\'', `env.${DefaultEnvKeys.PROD_ROOT_DOMAIN}`); diff --git a/src/env/env.utilities.ts b/src/env/env.utilities.ts index 9e4dd44..7bf8e09 100644 --- a/src/env/env.utilities.ts +++ b/src/env/env.utilities.ts @@ -3,7 +3,7 @@ import { DockerComposeFileName, ENV_FILE_NAME, ENVIRONMENT_MODEL_TS_FILE_NAME, E import { FileLine, FsUtilities, JsonUtilities } from '../encapsulation'; import { ParseObjectResult, TsUtilities } from '../ts'; import { KeyValue, OmitStrict } from '../types'; -import { getPath } from '../utilities'; +import { getPath, Path } from '../utilities'; import { WorkspaceProject, WorkspaceUtilities } from '../workspace'; import { DefaultEnvKeys } from './default-environment-keys'; import { EnvironmentVariableKey } from './environment-variable-key.model'; @@ -117,7 +117,7 @@ export abstract class EnvUtilities { */ static async addProjectVariableKey( name: string, - environmentModelPath: string, + environmentModelPath: Path, variable: EnvironmentVariableKey, failOnMissingVariable: boolean, rootDir: string @@ -135,7 +135,7 @@ export abstract class EnvUtilities { await this.buildEnvironmentFileForApp(app, failOnMissingVariable, 'dev.docker-compose.yaml', rootDir); } - private static async getProjectVariableKeys(environmentModelPath: string): Promise { + private static async getProjectVariableKeys(environmentModelPath: Path): Promise { const lines: string[] = await FsUtilities.readFileLines(environmentModelPath); const firstLine: FileLine = await FsUtilities.findLineWithContent(lines, 'defineVariables('); const lastLine: FileLine = await FsUtilities.findLineWithContent(lines, ']', firstLine.index); @@ -474,7 +474,7 @@ export abstract class EnvUtilities { } private static async getVariableDefinitions( - globalEnvModelPath: string, + globalEnvModelPath: Path, firstLineIdentifier: 'StaticGlobalEnvironment = {' | 'CalculatedGlobalEnvironment = {' ): Promise[]> { const lines: string[] = await FsUtilities.readFileLines(globalEnvModelPath); @@ -512,13 +512,13 @@ export abstract class EnvUtilities { * @param variable - The variable to add. */ static async addStaticVariable(variable: EnvVariable): Promise { - const environmentFilePath: string = getPath(ENV_FILE_NAME); + const environmentFilePath: Path = getPath(ENV_FILE_NAME); if ((await FsUtilities.readFile(environmentFilePath)).includes(`${variable.key}=`)) { throw new Error(`The variable ${variable.key} has already been set.`); } await FsUtilities.updateFile(environmentFilePath, `${variable.key}=${variable.value ?? ''}`, 'append'); - const environmentModelFilePath: string = getPath(GLOBAL_ENVIRONMENT_MODEL_FILE_NAME); + const environmentModelFilePath: Path = getPath(GLOBAL_ENVIRONMENT_MODEL_FILE_NAME); const lines: string[] = await FsUtilities.readFileLines(environmentModelFilePath); const firstLine: FileLine = await FsUtilities.findLineWithContent(lines, 'StaticGlobalEnvironment = {'); @@ -551,7 +551,7 @@ export abstract class EnvUtilities { * @param variable - The variable to add. */ static async addCalculatedVariable(variable: CalculatedEnvVariable): Promise { - const environmentModelFilePath: string = getPath(GLOBAL_ENVIRONMENT_MODEL_FILE_NAME); + const environmentModelFilePath: Path = getPath(GLOBAL_ENVIRONMENT_MODEL_FILE_NAME); if ((await FsUtilities.readFile(environmentModelFilePath)).includes(`${variable.key}: `)) { throw new Error(`The variable ${variable.key} has already been set.`); } diff --git a/src/github/github-utilities.test.ts b/src/github/github-utilities.test.ts index 55bcf0b..33c125c 100644 --- a/src/github/github-utilities.test.ts +++ b/src/github/github-utilities.test.ts @@ -4,7 +4,7 @@ import { beforeEach, describe, expect, test } from '@jest/globals'; import { FileMockUtilities, getMockConstants, MockConstants } from '../__testing__'; import { FsUtilities } from '../encapsulation'; import { GithubUtilities } from './github.utilities'; -import { getPath } from '../utilities'; +import { getPath, Path } from '../utilities'; const mockConstants: MockConstants = getMockConstants('github-utilities'); @@ -15,7 +15,7 @@ describe('GithubUtilities', () => { }); test('createWorkflow', async () => { - const WORKFLOW_FILE: string = getPath(mockConstants.GITHUB_WORKFLOW_DIR, 'main.yml'); + const WORKFLOW_FILE: Path = getPath(mockConstants.GITHUB_WORKFLOW_DIR, 'main.yml'); await GithubUtilities['createWorkflowFile'](WORKFLOW_FILE, { name: 'main', on: 'push', diff --git a/src/github/github.utilities.ts b/src/github/github.utilities.ts index 2326e27..843dd52 100644 --- a/src/github/github.utilities.ts +++ b/src/github/github.utilities.ts @@ -3,7 +3,7 @@ import yaml from 'js-yaml'; import { FsUtilities } from '../encapsulation'; import { GithubWorkflow } from './github-workflow.model'; -import { getPath } from '../utilities'; +import { getPath, Path } from '../utilities'; /** * Utilities for github. @@ -14,11 +14,11 @@ export abstract class GithubUtilities { * @param data - The data of the workflow to create. */ static async createWorkflow(data: GithubWorkflow): Promise { - const workflowFilePath: string = getPath('.github', 'workflows', `${data.name}.yml`); + const workflowFilePath: Path = getPath('.github', 'workflows', `${data.name}.yml`); await this.createWorkflowFile(workflowFilePath, data); } - private static async createWorkflowFile(workflowFilePath: string, data: GithubWorkflow): Promise { + private static async createWorkflowFile(workflowFilePath: Path, data: GithubWorkflow): Promise { await FsUtilities.createFile(workflowFilePath, yaml.dump(data, { indent: 4 })); await FsUtilities.replaceInFile(workflowFilePath, '\'on\'', 'on'); } diff --git a/src/loopback/loopback.utilities.ts b/src/loopback/loopback.utilities.ts index 30424e4..1bfcc3e 100644 --- a/src/loopback/loopback.utilities.ts +++ b/src/loopback/loopback.utilities.ts @@ -4,7 +4,7 @@ import { ENVIRONMENT_MODEL_TS_FILE_NAME } from '../constants'; import { CPUtilities, FsUtilities } from '../encapsulation'; import { DefaultEnvKeys, EnvUtilities } from '../env'; import { TsUtilities } from '../ts'; -import { generatePlaceholderPassword, getPath, optionsToCliString, toKebabCase, toPascalCase } from '../utilities'; +import { generatePlaceholderPassword, getPath, optionsToCliString, Path, toKebabCase, toPascalCase } from '../utilities'; import { LbDatabaseConfig } from './lb-database-config.model'; import { NpmPackage, NpmUtilities } from '../npm'; import { adminControllerContent } from './admin-controller.content'; @@ -174,7 +174,7 @@ export abstract class LoopbackUtilities { } CPUtilities.execSync(`cd ${directory} && npx @loopback/cli@${this.CLI_VERSION} ${command} ${optionsToCliString(options, ' ')}`); if (command.startsWith('service')) { - const servicePath: string = getPath(directory, 'src', 'services', `${toKebabCase(command.split(' ')[1])}.service.ts`); + const servicePath: Path = getPath(directory, 'src', 'services', `${toKebabCase(command.split(' ')[1])}.service.ts`); await FsUtilities.replaceInFile(servicePath, '/* inject, */', ''); await FsUtilities.replaceInFile(servicePath, '/* Add @inject to inject parameters */', ''); await FsUtilities.replaceInFile(servicePath, '\n /*\n * Add service methods here\n */', ''); @@ -204,7 +204,7 @@ export abstract class LoopbackUtilities { private static async createBiometricCredentialsService(root: string, config: AddLoopbackConfiguration): Promise { await this.runCommand(root, 'service BiometricCredentials', { '--skip-install': true, '--type': 'class', '--yes': true }); - const servicePath: string = getPath(root, 'src', 'services', 'biometric-credentials.service.ts'); + const servicePath: Path = getPath(root, 'src', 'services', 'biometric-credentials.service.ts'); await TsUtilities.addImportStatements( servicePath, [ @@ -225,7 +225,7 @@ export abstract class LoopbackUtilities { } private static async createAdminFiles(root: string, dbName: string): Promise { - const adminModelTs: string = getPath(root, 'src', 'models', 'admin.model.ts'); + const adminModelTs: Path = getPath(root, 'src', 'models', 'admin.model.ts'); await FsUtilities.createFile(adminModelTs, adminModelContent); await this.runCommand( @@ -233,7 +233,7 @@ export abstract class LoopbackUtilities { 'repository Admin', { '--skip-install': true, '--yes': true, '--datasource': dbName, '--model': 'Admin' } ); - const adminRepositoryTs: string = getPath(root, 'src', 'repositories', 'admin.repository.ts'); + const adminRepositoryTs: Path = getPath(root, 'src', 'repositories', 'admin.repository.ts'); await TsUtilities.addImportStatements(adminRepositoryTs, [ { defaultImport: false, element: 'Getter', path: '@loopback/core' }, { defaultImport: false, element: 'BelongsToAccessor', path: '@loopback/repository' }, @@ -295,7 +295,7 @@ export abstract class LoopbackUtilities { private static async createMailService(root: string, config: AddLoopbackConfiguration): Promise { await this.runCommand(root, 'service mail', { '--skip-install': true, '--type': 'class', '--yes': true }); - const servicePath: string = getPath(root, 'src', 'services', 'mail.service.ts'); + const servicePath: Path = getPath(root, 'src', 'services', 'mail.service.ts'); await TsUtilities.addImportStatements( servicePath, [ @@ -366,7 +366,7 @@ export abstract class LoopbackUtilities { { key: DefaultEnvKeys.WEBSERVER_MAIL_PORT, required: true, type: 'number', value: undefined } ); - const environmentModel: string = getPath(root, 'src', 'environment', ENVIRONMENT_MODEL_TS_FILE_NAME); + const environmentModel: Path = getPath(root, 'src', 'environment', ENVIRONMENT_MODEL_TS_FILE_NAME); await EnvUtilities.addProjectVariableKey( config.name, environmentModel, @@ -409,7 +409,7 @@ export abstract class LoopbackUtilities { root: string, config: AddLoopbackConfiguration ): Promise { - const indexTs: string = getPath(root, 'src', 'index.ts'); + const indexTs: Path = getPath(root, 'src', 'index.ts'); await TsUtilities.addImportStatements( indexTs, [ @@ -443,7 +443,7 @@ export abstract class LoopbackUtilities { private static async applyAuthToApplicationTs(root: string): Promise { // eslint-disable-next-line sonar/no-duplicate-string - const applicationTs: string = getPath(root, 'src', 'application.ts'); + const applicationTs: Path = getPath(root, 'src', 'application.ts'); await TsUtilities.addImportStatements( applicationTs, [ @@ -509,7 +509,7 @@ export abstract class LoopbackUtilities { static async setupLogging(root: string, name: string): Promise { await NpmUtilities.install(name, [NpmPackage.LBX_PERSISTENCE_LOGGER, NpmPackage.LOOPBACK_CRON]); - const applicationTs: string = getPath(root, 'src', 'application.ts'); + const applicationTs: Path = getPath(root, 'src', 'application.ts'); await TsUtilities.addImportStatements( applicationTs, [ @@ -535,7 +535,7 @@ export abstract class LoopbackUtilities { ' }' ]); await TsUtilities.addToConstructorBody(applicationTs, 'this.setupLogging();'); - const indexTs: string = getPath(root, 'src', 'index.ts'); + const indexTs: Path = getPath(root, 'src', 'index.ts'); await TsUtilities.addImportStatements( indexTs, [ @@ -554,7 +554,7 @@ export abstract class LoopbackUtilities { ); await FsUtilities.replaceInFile(indexTs, 'console.log(`Server', 'await logger.info(`Server'); - const mailServiceTs: string = getPath(root, 'src', 'services', 'mail.service.ts'); + const mailServiceTs: Path = getPath(root, 'src', 'services', 'mail.service.ts'); await TsUtilities.addImportStatements( mailServiceTs, [{ defaultImport: false, element: 'Log, LoggerNotificationService', path: NpmPackage.LBX_PERSISTENCE_LOGGER }] @@ -578,7 +578,7 @@ export abstract class LoopbackUtilities { */ static async setupChangeSets(root: string, name: string): Promise { await NpmUtilities.install(name, [NpmPackage.LBX_CHANGE_SETS]); - const applicationTs: string = getPath(root, 'src', 'application.ts'); + const applicationTs: Path = getPath(root, 'src', 'application.ts'); await TsUtilities.addImportStatements( applicationTs, [ @@ -607,7 +607,7 @@ export abstract class LoopbackUtilities { */ static async setupMigrations(root: string, name: string): Promise { await NpmUtilities.install(name, [NpmPackage.LOOPBACK_4_MIGRATION]); - const applicationTs: string = getPath(root, 'src', 'application.ts'); + const applicationTs: Path = getPath(root, 'src', 'application.ts'); await TsUtilities.addImportStatements( applicationTs, [ diff --git a/src/npm/npm.utilities.ts b/src/npm/npm.utilities.ts index 267d8b6..79b8c9b 100644 --- a/src/npm/npm.utilities.ts +++ b/src/npm/npm.utilities.ts @@ -3,7 +3,7 @@ import { WorkspaceProject, WorkspaceUtilities } from '../workspace'; import { PackageJson } from './package-json.model'; import { PACKAGE_JSON_FILE_NAME } from '../constants'; import { NpmPackage } from './npm-package.enum'; -import { getPath, mergeDeep } from '../utilities'; +import { getPath, mergeDeep, Path } from '../utilities'; /** * Options for running the npm init command. @@ -42,16 +42,17 @@ export abstract class NpmUtilities { */ static async init(config: 'root' | NpmInitConfig, output?: boolean): Promise { if (config === 'root') { + const rootPackageJson: Path = getPath(PACKAGE_JSON_FILE_NAME); CPUtilities.execSync('npm init -y', output); - const oldPackageJson: PackageJson = await FsUtilities.parseFileAs(PACKAGE_JSON_FILE_NAME); - await FsUtilities.updateFile(PACKAGE_JSON_FILE_NAME, JsonUtilities.stringify(oldPackageJson), 'replace', false); + const oldPackageJson: PackageJson = await FsUtilities.parseFileAs(rootPackageJson); + await FsUtilities.updateFile(rootPackageJson, JsonUtilities.stringify(oldPackageJson), 'replace', false); return; } CPUtilities.execSync( `npm init -y --scope=${config.scope} -w ${config.path}`, output ); - const packageJsonPath: string = getPath(config.path, PACKAGE_JSON_FILE_NAME); + const packageJsonPath: Path = getPath(config.path, PACKAGE_JSON_FILE_NAME); const oldPackageJson: PackageJson = await FsUtilities.parseFileAs(packageJsonPath); await FsUtilities.updateFile(packageJsonPath, JsonUtilities.stringify(oldPackageJson), 'replace', false); } @@ -104,7 +105,7 @@ export abstract class NpmUtilities { */ static async updatePackageJson(projectName: string, data: Partial): Promise { const project: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(projectName, getPath('.')); - const packageJsonPath: string = getPath(project.path, PACKAGE_JSON_FILE_NAME); + const packageJsonPath: Path = getPath(project.path, PACKAGE_JSON_FILE_NAME); await this.updatePackageJsonFile(packageJsonPath, data); } @@ -113,7 +114,7 @@ export abstract class NpmUtilities { * @param data - The data to update the package.json with. */ static async updateRootPackageJson(data: Partial): Promise { - await this.updatePackageJsonFile(PACKAGE_JSON_FILE_NAME, data); + await this.updatePackageJsonFile(getPath(PACKAGE_JSON_FILE_NAME), data); } /** @@ -121,7 +122,7 @@ export abstract class NpmUtilities { * @param path - The path of the package.json to update. * @param data - The data to update the package.json with. */ - static async updatePackageJsonFile(path: string, data: Partial): Promise { + static async updatePackageJsonFile(path: Path, data: Partial): Promise { const oldPackageJson: PackageJson = await FsUtilities.parseFileAs(path); const packageJson: PackageJson = mergeDeep(oldPackageJson, data); await FsUtilities.updateFile(path, JsonUtilities.stringify(packageJson), 'replace', false); diff --git a/src/robots/robots.utilities.ts b/src/robots/robots.utilities.ts index 9337bef..dea61bd 100644 --- a/src/robots/robots.utilities.ts +++ b/src/robots/robots.utilities.ts @@ -1,7 +1,7 @@ import { DockerComposeFileName, ENV_FILE_NAME, ROBOTS_FILE_NAME, SITEMAP_FILE_NAME } from '../constants'; import { FsUtilities } from '../encapsulation'; import { DefaultEnvKeys, EnvUtilities } from '../env'; -import { filterAsync, getPath } from '../utilities'; +import { filterAsync, getPath, Path } from '../utilities'; import { WorkspaceProject, WorkspaceUtilities } from '../workspace'; /** @@ -15,14 +15,14 @@ export abstract class RobotsUtilities { * @param rootDir - The directory of the Monux monorepo where the files should be created. */ static async createRobotsTxtFiles(fileName: DockerComposeFileName, rootDir: string): Promise { - const environmentFilePath: string = getPath(rootDir, ENV_FILE_NAME); + const environmentFilePath: Path = getPath(rootDir, ENV_FILE_NAME); if (!(await FsUtilities.readFile(environmentFilePath)).includes(`${DefaultEnvKeys.IS_PUBLIC}=`)) { return; } // Only projects that have a sitemap file get a robots.txt file. const apps: WorkspaceProject[] = await filterAsync(await WorkspaceUtilities.getProjects('apps', rootDir), async a => { - const sitemapPath: string = getPath(a.path, 'src', SITEMAP_FILE_NAME); + const sitemapPath: Path = getPath(a.path, 'src', SITEMAP_FILE_NAME); return await FsUtilities.exists(sitemapPath); }); await Promise.all(apps.map(async a => { @@ -43,7 +43,7 @@ export abstract class RobotsUtilities { domain: string | undefined, rootDir: string ): Promise { - const robotsTxtPath: string = getPath(app.path, 'src', ROBOTS_FILE_NAME); + const robotsTxtPath: Path = getPath(app.path, 'src', ROBOTS_FILE_NAME); await FsUtilities.rm(robotsTxtPath); const isPublic: boolean = await EnvUtilities.getEnvVariable(DefaultEnvKeys.IS_PUBLIC, fileName, rootDir); diff --git a/src/storybook/storybook.utilities.ts b/src/storybook/storybook.utilities.ts index 3800991..2f836ac 100644 --- a/src/storybook/storybook.utilities.ts +++ b/src/storybook/storybook.utilities.ts @@ -4,11 +4,16 @@ import { CPUtilities } from '../encapsulation'; * Handles functionality around storybook. */ export abstract class StorybookUtilities { + + private static readonly CLI_VERSION: number = 8; + /** * Sets up storybook inside the given root. * @param root - The root of the project where storybook should be setup. */ static setup(root: string): void { - CPUtilities.execSync(`cd ${root} && npm create storybook@latest --yes --features docs test --disable-telemetry`); + CPUtilities.execSync( + `cd ${root} && npm create storybook@${this.CLI_VERSION} -- --no-dev --yes --features docs test --disable-telemetry` + ); } } \ No newline at end of file diff --git a/src/ts/ts.utilities.ts b/src/ts/ts.utilities.ts index 45f2194..b1e4f0d 100644 --- a/src/ts/ts.utilities.ts +++ b/src/ts/ts.utilities.ts @@ -1,4 +1,5 @@ import { FileLine, FsUtilities, JsonUtilities } from '../encapsulation'; +import { Path } from '../utilities'; import { TsImportDefinition } from './ts-import-definition.model'; /** @@ -53,7 +54,7 @@ export abstract class TsUtilities { * @param path - The path of the ts file with a class in it. * @param content - The content to add. */ - static async addToStartOfClass(path: string, content: string[]): Promise { + static async addToStartOfClass(path: Path, content: string[]): Promise { const lines: string[] = await FsUtilities.readFileLines(path); const classStart: FileLine = await FsUtilities.findLineWithContent(lines, 'class '); const classEnd: string | undefined = lines.find(l => l === '}' && lines.indexOf(l) >= classStart.index); @@ -73,7 +74,7 @@ export abstract class TsUtilities { * @param path - The path of the ts file with a class in it. * @param content - The content to add. */ - static async addToEndOfClass(path: string, content: string[]): Promise { + static async addToEndOfClass(path: Path, content: string[]): Promise { const lines: string[] = await FsUtilities.readFileLines(path); const classStart: FileLine = await FsUtilities.findLineWithContent(lines, 'class '); const classEnd: string | undefined = lines.find(l => l === '}' && lines.indexOf(l) >= classStart.index); @@ -88,7 +89,7 @@ export abstract class TsUtilities { * @param path - The path of the file where the content should be added. * @param content - The content that should be added. Must include indentation already. */ - static async addToConstructorBody(path: string, content: string): Promise { + static async addToConstructorBody(path: Path, content: string): Promise { const lines: string[] = await FsUtilities.readFileLines(path); const superLine: string | undefined = lines.find(l => l.includes(' super(')); const constructorLine: FileLine = await FsUtilities.findLineWithContent(lines, constructorLineIdentifier); @@ -133,7 +134,7 @@ export abstract class TsUtilities { * @param path - The path of the file where the content should be added. * @param content - The content that should be added. Must include indentation already. */ - static async addToConstructorHeader(path: string, content: string): Promise { + static async addToConstructorHeader(path: Path, content: string): Promise { const lines: string[] = await FsUtilities.readFileLines(path); const constructorLine: FileLine = await FsUtilities.findLineWithContent(lines, constructorLineIdentifier); if (constructorLine.content.includes('constructor()')) { @@ -152,7 +153,7 @@ export abstract class TsUtilities { * @param path - The path of the ts file to add the content to. * @param content - The content to add. Each entry is a line. */ - static async addBelowImports(path: string, content: string[]): Promise { + static async addBelowImports(path: Path, content: string[]): Promise { const lines: string[] = await FsUtilities.readFileLines(path); let replaceContent: string = ''; for (let i: number = lines.length - 1; i >= 0; i--) { @@ -169,7 +170,7 @@ export abstract class TsUtilities { * @param startIdentifier - The identifier for the start of the array. * @returns The parsed array as well as the string in the file. */ - static async getArrayStartingWith(filePath: string, startIdentifier: ArrayStartIdentifier): Promise> { + static async getArrayStartingWith(filePath: Path, startIdentifier: ArrayStartIdentifier): Promise> { const lines: string[] = await FsUtilities.readFileLines(filePath); const firstLine: FileLine = await FsUtilities.findLineWithContent(lines, startIdentifier); @@ -215,7 +216,7 @@ export abstract class TsUtilities { * @param startIdentifier - The identifier for the start of the object. * @returns The parsed object as well as the string in the file. */ - static async getObjectStartingWith(filePath: string, startIdentifier: ObjectStartIdentifier): Promise> { + static async getObjectStartingWith(filePath: Path, startIdentifier: ObjectStartIdentifier): Promise> { const lines: string[] = await FsUtilities.readFileLines(filePath); const firstLine: FileLine = await FsUtilities.findLineWithContent(lines, startIdentifier); @@ -256,7 +257,7 @@ export abstract class TsUtilities { * @param path - The path of the ts file to add the imports to. * @param imports - The imports to add. */ - static async addImportStatements(path: string, imports: TsImportDefinition[]): Promise { + static async addImportStatements(path: Path, imports: TsImportDefinition[]): Promise { for (const imp of imports) { let lines: string[] = await FsUtilities.readFileLines(path); lines = this.addImportStatement(lines, imp); diff --git a/src/tsconfig/tsconfig-utilities.test.ts b/src/tsconfig/tsconfig-utilities.test.ts index 4589023..1319217 100644 --- a/src/tsconfig/tsconfig-utilities.test.ts +++ b/src/tsconfig/tsconfig-utilities.test.ts @@ -6,7 +6,7 @@ import { TsConfigUtilities } from './tsconfig.utilities'; import { TS_CONFIG_FILE_NAME } from '../constants'; import { FsUtilities } from '../encapsulation'; import { TsConfig } from './tsconfig.model'; -import { getPath } from '../utilities'; +import { getPath, Path } from '../utilities'; const mockConstants: MockConstants = getMockConstants('tsconfig-utilities'); @@ -32,7 +32,7 @@ describe('TsConfigUtilities', () => { test('update', async () => { TsConfigUtilities.init(mockConstants.TS_LIBRARY_DIR); - const tsconfigPath: string = getPath(mockConstants.TS_LIBRARY_DIR, TS_CONFIG_FILE_NAME); + const tsconfigPath: Path = getPath(mockConstants.TS_LIBRARY_DIR, TS_CONFIG_FILE_NAME); await TsConfigUtilities['update'](tsconfigPath, { extends: '../../tsconfig.base.json', compilerOptions: { diff --git a/src/tsconfig/tsconfig.utilities.ts b/src/tsconfig/tsconfig.utilities.ts index 4176809..72a1870 100644 --- a/src/tsconfig/tsconfig.utilities.ts +++ b/src/tsconfig/tsconfig.utilities.ts @@ -4,7 +4,7 @@ import { CPUtilities, FsUtilities, JsonUtilities } from '../encapsulation'; import { WorkspaceProject, WorkspaceUtilities } from '../workspace'; import { TsConfig } from './tsconfig.model'; import { TS_CONFIG_FILE_NAME } from '../constants'; -import { getPath, mergeDeep } from '../utilities'; +import { getPath, mergeDeep, Path } from '../utilities'; /** * Utilities for tsconfig. @@ -50,7 +50,7 @@ export abstract class TsConfigUtilities { }, exclude: ['node_modules', 'tmp', 'dist'] }; - await FsUtilities.createFile('tsconfig.base.json', JsonUtilities.stringify(tsconfig)); + await FsUtilities.createFile(getPath('tsconfig.base.json'), JsonUtilities.stringify(tsconfig)); } /** @@ -60,7 +60,7 @@ export abstract class TsConfigUtilities { */ static async updateTsConfig(projectName: string, data: Partial): Promise { const project: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(projectName, getPath('.')); - const tsConfigPath: string = getPath(project.path, TS_CONFIG_FILE_NAME); + const tsConfigPath: Path = getPath(project.path, TS_CONFIG_FILE_NAME); await this.update(tsConfigPath, data); } @@ -69,10 +69,10 @@ export abstract class TsConfigUtilities { * @param data - The data to update the tsconfig with. */ static async updateBaseTsConfig(data: Partial): Promise { - await this.update('tsconfig.base.json', data); + await this.update(getPath('tsconfig.base.json'), data); } - private static async update(path: string, data: Partial): Promise { + private static async update(path: Path, data: Partial): Promise { const oldConfig: TsConfig = await FsUtilities.parseFileAs(path); const tsconfig: TsConfig = mergeDeep(oldConfig, data); await FsUtilities.updateFile(path, JsonUtilities.stringify(tsconfig), 'replace', false); diff --git a/src/utilities/get-path.function.ts b/src/utilities/get-path.function.ts index b486388..7015c83 100644 --- a/src/utilities/get-path.function.ts +++ b/src/utilities/get-path.function.ts @@ -2,20 +2,29 @@ import path from 'path'; import { CPUtilities } from '../encapsulation'; +/** + * + */ +export type Path = string & { + /** + * + */ + __brand: 'Path' }; + /** * Gets a os agnostic path by joining the given parts. * @param paths - The paths to combine. * @returns The os agnostic file/dir path. * @throws When the given paths could not be joined. */ -export function getPath(...paths: string[]): string { +export function getPath(...paths: string[]): Path { try { const basePath: string = path.join(...paths); if (path.isAbsolute(basePath)) { - return basePath; + return basePath as Path; } const baseRoot: string = CPUtilities['cwd'] ?? ''; - return path.join(baseRoot, basePath); + return path.join(baseRoot, basePath) as Path; } catch (error) { throw new Error(`Error trying to get the path ${paths.join()}`, { cause: error }); diff --git a/src/workspace/workspace.utilities.ts b/src/workspace/workspace.utilities.ts index 0ff985f..3d3f850 100644 --- a/src/workspace/workspace.utilities.ts +++ b/src/workspace/workspace.utilities.ts @@ -3,7 +3,7 @@ import { Dirent } from 'fs'; import { APPS_DIRECTORY_NAME, LIBS_DIRECTORY_NAME, WORKSPACE_FILE_NAME } from '../constants'; import { CPUtilities, FsUtilities, JsonUtilities } from '../encapsulation'; import { WorkspaceConfig } from './workspace-config.model'; -import { getPath } from '../utilities'; +import { getPath, Path } from '../utilities'; /** * Definition for a single project inside the apps or libs dir. @@ -20,7 +20,7 @@ export type WorkspaceProject = { /** * The path to the project folder. */ - path: string + path: Path }; /** @@ -43,7 +43,7 @@ export abstract class WorkspaceUtilities { * @param workspaceFilePath - The path of the mx workspace file. Can be used when not running in the context of a workspace. * @returns The found config or undefined. */ - static async getConfig(workspaceFilePath: string = getPath(WORKSPACE_FILE_NAME)): Promise { + static async getConfig(workspaceFilePath: Path = getPath(WORKSPACE_FILE_NAME)): Promise { if (!await FsUtilities.exists(workspaceFilePath)) { return; } From 469bf940c8741e5af9a84bdfc634f293f92d2d5f Mon Sep 17 00:00:00 2001 From: Tim Fabian Date: Sun, 20 Apr 2025 18:55:10 +0200 Subject: [PATCH 2/2] fixed linting --- src/__testing__/mock/file-mock.utilities.ts | 2 +- src/utilities/get-path.function.ts | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/__testing__/mock/file-mock.utilities.ts b/src/__testing__/mock/file-mock.utilities.ts index f9fe05a..f06afb7 100644 --- a/src/__testing__/mock/file-mock.utilities.ts +++ b/src/__testing__/mock/file-mock.utilities.ts @@ -3,8 +3,8 @@ import { MockConstants, FileMockConstants, DirMockConstants } from './constants' import { AngularJson } from '../../angular'; import { CPUtilities, FsUtilities, JsonUtilities } from '../../encapsulation'; import { EnvUtilities } from '../../env'; -import { WorkspaceUtilities } from '../../workspace'; import { getPath } from '../../utilities'; +import { WorkspaceUtilities } from '../../workspace'; export abstract class FileMockUtilities { diff --git a/src/utilities/get-path.function.ts b/src/utilities/get-path.function.ts index 7015c83..c44f924 100644 --- a/src/utilities/get-path.function.ts +++ b/src/utilities/get-path.function.ts @@ -3,13 +3,12 @@ import path from 'path'; import { CPUtilities } from '../encapsulation'; /** - * + * The type for a file path. */ export type Path = string & { - /** - * - */ - __brand: 'Path' }; + // eslint-disable-next-line jsdoc/require-jsdoc + __brand: 'Path' +}; /** * Gets a os agnostic path by joining the given parts.