@o3r/eslint-plugin 9.6.0-alpha.3 → 9.6.0-alpha.30
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 +7 -7
- package/src/index.js +7 -1
- package/src/rules/template/no-inner-html/no-inner-html.d.ts +5 -0
- package/src/rules/template/no-inner-html/no-inner-html.js +57 -0
- package/src/rules/typescript/no-multiple-type-configuration-property/no-multiple-type-configuration-property.d.ts +5 -0
- package/src/rules/typescript/no-multiple-type-configuration-property/no-multiple-type-configuration-property.js +69 -0
- package/src/rules/typescript/o3r-widget-tags/o3r-widget-tags.js +4 -7
- package/src/rules/utils.d.ts +9 -1
- package/src/rules/utils.js +16 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@o3r/eslint-plugin",
|
|
3
|
-
"version": "9.6.0-alpha.
|
|
3
|
+
"version": "9.6.0-alpha.30",
|
|
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.
|
|
39
|
-
"@angular-eslint/utils": "~16.
|
|
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.
|
|
50
|
-
"@angular-eslint/template-parser": "~16.
|
|
51
|
-
"@angular-eslint/utils": "~16.
|
|
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.
|
|
58
|
+
"@o3r/build-helpers": "^9.6.0-alpha.30",
|
|
59
59
|
"@types/jest": "~29.5.2",
|
|
60
60
|
"@types/node": "^18.0.0",
|
|
61
61
|
"@types/semver": "^7.3.13",
|
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
|
+
});
|
|
@@ -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", NoMultipleTypeConfigurationPropertyOption[], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
5
|
+
export default _default;
|
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
create: (context) => {
|
|
36
|
+
const supportedInterfaceNames = context.options.reduce((acc, option) => acc.concat(option.supportedInterfaceNames || []), []);
|
|
37
|
+
const sourceCode = context.getSourceCode();
|
|
38
|
+
const rule = (node) => {
|
|
39
|
+
const interfaceDeclNode = node.parent?.parent?.parent?.parent;
|
|
40
|
+
if (!(0, utils_1.isExtendingConfiguration)(interfaceDeclNode, supportedInterfaceNames)) {
|
|
41
|
+
return; // Not in a configuration interface
|
|
42
|
+
}
|
|
43
|
+
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)
|
|
44
|
+
&& [...(new Set(node.types.map((literalType) => typeof literalType.literal.value)))].length === 1) {
|
|
45
|
+
return; // Only the same literal type
|
|
46
|
+
}
|
|
47
|
+
const text = sourceCode.getText(node);
|
|
48
|
+
context.report({
|
|
49
|
+
messageId: 'error',
|
|
50
|
+
node,
|
|
51
|
+
loc: node.loc,
|
|
52
|
+
suggest: text.split(separatorRegExp).map((type) => ({
|
|
53
|
+
messageId: 'suggestion',
|
|
54
|
+
data: {
|
|
55
|
+
currentValue: text,
|
|
56
|
+
recommendedValue: type
|
|
57
|
+
},
|
|
58
|
+
fix: (fixer) => fixer.replaceTextRange(node.range, type)
|
|
59
|
+
}))
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
64
|
+
TSUnionType: rule,
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
66
|
+
TSIntersectionType: rule
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
});
|
|
@@ -1,6 +1,5 @@
|
|
|
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[]'];
|
|
@@ -24,7 +23,8 @@ exports.default = (0, utils_1.createRule)({
|
|
|
24
23
|
type: 'array',
|
|
25
24
|
items: {
|
|
26
25
|
type: 'string'
|
|
27
|
-
}
|
|
26
|
+
},
|
|
27
|
+
default: utils_1.defaultSupportedInterfaceNames
|
|
28
28
|
},
|
|
29
29
|
widgets: {
|
|
30
30
|
additionalProperties: {
|
|
@@ -76,7 +76,7 @@ exports.default = (0, utils_1.createRule)({
|
|
|
76
76
|
...option.widgets
|
|
77
77
|
};
|
|
78
78
|
return acc;
|
|
79
|
-
}, { widgets: {}, supportedInterfaceNames: [
|
|
79
|
+
}, { widgets: {}, supportedInterfaceNames: [] });
|
|
80
80
|
const supportedO3rWidgets = new Set(Object.keys(options.widgets));
|
|
81
81
|
return {
|
|
82
82
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
@@ -125,10 +125,7 @@ exports.default = (0, utils_1.createRule)({
|
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
127
|
const interfaceDeclNode = node.parent?.parent;
|
|
128
|
-
if (interfaceDeclNode
|
|
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))) {
|
|
128
|
+
if (!(0, utils_1.isExtendingConfiguration)(interfaceDeclNode, options.supportedInterfaceNames)) {
|
|
132
129
|
return context.report({
|
|
133
130
|
messageId: 'notInConfigurationInterface',
|
|
134
131
|
node,
|
package/src/rules/utils.d.ts
CHANGED
|
@@ -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;
|
package/src/rules/utils.js
CHANGED
|
@@ -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;
|