diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index c338175faa..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,14 +0,0 @@ -.angular -nxcache -node_modules -dist -coverage -.github -.vscode -scripts -/angular.json -docs/**/*.md -lib/js-api/docs/**/*.md -.storybook -webpack.config.js -lib/core/src/lib/icon diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 04a801938c..0000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,248 +0,0 @@ -module.exports = { - root: true, - - ignorePatterns: ['projects/**/*', '**/node_modules/**/*', 'lib/cli/node_modules/**/*', '**/node_modules', '**/assets', '**/scripts', '**/docs'], - - plugins: ['@nx'], - - overrides: [ - { - files: ['*.ts'], - parserOptions: { - project: ['tsconfig.json'], - createDefaultProgram: true - }, - extends: [ - 'plugin:@nx/typescript', - 'plugin:@nx/angular', - 'plugin:@cspell/recommended', - 'plugin:@angular-eslint/recommended', - 'plugin:@angular-eslint/template/process-inline-templates', - 'plugin:jsdoc/recommended-typescript-error' - // Uncomment this once all linting issues are fixed - // Note to developers: - // you can uncomment the full ruleset locally when fixing issues, and then comment - // that will allow splitting the work into smaller chunks - // 'plugin:unicorn/recommended' - ], - plugins: [ - 'eslint-plugin-unicorn', - 'eslint-plugin-rxjs', - 'prettier', - 'ban', - 'license-header', - '@cspell', - 'eslint-plugin-import', - '@angular-eslint/eslint-plugin', - '@typescript-eslint', - 'jsdoc' - ], - rules: { - // Uncomment this to enable prettier checks as part of the ESLint - // 'prettier/prettier': 'error', - 'ban/ban': [ - 'error', - { name: 'eval', message: 'Calls to eval is not allowed.' }, - { name: 'fdescribe', message: 'Calls to fdescribe is not allowed' }, - { name: 'fit', message: 'Calls to fit is not allowed' }, - { name: 'xit', message: 'Calls to xit is not allowed' }, - { name: 'xdescribe', message: 'Calls to xdescribe is not allowed' }, - { name: ['test', 'only'], message: 'Calls to test.only is not allowed' }, - { name: ['describe', 'only'], message: 'Calls to describe.only is not allowed' } - ], - '@angular-eslint/component-selector': [ - 'error', - { - type: 'element', - prefix: ['adf', 'app'], - style: 'kebab-case' - } - ], - '@angular-eslint/directive-selector': [ - 'error', - { - type: ['element', 'attribute'], - prefix: ['adf', 'app'], - style: 'kebab-case' - } - ], - '@angular-eslint/no-host-metadata-property': 'off', - '@angular-eslint/no-input-prefix': 'error', - '@angular-eslint/prefer-inject': 'error', - '@typescript-eslint/consistent-type-definitions': 'error', - '@typescript-eslint/dot-notation': 'off', - '@typescript-eslint/explicit-member-accessibility': [ - 'off', - { - accessibility: 'explicit' - } - ], - '@typescript-eslint/await-thenable': 'error', - '@typescript-eslint/prefer-optional-chain': 'warn', - '@typescript-eslint/prefer-readonly': 'error', - '@typescript-eslint/no-inferrable-types': 'off', - '@typescript-eslint/no-require-imports': 'off', - '@typescript-eslint/no-var-requires': 'error', - '@typescript-eslint/naming-convention': [ - 'error', - { - selector: [ - 'classProperty', - 'objectLiteralProperty', - 'typeProperty', - 'classMethod', - 'objectLiteralMethod', - 'typeMethod', - 'accessor', - 'enumMember' - ], - format: null, - modifiers: ['requiresQuotes'] - } - ], - '@typescript-eslint/member-ordering': 'off', - '@typescript-eslint/no-empty-function': 'off', - '@typescript-eslint/no-explicit-any': 'off', - 'prefer-promise-reject-errors': 'error', - 'brace-style': 'off', - 'comma-dangle': 'error', - 'default-case': 'error', - 'import/order': 'off', - 'max-len': [ - 'error', - { - code: 240 - } - ], - 'no-bitwise': 'off', - 'no-console': [ - 'error', - { - allow: [ - 'warn', - 'dir', - 'timeLog', - 'assert', - 'clear', - 'count', - 'countReset', - 'group', - 'groupEnd', - 'table', - 'dirxml', - 'error', - 'groupCollapsed', - 'Console', - 'profile', - 'profileEnd', - 'timeStamp', - 'context' - ] - } - ], - 'no-duplicate-imports': 'error', - 'no-multiple-empty-lines': 'error', - 'no-redeclare': 'off', - '@typescript-eslint/no-redeclare': ['off', { ignoreDeclarationMerge: true }], - '@typescript-eslint/no-unused-vars': [ - 'error', - { - argsIgnorePattern: '^_', - varsIgnorePattern: '^_', - caughtErrorsIgnorePattern: '^_' - } - ], - 'no-return-await': 'error', - 'rxjs/no-create': 'error', - 'rxjs/no-subject-unsubscribe': 'error', - 'rxjs/no-subject-value': 'error', - 'rxjs/no-unsafe-takeuntil': 'error', - 'unicorn/filename-case': 'error', - 'unicorn/prefer-optional-catch-binding': 'error', - '@typescript-eslint/no-unused-expressions': [ - 'error', - { - allowShortCircuit: true, - allowTernary: true - } - ], - 'license-header/header': [ - 'error', - [ - '/*!', - ' * @license', - ' * Copyright © 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved.', - ' *', - ' * Licensed under the Apache License, Version 2.0 (the "License");', - ' * you may not use this file except in compliance with the License.', - ' * You may obtain a copy of the License at', - ' *', - ' * http://www.apache.org/licenses/LICENSE-2.0', - ' *', - ' * Unless required by applicable law or agreed to in writing, software', - ' * distributed under the License is distributed on an "AS IS" BASIS,', - ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.', - ' * See the License for the specific language governing permissions and', - ' * limitations under the License.', - ' */' - ] - ], - 'no-restricted-syntax': [ - 'error', - { - selector: "Identifier[name='CUSTOM_ELEMENTS_SCHEMA']", - message: 'The use of CUSTOM_ELEMENTS_SCHEMA is not allowed. Consider alternatives for proper schema handling.' - }, - { - selector: "Identifier[name='NO_ERRORS_SCHEMA']", - message: 'The use of NO_ERRORS_SCHEMA is not allowed. Consider alternatives for proper schema handling.' - }, - { - selector: 'TSEnumDeclaration', - message: 'Enums are not allowed. Use string literal types (e.g., type Foo = "a" | "b") or const objects instead.' - }, - { - selector: ':matches(Literal[value=/ng-reflect-/], TemplateElement[value.cooked=/ng-reflect-/])', - message: '*ng-reflect-* attributes should not be used. Consider alternatives for proper selectors.' - } - ] - } - }, - { - files: ['*.html'], - extends: ['plugin:@angular-eslint/template/recommended', 'plugin:@angular-eslint/template/accessibility'], - parser: '@angular-eslint/template-parser', - rules: { - '@angular-eslint/template/prefer-self-closing-tags': 'error' - } - }, - { - files: ['*.spec.ts'], - plugins: ['@alfresco/eslint-angular'], - rules: { - '@alfresco/eslint-angular/no-angular-material-selectors': 'error', - '@angular-eslint/component-class-suffix': 'off' - } - }, - { - files: ['*.ts'], - extends: ['plugin:@angular-eslint/template/process-inline-templates'], - excludedFiles: ['*.spec.ts'] - }, - { - files: ['*.json'], - parser: 'jsonc-eslint-parser', - rules: { - 'comma-dangle': ['error', 'never'] - } - }, - { - files: ['**/*.stories.ts'], - rules: { - '@cspell/spellchecker': 'off' - } - } - ], - - extends: ['plugin:storybook/recommended'] -}; diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 81894c2c7d..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": ["./.eslintrc.js"] -} diff --git a/.lintstagedrc.json b/.lintstagedrc.json index 30ba7528e5..50921ff006 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,4 +1,4 @@ { - "*.{ts,js}": ["prettier --write", "eslint"], + "*.{ts,js}": ["prettier --write", "eslint --flag v10_config_lookup_from_file"], "*.{css,scss}": ["prettier --write", "stylelint --fix"] } diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000..c257eb3806 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,357 @@ +/*! + * @license + * Copyright © 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import js from '@eslint/js'; +import { FlatCompat } from '@eslint/eslintrc'; +import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import { fixupPluginRules } from '@eslint/compat'; +import unicorn from 'eslint-plugin-unicorn'; +import rxjs from 'eslint-plugin-rxjs'; +import prettier from 'eslint-plugin-prettier'; +import ban from 'eslint-plugin-ban'; +import licenseHeader from 'eslint-plugin-license-header'; +import cspell from '@cspell/eslint-plugin'; +import importPlugin from 'eslint-plugin-import'; +import storybook from 'eslint-plugin-storybook'; +import nxPlugin from '@nx/eslint-plugin'; +import angularEslintEslintPlugin from '@angular-eslint/eslint-plugin'; +import angularTemplateParser from '@angular-eslint/template-parser'; +import tsParser from '@typescript-eslint/parser'; +import jsonParser from 'jsonc-eslint-parser'; +import alfrescoEslintAngular from './lib/eslint-angular/main.js'; +import jsdoc from 'eslint-plugin-jsdoc'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}); + +export default [ + { + ignores: [ + '.angular', + '.DS_Store', + '.github', + '.history', + '.husky', + '.nx', + '.vscode', + 'coverage', + 'dist', + '**/docs', + 'nxcache', + 'tmp', + 'projects/**/*', + '**/node_modules/**/*', + 'lib/cli/node_modules/**/*', + 'lib/core/src/lib/icon', + '**/node_modules', + '**/assets', + '/scripts' + ] + }, + // You can uncomment unicorn.configs['recommended'], fix a few issues, and comment it out again until all issues are resolved. + // Expect significant effort to fix all reported issues. + // Note to developers: when enabling unicorn.configs['recommended'], remove unicorn from plugins to avoid plugin redefinition errors. + // unicorn.configs['recommended'], + ...storybook.configs['flat/recommended'], + { + files: ['**/*.{js,mjs,cjs,ts}'], + ignores: ['**/*.d.ts'], + plugins: { + 'license-header': licenseHeader + }, + rules: { + 'license-header/header': [ + 'error', + [ + '/*!', + ' * @license', + ' * Copyright © 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved.', + ' *', + ' * Licensed under the Apache License, Version 2.0 (the "License");', + ' * you may not use this file except in compliance with the License.', + ' * You may obtain a copy of the License at', + ' *', + ' * http://www.apache.org/licenses/LICENSE-2.0', + ' *', + ' * Unless required by applicable law or agreed to in writing, software', + ' * distributed under the License is distributed on an "AS IS" BASIS,', + ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.', + ' * See the License for the specific language governing permissions and', + ' * limitations under the License.', + ' */' + ] + ] + } + }, + { + files: ['**/*.ts', '**/*.js', '**/*.mjs'], + ignores: ['**/*.d.ts', '**/*.spec.ts'], + ...jsdoc.configs['flat/recommended-typescript-error'] + }, + { + files: ['**/*.ts'], + ignores: ['**/*.d.ts', '**/*.mjs'], + ...compat.extends( + 'plugin:@nx/typescript', + 'plugin:@nx/angular', + 'plugin:@cspell/recommended', + 'plugin:@angular-eslint/recommended', + 'plugin:@angular-eslint/template/process-inline-templates' + )[0], + plugins: { + '@nx': nxPlugin, + jsdoc, + unicorn, + rxjs: fixupPluginRules(rxjs), + prettier: prettier, + ban: ban, + '@cspell': cspell, + import: importPlugin, + '@angular-eslint': angularEslintEslintPlugin, + '@typescript-eslint': typescriptEslint + }, + languageOptions: { + parser: tsParser, + parserOptions: { + projectService: true, + allowDefaultProject: true, + tsconfigRootDir: __dirname, + sourceType: 'module' + } + }, + rules: { + // Uncomment this to enable prettier checks as part of the ESLint + // Note to developers: + // you can uncomment the full ruleset locally when fixing issues, and then comment + // that will allow splitting the work into smaller chunks + // 'prettier/prettier': 'error', + 'ban/ban': [ + 'error', + { name: 'eval', message: 'Calls to eval is not allowed.' }, + { name: 'fdescribe', message: 'Calls to fdescribe is not allowed' }, + { name: 'fit', message: 'Calls to fit is not allowed' }, + { name: 'xit', message: 'Calls to xit is not allowed' }, + { name: 'xdescribe', message: 'Calls to xdescribe is not allowed' }, + { name: ['test', 'only'], message: 'Calls to test.only is not allowed' }, + { name: ['describe', 'only'], message: 'Calls to describe.only is not allowed' } + ], + '@angular-eslint/component-selector': [ + 'error', + { + type: 'element', + prefix: ['adf', 'app'], + style: 'kebab-case' + } + ], + '@angular-eslint/directive-selector': [ + 'error', + { + type: ['element', 'attribute'], + prefix: ['adf', 'app'], + style: 'kebab-case' + } + ], + '@angular-eslint/no-host-metadata-property': 'off', + '@angular-eslint/no-input-prefix': 'error', + '@angular-eslint/prefer-inject': 'error', + '@typescript-eslint/consistent-type-definitions': 'error', + '@typescript-eslint/dot-notation': 'off', + '@typescript-eslint/explicit-member-accessibility': [ + 'off', + { + accessibility: 'explicit' + } + ], + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/prefer-optional-chain': 'warn', + '@typescript-eslint/prefer-readonly': 'error', + '@typescript-eslint/no-inferrable-types': 'off', + '@typescript-eslint/no-require-imports': 'off', + '@typescript-eslint/no-var-requires': 'error', + 'jsdoc/tag-lines': [ + 'error', + 'any', + { + startLines: 1 + } + ], + '@typescript-eslint/naming-convention': [ + 'error', + { + selector: [ + 'classProperty', + 'objectLiteralProperty', + 'typeProperty', + 'classMethod', + 'objectLiteralMethod', + 'typeMethod', + 'accessor', + 'enumMember' + ], + format: null, + modifiers: ['requiresQuotes'] + } + ], + '@typescript-eslint/member-ordering': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'prefer-promise-reject-errors': 'error', + 'brace-style': 'off', + 'comma-dangle': 'error', + 'default-case': 'error', + 'import/order': 'off', + 'max-len': [ + 'error', + { + code: 240 + } + ], + 'no-bitwise': 'off', + 'no-console': [ + 'error', + { + allow: [ + 'warn', + 'dir', + 'timeLog', + 'assert', + 'clear', + 'count', + 'countReset', + 'group', + 'groupEnd', + 'table', + 'dirxml', + 'error', + 'groupCollapsed', + 'Console', + 'profile', + 'profileEnd', + 'timeStamp', + 'context' + ] + } + ], + 'no-duplicate-imports': 'error', + 'no-multiple-empty-lines': 'error', + 'no-redeclare': 'off', + '@typescript-eslint/no-redeclare': ['off', { ignoreDeclarationMerge: true }], + '@typescript-eslint/no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_' + } + ], + 'no-return-await': 'error', + 'rxjs/no-create': 'error', + 'rxjs/no-subject-unsubscribe': 'error', + 'rxjs/no-subject-value': 'error', + 'rxjs/no-unsafe-takeuntil': 'error', + 'unicorn/filename-case': 'error', + 'unicorn/prefer-optional-catch-binding': 'error', + '@typescript-eslint/no-unused-expressions': [ + 'error', + { + allowShortCircuit: true, + allowTernary: true + } + ], + 'no-restricted-syntax': [ + 'error', + { + selector: "Identifier[name='CUSTOM_ELEMENTS_SCHEMA']", + message: 'The use of CUSTOM_ELEMENTS_SCHEMA is not allowed. Consider alternatives for proper schema handling.' + }, + { + selector: "Identifier[name='NO_ERRORS_SCHEMA']", + message: 'The use of NO_ERRORS_SCHEMA is not allowed. Consider alternatives for proper schema handling.' + }, + { + selector: 'TSEnumDeclaration', + message: 'Enums are not allowed. Use string literal types (e.g., type Foo = "a" | "b") or const objects instead.' + }, + { + selector: ':matches(Literal[value=/ng-reflect-/], TemplateElement[value.cooked=/ng-reflect-/])', + message: '*ng-reflect-* attributes should not be used. Consider alternatives for proper selectors.' + } + ] + } + }, + { + files: ['**/*.html'], + ...compat.extends( + 'plugin:@angular-eslint/template/recommended', + 'plugin:@angular-eslint/template/accessibility', + 'plugin:@nx/angular-template' + )[0], + languageOptions: { + parser: angularTemplateParser + }, + rules: { + '@angular-eslint/template/prefer-self-closing-tags': 'error' + } + }, + { + files: ['**/*.spec.ts'], + plugins: { + '@alfresco/eslint-angular': alfrescoEslintAngular + }, + rules: { + '@alfresco/eslint-angular/no-angular-material-selectors': 'error', + '@angular-eslint/component-class-suffix': 'off' + } + }, + { + files: ['**/*.json'], + languageOptions: { + parser: jsonParser + }, + rules: { + 'comma-dangle': ['error', 'never'] + } + }, + { + files: ['**/*.stories.ts'], + rules: { + '@cspell/spellchecker': 'off' + } + }, + { + files: ['**/*.mjs'], + rules: { + 'unicorn/no-null': 'off' + }, + languageOptions: { + parser: tsParser, + parserOptions: { + tsconfigRootDir: __dirname, + ecmaVersion: 'latest', + sourceType: 'module' + } + } + } +]; diff --git a/lib/cli/.eslintrc.json b/lib/cli/.eslintrc.json deleted file mode 100644 index c692710d50..0000000000 --- a/lib/cli/.eslintrc.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "extends": ["../../.eslintrc.js"], - "ignorePatterns": ["!**/*", "dist", "node_modules"], - "overrides": [ - { - "files": ["*.ts"], - "extends": ["plugin:@nx/angular"], - "parserOptions": { - "project": ["lib/cli/tsconfig.json"], - "createDefaultProgram": true - }, - "rules": { - "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/naming-convention": "warn", - "quote-props": "off", - "no-shadow": "warn", - "no-restricted-syntax": "off", - "no-underscore-dangle": "off", - "@typescript-eslint/consistent-type-assertions": "warn", - "@typescript-eslint/prefer-for-of": "off", - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/no-inferrable-types": "off", - "@typescript-eslint/no-require-imports": "off", - "default-case": "error", - "import/order": "off", - "max-len": [ - "error", - { - "code": 240 - } - ], - "no-duplicate-imports": "error", - "no-multiple-empty-lines": "error", - "no-redeclare": "error", - "no-return-await": "error", - "no-console": "off" - } - }, - { - "files": ["*.html"], - "parserOptions": { - "project": ["lib/cli/tsconfig.json"], - "createDefaultProgram": true - }, - "extends": ["plugin:@nx/angular-template"], - "rules": {} - } - ] -} diff --git a/lib/cli/eslint.config.mjs b/lib/cli/eslint.config.mjs new file mode 100644 index 0000000000..ce2ab3ea5d --- /dev/null +++ b/lib/cli/eslint.config.mjs @@ -0,0 +1,49 @@ +/*! + * @license + * Copyright © 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import rootConfig from '../../eslint.config.mjs'; + +export default [ + ...rootConfig, + { + files: ['**/*.ts'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: 'scope:cli', + onlyDependOnLibsWithTags: ['scope:js-api'] + } + ] + } + ], + '@typescript-eslint/no-var-requires': 'off', + 'quote-props': 'off', + 'no-shadow': 'warn', + 'no-restricted-syntax': 'off', + 'no-underscore-dangle': 'off', + '@typescript-eslint/consistent-type-assertions': 'warn', + '@typescript-eslint/prefer-for-of': 'off', + 'no-redeclare': 'error', + 'no-console': 'off', + } + } +]; diff --git a/lib/cli/project.json b/lib/cli/project.json index ba2b327022..a4a1d5c117 100644 --- a/lib/cli/project.json +++ b/lib/cli/project.json @@ -4,6 +4,7 @@ "sourceRoot": "lib/cli", "projectType": "library", "prefix": "adf", + "tags": ["scope:cli", "type:tooling"], "targets": { "build": { "executor": "nx:run-commands", diff --git a/lib/cli/scripts/audit.ts b/lib/cli/scripts/audit.ts index 5afa0e8803..b8fc27089c 100644 --- a/lib/cli/scripts/audit.ts +++ b/lib/cli/scripts/audit.ts @@ -29,6 +29,14 @@ interface AuditCommandArgs { outDir?: string; } +/** + * Render the audit report as a Markdown page. + * + * @param jsonAudit parsed npm audit JSON output + * @param projName project name + * @param projVersion project version + * @returns rendered Markdown string + */ function renderAuditPage(jsonAudit: any, projName: string, projVersion: string): string { const rows: string[] = []; if (jsonAudit.auditReportVersion >= 2) { @@ -122,7 +130,6 @@ Options: } return new Promise((resolve, reject) => { - // eslint-disable-next-line no-console console.log(`Running audit on ${packagePath}`); const packageJson = JSON.parse(fs.readFileSync(packagePath).toString()); @@ -172,7 +179,6 @@ Options: fs.writeFileSync(outputFile, mdText); - // eslint-disable-next-line no-console console.log(`Report saved as ${outputFile}`); resolve(0); }); diff --git a/lib/cli/scripts/changelog.ts b/lib/cli/scripts/changelog.ts index 9080d84d19..e3117aeffe 100644 --- a/lib/cli/scripts/changelog.ts +++ b/lib/cli/scripts/changelog.ts @@ -17,8 +17,6 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/naming-convention */ - import { argv, exit } from 'node:process'; import { parseArgs } from 'node:util'; import { spawnSync } from 'node:child_process'; @@ -146,7 +144,7 @@ function getCommits(options: DiffOptions): Array { .map((str: string) => { try { return JSON.parse(str) as Commit; - } catch (error) { + } catch { logger.error(`Unparsable commit message: ${str}, dropping it... Please apply manual fix.`); return null; } @@ -167,6 +165,15 @@ function commitAuthorAllowed(commit: Commit, authorFilter: string): boolean { return !(filterRegex.test(commit.author) || filterRegex.test(commit.author_email)); } +/** + * Render changelog as Markdown. + * + * @param commits list of commits + * @param projName project name + * @param projVersion project version + * @param repoUrl repository URL + * @returns rendered Markdown string + */ function renderChangelogMd(commits: Commit[], projName: string, projVersion: string, repoUrl: string): string { const lines = commits.map((c) => `- [${c.hash}](${repoUrl}/commit/${c.hash}) ${escapeHtml(c.subject)}`); return `--- @@ -179,6 +186,15 @@ ${lines.join('\n')} `; } +/** + * Render changelog as HTML. + * + * @param commits list of commits + * @param projName project name + * @param projVersion project version + * @param repoUrl repository URL + * @returns rendered HTML string + */ function renderChangelogHtml(commits: Commit[], projName: string, projVersion: string, repoUrl: string): string { const items = commits .map((c) => `
  • \n [${c.hash}] ${escapeHtml(c.subject)}\n
  • `) diff --git a/lib/cli/scripts/init-aae-env.ts b/lib/cli/scripts/init-aae-env.ts index 29d28445d6..e8211596f3 100755 --- a/lib/cli/scripts/init-aae-env.ts +++ b/lib/cli/scripts/init-aae-env.ts @@ -90,8 +90,9 @@ async function healthCheck(nameService: string) { } /** - * Get deployed application + * Get deployed application. * + * @returns list of deployed applications */ async function getApplications(): Promise<{ list: { entries: any[] } }> { const url = `${args.host}/deployment-service/v1/applications`; @@ -236,9 +237,10 @@ function getProjectRelease(projectId: string) { } /** - * Release project + * Release project. * * @param projectId project id + * @returns release response */ async function releaseProject(projectId: string) { const url = `${args.host}/modeling-service/v1/projects/${projectId}/releases`; @@ -307,9 +309,10 @@ function deleteProject(projectId: string) { } /** - * Import and release project + * Import and release project. * * @param absoluteFilePath path to project file + * @returns released project */ async function importAndReleaseProject(absoluteFilePath: string) { const fileContent = fs.createReadStream(absoluteFilePath); @@ -585,9 +588,10 @@ async function deployWithPayload(currentAbsentApp: any, projectRelease: any, env } /** - * Check if descriptor exists + * Check if descriptor exists. * * @param name descriptor name + * @returns `true` if descriptor exists */ async function checkDescriptorExist(name: string): Promise { logger.info(`Check descriptor ${name} exist in the list `); @@ -606,10 +610,11 @@ async function checkDescriptorExist(name: string): Promise { } /** - * Import and release project + * Import and release project. * * @param app application * @param tag tag + * @returns released project */ async function importProjectAndRelease(app: any, tag?: string) { const appLocationReplaced = app.file_location(tag); @@ -667,10 +672,11 @@ function findFailingApps(deployedApps: any[]): any[] { } /** - * Get file from the remote + * Get file from the remote. * * @param url url to file * @param name name + * @returns resolves when the file is downloaded */ async function getFileFromRemote(url: string, name: string): Promise { return fetch(url) diff --git a/lib/cli/scripts/init-acs-env.ts b/lib/cli/scripts/init-acs-env.ts index 03793fecd7..1f8e21b6e4 100755 --- a/lib/cli/scripts/init-acs-env.ts +++ b/lib/cli/scripts/init-acs-env.ts @@ -119,6 +119,7 @@ async function initializeDefaultFiles() { /** * Process a single file: upload if missing, then apply its action (lock/share/favorite). + * * @param fileInfo file descriptor from ACS_DEFAULT * @param fileInfo.name file name * @param fileInfo.action action to apply (LOCK, SHARE, FAVORITE) @@ -154,6 +155,7 @@ async function processFile(fileInfo: { name: string; action: string }, parentFol /** * Ensure a folder exists under the given parent. Creates it if missing. * Handles 409 conflict (race condition) by fetching the existing folder. + * * @param folderName folder name * @param parentId parent node id * @returns the folder node entry @@ -196,6 +198,7 @@ async function ensureFolder(folderName: string, parentId: string): Promise(fn: () => Promise, label: string, maxAttempts = 3 /** * Async delay. + * * @param ms milliseconds to wait * @returns a promise that resolves after the delay */ @@ -373,6 +384,7 @@ function wait(ms: number): Promise { /** * Check environment state and authenticate. Retries on transient failures. + * * @param opts command options * @param attempt current attempt number */ diff --git a/lib/cli/scripts/init-aps-env.ts b/lib/cli/scripts/init-aps-env.ts index 127c8fcf03..570038fe17 100755 --- a/lib/cli/scripts/init-aps-env.ts +++ b/lib/cli/scripts/init-aps-env.ts @@ -182,6 +182,7 @@ Options: * If the app is already present, returns true (skip full init). * If hruser can log in but the app is missing, imports, publishes and deploys it. * Returns false only if hruser cannot log in or deployment fails. + * * @returns `true` if app is deployed, otherwise `false` */ async function ensureE2eApplicationDeployed(): Promise { @@ -236,6 +237,7 @@ async function initializeDefaultApps() { /** * Check environment state and authenticate. Retries on transient failures. + * * @param opts command options * @param attempt current attempt number */ @@ -277,6 +279,7 @@ async function checkEnv(opts: InitApsEnvArgs, attempt = 1) { /** * Check if the default tenant is present + * * @param tenantId tenant id * @param tenantName tenant name * @returns `true` if tenant is found, otherwise `false` @@ -304,6 +307,7 @@ async function hasDefaultTenant(tenantId: number, tenantName: string): Promise { /** * Import and publish the application + * * @param appName application name * @returns the app definition result */ @@ -423,6 +431,7 @@ async function importPublishApp(appName: string): Promise { /** * Get default users from the realm + * * @param opts command options * @returns array of default APS users or null */ @@ -500,6 +511,7 @@ async function getDefaultApsUsersFromRealm(opts: InitApsEnvArgs) { /** * Validate that ACS repo for Activiti is present + * * @param opts command options * @param tenantId tenant id * @param contentName content service name @@ -527,6 +539,7 @@ async function isContentRepoPresent(opts: InitApsEnvArgs, tenantId: number, cont /** * Add content service with basic auth + * * @param opts command options * @param tenantId tenant id * @param name content name @@ -567,6 +580,7 @@ async function addContentRepoWithBasic(opts: InitApsEnvArgs, tenantId: number, n /** * Authorize activiti user to ACS repo + * * @param opts command options * @param user user object */ @@ -600,6 +614,7 @@ async function authorizeUserToContentRepo(opts: InitApsEnvArgs, user: any) { /** * Authorize user with content using basic auth + * * @param opts command options * @param username username * @param contentId content id @@ -629,6 +644,7 @@ async function authorizeUserToContentWithBasic(opts: InitApsEnvArgs, username: s /** * Download APS license file + * * @param apsLicensePath path to license file * @returns `true` if download succeeded, otherwise `false` */ @@ -649,6 +665,7 @@ async function downloadLicenseFile(apsLicensePath: string) { /** * Format an error for logging. + * * @param error error object * @returns formatted error string */ @@ -670,6 +687,7 @@ function formatError(error: any): string { /** * Async delay. + * * @param ms milliseconds to wait * @returns a promise that resolves after the delay */ diff --git a/lib/cli/scripts/licenses.ts b/lib/cli/scripts/licenses.ts index 231af08deb..5799c1daaf 100644 --- a/lib/cli/scripts/licenses.ts +++ b/lib/cli/scripts/licenses.ts @@ -101,6 +101,12 @@ function getPackageFile(packagePath: string): PackageInfo { } } +/** + * Convert a license expression to linked Markdown. + * + * @param rawExpression raw SPDX license expression + * @returns expression with Markdown links + */ function toLinkedLicenseExpression(rawExpression: string): string { return rawExpression.replace(/\*/g, '').replace(/[a-zA-Z0-9\-.]+/g, (match: string) => { const lowerMatch = match.toLowerCase(); @@ -112,6 +118,14 @@ function toLinkedLicenseExpression(rawExpression: string): string { }); } +/** + * Render the license page as Markdown. + * + * @param filteredPackages packages with license metadata + * @param projName project name + * @param projVersion project version + * @returns rendered Markdown string + */ function renderLicensePage(filteredPackages: Record, projName: string, projVersion: string): string { const rows = Object.entries(filteredPackages).map(([packageName, pack]) => { const lastAtSignPos = packageName.lastIndexOf('@'); @@ -192,7 +206,6 @@ Options: } return new Promise((resolve, reject) => { - // eslint-disable-next-line no-console console.info(`Checking ${packagePath}`); const licenseScan = collectProductionLicenses(packagePath, { denyList: ['GPL'], @@ -223,7 +236,7 @@ Options: const outputFile = path.join(outputPath, `license-info-${packageJson.version}.md`); fs.writeFileSync(outputFile, mdText); - // eslint-disable-next-line no-console + console.log(`Report saved as ${outputFile}`); resolve(0); }); diff --git a/lib/cli/scripts/logger.ts b/lib/cli/scripts/logger.ts index d9a2e19151..ae3afeb61a 100644 --- a/lib/cli/scripts/logger.ts +++ b/lib/cli/scripts/logger.ts @@ -17,7 +17,6 @@ import { exit } from 'node:process'; -/* eslint-disable */ let log = null; log = { @@ -33,4 +32,3 @@ log = { }; export let logger = log; -/* eslint-enable */ diff --git a/lib/cli/scripts/plugins/check-env.ts b/lib/cli/scripts/plugins/check-env.ts index 7c682fc09a..067a81fd72 100644 --- a/lib/cli/scripts/plugins/check-env.ts +++ b/lib/cli/scripts/plugins/check-env.ts @@ -25,7 +25,12 @@ export class CheckEnv { _alfrescoJsApi: AlfrescoApi; counter = 0; - constructor(private host: string, private username: string, private password: string, private clientId: string = 'alfresco') {} + constructor( + private readonly host: string, + private readonly username: string, + private readonly password: string, + private readonly clientId: string = 'alfresco' + ) {} async checkEnv() { try { diff --git a/lib/cli/scripts/plugins/governance-check-plugin.ts b/lib/cli/scripts/plugins/governance-check-plugin.ts index 05aee0ccf1..b20c29aa91 100644 --- a/lib/cli/scripts/plugins/governance-check-plugin.ts +++ b/lib/cli/scripts/plugins/governance-check-plugin.ts @@ -21,7 +21,10 @@ import { AlfrescoApi } from '@alfresco/js-api'; export class GovernanceCheckPlugin { governanceHealth: GovernanceHealth; - constructor(private pluginInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) { + constructor( + private readonly pluginInfo: PluginInterface, + private readonly alfrescoJsApi: AlfrescoApi + ) { this.governanceHealth = new GovernanceHealth(this.pluginInfo, this.alfrescoJsApi); } diff --git a/lib/cli/scripts/plugins/governance-health.ts b/lib/cli/scripts/plugins/governance-health.ts index 5b47cb2a36..52d2866de5 100644 --- a/lib/cli/scripts/plugins/governance-health.ts +++ b/lib/cli/scripts/plugins/governance-health.ts @@ -15,14 +15,15 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/naming-convention */ - import { logger } from '../logger'; import { PluginInterface } from './plugin-model'; import { AlfrescoApi, GsSitesApi } from '@alfresco/js-api'; export class GovernanceHealth { - constructor(private pluginInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {} + constructor( + private readonly pluginInfo: PluginInterface, + private readonly alfrescoJsApi: AlfrescoApi + ) {} async isRecordManagementAvailable(): Promise { try { diff --git a/lib/cli/scripts/plugins/plugin-config.ts b/lib/cli/scripts/plugins/plugin-config.ts index eff7a70d45..7ef1082192 100644 --- a/lib/cli/scripts/plugins/plugin-config.ts +++ b/lib/cli/scripts/plugins/plugin-config.ts @@ -20,7 +20,10 @@ import { logger } from '../logger'; import { AlfrescoApi } from '@alfresco/js-api'; export class PluginConfiguration { - constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {} + constructor( + private readonly plugInInfo: PluginInterface, + private readonly alfrescoJsApi: AlfrescoApi + ) {} async getAppConfig(url: string) { return this.callCustomApi(url); diff --git a/lib/cli/scripts/plugins/process-automation-check-plugin.ts b/lib/cli/scripts/plugins/process-automation-check-plugin.ts index a2c165ee26..f75c25e04c 100644 --- a/lib/cli/scripts/plugins/process-automation-check-plugin.ts +++ b/lib/cli/scripts/plugins/process-automation-check-plugin.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/naming-convention */ - import { PluginInterface } from './plugin-model'; import { logger } from '../logger'; import { ProcessAutomationHealth } from './process-automation-health'; @@ -26,7 +24,10 @@ import { exit } from 'node:process'; export class ProcessAutomationCheckPlugin { processAutomationHealth: ProcessAutomationHealth; - constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) { + constructor( + private readonly plugInInfo: PluginInterface, + private readonly alfrescoJsApi: AlfrescoApi + ) { this.processAutomationHealth = new ProcessAutomationHealth(this.plugInInfo, this.alfrescoJsApi); } diff --git a/lib/cli/scripts/plugins/process-automation-health.ts b/lib/cli/scripts/plugins/process-automation-health.ts index 05e9bcd4c5..be51bfc544 100644 --- a/lib/cli/scripts/plugins/process-automation-health.ts +++ b/lib/cli/scripts/plugins/process-automation-health.ts @@ -23,7 +23,10 @@ import { AlfrescoApi } from '@alfresco/js-api'; export class ProcessAutomationHealth { config: PluginConfiguration; - constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) { + constructor( + private readonly plugInInfo: PluginInterface, + private readonly alfrescoJsApi: AlfrescoApi + ) { this.config = new PluginConfiguration(this.plugInInfo, this.alfrescoJsApi); } diff --git a/lib/cli/scripts/plugins/process-service-check-plugin.ts b/lib/cli/scripts/plugins/process-service-check-plugin.ts index 6ae5e296f7..04fa303a2a 100644 --- a/lib/cli/scripts/plugins/process-service-check-plugin.ts +++ b/lib/cli/scripts/plugins/process-service-check-plugin.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/naming-convention */ - import { exit } from 'node:process'; import { PluginInterface } from './plugin-model'; import { logger } from '../logger'; @@ -26,7 +24,10 @@ import { AlfrescoApi } from '@alfresco/js-api'; export class ProcessServiceCheckPlugin { processServiceHealth: ProcessServiceHealth; - constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) { + constructor( + private readonly plugInInfo: PluginInterface, + private readonly alfrescoJsApi: AlfrescoApi + ) { this.processServiceHealth = new ProcessServiceHealth(this.plugInInfo, this.alfrescoJsApi); } diff --git a/lib/cli/scripts/plugins/process-services-health.ts b/lib/cli/scripts/plugins/process-services-health.ts index 82dab88f67..0d8499d19e 100644 --- a/lib/cli/scripts/plugins/process-services-health.ts +++ b/lib/cli/scripts/plugins/process-services-health.ts @@ -23,7 +23,10 @@ import { AlfrescoApi, SystemPropertiesApi } from '@alfresco/js-api'; export class ProcessServiceHealth { config: PluginConfiguration; - constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) { + constructor( + private readonly plugInInfo: PluginInterface, + private readonly alfrescoJsApi: AlfrescoApi + ) { this.config = new PluginConfiguration(this.plugInInfo, this.alfrescoJsApi); } diff --git a/lib/cli/scripts/resources.ts b/lib/cli/scripts/resources.ts index 45c12274fd..151b025161 100644 --- a/lib/cli/scripts/resources.ts +++ b/lib/cli/scripts/resources.ts @@ -16,7 +16,6 @@ */ /* cSpell:disable */ -/* eslint-disable @typescript-eslint/naming-convention */ export const ACTIVITI_CLOUD_APPS: any = { SIMPLE_APP: { diff --git a/lib/cli/scripts/utils.ts b/lib/cli/scripts/utils.ts index 0b0d8ea966..4a4d218019 100644 --- a/lib/cli/scripts/utils.ts +++ b/lib/cli/scripts/utils.ts @@ -15,6 +15,12 @@ * limitations under the License. */ +/** + * Escape HTML special characters. + * + * @param text input string + * @returns escaped string + */ export function escapeHtml(text: string): string { return text.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); } diff --git a/lib/cli/tooling/dotenv.ts b/lib/cli/tooling/dotenv.ts index f5d61d0482..0247164066 100644 --- a/lib/cli/tooling/dotenv.ts +++ b/lib/cli/tooling/dotenv.ts @@ -15,9 +15,8 @@ * limitations under the License. */ -// eslint-disable-next-line @typescript-eslint/no-var-requires const expand = require('dotenv-expand'); -// eslint-disable-next-line @typescript-eslint/no-var-requires + const nodeDotEnv = require('dotenv'); export const dotenv = () => expand(nodeDotEnv); diff --git a/lib/content-services/.eslintignore b/lib/content-services/.eslintignore deleted file mode 100644 index 4ebc8aea50..0000000000 --- a/lib/content-services/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -coverage diff --git a/lib/content-services/.eslintrc.json b/lib/content-services/.eslintrc.json deleted file mode 100644 index dba4be2c29..0000000000 --- a/lib/content-services/.eslintrc.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "extends": ["../../.eslintrc.js"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts"], - "extends": ["plugin:@nx/angular"], - "parserOptions": { - "project": [ - "lib/content-services/tsconfig.lib.json", - "lib/content-services/tsconfig.spec.json", - "lib/content-services/.storybook/tsconfig.json" - ], - "createDefaultProgram": true - }, - "rules": { - "jsdoc/tag-lines": [ - "error", - "any", - { - "startLines": 1 - } - ], - "@typescript-eslint/naming-convention": "warn", - "@typescript-eslint/consistent-type-assertions": "warn", - "@typescript-eslint/prefer-for-of": "warn", - "@typescript-eslint/member-ordering": "off", - "no-underscore-dangle": [ - "error", - { - "allowAfterThis": true - } - ], - "no-shadow": "warn", - "quote-props": "off", - "object-shorthand": "warn", - "prefer-const": "warn", - "arrow-body-style": "warn", - "@angular-eslint/no-output-native": "off", - "space-before-function-paren": "off", - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": ["adf", "app"], - "style": "kebab-case" - } - ], - "@angular-eslint/directive-selector": [ - "error", - { - "type": ["element", "attribute"], - "prefix": ["adf", "app"], - "style": "kebab-case" - } - ], - "@angular-eslint/no-input-prefix": "error", - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit" - } - ], - "@typescript-eslint/no-inferrable-types": "off", - "@typescript-eslint/no-require-imports": "off", - "@typescript-eslint/no-var-requires": "error", - "comma-dangle": "error", - "default-case": "error", - "import/order": "off", - "max-len": [ - "error", - { - "code": 240 - } - ], - "no-bitwise": "off", - "no-duplicate-imports": "error", - "no-multiple-empty-lines": "error", - "no-return-await": "error", - "rxjs/no-create": "error", - "rxjs/no-subject-unsubscribe": "error", - "rxjs/no-subject-value": "error", - "rxjs/no-unsafe-takeuntil": "error", - "unicorn/filename-case": "error", - "@angular-eslint/prefer-standalone": "off" - } - }, - { - "files": ["*.html"], - "parserOptions": { - "project": ["lib/content-services/tsconfig.lib.json", "lib/content-services/tsconfig.spec.json"], - "createDefaultProgram": true - }, - "extends": ["plugin:@nx/angular-template"], - "rules": { - "@angular-eslint/template/no-autofocus": "error", - "@angular-eslint/template/no-positive-tabindex": "error" - } - } - ] -} diff --git a/lib/content-services/.storybook/main.ts b/lib/content-services/.storybook/main.ts index e765d06a55..2c21b73b86 100644 --- a/lib/content-services/.storybook/main.ts +++ b/lib/content-services/.storybook/main.ts @@ -1,3 +1,20 @@ +/*! + * @license + * Copyright © 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { fileURLToPath } from 'node:url'; import { dirname } from 'node:path'; import type { StorybookConfig } from '@storybook/angular'; @@ -21,6 +38,12 @@ const config: StorybookConfig = { export default config; +/** + * Resolve absolute path for a package. + * + * @param value package name + * @returns absolute path to the package + */ function getAbsolutePath(value: string): any { return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`))); } diff --git a/lib/content-services/.storybook/preview.ts b/lib/content-services/.storybook/preview.ts index cf107c6e87..ee6e817888 100644 --- a/lib/content-services/.storybook/preview.ts +++ b/lib/content-services/.storybook/preview.ts @@ -1,3 +1,20 @@ +/*! + * @license + * Copyright © 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import type { Preview } from '@storybook/angular'; const preview: Preview = { diff --git a/lib/content-services/eslint.config.mjs b/lib/content-services/eslint.config.mjs new file mode 100644 index 0000000000..bf36cc220a --- /dev/null +++ b/lib/content-services/eslint.config.mjs @@ -0,0 +1,68 @@ +/*! + * @license + * Copyright © 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import rootConfig from '../../eslint.config.mjs'; + +export default [ + ...rootConfig, + { + files: ['**/*.ts'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: 'scope:content-services', + onlyDependOnLibsWithTags: ['scope:js-api', 'scope:core', 'scope:extensions'] + } + ] + } + ], + '@typescript-eslint/consistent-type-assertions': 'warn', + '@typescript-eslint/prefer-for-of': 'warn', + 'no-underscore-dangle': [ + 'error', + { + allowAfterThis: true + } + ], + 'no-shadow': 'warn', + 'quote-props': 'off', + 'object-shorthand': 'warn', + 'prefer-const': 'warn', + 'arrow-body-style': 'warn', + 'space-before-function-paren': 'off', + '@angular-eslint/prefer-standalone': 'off' + } + }, + { + files: ['lib/content-services/**/*.html'], + rules: { + '@angular-eslint/template/no-autofocus': 'error', + '@angular-eslint/template/no-positive-tabindex': 'error' + } + }, + { + files: ['**/.storybook/**/*.ts'], + rules: { + '@nx/enforce-module-boundaries': 'off' + } + } +]; diff --git a/lib/content-services/project.json b/lib/content-services/project.json index 97c88d6f33..1fcae5d545 100644 --- a/lib/content-services/project.json +++ b/lib/content-services/project.json @@ -4,6 +4,7 @@ "sourceRoot": "lib/content-services/src", "projectType": "library", "prefix": "adf", + "tags": ["scope:content-services", "type:library"], "targets": { "build": { "executor": "@angular/build:ng-packagr", diff --git a/lib/content-services/src/lib/content-metadata/services/property-groups-translator.service.spec.ts b/lib/content-services/src/lib/content-metadata/services/property-groups-translator.service.spec.ts index 412b72e732..a039b6aa3d 100644 --- a/lib/content-services/src/lib/content-metadata/services/property-groups-translator.service.spec.ts +++ b/lib/content-services/src/lib/content-metadata/services/property-groups-translator.service.spec.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint-disable @typescript-eslint/naming-convention */ - import { TestBed } from '@angular/core/testing'; import { PropertyGroupTranslatorService, RECOGNISED_ECM_TYPES } from './property-groups-translator.service'; import { Property, OrganisedPropertyGroup } from '../interfaces/content-metadata.interfaces'; diff --git a/lib/content-services/src/lib/content-node-selector/content-node-dialog.service.ts b/lib/content-services/src/lib/content-node-selector/content-node-dialog.service.ts index 7e499638ff..c17d766fb8 100644 --- a/lib/content-services/src/lib/content-node-selector/content-node-dialog.service.ts +++ b/lib/content-services/src/lib/content-node-selector/content-node-dialog.service.ts @@ -34,7 +34,6 @@ import { SitesService } from '../common/services/sites.service'; @Injectable({ providedIn: 'root' }) -// eslint-disable-next-line @angular-eslint/directive-class-suffix export class ContentNodeDialogService { private readonly dialog = inject(MatDialog); private readonly contentService = inject(ContentService); diff --git a/lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component-search.spec.ts b/lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component-search.spec.ts index d9ca45d655..26adaad97b 100644 --- a/lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component-search.spec.ts +++ b/lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component-search.spec.ts @@ -28,9 +28,8 @@ import { NodeEntryEvent, ShareDataRow } from '../../document-list'; import { SearchQueryBuilderService } from '../../search'; import { SitesService } from '../../common/services/sites.service'; import { NodesApiService } from '../../common/services/nodes-api.service'; -import { UnitTestingUtils } from '../../../../../core/src/lib/testing/unit-testing-utils'; import { provideRouter } from '@angular/router'; -import { NoopAuthModule } from '@alfresco/adf-core'; +import { NoopAuthModule, UnitTestingUtils } from '@alfresco/adf-core'; const fakeResultSetPaging: ResultSetPaging = { list: { @@ -70,6 +69,12 @@ describe('ContentNodeSelectorPanelComponent', () => { fixture.detectChanges(); }; + const searchAndTriggerDebounce = (searchTerm = 'string-to-search'): void => { + typeToSearchBox(searchTerm); + tick(debounceSearch); + fixture.detectChanges(); + }; + const getSearchIcon = (type: string): DebugElement => testingUtils.getByCSS(`[data-automation-id="content-node-selector-search-${type}"]`); const triggerSearchResults = (searchResults: ResultSetPaging): void => { @@ -160,10 +165,7 @@ describe('ContentNodeSelectorPanelComponent', () => { }); it('should the user query get updated when the user types in the search input', fakeAsync(() => { - typeToSearchBox('search-term'); - - tick(debounceSearch); - fixture.detectChanges(); + searchAndTriggerDebounce('search-term'); expect(searchSpy).toHaveBeenCalled(); expect(searchQueryBuilderService.userQuery).toEqual('(search-term*)'); @@ -171,39 +173,27 @@ describe('ContentNodeSelectorPanelComponent', () => { })); it('should set the query builder search mode to formula when the user types in the search input', fakeAsync(() => { - typeToSearchBox('search-term'); - - tick(debounceSearch); - fixture.detectChanges(); + searchAndTriggerDebounce('search-term'); expect(searchQueryBuilderService.searchMode).toEqual('formula'); })); it('should add the wildcard suffix to the user query when wildcards are enabled', fakeAsync(() => { spyOnProperty(searchQueryBuilderService, 'wildcardsEnabled', 'get').and.returnValue(true); - typeToSearchBox('search-term'); - - tick(debounceSearch); - fixture.detectChanges(); + searchAndTriggerDebounce('search-term'); expect(searchQueryBuilderService.userQuery).toEqual('(search-term*)'); })); it('should NOT add the wildcard suffix to the user query when wildcards are disabled', fakeAsync(() => { spyOnProperty(searchQueryBuilderService, 'wildcardsEnabled', 'get').and.returnValue(false); - typeToSearchBox('search-term'); - - tick(debounceSearch); - fixture.detectChanges(); + searchAndTriggerDebounce('search-term'); expect(searchQueryBuilderService.userQuery).toEqual('(search-term)'); })); it('should perform a search when the search request gets updated and it is defined', fakeAsync(() => { - typeToSearchBox('search-term'); - - tick(debounceSearch); - fixture.detectChanges(); + searchAndTriggerDebounce('search-term'); expect(searchSpy).toHaveBeenCalledWith(false); })); @@ -211,10 +201,7 @@ describe('ContentNodeSelectorPanelComponent', () => { it('should NOT perform a search and clear the results when the search input is empty', fakeAsync(() => { spyOn(component, 'clearSearch'); - typeToSearchBox(''); - - tick(debounceSearch); - fixture.detectChanges(); + searchAndTriggerDebounce(''); expect(searchSpy).not.toHaveBeenCalled(); expect(component.clearSearch).toHaveBeenCalled(); @@ -237,10 +224,7 @@ describe('ContentNodeSelectorPanelComponent', () => { }); it('should load the results by calling the search api on search change', fakeAsync(() => { - typeToSearchBox('search-term'); - - tick(debounceSearch); - fixture.detectChanges(); + searchAndTriggerDebounce('search-term'); expect(searchSpy).toHaveBeenCalledWith(false); })); @@ -248,23 +232,17 @@ describe('ContentNodeSelectorPanelComponent', () => { it('should the query include the show files filterQuery', fakeAsync(() => { spyOn(searchQueryBuilderService, 'addFilterQuery').and.callThrough(); component.showFilesInResult = true; - typeToSearchBox('search-term'); + searchAndTriggerDebounce('search-term'); const expectedRequest = `TYPE:'cm:folder' OR TYPE:'cm:content'`; - tick(debounceSearch); - fixture.detectChanges(); - expect(searchSpy).toHaveBeenCalledWith(false); expect(searchQueryBuilderService.addFilterQuery).toHaveBeenCalledWith(expectedRequest); })); it('should reset the currently chosen node in case of starting a new search', fakeAsync(() => { component.chosenNode = [entry]; - typeToSearchBox('kakarot'); - - tick(debounceSearch); - fixture.detectChanges(); + searchAndTriggerDebounce('kakarot'); expect(component.chosenNode).toBeNull(); })); @@ -279,9 +257,7 @@ describe('ContentNodeSelectorPanelComponent', () => { it('should perform a search when selecting a site with the correct query', fakeAsync(() => { spyOn(searchQueryBuilderService, 'addFilterQuery').and.callThrough(); - typeToSearchBox('search-term'); - - tick(debounceSearch); + searchAndTriggerDebounce('search-term'); expect(searchSpy.calls.count()).toBe(1); @@ -297,8 +273,7 @@ describe('ContentNodeSelectorPanelComponent', () => { it('should remove the previous site filter query when changing the selected site', fakeAsync(() => { spyOn(searchQueryBuilderService, 'addFilterQuery').and.callThrough(); spyOn(searchQueryBuilderService, 'removeFilterQuery').and.callThrough(); - typeToSearchBox('search-term'); - tick(debounceSearch); + searchAndTriggerDebounce('search-term'); component.siteChanged({ entry: { guid: 'namek' } } as SiteEntry); component.siteChanged({ entry: { guid: 'vegeta' } } as SiteEntry); @@ -326,9 +301,7 @@ describe('ContentNodeSelectorPanelComponent', () => { component.documentList.folderNode = { id: 'fakeNodeId', isFolder: true, path: {} } as Node; fixture.detectChanges(); - typeToSearchBox('search-term'); - - tick(debounceSearch); + searchAndTriggerDebounce('search-term'); expect(searchSpy.calls.count()).toBe(1); @@ -345,9 +318,7 @@ describe('ContentNodeSelectorPanelComponent', () => { it('should get the corresponding node ids on search when a known alias is selected from dropdown', fakeAsync(() => { component.documentList.folderNode = { id: 'fakeNodeId', isFolder: true, path: {} } as Node; - typeToSearchBox('vegeta'); - - tick(debounceSearch); + searchAndTriggerDebounce('vegeta'); component.siteChanged({ entry: { guid: '-sites-' } } as SiteEntry); expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(1); @@ -360,9 +331,7 @@ describe('ContentNodeSelectorPanelComponent', () => { fixture.detectChanges(); - typeToSearchBox('vegeta'); - - tick(debounceSearch); + searchAndTriggerDebounce('vegeta'); component.siteChanged({ entry: { guid: '-sites-' } } as SiteEntry); expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(1); @@ -375,8 +344,7 @@ describe('ContentNodeSelectorPanelComponent', () => { const nodeIds$ = new Subject(); getCorrespondingNodeIdsSpy.and.returnValue(nodeIds$.asObservable()); - typeToSearchBox('vegeta'); - tick(debounceSearch); + searchAndTriggerDebounce('vegeta'); searchSpy.calls.reset(); @@ -396,9 +364,7 @@ describe('ContentNodeSelectorPanelComponent', () => { component.dropdownSiteList = { list: { entries: [{ entry: { guid: '-sites-' } }, { entry: { guid: 'namek' } }] } } as SitePaging; fixture.detectChanges(); - typeToSearchBox('vegeta'); - - tick(debounceSearch); + searchAndTriggerDebounce('vegeta'); expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(0); })); diff --git a/lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component.ts b/lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component.ts index 8d3cb12eda..51df370ece 100644 --- a/lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component.ts +++ b/lib/content-services/src/lib/content-node-selector/content-node-selector-panel/content-node-selector-panel.component.ts @@ -99,7 +99,6 @@ export class ContentNodeSelectorPanelComponent implements OnInit { private readonly sitesService = inject(SitesService); private readonly contentNodeSelectorPanelService = inject(ContentNodeSelectorPanelService); - // eslint-disable-next-line @typescript-eslint/naming-convention DEFAULT_PAGINATION: Pagination = new Pagination({ maxItems: 25, skipCount: 0 diff --git a/lib/content-services/src/lib/content-node-selector/site-dropdown/sites-dropdown.component.ts b/lib/content-services/src/lib/content-node-selector/site-dropdown/sites-dropdown.component.ts index ad3237e5a2..d3a992eeba 100644 --- a/lib/content-services/src/lib/content-node-selector/site-dropdown/sites-dropdown.component.ts +++ b/lib/content-services/src/lib/content-node-selector/site-dropdown/sites-dropdown.component.ts @@ -25,9 +25,6 @@ import { SitesService } from '../../common/services/sites.service'; import { CommonModule } from '@angular/common'; import { MatFormFieldModule } from '@angular/material/form-field'; -/* eslint-disable no-shadow */ -/* eslint-disable @typescript-eslint/naming-convention */ - export const Relations = { Members: 'members', Containers: 'containers' diff --git a/lib/content-services/src/lib/content-node-share/content-node-share.dialog.ts b/lib/content-services/src/lib/content-node-share/content-node-share.dialog.ts index 58e4af745f..2b2b836eba 100644 --- a/lib/content-services/src/lib/content-node-share/content-node-share.dialog.ts +++ b/lib/content-services/src/lib/content-node-share/content-node-share.dialog.ts @@ -196,7 +196,6 @@ export class ShareDialogComponent implements OnInit { this.isDisabled = false; this.isFileShared = true; - // eslint-disable-next-line this.renditionService.getNodeRendition(this.data.node.entry.id); this.updateForm(); diff --git a/lib/content-services/src/lib/content-node-share/content-node-share.directive.ts b/lib/content-services/src/lib/content-node-share/content-node-share.directive.ts index 784b832e82..bb85055af9 100644 --- a/lib/content-services/src/lib/content-node-share/content-node-share.directive.ts +++ b/lib/content-services/src/lib/content-node-share/content-node-share.directive.ts @@ -37,7 +37,7 @@ export class NodeSharedDirective implements OnChanges { isShared: boolean = false; /** Node to share. */ - // eslint-disable-next-line @angular-eslint/no-input-rename + @Input('adf-share') node: NodeEntry; diff --git a/lib/content-services/src/lib/dialogs/folder/folder-name.validators.ts b/lib/content-services/src/lib/dialogs/folder/folder-name.validators.ts index 6f185cbe7b..455e030b6c 100644 --- a/lib/content-services/src/lib/dialogs/folder/folder-name.validators.ts +++ b/lib/content-services/src/lib/dialogs/folder/folder-name.validators.ts @@ -20,7 +20,6 @@ import { UntypedFormControl } from '@angular/forms'; const I18N_ERRORS_PATH = 'CORE.FOLDER_DIALOG.FOLDER_NAME.ERRORS'; export const forbidSpecialCharacters = ({ value }: UntypedFormControl) => { - // eslint-disable-next-line no-useless-escape const specialCharacters: RegExp = /([\*\"\<\>\\\/\?\:\|])/; const isValid: boolean = !specialCharacters.test(value); diff --git a/lib/content-services/src/lib/directives/library-favorite.directive.ts b/lib/content-services/src/lib/directives/library-favorite.directive.ts index b26cf0b819..d68ba23a9d 100644 --- a/lib/content-services/src/lib/directives/library-favorite.directive.ts +++ b/lib/content-services/src/lib/directives/library-favorite.directive.ts @@ -34,7 +34,7 @@ export class LibraryFavoriteDirective implements OnChanges { library: LibraryEntity = null; @Output() toggle = new EventEmitter(); - // eslint-disable-next-line @angular-eslint/no-output-native + @Output() error = new EventEmitter(); private targetLibrary = null; diff --git a/lib/content-services/src/lib/directives/library-membership.directive.ts b/lib/content-services/src/lib/directives/library-membership.directive.ts index 95039537a2..bae66fef28 100644 --- a/lib/content-services/src/lib/directives/library-membership.directive.ts +++ b/lib/content-services/src/lib/directives/library-membership.directive.ts @@ -52,7 +52,6 @@ export class LibraryMembershipDirective implements OnChanges { @Output() toggle = new EventEmitter(); - // eslint-disable-next-line @angular-eslint/no-output-native @Output() error = new EventEmitter(); diff --git a/lib/content-services/src/lib/directives/node-delete.directive.ts b/lib/content-services/src/lib/directives/node-delete.directive.ts index e09ac0486f..e28c32d341 100644 --- a/lib/content-services/src/lib/directives/node-delete.directive.ts +++ b/lib/content-services/src/lib/directives/node-delete.directive.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint-disable @angular-eslint/no-input-rename */ - import { Directive, ElementRef, EventEmitter, HostListener, Input, OnChanges, Output, inject } from '@angular/core'; import { NodeEntry, Node, DeletedNodeEntry, DeletedNode, TrashcanApi, NodesApi, LazyApi } from '@alfresco/js-api'; import { Observable, forkJoin, from, of } from 'rxjs'; @@ -176,7 +174,7 @@ export class NodeDeleteDirective implements OnChanges { if (status.allFailed && !status.oneFailed) { return this.translation.instant( 'CORE.DELETE_NODE.ERROR_PLURAL', - // eslint-disable-next-line id-blacklist + { number: status.failed.length } ); } @@ -184,7 +182,7 @@ export class NodeDeleteDirective implements OnChanges { if (status.allSucceeded && !status.oneSucceeded) { return this.translation.instant( 'CORE.DELETE_NODE.PLURAL', - // eslint-disable-next-line id-blacklist + { number: status.success.length } ); } diff --git a/lib/content-services/src/lib/directives/node-favorite.directive.ts b/lib/content-services/src/lib/directives/node-favorite.directive.ts index 1ccaa49b9f..49749b19c8 100644 --- a/lib/content-services/src/lib/directives/node-favorite.directive.ts +++ b/lib/content-services/src/lib/directives/node-favorite.directive.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint-disable @angular-eslint/no-input-rename */ - import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges, inject } from '@angular/core'; import { FavoriteBodyCreate, NodeEntry, SharedLinkEntry, Node, SharedLink, FavoritesApi, LazyApi } from '@alfresco/js-api'; import { Observable, from, forkJoin, of } from 'rxjs'; diff --git a/lib/content-services/src/lib/directives/node-lock.directive.ts b/lib/content-services/src/lib/directives/node-lock.directive.ts index 45d84b51ed..cd8dbbeb77 100644 --- a/lib/content-services/src/lib/directives/node-lock.directive.ts +++ b/lib/content-services/src/lib/directives/node-lock.directive.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint-disable @angular-eslint/no-input-rename */ - import { Directive, ElementRef, Renderer2, HostListener, Input, AfterViewInit, inject } from '@angular/core'; import { Node } from '@alfresco/js-api'; import { ContentService } from '../common/services/content.service'; diff --git a/lib/content-services/src/lib/directives/node-restore.directive.ts b/lib/content-services/src/lib/directives/node-restore.directive.ts index b90b981883..89dbb58c98 100644 --- a/lib/content-services/src/lib/directives/node-restore.directive.ts +++ b/lib/content-services/src/lib/directives/node-restore.directive.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint-disable @angular-eslint/component-selector, @angular-eslint/no-input-rename */ - import { Directive, EventEmitter, HostListener, Input, Output, inject } from '@angular/core'; import { TrashcanApi, DeletedNodeEntry, DeletedNodesPaging, LazyApi } from '@alfresco/js-api'; import { Observable, forkJoin, from, of } from 'rxjs'; @@ -184,7 +182,6 @@ export class NodeRestoreDirective { if (status.someFailed && !status.oneFailed) { return this.translation.instant('CORE.RESTORE_NODE.PARTIAL_PLURAL', { - // eslint-disable-next-line id-blacklist number: status.fail.length }); } diff --git a/lib/content-services/src/lib/document-list/components/document-list.component.ts b/lib/content-services/src/lib/document-list/components/document-list.component.ts index 9e9ac0f286..e531107e6e 100644 --- a/lib/content-services/src/lib/document-list/components/document-list.component.ts +++ b/lib/content-services/src/lib/document-list/components/document-list.component.ts @@ -15,9 +15,6 @@ * limitations under the License. */ -/* eslint-disable rxjs/no-subject-value */ -/* eslint-disable @typescript-eslint/naming-convention */ - import { AppConfigService, ColumnsSelectorComponent, diff --git a/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.spec.ts b/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.spec.ts index 18c80ff7a6..7c3b7657bf 100644 --- a/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.spec.ts +++ b/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.spec.ts @@ -23,8 +23,8 @@ import { SimpleChange } from '@angular/core'; import { SearchHeaderQueryBuilderService } from './../../../search/services/search-header-query-builder.service'; import { FilterHeaderComponent } from './filter-header.component'; import { provideRouter } from '@angular/router'; -import { SearchCategory } from '@alfresco/adf-content-services'; import { NodePaging } from '@alfresco/js-api'; +import { SearchCategory } from '../../../search/models/search-category.interface'; describe('FilterHeaderComponent', () => { let fixture: ComponentFixture; diff --git a/lib/content-services/src/lib/document-list/components/name-column/name-column.component.ts b/lib/content-services/src/lib/document-list/components/name-column/name-column.component.ts index 63c2609073..660511f7b6 100644 --- a/lib/content-services/src/lib/document-list/components/name-column/name-column.component.ts +++ b/lib/content-services/src/lib/document-list/components/name-column/name-column.component.ts @@ -56,7 +56,6 @@ export class NameColumnComponent implements OnInit { private readonly nodesApiService = inject(NodesApiService); @Input({ required: true }) - // eslint-disable-next-line @typescript-eslint/no-explicit-any context: any; @Input() diff --git a/lib/content-services/src/lib/document-list/components/trashcan-name-column/trashcan-name-column.component.ts b/lib/content-services/src/lib/document-list/components/trashcan-name-column/trashcan-name-column.component.ts index bc17142976..fa7aff2d4b 100644 --- a/lib/content-services/src/lib/document-list/components/trashcan-name-column/trashcan-name-column.component.ts +++ b/lib/content-services/src/lib/document-list/components/trashcan-name-column/trashcan-name-column.component.ts @@ -29,7 +29,6 @@ import { NodeTooltipUtils } from '../../utils/node-tooltip.utils'; }) export class TrashcanNameColumnComponent implements OnInit { @Input({ required: true }) - // eslint-disable-next-line @typescript-eslint/no-explicit-any context: any; isLibrary = false; diff --git a/lib/content-services/src/lib/document-list/models/content-action.model.ts b/lib/content-services/src/lib/document-list/models/content-action.model.ts index d51818f031..88cf7c27f9 100644 --- a/lib/content-services/src/lib/document-list/models/content-action.model.ts +++ b/lib/content-services/src/lib/document-list/models/content-action.model.ts @@ -15,9 +15,6 @@ * limitations under the License. */ -/* eslint-disable no-shadow */ -/* eslint-disable @typescript-eslint/naming-convention */ - export class ContentActionModel { icon: string; title: string; diff --git a/lib/content-services/src/lib/document-list/models/node-action.enum.ts b/lib/content-services/src/lib/document-list/models/node-action.enum.ts index d2fbe15888..847cbc54c3 100644 --- a/lib/content-services/src/lib/document-list/models/node-action.enum.ts +++ b/lib/content-services/src/lib/document-list/models/node-action.enum.ts @@ -15,9 +15,6 @@ * limitations under the License. */ -/* eslint-disable no-shadow */ -/* eslint-disable @typescript-eslint/naming-convention */ - export const NodeAction = { ATTACH: 'ATTACH', CHOOSE: 'CHOOSE', diff --git a/lib/content-services/src/lib/document-list/services/node-actions.service.ts b/lib/content-services/src/lib/document-list/services/node-actions.service.ts index 374f145417..7315dada72 100644 --- a/lib/content-services/src/lib/document-list/services/node-actions.service.ts +++ b/lib/content-services/src/lib/document-list/services/node-actions.service.ts @@ -30,7 +30,6 @@ import { NodeAction } from '../models/node-action.enum'; @Injectable({ providedIn: 'root' }) -// eslint-disable-next-line @angular-eslint/directive-class-suffix export class NodeActionsService { private readonly contentDialogService = inject(ContentNodeDialogService); dialogRef = inject(MatDialog); diff --git a/lib/content-services/src/lib/document-list/utils/node-tooltip.utils.ts b/lib/content-services/src/lib/document-list/utils/node-tooltip.utils.ts index 6c1a6e659e..dd8186dbbd 100644 --- a/lib/content-services/src/lib/document-list/utils/node-tooltip.utils.ts +++ b/lib/content-services/src/lib/document-list/utils/node-tooltip.utils.ts @@ -75,7 +75,6 @@ export class NodeTooltipUtils { return ''; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any const { properties, description, title } = node.entry as any; // Check both direct properties and cm: properties for compatibility @@ -93,7 +92,7 @@ export class NodeTooltipUtils { * @param allEntries - Array of all entries to check for duplicates * @returns The display title, with ID/name appended if duplicate exists */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any + static getLibraryTitle(library: any, allEntries: any[]): string { if (!library) { return ''; diff --git a/lib/content-services/src/lib/folder-directive/folder-edit.directive.ts b/lib/content-services/src/lib/folder-directive/folder-edit.directive.ts index dbe7e1d953..09a8237b3f 100644 --- a/lib/content-services/src/lib/folder-directive/folder-edit.directive.ts +++ b/lib/content-services/src/lib/folder-directive/folder-edit.directive.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint-disable @angular-eslint/no-input-rename */ - import { Directive, ElementRef, HostListener, Input, Output, EventEmitter, inject } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Node } from '@alfresco/js-api'; diff --git a/lib/content-services/src/lib/node-comments/node-comments.component.spec.ts b/lib/content-services/src/lib/node-comments/node-comments.component.spec.ts index bde3bb75ce..1fdcb3f0bf 100644 --- a/lib/content-services/src/lib/node-comments/node-comments.component.spec.ts +++ b/lib/content-services/src/lib/node-comments/node-comments.component.spec.ts @@ -17,10 +17,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NodeCommentsComponent } from './node-comments.component'; -import { CommentsComponent } from '../../../../core/src/lib/comments/comments.component'; -import { CommentModel } from '../../../../core/src/lib/models'; -import { UnitTestingUtils } from '../../../../core/src/lib/testing/unit-testing-utils'; import { provideApiTesting } from '../testing/providers'; +import { CommentModel, CommentsComponent, UnitTestingUtils } from '@alfresco/adf-core'; describe('NodeCommentsComponent', () => { let fixture: ComponentFixture; diff --git a/lib/content-services/src/lib/permission-manager/components/add-permission/add-permission-panel.component.ts b/lib/content-services/src/lib/permission-manager/components/add-permission/add-permission-panel.component.ts index cd49d89199..76b1001199 100644 --- a/lib/content-services/src/lib/permission-manager/components/add-permission/add-permission-panel.component.ts +++ b/lib/content-services/src/lib/permission-manager/components/add-permission/add-permission-panel.component.ts @@ -68,7 +68,6 @@ export class AddPermissionPanelComponent { selectedItems: NodeEntry[] = []; - // eslint-disable-next-line @typescript-eslint/naming-convention EVERYONE: NodeEntry = new NodeEntry({ entry: new Node({ nodeType: 'cm:authorityContainer', properties: { 'cm:authorityName': 'GROUP_EVERYONE' } }) }); diff --git a/lib/content-services/src/lib/permission-manager/components/add-permission/search-config-permission.service.ts b/lib/content-services/src/lib/permission-manager/components/add-permission/search-config-permission.service.ts index 41157ebad6..6aefa4f990 100644 --- a/lib/content-services/src/lib/permission-manager/components/add-permission/search-config-permission.service.ts +++ b/lib/content-services/src/lib/permission-manager/components/add-permission/search-config-permission.service.ts @@ -38,10 +38,7 @@ export class SearchPermissionConfigurationService implements SearchConfiguration maxItems: maxResults, skipCount }, - filterQueries: [ - /* eslint-disable-next-line */ - { query: "TYPE:'cm:authority'" } - ] + filterQueries: [{ query: "TYPE:'cm:authority'" }] }; } diff --git a/lib/content-services/src/lib/permission-manager/components/inherited-button.directive.ts b/lib/content-services/src/lib/permission-manager/components/inherited-button.directive.ts index c740658e40..8ef9a430ab 100644 --- a/lib/content-services/src/lib/permission-manager/components/inherited-button.directive.ts +++ b/lib/content-services/src/lib/permission-manager/components/inherited-button.directive.ts @@ -15,7 +15,6 @@ * limitations under the License. */ -/* eslint-disable @angular-eslint/no-input-rename */ import { Directive, Input, Output, EventEmitter, inject } from '@angular/core'; import { Node } from '@alfresco/js-api'; import { ContentService } from '../../common/services/content.service'; diff --git a/lib/content-services/src/lib/search/components/search.component.ts b/lib/content-services/src/lib/search/components/search.component.ts index b566feecd7..2248ebf6e2 100644 --- a/lib/content-services/src/lib/search/components/search.component.ts +++ b/lib/content-services/src/lib/search/components/search.component.ts @@ -79,7 +79,7 @@ export class SearchComponent implements SearchComponentInterface, AfterContentIn searchTerm: string = ''; /** CSS class for display. */ - // eslint-disable-next-line @angular-eslint/no-input-rename + @Input('class') set classList(classList: string) { if (classList?.length) { diff --git a/lib/content-services/src/lib/search/forms/search-term-validator.spec.ts b/lib/content-services/src/lib/search/forms/search-term-validator.spec.ts index ff74dc4f8a..7be17939ce 100644 --- a/lib/content-services/src/lib/search/forms/search-term-validator.spec.ts +++ b/lib/content-services/src/lib/search/forms/search-term-validator.spec.ts @@ -19,7 +19,6 @@ import { UntypedFormControl } from '@angular/forms'; import { SearchTermValidator } from './search-term-validator'; describe('Search term validator', () => { - it('should pass validation for a value with the specified required number of alphanumeric characters', () => { const control = new UntypedFormControl('ab', SearchTermValidator.minAlphanumericChars(2)); expect(control.valid).toBe(true); @@ -35,7 +34,6 @@ describe('Search term validator', () => { expect(control.valid).toBe(false); }); - /* eslint-disable max-len */ it('should fail validation for a value with less than the specified required number of alphanumeric characters but with other non-alphanumeric characters', () => { const control = new UntypedFormControl('a ._-?b', SearchTermValidator.minAlphanumericChars(3)); expect(control.valid).toBe(false); diff --git a/lib/content-services/src/lib/tag/tags-creator/tags-creator.component.spec.ts b/lib/content-services/src/lib/tag/tags-creator/tags-creator.component.spec.ts index 2fca020cac..a7e827cfa0 100644 --- a/lib/content-services/src/lib/tag/tags-creator/tags-creator.component.spec.ts +++ b/lib/content-services/src/lib/tag/tags-creator/tags-creator.component.spec.ts @@ -15,7 +15,6 @@ * limitations under the License. */ -import { TagsCreatorMode, TagService } from '@alfresco/adf-content-services'; import { NotificationService, UnitTestingUtils } from '@alfresco/adf-core'; import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; @@ -26,6 +25,8 @@ import { MatError } from '@angular/material/form-field'; import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing'; import { EMPTY, of, throwError } from 'rxjs'; import { TagsCreatorComponent } from './tags-creator.component'; +import { TagService } from '../services/tag.service'; +import { TagsCreatorMode } from './tags-creator-mode'; describe('TagsCreatorComponent', () => { let fixture: ComponentFixture; diff --git a/lib/content-services/src/lib/upload/components/base-upload/upload-base.ts b/lib/content-services/src/lib/upload/components/base-upload/upload-base.ts index 5072d939bf..38ab900cf7 100644 --- a/lib/content-services/src/lib/upload/components/base-upload/upload-base.ts +++ b/lib/content-services/src/lib/upload/components/base-upload/upload-base.ts @@ -24,7 +24,6 @@ import { UploadFilesEvent } from '../upload-files.event'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Directive() -// eslint-disable-next-line @angular-eslint/directive-class-suffix export abstract class UploadBase implements OnInit { protected uploadService = inject(UploadService); protected translationService: TranslationService = inject(TranslationService); @@ -87,9 +86,7 @@ export abstract class UploadBase implements OnInit { private readonly destroyRef = inject(DestroyRef); ngOnInit() { - this.uploadService.fileUploadError - .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(error => this.error.emit(error)); + this.uploadService.fileUploadError.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((error) => this.error.emit(error)); } /** @@ -99,7 +96,7 @@ export abstract class UploadBase implements OnInit { */ uploadFiles(files: File[]): void { const filteredFiles: FileModel[] = files.map((file: File) => - this.createFileModel(file, this.rootFolderId, ((file).webkitRelativePath || '').replace(/\/[^/]*$/, '')) + this.createFileModel(file, this.rootFolderId, (file.webkitRelativePath || '').replace(/\/[^/]*$/, '')) ); this.uploadQueue(filteredFiles); diff --git a/lib/content-services/src/lib/upload/directives/file-draggable.directive.ts b/lib/content-services/src/lib/upload/directives/file-draggable.directive.ts index a045d3610e..69a615bb1e 100644 --- a/lib/content-services/src/lib/upload/directives/file-draggable.directive.ts +++ b/lib/content-services/src/lib/upload/directives/file-draggable.directive.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -/* eslint-disable @angular-eslint/no-input-rename */ - import { FileUtils } from '@alfresco/adf-core'; import { Directive, ElementRef, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output, inject } from '@angular/core'; diff --git a/lib/content-services/src/lib/viewer/components/alfresco-viewer.component.spec.ts b/lib/content-services/src/lib/viewer/components/alfresco-viewer.component.spec.ts index 1fe00de369..4a9c6c24c2 100644 --- a/lib/content-services/src/lib/viewer/components/alfresco-viewer.component.spec.ts +++ b/lib/content-services/src/lib/viewer/components/alfresco-viewer.component.spec.ts @@ -68,7 +68,7 @@ class ViewerWithCustomToolbarComponent {} @Component({ selector: 'adf-viewer-container-toolbar-actions', imports: [MatIconModule, MatButtonModule, ViewerToolbarActionsComponent, AlfrescoViewerComponent, IconModule], - // eslint-disable-next-line @alfresco/eslint-angular/no-angular-material-selectors + template: `