@taiga-ui/eslint-plugin-experience-next 0.512.0 → 0.514.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
CHANGED
|
@@ -95,6 +95,7 @@ from third-party plugins. The exact severities and file globs live in
|
|
|
95
95
|
| [no-implicit-public](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-implicit-public.md) | Require explicit `public` modifier for class members and parameter properties | ✅ | 🔧 | |
|
|
96
96
|
| [no-infinite-loop](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-infinite-loop.md) | Disallow `while (true)` and `for` loops without an explicit condition | ✅ | | |
|
|
97
97
|
| [no-legacy-peer-deps](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-legacy-peer-deps.md) | Disallow `legacy-peer-deps=true` in `.npmrc` | ✅ | | |
|
|
98
|
+
| [no-nested-interactive](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-nested-interactive.md) | Disallow interactive HTML elements nested inside other interactive elements | ✅ | | |
|
|
98
99
|
| [no-obsolete-attrs](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-obsolete-attrs.md) | Disallow obsolete HTML attributes | ✅ | | |
|
|
99
100
|
| [no-obsolete-tags](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-obsolete-tags.md) | Disallow obsolete HTML tags | ✅ | | |
|
|
100
101
|
| [no-playwright-empty-fill](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-playwright-empty-fill.md) | Enforce `clear()` over `fill('')` in Playwright tests | ✅ | 🔧 | |
|
package/index.d.ts
CHANGED
|
@@ -99,6 +99,9 @@ declare const plugin: {
|
|
|
99
99
|
'no-legacy-peer-deps': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noLegacyPeerDeps", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
100
100
|
name: string;
|
|
101
101
|
};
|
|
102
|
+
'no-nested-interactive': import("eslint").Rule.RuleModule & {
|
|
103
|
+
name: string;
|
|
104
|
+
};
|
|
102
105
|
'no-obsolete-attrs': import("eslint").Rule.RuleModule & {
|
|
103
106
|
name: string;
|
|
104
107
|
};
|
package/index.esm.js
CHANGED
|
@@ -1309,6 +1309,7 @@ var recommended = defineConfig([
|
|
|
1309
1309
|
'@taiga-ui/experience-next/no-duplicate-id': 'error',
|
|
1310
1310
|
'@taiga-ui/experience-next/no-duplicate-in-head': 'error',
|
|
1311
1311
|
'@taiga-ui/experience-next/no-href-with-router-link': 'error',
|
|
1312
|
+
'@taiga-ui/experience-next/no-nested-interactive': 'error',
|
|
1312
1313
|
'@taiga-ui/experience-next/no-obsolete-attrs': 'error',
|
|
1313
1314
|
'@taiga-ui/experience-next/no-obsolete-tags': 'error',
|
|
1314
1315
|
'@taiga-ui/experience-next/no-project-as-in-ng-template': 'error',
|
|
@@ -33212,9 +33213,44 @@ __name(compileHmrUpdateCallback, "compileHmrUpdateCallback");
|
|
|
33212
33213
|
var VERSION = new Version("20.3.12");
|
|
33213
33214
|
publishFacade(_global);
|
|
33214
33215
|
|
|
33216
|
+
function getAttributeNames(name) {
|
|
33217
|
+
return typeof name === 'string'
|
|
33218
|
+
? [name.toLowerCase()]
|
|
33219
|
+
: name.map((item) => item.toLowerCase());
|
|
33220
|
+
}
|
|
33221
|
+
function isMatchingAttributeName(name, names) {
|
|
33222
|
+
return names.includes(name.toLowerCase());
|
|
33223
|
+
}
|
|
33215
33224
|
function getAttributeValueSpan(attr) {
|
|
33216
33225
|
return attr instanceof dist$4.TmplAstBoundEvent ? attr.handlerSpan : attr.valueSpan;
|
|
33217
33226
|
}
|
|
33227
|
+
function getStaticAttribute(element, name) {
|
|
33228
|
+
const attrName = name.toLowerCase();
|
|
33229
|
+
return element.attributes.find((attr) => attr.name.toLowerCase() === attrName);
|
|
33230
|
+
}
|
|
33231
|
+
function getStaticAttributeValue(element, name) {
|
|
33232
|
+
return getStaticAttribute(element, name)?.value;
|
|
33233
|
+
}
|
|
33234
|
+
function hasInputBinding(element, name) {
|
|
33235
|
+
const names = getAttributeNames(name);
|
|
33236
|
+
return element.inputs.some((input) => isMatchingAttributeName(input.name, names));
|
|
33237
|
+
}
|
|
33238
|
+
function hasElementAttribute(element, name) {
|
|
33239
|
+
const names = getAttributeNames(name);
|
|
33240
|
+
return (element.attributes.some((attr) => isMatchingAttributeName(attr.name, names)) ||
|
|
33241
|
+
element.inputs.some((input) => {
|
|
33242
|
+
if (isMatchingAttributeName(input.name, names)) {
|
|
33243
|
+
return true;
|
|
33244
|
+
}
|
|
33245
|
+
const details = input.keySpan.details?.toLowerCase();
|
|
33246
|
+
return (details?.startsWith('attr.') === true && names.includes(details.slice(5)));
|
|
33247
|
+
}));
|
|
33248
|
+
}
|
|
33249
|
+
function hasOutputBinding(element, name) {
|
|
33250
|
+
{
|
|
33251
|
+
return element.outputs.length > 0;
|
|
33252
|
+
}
|
|
33253
|
+
}
|
|
33218
33254
|
function getElementAttributeLikes(element) {
|
|
33219
33255
|
const seen = new Set();
|
|
33220
33256
|
return [
|
|
@@ -46233,7 +46269,7 @@ function buildMultilineStartTag(node, sourceText) {
|
|
|
46233
46269
|
closing,
|
|
46234
46270
|
].join('\n');
|
|
46235
46271
|
}
|
|
46236
|
-
const rule$
|
|
46272
|
+
const rule$U = createRule({
|
|
46237
46273
|
name: 'attrs-newline',
|
|
46238
46274
|
rule: {
|
|
46239
46275
|
create(context) {
|
|
@@ -46413,7 +46449,7 @@ function sameOrder(a, b) {
|
|
|
46413
46449
|
return a.length === b.length && a.every((value, index) => value === b[index]);
|
|
46414
46450
|
}
|
|
46415
46451
|
|
|
46416
|
-
const rule$
|
|
46452
|
+
const rule$T = createRule({
|
|
46417
46453
|
create(context, [order]) {
|
|
46418
46454
|
const decorators = new Set(Object.keys(order));
|
|
46419
46455
|
return {
|
|
@@ -46525,7 +46561,7 @@ const INLINE_HTML_ELEMENTS = new Set([
|
|
|
46525
46561
|
'wbr',
|
|
46526
46562
|
]);
|
|
46527
46563
|
|
|
46528
|
-
const MESSAGE_ID$
|
|
46564
|
+
const MESSAGE_ID$h = 'expectAfter';
|
|
46529
46565
|
const SKIP_CHILDREN = new Set(['code', 'pre']);
|
|
46530
46566
|
function isChildNode(node) {
|
|
46531
46567
|
return (node instanceof dist$4.TmplAstBoundText ||
|
|
@@ -46549,7 +46585,7 @@ function getNodeLabel(node) {
|
|
|
46549
46585
|
}
|
|
46550
46586
|
return node instanceof dist$4.TmplAstBoundText ? 'binding' : 'text';
|
|
46551
46587
|
}
|
|
46552
|
-
const rule$
|
|
46588
|
+
const rule$S = createRule({
|
|
46553
46589
|
name: 'element-newline',
|
|
46554
46590
|
rule: {
|
|
46555
46591
|
create(context) {
|
|
@@ -46575,7 +46611,7 @@ const rule$R = createRule({
|
|
|
46575
46611
|
firstChild.sourceSpan.start.offset,
|
|
46576
46612
|
], '\n'),
|
|
46577
46613
|
loc: sourceSpanToLoc(firstChild.sourceSpan),
|
|
46578
|
-
messageId: MESSAGE_ID$
|
|
46614
|
+
messageId: MESSAGE_ID$h,
|
|
46579
46615
|
});
|
|
46580
46616
|
return;
|
|
46581
46617
|
}
|
|
@@ -46593,7 +46629,7 @@ const rule$R = createRule({
|
|
|
46593
46629
|
child.sourceSpan.end.offset,
|
|
46594
46630
|
], '\n'),
|
|
46595
46631
|
loc: sourceSpanToLoc(next.sourceSpan),
|
|
46596
|
-
messageId: MESSAGE_ID$
|
|
46632
|
+
messageId: MESSAGE_ID$h,
|
|
46597
46633
|
});
|
|
46598
46634
|
return;
|
|
46599
46635
|
}
|
|
@@ -46607,7 +46643,7 @@ const rule$R = createRule({
|
|
|
46607
46643
|
lastChild.sourceSpan.end.offset,
|
|
46608
46644
|
], '\n'),
|
|
46609
46645
|
loc: sourceSpanToLoc(lastChild.sourceSpan),
|
|
46610
|
-
messageId: MESSAGE_ID$
|
|
46646
|
+
messageId: MESSAGE_ID$h,
|
|
46611
46647
|
});
|
|
46612
46648
|
}
|
|
46613
46649
|
},
|
|
@@ -46616,7 +46652,7 @@ const rule$R = createRule({
|
|
|
46616
46652
|
meta: {
|
|
46617
46653
|
docs: { description: 'Enforce line breaks between block-level child nodes' },
|
|
46618
46654
|
fixable: 'code',
|
|
46619
|
-
messages: { [MESSAGE_ID$
|
|
46655
|
+
messages: { [MESSAGE_ID$h]: 'There should be a linebreak after {{name}}.' },
|
|
46620
46656
|
schema: [],
|
|
46621
46657
|
type: 'layout',
|
|
46622
46658
|
},
|
|
@@ -46688,7 +46724,7 @@ const PRESETS = {
|
|
|
46688
46724
|
$VUE: ['$CLASS', '$ID', '$VUE_ATTRIBUTE'],
|
|
46689
46725
|
$VUE_ATTRIBUTE: /^v-/,
|
|
46690
46726
|
};
|
|
46691
|
-
const rule$
|
|
46727
|
+
const rule$R = createRule({
|
|
46692
46728
|
create(context, [options]) {
|
|
46693
46729
|
const sourceCode = context.sourceCode;
|
|
46694
46730
|
const settings = {
|
|
@@ -46968,7 +47004,7 @@ const DIRECTIONAL_TO_LOGICAL = {
|
|
|
46968
47004
|
top: 'inset-block-start',
|
|
46969
47005
|
};
|
|
46970
47006
|
const STYLE_PREFIX = 'style.';
|
|
46971
|
-
const MESSAGE_ID$
|
|
47007
|
+
const MESSAGE_ID$g = 'html-logical-properties';
|
|
46972
47008
|
const MESSAGE = `
|
|
46973
47009
|
Use logical CSS properties instead of directional properties. Replace:
|
|
46974
47010
|
• left → inset-inline-start
|
|
@@ -47006,7 +47042,7 @@ const config$4 = {
|
|
|
47006
47042
|
context.report({
|
|
47007
47043
|
fix: (fixer) => fixer.replaceTextRange([propertyStart, propertyEnd], logicalProperty),
|
|
47008
47044
|
loc: sourceSpanToLoc(keySpan),
|
|
47009
|
-
messageId: MESSAGE_ID$
|
|
47045
|
+
messageId: MESSAGE_ID$g,
|
|
47010
47046
|
});
|
|
47011
47047
|
},
|
|
47012
47048
|
};
|
|
@@ -47014,12 +47050,12 @@ const config$4 = {
|
|
|
47014
47050
|
meta: {
|
|
47015
47051
|
docs: { description: MESSAGE },
|
|
47016
47052
|
fixable: 'code',
|
|
47017
|
-
messages: { [MESSAGE_ID$
|
|
47053
|
+
messages: { [MESSAGE_ID$g]: MESSAGE },
|
|
47018
47054
|
schema: [],
|
|
47019
47055
|
type: 'suggestion',
|
|
47020
47056
|
},
|
|
47021
47057
|
};
|
|
47022
|
-
const rule$
|
|
47058
|
+
const rule$Q = createRule({
|
|
47023
47059
|
name: 'html-logical-properties',
|
|
47024
47060
|
rule: config$4,
|
|
47025
47061
|
});
|
|
@@ -248261,7 +248297,7 @@ function isImportUsedOnlyAsAngularDiFirstArg(node, sourceCode) {
|
|
|
248261
248297
|
}
|
|
248262
248298
|
return hasSafeRuntimeUsage;
|
|
248263
248299
|
}
|
|
248264
|
-
const rule$
|
|
248300
|
+
const rule$P = createRule({
|
|
248265
248301
|
create(context) {
|
|
248266
248302
|
const { checker, esTreeNodeToTSNodeMap, sourceCode, tsProgram } = getTypeAwareRuleContext(context);
|
|
248267
248303
|
const checkCycles = context.options[0]?.checkCycles ?? true;
|
|
@@ -248923,7 +248959,7 @@ const rule$O = createRule({
|
|
|
248923
248959
|
name: 'import-integrity',
|
|
248924
248960
|
});
|
|
248925
248961
|
|
|
248926
|
-
const MESSAGE_ID$
|
|
248962
|
+
const MESSAGE_ID$f = 'invalid-injection-token-description';
|
|
248927
248963
|
const ERROR_MESSAGE$3 = "InjectionToken's description should contain token's name";
|
|
248928
248964
|
const NG_DEV_MODE = 'ngDevMode';
|
|
248929
248965
|
function getVariableName(node) {
|
|
@@ -248986,7 +249022,7 @@ function getNgDevModeDeclarationFix(program, fixer) {
|
|
|
248986
249022
|
? fixer.insertTextBefore(firstStatement, 'declare const ngDevMode: boolean;\n\n')
|
|
248987
249023
|
: fixer.insertTextBeforeRange([0, 0], 'declare const ngDevMode: boolean;\n');
|
|
248988
249024
|
}
|
|
248989
|
-
const rule$
|
|
249025
|
+
const rule$O = createRule({
|
|
248990
249026
|
create(context) {
|
|
248991
249027
|
const { sourceCode } = context;
|
|
248992
249028
|
const program = sourceCode.ast;
|
|
@@ -249018,7 +249054,7 @@ const rule$N = createRule({
|
|
|
249018
249054
|
}
|
|
249019
249055
|
return fixes;
|
|
249020
249056
|
},
|
|
249021
|
-
messageId: MESSAGE_ID$
|
|
249057
|
+
messageId: MESSAGE_ID$f,
|
|
249022
249058
|
node: description,
|
|
249023
249059
|
});
|
|
249024
249060
|
}
|
|
@@ -249028,14 +249064,14 @@ const rule$N = createRule({
|
|
|
249028
249064
|
meta: {
|
|
249029
249065
|
docs: { description: ERROR_MESSAGE$3 },
|
|
249030
249066
|
fixable: 'code',
|
|
249031
|
-
messages: { [MESSAGE_ID$
|
|
249067
|
+
messages: { [MESSAGE_ID$f]: ERROR_MESSAGE$3 },
|
|
249032
249068
|
schema: [],
|
|
249033
249069
|
type: 'problem',
|
|
249034
249070
|
},
|
|
249035
249071
|
name: 'injection-token-description',
|
|
249036
249072
|
});
|
|
249037
249073
|
|
|
249038
|
-
const rule$
|
|
249074
|
+
const rule$N = createRule({
|
|
249039
249075
|
create(context) {
|
|
249040
249076
|
const { sourceCode } = context;
|
|
249041
249077
|
const namespaceImports = new Map();
|
|
@@ -249111,7 +249147,7 @@ const rule$M = createRule({
|
|
|
249111
249147
|
name: 'no-commonjs-import-patterns',
|
|
249112
249148
|
});
|
|
249113
249149
|
|
|
249114
|
-
const MESSAGE_ID$
|
|
249150
|
+
const MESSAGE_ID$e = 'no-deep-imports';
|
|
249115
249151
|
const ERROR_MESSAGE$2 = 'Deep imports of Taiga UI packages are prohibited';
|
|
249116
249152
|
const CODE_EXTENSIONS = new Set([
|
|
249117
249153
|
'.cjs',
|
|
@@ -249130,7 +249166,7 @@ const DEFAULT_OPTIONS = {
|
|
|
249130
249166
|
importDeclaration: '^@taiga-ui*',
|
|
249131
249167
|
projectName: String.raw `(?<=^@taiga-ui/)([-\w]+)`,
|
|
249132
249168
|
};
|
|
249133
|
-
const rule$
|
|
249169
|
+
const rule$M = createRule({
|
|
249134
249170
|
create(context) {
|
|
249135
249171
|
const { currentProject, deepImport, ignoreImports, importDeclaration, projectName, } = { ...DEFAULT_OPTIONS, ...context.options[0] };
|
|
249136
249172
|
const hasNonCodeExtension = (source) => {
|
|
@@ -249172,7 +249208,7 @@ const rule$L = createRule({
|
|
|
249172
249208
|
const [start, end] = node.source.range;
|
|
249173
249209
|
return fixer.replaceTextRange([start + 1, end - 1], importSource.replaceAll(new RegExp(deepImport, 'g'), ''));
|
|
249174
249210
|
},
|
|
249175
|
-
messageId: MESSAGE_ID$
|
|
249211
|
+
messageId: MESSAGE_ID$e,
|
|
249176
249212
|
node: node.source,
|
|
249177
249213
|
});
|
|
249178
249214
|
},
|
|
@@ -249182,7 +249218,7 @@ const rule$L = createRule({
|
|
|
249182
249218
|
defaultOptions: [DEFAULT_OPTIONS],
|
|
249183
249219
|
docs: { description: ERROR_MESSAGE$2 },
|
|
249184
249220
|
fixable: 'code',
|
|
249185
|
-
messages: { [MESSAGE_ID$
|
|
249221
|
+
messages: { [MESSAGE_ID$e]: ERROR_MESSAGE$2 },
|
|
249186
249222
|
schema: [
|
|
249187
249223
|
{
|
|
249188
249224
|
additionalProperties: false,
|
|
@@ -249222,7 +249258,7 @@ const nearestFileUpCache = new Map();
|
|
|
249222
249258
|
const markerCache = new Map();
|
|
249223
249259
|
const indexFileCache = new Map();
|
|
249224
249260
|
const indexExportsCache = new Map();
|
|
249225
|
-
const rule$
|
|
249261
|
+
const rule$L = createRule({
|
|
249226
249262
|
create(context) {
|
|
249227
249263
|
const parserServices = dist$3.ESLintUtils.getParserServices(context);
|
|
249228
249264
|
const program = parserServices.program;
|
|
@@ -249416,13 +249452,13 @@ const noDuplicateAttributesRule = angular.templatePlugin.rules?.['no-duplicate-a
|
|
|
249416
249452
|
if (!noDuplicateAttributesRule) {
|
|
249417
249453
|
throw new Error('angular-eslint template rule "no-duplicate-attributes" is not available');
|
|
249418
249454
|
}
|
|
249419
|
-
const rule$
|
|
249455
|
+
const rule$K = createRule({
|
|
249420
249456
|
name: 'no-duplicate-attrs',
|
|
249421
249457
|
rule: noDuplicateAttributesRule,
|
|
249422
249458
|
});
|
|
249423
249459
|
|
|
249424
|
-
const MESSAGE_ID$
|
|
249425
|
-
const rule$
|
|
249460
|
+
const MESSAGE_ID$d = 'duplicateId';
|
|
249461
|
+
const rule$J = createRule({
|
|
249426
249462
|
name: 'no-duplicate-id',
|
|
249427
249463
|
rule: {
|
|
249428
249464
|
create(context) {
|
|
@@ -249445,7 +249481,7 @@ const rule$I = createRule({
|
|
|
249445
249481
|
context.report({
|
|
249446
249482
|
data: { id },
|
|
249447
249483
|
loc: sourceSpanToLoc(attr.sourceSpan),
|
|
249448
|
-
messageId: MESSAGE_ID$
|
|
249484
|
+
messageId: MESSAGE_ID$d,
|
|
249449
249485
|
});
|
|
249450
249486
|
}
|
|
249451
249487
|
}
|
|
@@ -249454,36 +249490,33 @@ const rule$I = createRule({
|
|
|
249454
249490
|
},
|
|
249455
249491
|
meta: {
|
|
249456
249492
|
docs: { description: 'Disallow duplicate static id attributes' },
|
|
249457
|
-
messages: { [MESSAGE_ID$
|
|
249493
|
+
messages: { [MESSAGE_ID$d]: "The id '{{id}}' is duplicated." },
|
|
249458
249494
|
schema: [],
|
|
249459
249495
|
type: 'problem',
|
|
249460
249496
|
},
|
|
249461
249497
|
},
|
|
249462
249498
|
});
|
|
249463
249499
|
|
|
249464
|
-
const MESSAGE_ID$
|
|
249465
|
-
function findAttr(node, attrName) {
|
|
249466
|
-
return node.attributes.find((attr) => attr.name === attrName);
|
|
249467
|
-
}
|
|
249500
|
+
const MESSAGE_ID$c = 'duplicateTag';
|
|
249468
249501
|
function getTrackingKey(node) {
|
|
249469
249502
|
if (node.name === 'title' || node.name === 'base') {
|
|
249470
249503
|
return node.name;
|
|
249471
249504
|
}
|
|
249472
249505
|
if (node.name === 'meta') {
|
|
249473
|
-
if (
|
|
249506
|
+
if (getStaticAttribute(node, 'charset')) {
|
|
249474
249507
|
return 'meta[charset]';
|
|
249475
249508
|
}
|
|
249476
|
-
if (
|
|
249509
|
+
if (getStaticAttribute(node, 'name')?.value === 'viewport') {
|
|
249477
249510
|
return 'meta[name=viewport]';
|
|
249478
249511
|
}
|
|
249479
249512
|
}
|
|
249480
249513
|
return node.name === 'link' &&
|
|
249481
|
-
|
|
249482
|
-
|
|
249514
|
+
getStaticAttribute(node, 'rel')?.value === 'canonical' &&
|
|
249515
|
+
getStaticAttribute(node, 'href')
|
|
249483
249516
|
? 'link[rel=canonical]'
|
|
249484
249517
|
: null;
|
|
249485
249518
|
}
|
|
249486
|
-
const rule$
|
|
249519
|
+
const rule$I = createRule({
|
|
249487
249520
|
name: 'no-duplicate-in-head',
|
|
249488
249521
|
rule: {
|
|
249489
249522
|
create(context) {
|
|
@@ -249520,7 +249553,7 @@ const rule$H = createRule({
|
|
|
249520
249553
|
context.report({
|
|
249521
249554
|
data: { tag },
|
|
249522
249555
|
loc: sourceSpanToLoc(duplicate.startSourceSpan),
|
|
249523
|
-
messageId: MESSAGE_ID$
|
|
249556
|
+
messageId: MESSAGE_ID$c,
|
|
249524
249557
|
});
|
|
249525
249558
|
}
|
|
249526
249559
|
}
|
|
@@ -249531,7 +249564,7 @@ const rule$H = createRule({
|
|
|
249531
249564
|
docs: {
|
|
249532
249565
|
description: 'Disallow duplicate title/base/meta/link tags inside head',
|
|
249533
249566
|
},
|
|
249534
|
-
messages: { [MESSAGE_ID$
|
|
249567
|
+
messages: { [MESSAGE_ID$c]: 'Duplicate <{{tag}}> tag in <head>.' },
|
|
249535
249568
|
schema: [],
|
|
249536
249569
|
type: 'problem',
|
|
249537
249570
|
},
|
|
@@ -249539,7 +249572,7 @@ const rule$H = createRule({
|
|
|
249539
249572
|
});
|
|
249540
249573
|
|
|
249541
249574
|
const COMPONENT_DECORATORS = new Set(['Component']);
|
|
249542
|
-
const rule$
|
|
249575
|
+
const rule$H = createRule({
|
|
249543
249576
|
create(context) {
|
|
249544
249577
|
const { sourceCode } = context;
|
|
249545
249578
|
return {
|
|
@@ -250187,7 +250220,7 @@ const ANGULAR_SIGNALS_UNTRACKED_GUIDE_URL = 'https://angular.dev/guide/signals#r
|
|
|
250187
250220
|
const ANGULAR_SIGNALS_ASYNC_GUIDE_URL = 'https://angular.dev/guide/signals#reactive-context-and-async-operations';
|
|
250188
250221
|
const createUntrackedRule = createRule;
|
|
250189
250222
|
|
|
250190
|
-
const rule$
|
|
250223
|
+
const rule$G = createUntrackedRule({
|
|
250191
250224
|
create(context) {
|
|
250192
250225
|
const { checker, esTreeNodeToTSNodeMap, program } = getTypeAwareRuleContext(context);
|
|
250193
250226
|
const signalNodeMap = esTreeNodeToTSNodeMap;
|
|
@@ -250225,7 +250258,7 @@ const rule$F = createUntrackedRule({
|
|
|
250225
250258
|
name: 'no-fully-untracked-effect',
|
|
250226
250259
|
});
|
|
250227
250260
|
|
|
250228
|
-
const MESSAGE_ID$
|
|
250261
|
+
const MESSAGE_ID$b = 'no-href-with-router-link';
|
|
250229
250262
|
const ERROR_MESSAGE$1 = 'Do not use href and routerLink attributes together on the same element';
|
|
250230
250263
|
const config$3 = {
|
|
250231
250264
|
create(context) {
|
|
@@ -250235,9 +250268,9 @@ const config$3 = {
|
|
|
250235
250268
|
if (node.name !== 'a') {
|
|
250236
250269
|
return;
|
|
250237
250270
|
}
|
|
250238
|
-
const hrefAttr = node
|
|
250239
|
-
const hasRouterLink =
|
|
250240
|
-
node
|
|
250271
|
+
const hrefAttr = getStaticAttribute(node, 'href');
|
|
250272
|
+
const hasRouterLink = Boolean(getStaticAttribute(node, 'routerlink')) ||
|
|
250273
|
+
hasInputBinding(node, 'routerlink');
|
|
250241
250274
|
if (!hrefAttr || !hasRouterLink) {
|
|
250242
250275
|
return;
|
|
250243
250276
|
}
|
|
@@ -250247,7 +250280,7 @@ const config$3 = {
|
|
|
250247
250280
|
hrefAttr.sourceSpan.end.offset,
|
|
250248
250281
|
]),
|
|
250249
250282
|
loc: sourceSpanToLoc(hrefAttr.sourceSpan),
|
|
250250
|
-
messageId: MESSAGE_ID$
|
|
250283
|
+
messageId: MESSAGE_ID$b,
|
|
250251
250284
|
});
|
|
250252
250285
|
},
|
|
250253
250286
|
};
|
|
@@ -250255,12 +250288,12 @@ const config$3 = {
|
|
|
250255
250288
|
meta: {
|
|
250256
250289
|
docs: { description: ERROR_MESSAGE$1 },
|
|
250257
250290
|
fixable: 'code',
|
|
250258
|
-
messages: { [MESSAGE_ID$
|
|
250291
|
+
messages: { [MESSAGE_ID$b]: ERROR_MESSAGE$1 },
|
|
250259
250292
|
schema: [],
|
|
250260
250293
|
type: 'problem',
|
|
250261
250294
|
},
|
|
250262
250295
|
};
|
|
250263
|
-
const rule$
|
|
250296
|
+
const rule$F = createRule({
|
|
250264
250297
|
name: 'no-href-with-router-link',
|
|
250265
250298
|
rule: config$3,
|
|
250266
250299
|
});
|
|
@@ -250321,7 +250354,7 @@ function getScopeRoot(node) {
|
|
|
250321
250354
|
return (findAncestor(node, (ancestor) => ancestor.type === dist$3.AST_NODE_TYPES.Program || isFunctionLike(ancestor)) ?? node);
|
|
250322
250355
|
}
|
|
250323
250356
|
|
|
250324
|
-
const rule$
|
|
250357
|
+
const rule$E = createRule({
|
|
250325
250358
|
create(context) {
|
|
250326
250359
|
const checkImplicitPublic = (node) => {
|
|
250327
250360
|
const classRef = getEnclosingClass(node);
|
|
@@ -250383,7 +250416,7 @@ const rule$D = createRule({
|
|
|
250383
250416
|
name: 'no-implicit-public',
|
|
250384
250417
|
});
|
|
250385
250418
|
|
|
250386
|
-
const rule$
|
|
250419
|
+
const rule$D = createRule({
|
|
250387
250420
|
create(context) {
|
|
250388
250421
|
const { sourceCode } = context;
|
|
250389
250422
|
return {
|
|
@@ -250439,7 +250472,7 @@ function isInfiniteLoopLiteral(node) {
|
|
|
250439
250472
|
function isInfiniteLoopTest(test) {
|
|
250440
250473
|
return test == null || isInfiniteLoopLiteral(test);
|
|
250441
250474
|
}
|
|
250442
|
-
const rule$
|
|
250475
|
+
const rule$C = createRule({
|
|
250443
250476
|
create(context) {
|
|
250444
250477
|
return {
|
|
250445
250478
|
DoWhileStatement(node) {
|
|
@@ -250484,7 +250517,7 @@ const rule$B = createRule({
|
|
|
250484
250517
|
});
|
|
250485
250518
|
|
|
250486
250519
|
const LEGACY_PEER_DEPS_PATTERN = /^legacy-peer-deps\s*=\s*true$/i;
|
|
250487
|
-
const rule$
|
|
250520
|
+
const rule$B = createRule({
|
|
250488
250521
|
create(context) {
|
|
250489
250522
|
return {
|
|
250490
250523
|
Program(node) {
|
|
@@ -250522,6 +250555,100 @@ const rule$A = createRule({
|
|
|
250522
250555
|
name: 'no-legacy-peer-deps',
|
|
250523
250556
|
});
|
|
250524
250557
|
|
|
250558
|
+
function isInteractiveElement(node) {
|
|
250559
|
+
const tagName = node.name.toLowerCase();
|
|
250560
|
+
if (hasElementAttribute(node, 'tabindex') || hasOutputBinding(node)) {
|
|
250561
|
+
return true;
|
|
250562
|
+
}
|
|
250563
|
+
switch (tagName) {
|
|
250564
|
+
case 'a':
|
|
250565
|
+
return hasElementAttribute(node, ['href', 'routerLink']);
|
|
250566
|
+
case 'area':
|
|
250567
|
+
return hasElementAttribute(node, 'href');
|
|
250568
|
+
case 'audio':
|
|
250569
|
+
return hasElementAttribute(node, 'controls');
|
|
250570
|
+
case 'button':
|
|
250571
|
+
return true;
|
|
250572
|
+
case 'details':
|
|
250573
|
+
return true;
|
|
250574
|
+
case 'embed':
|
|
250575
|
+
return true;
|
|
250576
|
+
case 'iframe':
|
|
250577
|
+
return true;
|
|
250578
|
+
case 'img':
|
|
250579
|
+
return hasElementAttribute(node, 'usemap');
|
|
250580
|
+
case 'input':
|
|
250581
|
+
return (getStaticAttributeValue(node, 'type')?.trim().toLowerCase() !== 'hidden');
|
|
250582
|
+
case 'label':
|
|
250583
|
+
return true;
|
|
250584
|
+
case 'select':
|
|
250585
|
+
return true;
|
|
250586
|
+
case 'summary':
|
|
250587
|
+
return true;
|
|
250588
|
+
case 'textarea':
|
|
250589
|
+
return true;
|
|
250590
|
+
case 'video':
|
|
250591
|
+
return hasElementAttribute(node, 'controls');
|
|
250592
|
+
default:
|
|
250593
|
+
return false;
|
|
250594
|
+
}
|
|
250595
|
+
}
|
|
250596
|
+
|
|
250597
|
+
const MESSAGE_ID$a = 'noNestedInteractive';
|
|
250598
|
+
function getAvailableLabelParent(stack, node, labelsWithControl) {
|
|
250599
|
+
const parent = stack[stack.length - 1];
|
|
250600
|
+
return stack.length === 1 &&
|
|
250601
|
+
parent?.name.toLowerCase() === 'label' &&
|
|
250602
|
+
node.name.toLowerCase() !== 'label' &&
|
|
250603
|
+
!labelsWithControl.has(parent)
|
|
250604
|
+
? parent
|
|
250605
|
+
: null;
|
|
250606
|
+
}
|
|
250607
|
+
const rule$A = createRule({
|
|
250608
|
+
name: 'no-nested-interactive',
|
|
250609
|
+
rule: {
|
|
250610
|
+
create(context) {
|
|
250611
|
+
const interactiveStack = [];
|
|
250612
|
+
const labelsWithControl = new WeakSet();
|
|
250613
|
+
return {
|
|
250614
|
+
Element(rawNode) {
|
|
250615
|
+
const node = rawNode;
|
|
250616
|
+
if (!isInteractiveElement(node)) {
|
|
250617
|
+
return;
|
|
250618
|
+
}
|
|
250619
|
+
const parent = interactiveStack[interactiveStack.length - 1];
|
|
250620
|
+
const availableLabelParent = getAvailableLabelParent(interactiveStack, node, labelsWithControl);
|
|
250621
|
+
if (availableLabelParent) {
|
|
250622
|
+
labelsWithControl.add(availableLabelParent);
|
|
250623
|
+
}
|
|
250624
|
+
else if (parent) {
|
|
250625
|
+
context.report({
|
|
250626
|
+
data: { tag: parent.name },
|
|
250627
|
+
loc: sourceSpanToLoc(node.startSourceSpan),
|
|
250628
|
+
messageId: MESSAGE_ID$a,
|
|
250629
|
+
});
|
|
250630
|
+
}
|
|
250631
|
+
interactiveStack.push(node);
|
|
250632
|
+
},
|
|
250633
|
+
'Element:exit'(rawNode) {
|
|
250634
|
+
const node = rawNode;
|
|
250635
|
+
if (interactiveStack[interactiveStack.length - 1] === node) {
|
|
250636
|
+
interactiveStack.pop();
|
|
250637
|
+
}
|
|
250638
|
+
},
|
|
250639
|
+
};
|
|
250640
|
+
},
|
|
250641
|
+
meta: {
|
|
250642
|
+
docs: { description: 'Disallow nested interactive elements' },
|
|
250643
|
+
messages: {
|
|
250644
|
+
[MESSAGE_ID$a]: 'Unexpected interactive element nested inside interactive <{{tag}}>.',
|
|
250645
|
+
},
|
|
250646
|
+
schema: [],
|
|
250647
|
+
type: 'problem',
|
|
250648
|
+
},
|
|
250649
|
+
},
|
|
250650
|
+
});
|
|
250651
|
+
|
|
250525
250652
|
const OBSOLETE_HTML_ATTRS = {
|
|
250526
250653
|
abbr: [
|
|
250527
250654
|
{
|
|
@@ -254048,10 +254175,6 @@ const rule$e = createRule({
|
|
|
254048
254175
|
});
|
|
254049
254176
|
|
|
254050
254177
|
const MESSAGE_ID$5 = 'missingAlt';
|
|
254051
|
-
function hasAlt(node) {
|
|
254052
|
-
return (node.attributes.some((attr) => attr.name === 'alt') ||
|
|
254053
|
-
node.inputs.some((input) => input.name === 'alt' || input.keySpan.details === 'attr.alt'));
|
|
254054
|
-
}
|
|
254055
254178
|
const rule$d = createRule({
|
|
254056
254179
|
name: 'require-img-alt',
|
|
254057
254180
|
rule: {
|
|
@@ -254059,7 +254182,7 @@ const rule$d = createRule({
|
|
|
254059
254182
|
return {
|
|
254060
254183
|
Element(rawNode) {
|
|
254061
254184
|
const node = rawNode;
|
|
254062
|
-
if (node.name !== 'img' ||
|
|
254185
|
+
if (node.name !== 'img' || hasElementAttribute(node, 'alt')) {
|
|
254063
254186
|
return;
|
|
254064
254187
|
}
|
|
254065
254188
|
context.report({
|
|
@@ -254092,16 +254215,14 @@ const rule$c = createRule({
|
|
|
254092
254215
|
if (node.name !== 'html') {
|
|
254093
254216
|
return;
|
|
254094
254217
|
}
|
|
254095
|
-
|
|
254096
|
-
const hasBoundLang = node.inputs.some((input) => input.name === 'lang' ||
|
|
254097
|
-
input.keySpan.details === 'attr.lang');
|
|
254098
|
-
if (!langAttr && !hasBoundLang) {
|
|
254218
|
+
if (!hasElementAttribute(node, 'lang')) {
|
|
254099
254219
|
context.report({
|
|
254100
254220
|
loc: sourceSpanToLoc(node.startSourceSpan),
|
|
254101
254221
|
messageId: MESSAGE_IDS$1.MISSING,
|
|
254102
254222
|
});
|
|
254103
254223
|
return;
|
|
254104
254224
|
}
|
|
254225
|
+
const langAttr = getStaticAttribute(node, 'lang');
|
|
254105
254226
|
if (langAttr?.value.trim().length === 0) {
|
|
254106
254227
|
context.report({
|
|
254107
254228
|
loc: sourceSpanToLoc(langAttr.sourceSpan),
|
|
@@ -255707,28 +255828,29 @@ const plugin = {
|
|
|
255707
255828
|
},
|
|
255708
255829
|
rules: {
|
|
255709
255830
|
'array-as-const': rule$5,
|
|
255710
|
-
'attrs-newline': rule$
|
|
255831
|
+
'attrs-newline': rule$U,
|
|
255711
255832
|
'class-property-naming': rule$4,
|
|
255712
|
-
'decorator-key-sort': rule$
|
|
255713
|
-
'element-newline': rule$
|
|
255833
|
+
'decorator-key-sort': rule$T,
|
|
255834
|
+
'element-newline': rule$S,
|
|
255714
255835
|
'flat-exports': rule$3,
|
|
255715
|
-
'host-attributes-sort': rule$
|
|
255716
|
-
'html-logical-properties': rule$
|
|
255717
|
-
'import-integrity': rule$
|
|
255718
|
-
'injection-token-description': rule$
|
|
255719
|
-
'no-commonjs-import-patterns': rule$
|
|
255720
|
-
'no-deep-imports': rule$
|
|
255721
|
-
'no-deep-imports-to-indexed-packages': rule$
|
|
255722
|
-
'no-duplicate-attrs': rule$
|
|
255723
|
-
'no-duplicate-id': rule$
|
|
255724
|
-
'no-duplicate-in-head': rule$
|
|
255725
|
-
'no-empty-style-metadata': rule$
|
|
255726
|
-
'no-fully-untracked-effect': rule$
|
|
255727
|
-
'no-href-with-router-link': rule$
|
|
255728
|
-
'no-implicit-public': rule$
|
|
255729
|
-
'no-import-assertions': rule$
|
|
255730
|
-
'no-infinite-loop': rule$
|
|
255731
|
-
'no-legacy-peer-deps': rule$
|
|
255836
|
+
'host-attributes-sort': rule$R,
|
|
255837
|
+
'html-logical-properties': rule$Q,
|
|
255838
|
+
'import-integrity': rule$P,
|
|
255839
|
+
'injection-token-description': rule$O,
|
|
255840
|
+
'no-commonjs-import-patterns': rule$N,
|
|
255841
|
+
'no-deep-imports': rule$M,
|
|
255842
|
+
'no-deep-imports-to-indexed-packages': rule$L,
|
|
255843
|
+
'no-duplicate-attrs': rule$K,
|
|
255844
|
+
'no-duplicate-id': rule$J,
|
|
255845
|
+
'no-duplicate-in-head': rule$I,
|
|
255846
|
+
'no-empty-style-metadata': rule$H,
|
|
255847
|
+
'no-fully-untracked-effect': rule$G,
|
|
255848
|
+
'no-href-with-router-link': rule$F,
|
|
255849
|
+
'no-implicit-public': rule$E,
|
|
255850
|
+
'no-import-assertions': rule$D,
|
|
255851
|
+
'no-infinite-loop': rule$C,
|
|
255852
|
+
'no-legacy-peer-deps': rule$B,
|
|
255853
|
+
'no-nested-interactive': rule$A,
|
|
255732
255854
|
'no-obsolete-attrs': rule$z,
|
|
255733
255855
|
'no-obsolete-tags': rule$y,
|
|
255734
255856
|
'no-playwright-empty-fill': rule$x,
|
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taiga-ui/eslint-plugin-experience-next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.514.0",
|
|
4
4
|
"description": "An ESLint plugin to enforce a consistent code styles across taiga-ui projects",
|
|
5
|
+
"homepage": "https://github.com/taiga-family/toolkit#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/taiga-family/toolkit/issues"
|
|
8
|
+
},
|
|
5
9
|
"repository": {
|
|
6
10
|
"type": "git",
|
|
7
11
|
"url": "https://github.com/taiga-family/toolkit.git"
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { type ParseSourceSpan, type TmplAstBoundAttribute, TmplAstBoundEvent, type TmplAstElement, type TmplAstReference, type TmplAstTextAttribute } from '@angular-eslint/bundled-angular-compiler';
|
|
2
2
|
export type ElementAttributeLike = TmplAstBoundAttribute | TmplAstBoundEvent | TmplAstReference | TmplAstTextAttribute;
|
|
3
|
+
export type ElementAttributeName = string | readonly string[];
|
|
3
4
|
export declare function getAttributeValueSpan(attr: ElementAttributeLike): ParseSourceSpan | undefined;
|
|
5
|
+
export declare function getStaticAttribute(element: TmplAstElement, name: string): TmplAstTextAttribute | undefined;
|
|
6
|
+
export declare function getStaticAttributeValue(element: TmplAstElement, name: string): string | undefined;
|
|
7
|
+
export declare function hasInputBinding(element: TmplAstElement, name: ElementAttributeName): boolean;
|
|
8
|
+
export declare function hasAttributeBinding(element: TmplAstElement, name: ElementAttributeName): boolean;
|
|
9
|
+
export declare function hasElementAttribute(element: TmplAstElement, name: ElementAttributeName): boolean;
|
|
10
|
+
export declare function hasOutputBinding(element: TmplAstElement, name?: ElementAttributeName): boolean;
|
|
4
11
|
export declare function getElementAttributeLikes(element: TmplAstElement): ElementAttributeLike[];
|