@o3r/eslint-plugin 10.0.0-next.8 → 11.0.0-next.0
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/README.md +1 -1
- package/package.json +44 -29
- package/src/index.d.ts +1 -0
- package/src/index.js +34 -3
- package/src/public_api.d.ts +1 -0
- package/src/rules/json/json-dependency-versions-harmonize/json-dependency-versions-harmonize.d.ts +15 -0
- package/src/rules/json/json-dependency-versions-harmonize/json-dependency-versions-harmonize.js +123 -0
- package/src/rules/json/json-dependency-versions-harmonize/version-harmonize.d.ts +40 -0
- package/src/rules/json/json-dependency-versions-harmonize/version-harmonize.js +96 -0
- package/src/rules/json/utils.d.ts +39 -0
- package/src/rules/json/utils.js +60 -0
- 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/template/template-async-number-limitation/template-async-number-limitation.d.ts +7 -0
- package/src/rules/{template-async-number-limitation → template/template-async-number-limitation}/template-async-number-limitation.js +4 -5
- package/src/rules/template/utils.d.ts +38 -0
- package/src/rules/{template-utils.js → template/utils.js} +0 -3
- package/src/rules/typescript/matching-configuration-name/matching-configuration-name.d.ts +5 -0
- package/src/rules/typescript/matching-configuration-name/matching-configuration-name.js +70 -0
- package/src/rules/typescript/no-folder-import-for-module/no-folder-import-for-module.d.ts +4 -0
- package/src/rules/{no-folder-import-for-module → typescript/no-folder-import-for-module}/no-folder-import-for-module.js +1 -1
- 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 +71 -0
- package/src/rules/typescript/o3r-categories-tags/o3r-categories-tags.d.ts +7 -0
- package/src/rules/typescript/o3r-categories-tags/o3r-categories-tags.js +137 -0
- package/src/rules/typescript/o3r-widget-tags/o3r-widget-tags.d.ts +16 -0
- package/src/rules/typescript/o3r-widget-tags/o3r-widget-tags.js +255 -0
- package/src/rules/utils.d.ts +22 -0
- package/src/rules/utils.js +34 -1
- package/src/rules/yaml/utils.d.ts +22 -0
- package/src/rules/yaml/utils.js +42 -0
- package/src/rules/yaml/yarnrc-package-extensions-harmonize/yarnrc-package-extensions-harmonize.d.ts +12 -0
- package/src/rules/yaml/yarnrc-package-extensions-harmonize/yarnrc-package-extensions-harmonize.js +122 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/schematics/ng-add/schema.json +0 -18
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../../utils");
|
|
4
|
+
const o3rWidgetParameterPattern = '^[a-zA-Z0-9-_:.]+$';
|
|
5
|
+
const o3rWidgetParamTypes = ['string', 'number', 'boolean', 'string[]', 'number[]', 'boolean[]'];
|
|
6
|
+
const defaultOptions = [{
|
|
7
|
+
supportedInterfaceNames: utils_1.defaultSupportedInterfaceNames,
|
|
8
|
+
widgets: {}
|
|
9
|
+
}];
|
|
10
|
+
exports.default = (0, utils_1.createRule)({
|
|
11
|
+
name: 'o3r-widget-tags',
|
|
12
|
+
meta: {
|
|
13
|
+
hasSuggestions: true,
|
|
14
|
+
fixable: 'code',
|
|
15
|
+
type: 'problem',
|
|
16
|
+
docs: {
|
|
17
|
+
description: 'Ensures that @o3rWidget and @o3rWidgetParam are used with correct value',
|
|
18
|
+
recommended: 'error'
|
|
19
|
+
},
|
|
20
|
+
schema: [
|
|
21
|
+
{
|
|
22
|
+
type: 'object',
|
|
23
|
+
required: ['widgets'],
|
|
24
|
+
properties: {
|
|
25
|
+
supportedInterfaceNames: {
|
|
26
|
+
type: 'array',
|
|
27
|
+
items: {
|
|
28
|
+
type: 'string'
|
|
29
|
+
},
|
|
30
|
+
default: utils_1.defaultSupportedInterfaceNames
|
|
31
|
+
},
|
|
32
|
+
widgets: {
|
|
33
|
+
additionalProperties: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
additionalProperties: false,
|
|
36
|
+
patternProperties: {
|
|
37
|
+
[o3rWidgetParameterPattern]: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
required: ['type'],
|
|
40
|
+
properties: {
|
|
41
|
+
required: {
|
|
42
|
+
type: 'boolean'
|
|
43
|
+
},
|
|
44
|
+
type: {
|
|
45
|
+
type: 'string',
|
|
46
|
+
enum: o3rWidgetParamTypes
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
messages: {
|
|
57
|
+
notSupportedType: '{{ o3rWidgetType }} is not supported. Supported o3rWidget types: {{ supportedO3rWidgets }}.',
|
|
58
|
+
notSupportedParamForType: '{{ o3rWidgetParam }} is not supported for {{ o3rWidgetType }}. Supported o3rWidgetParam for {{ o3rWidgetType }}: {{ supportedO3rWidgetParam }}.',
|
|
59
|
+
invalidParamValueType: '{{ o3rWidgetParam }} supports only {{ o3rWidgetParamType }}.',
|
|
60
|
+
noParamWithoutWidget: '@o3rWidgetParam cannot be used without @o3rWidget',
|
|
61
|
+
duplicatedParam: '@o3rWidgetParam {{ o3rWidgetParam }} must be defined only once.',
|
|
62
|
+
onlyOneWidgetAllowed: '@o3rWidget must be defined only once.',
|
|
63
|
+
notInConfigurationInterface: '@o3rWidget can only be used in `Configuration` interface.',
|
|
64
|
+
requiredParamMissing: '@o3rWidgetParam {{ o3rWidgetParam }} is mandatory when using @o3rWidget {{ o3rWidgetType }}.',
|
|
65
|
+
suggestParamMissing: 'Add @o3rWidgetParam {{ o3rWidgetParam }}.',
|
|
66
|
+
suggestRemoveDuplicatedO3rWidget: 'Remove the 2nd @o3rWidget.',
|
|
67
|
+
suggestRemoveDuplicatedO3rWidgetParam: 'Remove the 2nd @o3rWidgetParam.',
|
|
68
|
+
suggestAddO3rWidgetTag: 'Add @o3rWidget tag.',
|
|
69
|
+
suggestReplaceO3rWidgetType: 'Replace {{ currentType }} by {{ suggestedType }}.'
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
defaultOptions,
|
|
73
|
+
create: (context, [options]) => {
|
|
74
|
+
const supportedO3rWidgets = new Set(Object.keys(options.widgets));
|
|
75
|
+
return {
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
77
|
+
TSPropertySignature: (node) => {
|
|
78
|
+
const sourceCode = context.getSourceCode();
|
|
79
|
+
const comment = (0, utils_1.getNodeComment)(node, sourceCode);
|
|
80
|
+
if (!comment || !comment.value.length) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const { loc, value: docText } = comment;
|
|
84
|
+
const widgetTypes = Array.from(docText.matchAll(/@o3rWidget (.*)/g));
|
|
85
|
+
if (widgetTypes.length > 1) {
|
|
86
|
+
const fix = (fixer) => {
|
|
87
|
+
return fixer.replaceTextRange(comment.range, (0, utils_1.createCommentString)(comment.value.replace(/(.*(@o3rWidget ).*(\n.*)*)(\n.*)\2.*/, '$1')));
|
|
88
|
+
};
|
|
89
|
+
return context.report({
|
|
90
|
+
messageId: 'onlyOneWidgetAllowed',
|
|
91
|
+
node,
|
|
92
|
+
loc,
|
|
93
|
+
fix,
|
|
94
|
+
suggest: [{
|
|
95
|
+
messageId: 'suggestRemoveDuplicatedO3rWidget',
|
|
96
|
+
fix
|
|
97
|
+
}]
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const widgetType = widgetTypes[0]?.[1].trim();
|
|
101
|
+
const widgetParameterTexts = Array.from(docText.matchAll(/@o3rWidgetParam (.*)/g))
|
|
102
|
+
.map((match) => match[1].trim());
|
|
103
|
+
if (!widgetType) {
|
|
104
|
+
if (widgetParameterTexts.length) {
|
|
105
|
+
const fix = (fixer) => {
|
|
106
|
+
return fixer.replaceTextRange(comment.range, (0, utils_1.createCommentString)(comment.value.replace(/((.*)@o3rWidgetParam .*)/, '$2@o3rWidget widgetType\n$1')));
|
|
107
|
+
};
|
|
108
|
+
return context.report({
|
|
109
|
+
messageId: 'noParamWithoutWidget',
|
|
110
|
+
node,
|
|
111
|
+
loc,
|
|
112
|
+
fix,
|
|
113
|
+
suggest: [{
|
|
114
|
+
messageId: 'suggestAddO3rWidgetTag',
|
|
115
|
+
fix
|
|
116
|
+
}]
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const interfaceDeclNode = node.parent?.parent;
|
|
122
|
+
if (!(0, utils_1.isExtendingConfiguration)(interfaceDeclNode, options.supportedInterfaceNames)) {
|
|
123
|
+
return context.report({
|
|
124
|
+
messageId: 'notInConfigurationInterface',
|
|
125
|
+
node,
|
|
126
|
+
loc
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (!supportedO3rWidgets.has(widgetType)) {
|
|
130
|
+
return context.report({
|
|
131
|
+
messageId: 'notSupportedType',
|
|
132
|
+
node,
|
|
133
|
+
loc,
|
|
134
|
+
data: {
|
|
135
|
+
o3rWidgetType: widgetType,
|
|
136
|
+
supportedO3rWidgets: Array.from(supportedO3rWidgets).join(', ')
|
|
137
|
+
},
|
|
138
|
+
suggest: Array.from(supportedO3rWidgets).map((suggestedWidget) => ({
|
|
139
|
+
messageId: 'suggestReplaceO3rWidgetType',
|
|
140
|
+
data: {
|
|
141
|
+
currentType: widgetType,
|
|
142
|
+
suggestedType: suggestedWidget
|
|
143
|
+
},
|
|
144
|
+
fix: (fixer) => {
|
|
145
|
+
return fixer.replaceTextRange(comment.range, (0, utils_1.createCommentString)(comment.value.replace(`@o3rWidget ${widgetType}`, `@o3rWidget ${suggestedWidget}`)));
|
|
146
|
+
}
|
|
147
|
+
}))
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
const widgetParameters = widgetParameterTexts.map((text) => {
|
|
151
|
+
const [name, ...values] = text.split(' ');
|
|
152
|
+
return {
|
|
153
|
+
name,
|
|
154
|
+
textValue: values.join(' ')
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
const widgetParameterNames = widgetParameters.map(({ name }) => name);
|
|
158
|
+
const supportedO3rWidgetParam = new Set(Object.keys(options.widgets[widgetType]));
|
|
159
|
+
const checkedParam = new Set();
|
|
160
|
+
for (const widgetParameterName of widgetParameterNames) {
|
|
161
|
+
if (checkedParam.has(widgetParameterName)) {
|
|
162
|
+
const fix = (fixer) => {
|
|
163
|
+
return fixer.replaceTextRange(comment.range, (0, utils_1.createCommentString)(comment.value.replace(/(.*(@o3rWidgetParam ).*(\n.*)*)(\n.*)\2.*/m, '$1')));
|
|
164
|
+
};
|
|
165
|
+
return context.report({
|
|
166
|
+
messageId: 'duplicatedParam',
|
|
167
|
+
node,
|
|
168
|
+
loc,
|
|
169
|
+
data: {
|
|
170
|
+
o3rWidgetParam: widgetParameterName
|
|
171
|
+
},
|
|
172
|
+
fix,
|
|
173
|
+
suggest: [{
|
|
174
|
+
messageId: 'suggestRemoveDuplicatedO3rWidget',
|
|
175
|
+
fix
|
|
176
|
+
}]
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
if (!supportedO3rWidgetParam.has(widgetParameterName)) {
|
|
180
|
+
return context.report({
|
|
181
|
+
messageId: 'notSupportedParamForType',
|
|
182
|
+
node,
|
|
183
|
+
loc,
|
|
184
|
+
data: {
|
|
185
|
+
o3rWidgetParam: widgetParameterName,
|
|
186
|
+
o3rWidgetType: widgetType,
|
|
187
|
+
supportedO3rWidgetParam: Array.from(supportedO3rWidgetParam).join(', ')
|
|
188
|
+
},
|
|
189
|
+
suggest: Array.from(supportedO3rWidgetParam).map((suggestedParam) => ({
|
|
190
|
+
messageId: 'suggestReplaceO3rWidgetType',
|
|
191
|
+
data: {
|
|
192
|
+
currentType: widgetType,
|
|
193
|
+
suggestedType: suggestedParam
|
|
194
|
+
},
|
|
195
|
+
fix: (fixer) => {
|
|
196
|
+
return fixer.replaceTextRange(comment.range, (0, utils_1.createCommentString)(comment.value.replace(`@o3rWidgetParam ${widgetType}`, `@o3rWidgetParam ${suggestedParam}`)));
|
|
197
|
+
}
|
|
198
|
+
}))
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
checkedParam.add(widgetParameterName);
|
|
202
|
+
}
|
|
203
|
+
const firstRequiredParam = Object.entries(options.widgets[widgetType]).find(([param, { required }]) => required && !checkedParam.has(param));
|
|
204
|
+
if (firstRequiredParam) {
|
|
205
|
+
const [firstRequiredParamName] = firstRequiredParam;
|
|
206
|
+
const fix = (fixer) => {
|
|
207
|
+
return fixer.replaceTextRange(comment.range, (0, utils_1.createCommentString)(comment.value.replace(/((.*)@o3rWidget (.*))/, `$1\n$2@o3rWidgetParam ${firstRequiredParamName} value`)));
|
|
208
|
+
};
|
|
209
|
+
return context.report({
|
|
210
|
+
messageId: 'requiredParamMissing',
|
|
211
|
+
node,
|
|
212
|
+
loc,
|
|
213
|
+
data: {
|
|
214
|
+
o3rWidgetParam: firstRequiredParamName,
|
|
215
|
+
o3rWidgetType: widgetType
|
|
216
|
+
},
|
|
217
|
+
fix,
|
|
218
|
+
suggest: [{
|
|
219
|
+
messageId: 'suggestParamMissing',
|
|
220
|
+
data: {
|
|
221
|
+
o3rWidgetParam: firstRequiredParamName
|
|
222
|
+
},
|
|
223
|
+
fix
|
|
224
|
+
}]
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
for (const widgetParameter of widgetParameters) {
|
|
228
|
+
const { name, textValue } = widgetParameter;
|
|
229
|
+
const supportedTypeForParam = options.widgets[widgetType][name];
|
|
230
|
+
try {
|
|
231
|
+
const value = JSON.parse(textValue);
|
|
232
|
+
if (supportedTypeForParam.type.endsWith('[]')) {
|
|
233
|
+
if (Array.isArray(value) && value.every((element) => typeof element === supportedTypeForParam.type.substring(0, -2))) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else if (typeof value === supportedTypeForParam.type) {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch { }
|
|
242
|
+
return context.report({
|
|
243
|
+
messageId: 'invalidParamValueType',
|
|
244
|
+
node,
|
|
245
|
+
loc,
|
|
246
|
+
data: {
|
|
247
|
+
o3rWidgetParam: name,
|
|
248
|
+
o3rWidgetParamType: supportedTypeForParam.type
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ESLintUtils, TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';
|
|
2
|
+
/** ESLint rule generator */
|
|
3
|
+
export declare const createRule: <TOptions extends readonly unknown[], TMessageIds extends string, TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener>({ name, meta, ...rule }: Readonly<ESLintUtils.RuleWithMetaAndName<TOptions, TMessageIds, TRuleListener>>) => TSESLint.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[]) => interfaceDeclNode is TSESTree.Node;
|
|
12
|
+
/**
|
|
13
|
+
* Returns the comment above the node
|
|
14
|
+
* @param node
|
|
15
|
+
* @param sourceCode
|
|
16
|
+
*/
|
|
17
|
+
export declare const getNodeComment: (node: TSESTree.Node, sourceCode: TSESLint.SourceCode) => TSESTree.Comment | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Wraps `commentValue` into a comment
|
|
20
|
+
* @param commentValue
|
|
21
|
+
*/
|
|
22
|
+
export declare const createCommentString: (commentValue: string) => string;
|
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.createCommentString = exports.getNodeComment = 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,36 @@ 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;
|
|
31
|
+
/**
|
|
32
|
+
* Returns the comment above the node
|
|
33
|
+
* @param node
|
|
34
|
+
* @param sourceCode
|
|
35
|
+
*/
|
|
36
|
+
const getNodeComment = (node, sourceCode) => {
|
|
37
|
+
const [comment] = node.parent?.type === experimental_utils_1.TSESTree.AST_NODE_TYPES.ExportNamedDeclaration
|
|
38
|
+
? sourceCode.getCommentsBefore(node.parent)
|
|
39
|
+
: sourceCode.getCommentsBefore(node);
|
|
40
|
+
return comment;
|
|
41
|
+
};
|
|
42
|
+
exports.getNodeComment = getNodeComment;
|
|
43
|
+
/**
|
|
44
|
+
* Wraps `commentValue` into a comment
|
|
45
|
+
* @param commentValue
|
|
46
|
+
*/
|
|
47
|
+
const createCommentString = (commentValue) => `/*${commentValue.replace(/\*\//g, '*\\/')}*/`;
|
|
48
|
+
exports.createCommentString = createCommentString;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ParserServices, TSESLint } from '@typescript-eslint/experimental-utils';
|
|
2
|
+
/** Basic interface for the Parser Services object provided by yaml-eslint-parser */
|
|
3
|
+
interface YamlParserServices extends ParserServices {
|
|
4
|
+
isYAML: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Determine if yaml-eslint-parser is used
|
|
8
|
+
* @param parserServices Parser services object
|
|
9
|
+
*/
|
|
10
|
+
export declare function isYamlParserServices(parserServices: any): parserServices is YamlParserServices;
|
|
11
|
+
/**
|
|
12
|
+
* Retrieve the yaml parser services object or throw if the invalid parser is used
|
|
13
|
+
* @param context Rule context
|
|
14
|
+
*/
|
|
15
|
+
export declare function getYamlParserServices(context: Readonly<TSESLint.RuleContext<string, readonly unknown[]>>): YamlParserServices;
|
|
16
|
+
/**
|
|
17
|
+
* Utility for rule authors to ensure that their rule is correctly being used with yaml-eslint-parser
|
|
18
|
+
* If yaml-eslint-parser is not the configured parser when the function is invoked it will throw
|
|
19
|
+
* @param context
|
|
20
|
+
*/
|
|
21
|
+
export declare function ensureJsoncParser(context: Readonly<TSESLint.RuleContext<string, readonly unknown[]>>): void;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ensureJsoncParser = exports.getYamlParserServices = exports.isYamlParserServices = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Determine if yaml-eslint-parser is used
|
|
6
|
+
* @param parserServices Parser services object
|
|
7
|
+
*/
|
|
8
|
+
function isYamlParserServices(parserServices) {
|
|
9
|
+
return !!parserServices && parserServices.isYAML;
|
|
10
|
+
}
|
|
11
|
+
exports.isYamlParserServices = isYamlParserServices;
|
|
12
|
+
/**
|
|
13
|
+
* Retrieve the yaml parser services object or throw if the invalid parser is used
|
|
14
|
+
* @param context Rule context
|
|
15
|
+
*/
|
|
16
|
+
function getYamlParserServices(context) {
|
|
17
|
+
const parserService = context.parserServices;
|
|
18
|
+
if (!isYamlParserServices(parserService)) {
|
|
19
|
+
/*
|
|
20
|
+
* The user needs to have configured "parser" in their eslint config and set it
|
|
21
|
+
* to yaml-eslint-parser
|
|
22
|
+
*/
|
|
23
|
+
throw new Error('You have used a rule which requires \'yaml-eslint-parser\' to be used as the \'parser\' in your ESLint config.');
|
|
24
|
+
}
|
|
25
|
+
return parserService;
|
|
26
|
+
}
|
|
27
|
+
exports.getYamlParserServices = getYamlParserServices;
|
|
28
|
+
/**
|
|
29
|
+
* Utility for rule authors to ensure that their rule is correctly being used with yaml-eslint-parser
|
|
30
|
+
* If yaml-eslint-parser is not the configured parser when the function is invoked it will throw
|
|
31
|
+
* @param context
|
|
32
|
+
*/
|
|
33
|
+
function ensureJsoncParser(context) {
|
|
34
|
+
if (!(context.parserServices)) {
|
|
35
|
+
/*
|
|
36
|
+
* The user needs to have configured "parser" in their eslint config and set it
|
|
37
|
+
* to yaml-eslint-parser
|
|
38
|
+
*/
|
|
39
|
+
throw new Error('You have used a rule which requires \'yaml-eslint-parser\' to be used as the \'parser\' in your ESLint config.');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.ensureJsoncParser = ensureJsoncParser;
|
package/src/rules/yaml/yarnrc-package-extensions-harmonize/yarnrc-package-extensions-harmonize.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface Options {
|
|
2
|
+
/** List of package.json to ignore when determining the dependencies versions */
|
|
3
|
+
excludePackages: string[];
|
|
4
|
+
/** List of dependency types in package.json to parse */
|
|
5
|
+
dependencyTypesInPackages: string[];
|
|
6
|
+
/** List of dependencies to ignore */
|
|
7
|
+
ignoredDependencies: string[];
|
|
8
|
+
/** List of dependency types to validate in .yarnrc.yml */
|
|
9
|
+
yarnrcDependencyTypes: string[];
|
|
10
|
+
}
|
|
11
|
+
declare const _default: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"error" | "versionUpdate", [Options, ...any[]], any>;
|
|
12
|
+
export default _default;
|
package/src/rules/yaml/yarnrc-package-extensions-harmonize/yarnrc-package-extensions-harmonize.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const path = require("node:path");
|
|
4
|
+
const semver = require("semver");
|
|
5
|
+
const utils_1 = require("../../utils");
|
|
6
|
+
const utils_2 = require("../utils");
|
|
7
|
+
const yaml_eslint_parser_1 = require("yaml-eslint-parser");
|
|
8
|
+
const version_harmonize_1 = require("../../json/json-dependency-versions-harmonize/version-harmonize");
|
|
9
|
+
const defaultOptions = [{
|
|
10
|
+
ignoredDependencies: [],
|
|
11
|
+
excludePackages: [],
|
|
12
|
+
yarnrcDependencyTypes: ['peerDependencies', 'dependencies'],
|
|
13
|
+
dependencyTypesInPackages: ['optionalDependencies', 'dependencies', 'devDependencies', 'peerDependencies', 'generatorDependencies']
|
|
14
|
+
}];
|
|
15
|
+
exports.default = (0, utils_1.createRule)({
|
|
16
|
+
name: 'yarnrc-package-extensions-harmonize',
|
|
17
|
+
meta: {
|
|
18
|
+
hasSuggestions: true,
|
|
19
|
+
type: 'problem',
|
|
20
|
+
docs: {
|
|
21
|
+
description: 'Ensure that the package extension versions are aligned with range defined in packages.',
|
|
22
|
+
recommended: 'error'
|
|
23
|
+
},
|
|
24
|
+
schema: [
|
|
25
|
+
{
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
excludePackages: {
|
|
29
|
+
type: 'array',
|
|
30
|
+
description: 'List of package.json to ignore when determining the dependencies versions',
|
|
31
|
+
items: {
|
|
32
|
+
type: 'string'
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
yarnrcDependencyTypes: {
|
|
36
|
+
type: 'array',
|
|
37
|
+
description: 'List of dependency types to validate in .yarnrc.yml',
|
|
38
|
+
default: defaultOptions[0].yarnrcDependencyTypes,
|
|
39
|
+
items: {
|
|
40
|
+
type: 'string'
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
dependencyTypesInPackages: {
|
|
44
|
+
type: 'array',
|
|
45
|
+
description: 'List of dependency types in package.json to parse',
|
|
46
|
+
default: defaultOptions[0].dependencyTypesInPackages,
|
|
47
|
+
items: {
|
|
48
|
+
type: 'string'
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
ignoredDependencies: {
|
|
52
|
+
type: 'array',
|
|
53
|
+
description: 'List of dependencies to ignore',
|
|
54
|
+
items: {
|
|
55
|
+
type: 'string'
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
additionalProperties: false
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
messages: {
|
|
63
|
+
versionUpdate: 'Set version {{version}}',
|
|
64
|
+
error: '{{depName}} should be updated to version {{version}} (from: {{packageJsonFile}})'
|
|
65
|
+
},
|
|
66
|
+
fixable: 'code'
|
|
67
|
+
},
|
|
68
|
+
defaultOptions,
|
|
69
|
+
create: (context, [options]) => {
|
|
70
|
+
const parserServices = (0, utils_2.getYamlParserServices)(context);
|
|
71
|
+
const dirname = path.dirname(context.getFilename());
|
|
72
|
+
const workspace = (0, version_harmonize_1.findWorkspacePackageJsons)(dirname);
|
|
73
|
+
const bestRanges = workspace ?
|
|
74
|
+
(0, version_harmonize_1.getBestRanges)(options.dependencyTypesInPackages, workspace.packages.filter(({ content }) => !content.name || !options.excludePackages.includes(content.name))) :
|
|
75
|
+
{};
|
|
76
|
+
const ignoredDependencies = options.ignoredDependencies.map((dep) => new RegExp(dep.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*')));
|
|
77
|
+
if (parserServices.isYAML) {
|
|
78
|
+
return {
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
80
|
+
'YAMLPair': (node) => {
|
|
81
|
+
if (node.value) {
|
|
82
|
+
const range = (0, yaml_eslint_parser_1.getStaticYAMLValue)(node.value)?.toString();
|
|
83
|
+
const parent = node.parent.parent && node.parent.parent.type === 'YAMLPair' && (0, yaml_eslint_parser_1.getStaticYAMLValue)(node.parent.parent.key)?.toString();
|
|
84
|
+
const baseNode = node.parent.parent.parent.parent?.parent?.parent;
|
|
85
|
+
const isCorrectNode = baseNode && baseNode.type === 'YAMLPair' && (0, yaml_eslint_parser_1.getStaticYAMLValue)(baseNode.key)?.toString() === 'packageExtensions';
|
|
86
|
+
if (isCorrectNode && semver.validRange(range) && parent && options.yarnrcDependencyTypes.some((t) => t === parent)) {
|
|
87
|
+
const depName = node.key && (0, yaml_eslint_parser_1.getStaticYAMLValue)(node.key)?.toString();
|
|
88
|
+
if (!depName || !bestRanges[depName] || ignoredDependencies.some((ignore) => ignore.test(depName))) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const minYarnrcVersion = semver.minVersion(range);
|
|
92
|
+
const minBestRangeVersion = semver.minVersion(bestRanges[depName].range);
|
|
93
|
+
if (minYarnrcVersion && minBestRangeVersion && semver.lt(minYarnrcVersion, minBestRangeVersion)) {
|
|
94
|
+
const version = bestRanges[depName].range;
|
|
95
|
+
const packageJsonFile = bestRanges[depName].path;
|
|
96
|
+
context.report({
|
|
97
|
+
loc: node.value.loc,
|
|
98
|
+
messageId: 'error',
|
|
99
|
+
data: {
|
|
100
|
+
depName,
|
|
101
|
+
version,
|
|
102
|
+
packageJsonFile
|
|
103
|
+
},
|
|
104
|
+
fix: (fixer) => fixer.replaceTextRange(node.value.range, `${version}`),
|
|
105
|
+
suggest: [
|
|
106
|
+
{
|
|
107
|
+
messageId: 'versionUpdate',
|
|
108
|
+
data: {
|
|
109
|
+
version
|
|
110
|
+
},
|
|
111
|
+
fix: (fixer) => fixer.replaceTextRange(node.value.range, `${version}`)
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"5.2.2"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "http://json-schema.org/schema",
|
|
3
|
-
"$id": "ngAddSchematicsSchema",
|
|
4
|
-
"title": "Add Otter eslint-plugin ",
|
|
5
|
-
"description": "ngAdd Otter eslint-plugin ",
|
|
6
|
-
"properties": {
|
|
7
|
-
"projectName": {
|
|
8
|
-
"type": "string",
|
|
9
|
-
"description": "Project name",
|
|
10
|
-
"$default": {
|
|
11
|
-
"$source": "projectName"
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"additionalProperties": false,
|
|
16
|
-
"required": [
|
|
17
|
-
]
|
|
18
|
-
}
|