diff --git a/.eslintrc.json b/.eslintrc.json index 70c87deb2..08d0081f6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,6 +3,7 @@ "ignorePatterns": [ "projects/**/*" ], + "plugins": ["@nrwl/nx"], "overrides": [ { "files": [ @@ -12,8 +13,8 @@ "createDefaultProgram": true }, "extends": [ - "plugin:@angular-eslint/ng-cli-compat", - "plugin:@angular-eslint/ng-cli-compat--formatting-add-on", + "plugin:@nrwl/nx/typescript", + "plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates", "plugin:@cspell/recommended" ], @@ -23,7 +24,12 @@ "prettier", "ban", "@cspell", - "license-header" + "license-header", + "eslint-plugin-import", + "@angular-eslint/eslint-plugin", + "eslint-plugin-unicorn", + "eslint-plugin-rxjs", + "@typescript-eslint" ], "rules": { "ban/ban": [ @@ -67,14 +73,6 @@ "prettier/prettier": "error", "no-shadow": "off", "@typescript-eslint/no-shadow": "error", - "prefer-arrow/prefer-arrow-functions": [ - "warn", - { - "disallowPrototype": true, - "singleReturnOnly": true, - "classPropertiesAllowed": false - } - ], "@angular-eslint/component-selector": [ "error", { @@ -95,10 +93,33 @@ "style": "camelCase" } ], + "@angular-eslint/component-class-suffix": "error", + "@angular-eslint/directive-class-suffix": "error", + "@angular-eslint/no-conflicting-lifecycle": "error", + "@typescript-eslint/no-floating-promises": "off", + "@angular-eslint/no-input-rename": "error", + "@angular-eslint/no-output-native": "error", + "@angular-eslint/no-output-on-prefix": "error", + "@angular-eslint/no-output-rename": "error", "@angular-eslint/no-host-metadata-property": "off", + "@angular-eslint/no-outputs-metadata-property": "error", + "@angular-eslint/use-lifecycle-interface": "error", + "@angular-eslint/use-pipe-transform-interface": "error", + "@typescript-eslint/no-misused-new": "error", + "@typescript-eslint/no-non-null-assertion": "error", + "@typescript-eslint/prefer-function-type": "error", + "@typescript-eslint/triple-slash-reference": "error", + "@typescript-eslint/unified-signatures": "error", + "@typescript-eslint/no-unused-vars": "warn", "@typescript-eslint/consistent-type-definitions": "error", "@typescript-eslint/dot-notation": "off", "@typescript-eslint/member-ordering": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-empty-interface": "error", + "@typescript-eslint/no-unused-expressions": "error", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/ban-types": "error", "@typescript-eslint/explicit-member-accessibility": [ "off", { @@ -118,10 +139,7 @@ } } ], - "@typescript-eslint/semi": [ - "off", - null - ], + "@typescript-eslint/semi": ["error", "always"], "@typescript-eslint/naming-convention": [ "error", { @@ -131,32 +149,153 @@ ] } ], - "@typescript-eslint/type-annotation-spacing": "off", + "@typescript-eslint/no-inferrable-types": [ + "error", + { + "ignoreParameters": true + } + ], + "@typescript-eslint/quotes": [ + "error", + "single", + { + "avoidEscape": true, + "allowTemplateLiterals": true + } + ], + "@typescript-eslint/type-annotation-spacing": "error", "arrow-parents": [ "off", "always" ], "brace-style": [ - "off", - "off" + "error", + "1tbs", + { + "allowSingleLine": true + } ], - "eol-last": "off", + "constructor-super": "error", + "curly": "error", + "dot-notation": "off", + "eol-last": "error", + "eqeqeq": ["error", "smart"], + "guard-for-in": "error", "id-blacklist": "off", "id-match": "off", + "id-denylist": "off", + "import/no-deprecated": "error", "linebreak-style": "off", - "max-len": "off", "new-parens": "off", "newline-per-chained-call": "off", + "prefer-rest-params": "error", + "prefer-spread": "error", + "import/order": "off", + "max-len": [ + "error", + { + "code": 180 + } + ], "no-duplicate-imports": "error", "no-extra-semi": "off", - "no-irregular-whitespace": "off", + "no-empty": "off", + "no-empty-function": "off", + "no-irregular-whitespace": "error", "no-return-await": "error", "no-underscore-dangle": "off", + "no-useless-escape": "off", + "no-prototype-builtins": "error", + "no-async-promise-executor": "warn", + "no-unsafe-optional-chaining": "warn", + "no-bitwise": "error", + "no-caller": "error", + "no-global-assign": "error", + "no-cond-assign": "error", + "no-console": [ + "error", + { + "allow": [ + "warn", + "dir", + "timeLog", + "assert", + "clear", + "count", + "countReset", + "group", + "groupEnd", + "table", + "dirxml", + "error", + "groupCollapsed", + "Console", + "profile", + "profileEnd", + "timeStamp", + "context" + ] + } + ], + "no-case-declarations": "error", + "no-debugger": "error", + "no-constant-condition": "error", + "no-eval": "error", + "no-regex-spaces": "error", + "no-extra-boolean-cast": "error", + "no-fallthrough": "error", + "no-multiple-empty-lines": "error", + "no-new-wrappers": "error", + "no-restricted-imports": ["error", "rxjs/Rx"], + "no-self-assign": "error", + "no-throw-literal": "error", + "no-trailing-spaces": "error", + "no-undef-init": "error", + "no-unused-labels": "error", + "no-var": "error", + "prefer-const": "error", "quote-props": "off", + "quotes": "off", + "radix": "error", "rxjs/no-create": "error", "rxjs/no-subject-unsubscribe": "error", "rxjs/no-subject-value": "error", "rxjs/no-unsafe-takeuntil": "error", + "rxjs/ban-operators": "error", + "rxjs/no-ignored-subscribe": "error", + "rxjs/no-unsafe-catch": [ + "error", + { + "observable": "action(s|\\$)?" + } + ], + "rxjs/no-unsafe-switchmap": [ + "error", + { + "disallow": [ + "add", + "create", + "delete", + "post", + "put", + "remove", + "set", + "update" + ], + "observable": "action(s|\\$)?" + } + ], + "semi": "error", + "use-isnan": "error", + + "spaced-comment": [ + "error", + "always", + { + "markers": ["/"], + "exceptions": ["!", "*"] + } + ], "space-before-function-paren": "off", "space-in-parens": [ "off", @@ -165,13 +304,16 @@ "unicorn/filename-case": "error" } }, + { + "files": ["*.js"], + "extends": ["plugin:@nrwl/nx/javascript"], + "rules": {} + }, { "files": [ "*.html" ], - "extends": [ - "plugin:@angular-eslint/template/recommended" - ], + "extends": ["plugin:@nrwl/nx/angular-template"], "rules": { "@angular-eslint/template/no-autofocus": "error", "@angular-eslint/template/no-negated-async": "off", @@ -186,6 +328,13 @@ "@angular-eslint/template/accessibility-label-has-associated-control": "error", "@angular-eslint/template/eqeqeq": "error" } + }, + { + "files": ["*.spec.ts", "*.test.ts"], + "rules": { + "@typescript-eslint/no-floating-promises": "off", + "max-lines": "off" + } } ] } diff --git a/.github/actions/run-e2e/action.yml b/.github/actions/run-e2e/action.yml index ced5a274e..f07c06754 100644 --- a/.github/actions/run-e2e/action.yml +++ b/.github/actions/run-e2e/action.yml @@ -50,3 +50,10 @@ runs: echo "./node_modules/.bin/protractor \"./protractor.conf.js\" ${{ inputs.options }} || exit 1" ./node_modules/.bin/protractor "./protractor.conf.js" ${{ inputs.options }} $E2E_PROTRACTOR_OPTS || exit 1 fi + + - name: Upload E2Es results + if: ${{ always() }} + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.options }} + path: test-results/ diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 433742131..3a7595504 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -13,6 +13,8 @@ env: APP_CONFIG_ECM_HOST: ${{ secrets.PIPELINE_ENV_URL }} ADMIN_EMAIL: ${{ secrets.PIPELINE_ADMIN_USERNAME }} ADMIN_PASSWORD: ${{ secrets.PIPELINE_ADMIN_PASSWORD }} + SCREENSHOT_USERNAME: ${{ secrets.SCREENSHOT_USERNAME }} + SCREENSHOT_PASSWORD: ${{ secrets.SCREENSHOT_PASSWORD}} AWS_REGION: "eu-west-2" CONTENT_CE_DIST_PATH: "./dist/content-ce" APP_CONFIG_PROVIDER: ECM @@ -36,6 +38,7 @@ env: APP_CONFIG_DOWNLOAD_PROMPT_REMINDER_DELAY: 30 APP_CONFIG_ENABLE_FILE_AUTO_DOWNLOAD: true APP_CONFIG_FILE_AUTO_DOWNLOAD_SIZE_THRESHOLD_IN_MB: 15 + GH_BUILD_NUMBER: ${{ github.run_id }} jobs: lint: diff --git a/app/src/main.ts b/app/src/main.ts index dcd2f5e32..0e42d77f5 100644 --- a/app/src/main.ts +++ b/app/src/main.ts @@ -32,4 +32,4 @@ if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule); +void platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/e2e/.eslintrc.json b/e2e/.eslintrc.json index 10afca993..700775812 100644 --- a/e2e/.eslintrc.json +++ b/e2e/.eslintrc.json @@ -19,6 +19,7 @@ "unicorn" ], "rules": { + "@typescript-eslint/no-floating-promises": "off" } } ] diff --git a/e2e/e2e-config/utils/upload-output.js b/e2e/e2e-config/utils/upload-output.js index 081be59c6..e755bc437 100644 --- a/e2e/e2e-config/utils/upload-output.js +++ b/e2e/e2e-config/utils/upload-output.js @@ -5,7 +5,7 @@ const buildNumber = require('./build-number'); const outputDir = path.resolve(__dirname, '../../../e2e-output/'); async function saveScreenshots(retryCount) { - const folderName = process.env.TRAVIS_JOB_NAME.replace(/[^a-z0-9]/gi, '_').toLowerCase(); + const folderName = process.env.GITHUB_JOB; console.log(`Start uploading report in ${folderName}`); let alfrescoJsApi = new AlfrescoApi({ diff --git a/e2e/playwright/tests/folder-rules/fixtures/page-initialization.ts b/e2e/playwright/tests/folder-rules/fixtures/page-initialization.ts index ad5409208..84ef9e860 100644 --- a/e2e/playwright/tests/folder-rules/fixtures/page-initialization.ts +++ b/e2e/playwright/tests/folder-rules/fixtures/page-initialization.ts @@ -42,6 +42,7 @@ export const test = base.extend({ nodesPage: async ({ page }, use) => { await use(new NodesPage(page)); }, + // eslint-disable-next-line no-empty-pattern apiClient: async ({}, use) => { const apiClient = new ApiClientFactory(); await apiClient.setUpAcaBackend('admin'); diff --git a/package-lock.json b/package-lock.json index 2d246d39f..a029c90c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4290,6 +4290,79 @@ } } }, + "@nrwl/eslint-plugin-nx": { + "version": "15.9.2", + "resolved": "https://registry.npmjs.org/@nrwl/eslint-plugin-nx/-/eslint-plugin-nx-15.9.2.tgz", + "integrity": "sha512-WeR+/mjzteBz9401mZroyML7sgnxF32FjMBcmVjuG5a5Eji36ChXn8Vtzm3IhfAY3k2sFbANxYLSNQYf5JJyqw==", + "dev": true, + "requires": { + "@nrwl/devkit": "15.9.2", + "@typescript-eslint/utils": "^5.36.1", + "chalk": "^4.1.0", + "confusing-browser-globals": "^1.0.9", + "semver": "7.3.4" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "@nrwl/jest": { "version": "15.9.2", "resolved": "https://registry.npmjs.org/@nrwl/jest/-/jest-15.9.2.tgz", @@ -7902,6 +7975,12 @@ "xdg-basedir": "^4.0.0" } }, + "confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, "connect": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", diff --git a/package.json b/package.json index 282c8e482..7b06f583a 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "@angular/language-service": "14.1.2", "@cspell/eslint-plugin": "^6.31.1", "@nrwl/angular": "15.9.2", + "@nrwl/eslint-plugin-nx": "^15.9.2", "@nrwl/workspace": "15.9.2", "@playwright/test": "^1.31.2", "@schematics/angular": "14.1.2", diff --git a/projects/aca-content/src/lib/components/search/search-libraries-results/search-libraries-results.component.ts b/projects/aca-content/src/lib/components/search/search-libraries-results/search-libraries-results.component.ts index 8424856d6..97b78869b 100644 --- a/projects/aca-content/src/lib/components/search/search-libraries-results/search-libraries-results.component.ts +++ b/projects/aca-content/src/lib/components/search/search-libraries-results/search-libraries-results.component.ts @@ -103,6 +103,7 @@ export class SearchLibrariesResultsComponent extends PageComponent implements On if (this.route) { this.route.params.forEach((params: Params) => { + // eslint-disable-next-line no-prototype-builtins this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null; const query = this.formatSearchQuery(this.searchedWord); diff --git a/projects/aca-content/src/lib/components/search/search-results/search-results.component.ts b/projects/aca-content/src/lib/components/search/search-results/search-results.component.ts index 6bdafe277..31dca4b9a 100644 --- a/projects/aca-content/src/lib/components/search/search-results/search-results.component.ts +++ b/projects/aca-content/src/lib/components/search/search-results/search-results.component.ts @@ -85,6 +85,7 @@ export class SearchResultsComponent extends PageComponent implements OnInit { combineLatest([this.route.params, this.queryBuilder.configUpdated]) .pipe(takeUntil(this.onDestroy$)) .subscribe(([params, searchConfig]) => { + // eslint-disable-next-line no-prototype-builtins this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null; const query = this.formatSearchQuery(this.searchedWord, searchConfig['aca:fields']); if (query) { @@ -128,6 +129,7 @@ export class SearchResultsComponent extends PageComponent implements OnInit { if (this.route) { this.route.params.forEach((params: Params) => { + // eslint-disable-next-line no-prototype-builtins this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null; if (this.searchedWord) { this.queryBuilder.update(); diff --git a/projects/aca-content/src/lib/extensions/core.extensions.module.ts b/projects/aca-content/src/lib/extensions/core.extensions.module.ts index 288c090e9..7b7e5cfef 100644 --- a/projects/aca-content/src/lib/extensions/core.extensions.module.ts +++ b/projects/aca-content/src/lib/extensions/core.extensions.module.ts @@ -29,7 +29,6 @@ import { ExtensionsModule } from '@alfresco/adf-extensions'; import { AppExtensionService } from '@alfresco/aca-shared'; import { ContentServiceExtensionService } from '../services/content-service-extension.service'; -// eslint-disable-next-line prefer-arrow/prefer-arrow-functions export function setupExtensions(service: AppExtensionService): () => void { return () => service.load(); } diff --git a/projects/aca-folder-rules/src/lib/rule-details/conditions/rule-composite-condition.ui-component.ts b/projects/aca-folder-rules/src/lib/rule-details/conditions/rule-composite-condition.ui-component.ts index a7a5fcd7f..f3f061c1d 100644 --- a/projects/aca-folder-rules/src/lib/rule-details/conditions/rule-composite-condition.ui-component.ts +++ b/projects/aca-folder-rules/src/lib/rule-details/conditions/rule-composite-condition.ui-component.ts @@ -128,6 +128,7 @@ export class RuleCompositeConditionUiComponent implements ControlValueAccessor, } isFormControlSimpleCondition(control: FormControl): boolean { + // eslint-disable-next-line no-prototype-builtins return control.value.hasOwnProperty('field'); } diff --git a/projects/aca-shared/rules/src/app.rules.ts b/projects/aca-shared/rules/src/app.rules.ts index b23902d8d..4f501dce9 100644 --- a/projects/aca-shared/rules/src/app.rules.ts +++ b/projects/aca-shared/rules/src/app.rules.ts @@ -95,7 +95,7 @@ export const isContentServiceEnabled = (): boolean => localStorage && localStora * JSON ref: `app.isSearchSupported` */ export const isSearchSupported = (context: RuleContext): boolean => - [navigation.isNotSearchResults(context) /*, !hasSelection(context)*/].every(Boolean); + [navigation.isNotSearchResults(context) /* , !hasSelection(context)*/].every(Boolean); /** * Checks if upload action is supported for the given context @@ -617,6 +617,7 @@ export function canOpenWithOffice(context: RuleContext): boolean { // workaround for Shared files if (context.navigation && context.navigation.url && context.navigation.url.startsWith('/shared')) { + // eslint-disable-next-line no-prototype-builtins if (file.entry.hasOwnProperty('allowableOperationsOnTarget')) { return context.permissions.check(file, ['update'], { target: 'allowableOperationsOnTarget' diff --git a/projects/aca-shared/rules/src/navigation.rules.ts b/projects/aca-shared/rules/src/navigation.rules.ts index 35872d5c8..02d6a6df9 100644 --- a/projects/aca-shared/rules/src/navigation.rules.ts +++ b/projects/aca-shared/rules/src/navigation.rules.ts @@ -136,8 +136,8 @@ export const isNotRecentFiles = (context: RuleContext): boolean => !isRecentFile * JSON ref: `app.navigation.isSearchResults` */ export function isSearchResults( - context: RuleContext /*, - ...args: RuleParameter[]*/ + context: RuleContext + // ...args: RuleParameter[] ): boolean { const { url } = context.navigation; return url && url.startsWith('/search'); diff --git a/projects/aca-shared/src/lib/services/content-api.service.ts b/projects/aca-shared/src/lib/services/content-api.service.ts index 09448a01c..cefd917d5 100644 --- a/projects/aca-shared/src/lib/services/content-api.service.ts +++ b/projects/aca-shared/src/lib/services/content-api.service.ts @@ -154,9 +154,8 @@ export class ContentApiService { }; const queryOptions = Object.assign(defaults, options || {}); - // @ts-ignore return from( - new Promise((resolve, reject) => { + new Promise((resolve, reject) => { this.nodesApi.getNode(nodeId, queryOptions).then( (nodeEntry: NodeEntry) => { resolve(nodeEntry.entry); diff --git a/projects/adf-office-services-ext/src/lib/effects/aos.effects.spec.ts b/projects/adf-office-services-ext/src/lib/effects/aos.effects.spec.ts index 6330acd5a..ef421460b 100755 --- a/projects/adf-office-services-ext/src/lib/effects/aos.effects.spec.ts +++ b/projects/adf-office-services-ext/src/lib/effects/aos.effects.spec.ts @@ -64,7 +64,7 @@ describe('AosEffects', () => { const action = new AosAction(payload); aosActions$ = of(action); - effects.openOffice$.subscribe(); + effects.openOffice$.subscribe(() => {}); expect(onActionEditOnlineAosSpy).toHaveBeenCalledWith(payload); });