@o3r/eslint-plugin 9.6.0-alpha.4 → 9.6.0-alpha.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@o3r/eslint-plugin",
3
- "version": "9.6.0-alpha.4",
3
+ "version": "9.6.0-alpha.41",
4
4
  "description": "The module provides in-house eslint plugins to use in your own eslint configuration.",
5
5
  "main": "./src/public_api.js",
6
6
  "keywords": [
@@ -35,8 +35,8 @@
35
35
  }
36
36
  },
37
37
  "peerDependencies": {
38
- "@angular-eslint/template-parser": "~16.2.0",
39
- "@angular-eslint/utils": "~16.2.0",
38
+ "@angular-eslint/template-parser": "~16.3.0",
39
+ "@angular-eslint/utils": "~16.3.0",
40
40
  "@angular/compiler": "~16.2.0",
41
41
  "@typescript-eslint/eslint-plugin": "^5.60.1",
42
42
  "@typescript-eslint/parser": "^5.60.1",
@@ -46,16 +46,16 @@
46
46
  "devDependencies": {
47
47
  "@angular-devkit/core": "~16.2.0",
48
48
  "@angular-devkit/schematics": "~16.2.0",
49
- "@angular-eslint/eslint-plugin": "~16.2.0",
50
- "@angular-eslint/template-parser": "~16.2.0",
51
- "@angular-eslint/utils": "~16.2.0",
49
+ "@angular-eslint/eslint-plugin": "~16.3.0",
50
+ "@angular-eslint/template-parser": "~16.3.0",
51
+ "@angular-eslint/utils": "~16.3.0",
52
52
  "@angular/compiler": "~16.2.0",
53
53
  "@babel/core": "~7.23.0",
54
54
  "@babel/preset-typescript": "~7.23.0",
55
55
  "@compodoc/compodoc": "^1.1.19",
56
56
  "@nx/eslint-plugin": "~16.10.0",
57
57
  "@nx/jest": "~16.10.0",
58
- "@o3r/build-helpers": "^9.6.0-alpha.4",
58
+ "@o3r/build-helpers": "^9.6.0-alpha.41",
59
59
  "@types/jest": "~29.5.2",
60
60
  "@types/node": "^18.0.0",
61
61
  "@types/semver": "^7.3.13",
@@ -0,0 +1,6 @@
1
+ import type { Rule } from '@angular-devkit/schematics';
2
+ /**
3
+ * Add Otter eslint-plugin to an Angular Project
4
+ */
5
+ export declare function ngAdd(): Rule;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../schematics/ng-add/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AAEvD;;GAEG;AACH,wBAAgB,KAAK,IAAI,IAAI,CAG5B"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ngAdd = void 0;
4
+ const schematics_1 = require("@angular-devkit/schematics");
5
+ /**
6
+ * Add Otter eslint-plugin to an Angular Project
7
+ */
8
+ function ngAdd() {
9
+ /* ng add rules */
10
+ return (0, schematics_1.noop)();
11
+ }
12
+ exports.ngAdd = ngAdd;
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,5 @@
1
+ export interface NgAddSchematicsSchema {
2
+ /** Project name */
3
+ projectName?: string | undefined;
4
+ }
5
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../schematics/ng-add/schema.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,mBAAmB;IACnB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=schema.js.map
package/src/index.js CHANGED
@@ -3,25 +3,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  /* eslint-disable @typescript-eslint/naming-convention */
4
4
  const no_folder_import_for_module_1 = require("./rules/typescript/no-folder-import-for-module/no-folder-import-for-module");
5
5
  const o3r_widget_tags_1 = require("./rules/typescript/o3r-widget-tags/o3r-widget-tags");
6
+ const no_inner_html_1 = require("./rules/template/no-inner-html/no-inner-html");
6
7
  const template_async_number_limitation_1 = require("./rules/template/template-async-number-limitation/template-async-number-limitation");
7
8
  const json_dependency_versions_harmonize_1 = require("./rules/json/json-dependency-versions-harmonize/json-dependency-versions-harmonize");
8
9
  const matching_configuration_name_1 = require("./rules/typescript/matching-configuration-name/matching-configuration-name");
10
+ const no_multiple_type_configuration_property_1 = require("./rules/typescript/no-multiple-type-configuration-property/no-multiple-type-configuration-property");
9
11
  module.exports = {
10
12
  rules: {
11
13
  'no-folder-import-for-module': no_folder_import_for_module_1.default,
14
+ 'no-inner-html': no_inner_html_1.default,
12
15
  'template-async-number-limitation': template_async_number_limitation_1.default,
13
16
  'o3r-widget-tags': o3r_widget_tags_1.default,
14
17
  'json-dependency-versions-harmonize': json_dependency_versions_harmonize_1.default,
15
- 'matching-configuration-name': matching_configuration_name_1.default
18
+ 'matching-configuration-name': matching_configuration_name_1.default,
19
+ 'no-multiple-type-configuration-property': no_multiple_type_configuration_property_1.default
16
20
  },
17
21
  configs: {
18
22
  '@o3r/no-folder-import-for-module': 'error',
19
23
  '@o3r/json-dependency-versions-harmonize': 'error',
24
+ '@o3r/no-multiple-type-configuration-property': 'error',
20
25
  '@o3r/template-async-number-limitation': 'warn',
21
26
  '@o3r/matching-configuration-name': 'warn',
22
27
  recommended: {
23
28
  rules: {
24
29
  '@o3r/matching-configuration-name': 'error',
30
+ '@o3r/no-multiple-type-configuration-property': 'error',
25
31
  '@o3r/no-folder-import-for-module': 'error',
26
32
  '@o3r/template-async-number-limitation': 'off'
27
33
  }
@@ -0,0 +1,5 @@
1
+ /** Rule Name */
2
+ export declare const name = "no-inner-html";
3
+ type Messages = 'error' | 'fix';
4
+ declare const _default: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<Messages, [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
5
+ export default _default;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.name = void 0;
4
+ const utils_1 = require("../utils");
5
+ const utils_2 = require("../../utils");
6
+ /** Rule Name */
7
+ exports.name = 'no-inner-html';
8
+ exports.default = (0, utils_2.createRule)({
9
+ name: exports.name,
10
+ defaultOptions: [],
11
+ meta: {
12
+ type: 'problem',
13
+ hasSuggestions: true,
14
+ docs: {
15
+ description: 'Ensures that your template does not use innerHTML',
16
+ recommended: 'warn'
17
+ },
18
+ schema: [],
19
+ messages: {
20
+ error: 'Unexpected use of innerHTML',
21
+ fix: 'Replace innerHTML by innerText'
22
+ },
23
+ fixable: 'code'
24
+ },
25
+ create: (context) => {
26
+ // To throw error if use without @angular-eslint/template-parser
27
+ (0, utils_1.getTemplateParserServices)(context);
28
+ return {
29
+ // eslint-disable-next-line @typescript-eslint/naming-convention
30
+ 'Element$1': (node) => {
31
+ const innerHTMLAttribute = node.attributes.find((a) => /innerHTML/i.test(a.name));
32
+ if (innerHTMLAttribute && innerHTMLAttribute.keySpan) {
33
+ context.report({
34
+ messageId: 'error',
35
+ loc: {
36
+ column: innerHTMLAttribute.keySpan.start.col,
37
+ line: innerHTMLAttribute.keySpan.start.line,
38
+ end: {
39
+ column: innerHTMLAttribute.keySpan.end.col,
40
+ line: innerHTMLAttribute.keySpan.end.line
41
+ },
42
+ start: {
43
+ column: innerHTMLAttribute.keySpan.start.col,
44
+ line: innerHTMLAttribute.keySpan.start.line
45
+ }
46
+ },
47
+ fix: (fixer) => fixer.replaceTextRange([innerHTMLAttribute.keySpan.start.offset, innerHTMLAttribute.keySpan.end.offset], 'innerText'),
48
+ suggest: [{
49
+ messageId: 'fix',
50
+ fix: (fixer) => fixer.replaceTextRange([innerHTMLAttribute.keySpan.start.offset, innerHTMLAttribute.keySpan.end.offset], 'innerText')
51
+ }]
52
+ });
53
+ }
54
+ }
55
+ };
56
+ }
57
+ });
@@ -35,9 +35,8 @@ exports.default = (0, utils_2.createRule)({
35
35
  fixable: undefined
36
36
  },
37
37
  defaultOptions,
38
- create: (context) => {
38
+ create: (context, [options]) => {
39
39
  const parserServices = (0, utils_1.getTemplateParserServices)(context);
40
- const options = context.options[0] || defaultOptions[0];
41
40
  const asyncRegExp = /\| *async\b/g;
42
41
  return {
43
42
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -0,0 +1,5 @@
1
+ export interface NoMultipleTypeConfigurationPropertyOption {
2
+ supportedInterfaceNames?: string[];
3
+ }
4
+ declare const _default: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"suggestion" | "error", [Required<NoMultipleTypeConfigurationPropertyOption>, ...any[]], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
5
+ export default _default;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const experimental_utils_1 = require("@typescript-eslint/experimental-utils");
4
+ const utils_1 = require("../../utils");
5
+ const separatorRegExp = /\s*[|&]\s*/;
6
+ exports.default = (0, utils_1.createRule)({
7
+ name: 'no-multiple-type-configuration-property',
8
+ meta: {
9
+ hasSuggestions: true,
10
+ type: 'problem',
11
+ docs: {
12
+ description: 'Ensures that the configuration property does not accept multiple types.',
13
+ recommended: 'error'
14
+ },
15
+ schema: [
16
+ {
17
+ type: 'object',
18
+ properties: {
19
+ supportedInterfaceNames: {
20
+ type: 'array',
21
+ items: {
22
+ type: 'string'
23
+ },
24
+ default: utils_1.defaultSupportedInterfaceNames
25
+ }
26
+ }
27
+ }
28
+ ],
29
+ messages: {
30
+ error: 'Configuration cannot be the union of multiple type',
31
+ suggestion: 'Replace {{currentValue}} by {{recommendedValue}}'
32
+ }
33
+ },
34
+ defaultOptions: [{
35
+ supportedInterfaceNames: utils_1.defaultSupportedInterfaceNames
36
+ }],
37
+ create: (context, [options]) => {
38
+ const supportedInterfaceNames = options.supportedInterfaceNames;
39
+ const sourceCode = context.getSourceCode();
40
+ const rule = (node) => {
41
+ const interfaceDeclNode = node.parent?.parent?.parent?.parent;
42
+ if (!(0, utils_1.isExtendingConfiguration)(interfaceDeclNode, supportedInterfaceNames)) {
43
+ return; // Not in a configuration interface
44
+ }
45
+ if (node.types.every((type) => type.type === experimental_utils_1.TSESTree.AST_NODE_TYPES.TSLiteralType && type.literal.type === experimental_utils_1.TSESTree.AST_NODE_TYPES.Literal)
46
+ && [...(new Set(node.types.map((literalType) => typeof literalType.literal.value)))].length === 1) {
47
+ return; // Only the same literal type
48
+ }
49
+ const text = sourceCode.getText(node);
50
+ context.report({
51
+ messageId: 'error',
52
+ node,
53
+ loc: node.loc,
54
+ suggest: text.split(separatorRegExp).map((type) => ({
55
+ messageId: 'suggestion',
56
+ data: {
57
+ currentValue: text,
58
+ recommendedValue: type
59
+ },
60
+ fix: (fixer) => fixer.replaceTextRange(node.range, type)
61
+ }))
62
+ });
63
+ };
64
+ return {
65
+ // eslint-disable-next-line @typescript-eslint/naming-convention
66
+ TSUnionType: rule,
67
+ // eslint-disable-next-line @typescript-eslint/naming-convention
68
+ TSIntersectionType: rule
69
+ };
70
+ }
71
+ });
@@ -12,5 +12,5 @@ export interface O3rWidgetTagsRuleOption {
12
12
  };
13
13
  }
14
14
  type O3rWidgetRuleErrorId = 'notInConfigurationInterface' | 'notSupportedType' | 'notSupportedParamForType' | 'invalidParamValueType' | 'noParamWithoutWidget' | 'onlyOneWidgetAllowed' | 'duplicatedParam' | 'requiredParamMissing' | 'suggestParamMissing' | 'suggestRemoveDuplicatedO3rWidget' | 'suggestRemoveDuplicatedO3rWidgetParam' | 'suggestAddO3rWidgetTag' | 'suggestReplaceO3rWidgetType';
15
- declare const _default: TSESLint.RuleModule<O3rWidgetRuleErrorId, O3rWidgetTagsRuleOption[], TSESLint.RuleListener>;
15
+ declare const _default: TSESLint.RuleModule<O3rWidgetRuleErrorId, [Required<O3rWidgetTagsRuleOption>, ...any[]], TSESLint.RuleListener>;
16
16
  export default _default;
@@ -1,10 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const experimental_utils_1 = require("@typescript-eslint/experimental-utils");
4
3
  const utils_1 = require("../../utils");
5
4
  const o3rWidgetParameterPattern = '^[a-zA-Z0-9-_:.]+$';
6
5
  const o3rWidgetParamTypes = ['string', 'number', 'boolean', 'string[]', 'number[]', 'boolean[]'];
7
6
  const createCommentString = (comment) => `/*${comment}*/`;
7
+ const defaultOptions = [{
8
+ supportedInterfaceNames: utils_1.defaultSupportedInterfaceNames,
9
+ widgets: {}
10
+ }];
8
11
  exports.default = (0, utils_1.createRule)({
9
12
  name: 'o3r-widget-tags',
10
13
  meta: {
@@ -24,7 +27,8 @@ exports.default = (0, utils_1.createRule)({
24
27
  type: 'array',
25
28
  items: {
26
29
  type: 'string'
27
- }
30
+ },
31
+ default: utils_1.defaultSupportedInterfaceNames
28
32
  },
29
33
  widgets: {
30
34
  additionalProperties: {
@@ -66,17 +70,8 @@ exports.default = (0, utils_1.createRule)({
66
70
  suggestReplaceO3rWidgetType: 'Replace {{ currentType }} by {{ suggestedType }}.'
67
71
  }
68
72
  },
69
- defaultOptions: [],
70
- create: (context) => {
71
- const options = context.options
72
- .reduce((acc, option) => {
73
- acc.supportedInterfaceNames = (acc.supportedInterfaceNames || []).concat(option.supportedInterfaceNames || []);
74
- acc.widgets = {
75
- ...acc.widgets,
76
- ...option.widgets
77
- };
78
- return acc;
79
- }, { widgets: {}, supportedInterfaceNames: ['Configuration', 'NestedConfiguration'] });
73
+ defaultOptions,
74
+ create: (context, [options]) => {
80
75
  const supportedO3rWidgets = new Set(Object.keys(options.widgets));
81
76
  return {
82
77
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -125,10 +120,7 @@ exports.default = (0, utils_1.createRule)({
125
120
  return;
126
121
  }
127
122
  const interfaceDeclNode = node.parent?.parent;
128
- if (interfaceDeclNode?.type !== experimental_utils_1.TSESTree.AST_NODE_TYPES.TSInterfaceDeclaration
129
- || !interfaceDeclNode.extends?.some((ext) => ext.type === experimental_utils_1.TSESTree.AST_NODE_TYPES.TSInterfaceHeritage
130
- && ext.expression.type === experimental_utils_1.TSESTree.AST_NODE_TYPES.Identifier
131
- && options.supportedInterfaceNames.includes(ext.expression.name))) {
123
+ if (!(0, utils_1.isExtendingConfiguration)(interfaceDeclNode, options.supportedInterfaceNames)) {
132
124
  return context.report({
133
125
  messageId: 'notInConfigurationInterface',
134
126
  node,
@@ -1,3 +1,11 @@
1
- import { ESLintUtils } from '@typescript-eslint/experimental-utils';
1
+ import { ESLintUtils, TSESTree } from '@typescript-eslint/experimental-utils';
2
2
  /** ESLint rule generator */
3
3
  export declare const createRule: <TOptions extends readonly unknown[], TMessageIds extends string, TRuleListener extends import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener = import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>({ name, meta, ...rule }: Readonly<ESLintUtils.RuleWithMetaAndName<TOptions, TMessageIds, TRuleListener>>) => import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<TMessageIds, TOptions, TRuleListener>;
4
+ /** Default supported interface names */
5
+ export declare const defaultSupportedInterfaceNames: string[];
6
+ /**
7
+ * Returns true if the node extends one of the `supportedInterfaceNames`
8
+ * @param interfaceDeclNode
9
+ * @param supportedInterfaceNames
10
+ */
11
+ export declare const isExtendingConfiguration: (interfaceDeclNode: TSESTree.Node | undefined, supportedInterfaceNames?: string[]) => boolean | undefined;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createRule = void 0;
3
+ exports.isExtendingConfiguration = exports.defaultSupportedInterfaceNames = exports.createRule = void 0;
4
4
  const experimental_utils_1 = require("@typescript-eslint/experimental-utils");
5
5
  const path = require("node:path");
6
6
  /** Current package version (format: <major>.<minor>)*/
@@ -13,3 +13,18 @@ exports.createRule = experimental_utils_1.ESLintUtils.RuleCreator((name) => {
13
13
  }
14
14
  return `https://github.com/AmadeusITGroup/otter/tree/release/${version}/docs/linter/eslint-plugin/rules/${name}.md`;
15
15
  });
16
+ /** Default supported interface names */
17
+ exports.defaultSupportedInterfaceNames = ['Configuration', 'NestedConfiguration'];
18
+ /**
19
+ * Returns true if the node extends one of the `supportedInterfaceNames`
20
+ * @param interfaceDeclNode
21
+ * @param supportedInterfaceNames
22
+ */
23
+ const isExtendingConfiguration = (interfaceDeclNode, supportedInterfaceNames = []) => {
24
+ const supportedInterfaceNamesSet = new Set(supportedInterfaceNames.length > 0 ? supportedInterfaceNames : exports.defaultSupportedInterfaceNames);
25
+ return interfaceDeclNode?.type === experimental_utils_1.TSESTree.AST_NODE_TYPES.TSInterfaceDeclaration
26
+ && interfaceDeclNode.extends?.some((ext) => ext.type === experimental_utils_1.TSESTree.AST_NODE_TYPES.TSInterfaceHeritage
27
+ && ext.expression.type === experimental_utils_1.TSESTree.AST_NODE_TYPES.Identifier
28
+ && supportedInterfaceNamesSet.has(ext.expression.name));
29
+ };
30
+ exports.isExtendingConfiguration = isExtendingConfiguration;