linter-bundle 7.12.0 → 7.12.1

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/CHANGELOG.md CHANGED
@@ -6,7 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.12.0...HEAD)
9
+ [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.12.1...HEAD)
10
+
11
+ ## [7.12.1] - 2026-02-21
12
+
13
+ ### Fixed
14
+
15
+ - [stylelint] Fix stylistic plugins crashing with `TypeError: selector.startsWith is not a function` due to `parseSelector` API change in stylelint 17 (callback parameter removed, now returns AST instead of string)
16
+
17
+ [Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v7.12.0...v7.12.1)
10
18
 
11
19
  ## [7.12.0] - 2026-02-20
12
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linter-bundle",
3
- "version": "7.12.0",
3
+ "version": "7.12.1",
4
4
  "type": "module",
5
5
  "description": "Ready-to use bundle of linting tools, containing configurations for ESLint, stylelint and markdownlint.",
6
6
  "keywords": [
@@ -47,88 +47,92 @@ const rule = (primary, _secondaryOptions) => {
47
47
  const selector = ruleNode.raws.selector ? ruleNode.raws.selector.raw : ruleNode.selector;
48
48
 
49
49
  let hasFixed;
50
- const fixedSelector = parseSelector(selector, result, ruleNode, (selectorTree) => {
51
- selectorTree.walkAttributes((attributeNode) => {
52
- const attributeSelectorString = attributeNode.toString();
53
-
54
- styleSearch({ source: attributeSelectorString, target: '[' }, (match) => {
55
- const nextCharIsSpace = attributeSelectorString[match.startIndex + 1] === ' ';
56
- const index = attributeNode.sourceIndex + match.startIndex + 1;
57
-
58
- if (nextCharIsSpace && primary === 'never') {
59
- report({
60
- message: messages.rejectedOpening,
61
- index,
62
- endIndex: index,
63
- result,
64
- ruleName,
65
- node: ruleNode,
66
- fix: () => {
67
- hasFixed = true;
68
- fixBefore(attributeNode);
69
- }
70
- });
71
- }
72
-
73
- if (!nextCharIsSpace && primary === 'always') {
74
- report({
75
- message: messages.expectedOpening,
76
- index,
77
- endIndex: index,
78
- result,
79
- ruleName,
80
- node: ruleNode,
81
- fix: () => {
82
- hasFixed = true;
83
- fixBefore(attributeNode);
84
- }
85
- });
86
- }
87
- });
88
-
89
- styleSearch({ source: attributeSelectorString, target: ']' }, (match) => {
90
- const previousCharIsSpace = attributeSelectorString[match.startIndex - 1] === ' ';
91
- const index = attributeNode.sourceIndex + match.startIndex - 1;
92
-
93
- if (previousCharIsSpace && primary === 'never') {
94
- report({
95
- message: messages.rejectedClosing,
96
- index,
97
- endIndex: index,
98
- result,
99
- ruleName,
100
- node: ruleNode,
101
- fix: () => {
102
- hasFixed = true;
103
- fixAfter(attributeNode);
104
- }
105
- });
106
- }
107
-
108
- if (!previousCharIsSpace && primary === 'always') {
109
- report({
110
- message: messages.expectedClosing,
111
- index,
112
- endIndex: index,
113
- result,
114
- ruleName,
115
- node: ruleNode,
116
- fix: () => {
117
- hasFixed = true;
118
- fixAfter(attributeNode);
119
- }
120
- });
121
- }
122
- });
50
+ const selectorTree = parseSelector(selector, result, ruleNode);
51
+
52
+ if (!selectorTree) {
53
+ return;
54
+ }
55
+
56
+ selectorTree.walkAttributes((attributeNode) => {
57
+ const attributeSelectorString = attributeNode.toString();
58
+
59
+ styleSearch({ source: attributeSelectorString, target: '[' }, (match) => {
60
+ const nextCharIsSpace = attributeSelectorString[match.startIndex + 1] === ' ';
61
+ const index = attributeNode.sourceIndex + match.startIndex + 1;
62
+
63
+ if (nextCharIsSpace && primary === 'never') {
64
+ report({
65
+ message: messages.rejectedOpening,
66
+ index,
67
+ endIndex: index,
68
+ result,
69
+ ruleName,
70
+ node: ruleNode,
71
+ fix: () => {
72
+ hasFixed = true;
73
+ fixBefore(attributeNode);
74
+ }
75
+ });
76
+ }
77
+
78
+ if (!nextCharIsSpace && primary === 'always') {
79
+ report({
80
+ message: messages.expectedOpening,
81
+ index,
82
+ endIndex: index,
83
+ result,
84
+ ruleName,
85
+ node: ruleNode,
86
+ fix: () => {
87
+ hasFixed = true;
88
+ fixBefore(attributeNode);
89
+ }
90
+ });
91
+ }
92
+ });
93
+
94
+ styleSearch({ source: attributeSelectorString, target: ']' }, (match) => {
95
+ const previousCharIsSpace = attributeSelectorString[match.startIndex - 1] === ' ';
96
+ const index = attributeNode.sourceIndex + match.startIndex - 1;
97
+
98
+ if (previousCharIsSpace && primary === 'never') {
99
+ report({
100
+ message: messages.rejectedClosing,
101
+ index,
102
+ endIndex: index,
103
+ result,
104
+ ruleName,
105
+ node: ruleNode,
106
+ fix: () => {
107
+ hasFixed = true;
108
+ fixAfter(attributeNode);
109
+ }
110
+ });
111
+ }
112
+
113
+ if (!previousCharIsSpace && primary === 'always') {
114
+ report({
115
+ message: messages.expectedClosing,
116
+ index,
117
+ endIndex: index,
118
+ result,
119
+ ruleName,
120
+ node: ruleNode,
121
+ fix: () => {
122
+ hasFixed = true;
123
+ fixAfter(attributeNode);
124
+ }
125
+ });
126
+ }
123
127
  });
124
128
  });
125
129
 
126
- if (hasFixed && fixedSelector) {
130
+ if (hasFixed) {
127
131
  if (!ruleNode.raws.selector) {
128
- ruleNode.selector = fixedSelector;
132
+ ruleNode.selector = selectorTree.toString();
129
133
  }
130
134
  else {
131
- ruleNode.raws.selector.raw = fixedSelector;
135
+ ruleNode.raws.selector.raw = selectorTree.toString();
132
136
  }
133
137
  }
134
138
  });
@@ -40,47 +40,51 @@ const rule = (primary, _secondaryOptions) => (root, result) => {
40
40
  // @todo re-enable when parser and stylelint are compatible
41
41
  if (selector.includes('/*')) { return; }
42
42
 
43
- const fixedSelector = parseSelector(selector, result, ruleNode, (fullSelector) => {
44
- fullSelector.walkCombinators((combinatorNode) => {
45
- if (combinatorNode.value !== ' ') {
46
- return;
47
- }
48
-
49
- const value = combinatorNode.toString();
50
-
51
- if (
52
- value.includes(' ') ||
53
- value.includes('\t') ||
54
- value.includes('\n') ||
55
- value.includes('\r')
56
- ) {
57
- report({
58
- result,
59
- ruleName,
60
- message: messages.rejected(value),
61
- node: ruleNode,
62
- index: combinatorNode.sourceIndex,
63
- endIndex: combinatorNode.sourceIndex,
64
- fix: ((/^\s+$/u).test(value) ? () => {
65
- hasFixed = true;
66
-
67
- if (!combinatorNode.raws) { combinatorNode.raws = {}; }
68
-
69
- combinatorNode.raws.value = ' ';
70
- combinatorNode.rawSpaceBefore = combinatorNode.rawSpaceBefore.replace(/^\s+/u, '');
71
- combinatorNode.rawSpaceAfter = combinatorNode.rawSpaceAfter.replace(/\s+$/u, '');
72
- } : undefined)
73
- });
74
- }
75
- });
43
+ const selectorTree = parseSelector(selector, result, ruleNode);
44
+
45
+ if (!selectorTree) {
46
+ return;
47
+ }
48
+
49
+ selectorTree.walkCombinators((combinatorNode) => {
50
+ if (combinatorNode.value !== ' ') {
51
+ return;
52
+ }
53
+
54
+ const value = combinatorNode.toString();
55
+
56
+ if (
57
+ value.includes(' ') ||
58
+ value.includes('\t') ||
59
+ value.includes('\n') ||
60
+ value.includes('\r')
61
+ ) {
62
+ report({
63
+ result,
64
+ ruleName,
65
+ message: messages.rejected(value),
66
+ node: ruleNode,
67
+ index: combinatorNode.sourceIndex,
68
+ endIndex: combinatorNode.sourceIndex,
69
+ fix: ((/^\s+$/u).test(value) ? () => {
70
+ hasFixed = true;
71
+
72
+ if (!combinatorNode.raws) { combinatorNode.raws = {}; }
73
+
74
+ combinatorNode.raws.value = ' ';
75
+ combinatorNode.rawSpaceBefore = combinatorNode.rawSpaceBefore.replace(/^\s+/u, '');
76
+ combinatorNode.rawSpaceAfter = combinatorNode.rawSpaceAfter.replace(/\s+$/u, '');
77
+ } : undefined)
78
+ });
79
+ }
76
80
  });
77
81
 
78
- if (hasFixed && fixedSelector) {
82
+ if (hasFixed) {
79
83
  if (!ruleNode.raws.selector) {
80
- ruleNode.selector = fixedSelector;
84
+ ruleNode.selector = selectorTree.toString();
81
85
  }
82
86
  else {
83
- ruleNode.raws.selector.raw = fixedSelector;
87
+ ruleNode.raws.selector.raw = selectorTree.toString();
84
88
  }
85
89
  }
86
90
  });
@@ -44,54 +44,57 @@ const rule = (primary, _secondaryOptions) => (root, result) => {
44
44
  }
45
45
 
46
46
  let hasFixed = false;
47
- const fixedSelector = parseSelector(
47
+ const selectorTree = parseSelector(
48
48
  ruleNode.raws.selector ? ruleNode.raws.selector.raw : ruleNode.selector,
49
49
  result,
50
- ruleNode,
51
- (selectorTree) => {
52
- selectorTree.walkPseudos((pseudoNode) => {
53
- const pseudo = pseudoNode.value;
54
-
55
- if (!isStandardSyntaxSelector(pseudo)) {
56
- return;
57
- }
58
-
59
- if (
60
- pseudo.includes('::') ||
61
- levelOneAndTwoPseudoElements.has(pseudo.toLowerCase().slice(1))
62
- ) {
63
- return;
64
- }
65
-
66
- const expectedPseudo =
67
- primary === 'lower' ? pseudo.toLowerCase() : pseudo.toUpperCase();
68
-
69
- if (pseudo === expectedPseudo) {
70
- return;
71
- }
72
-
73
- report({
74
- message: messages.expected(pseudo, expectedPseudo),
75
- node: ruleNode,
76
- index: pseudoNode.sourceIndex,
77
- endIndex: pseudoNode.sourceIndex,
78
- ruleName,
79
- result,
80
- fix: () => {
81
- hasFixed = true;
82
- pseudoNode.value = expectedPseudo;
83
- }
84
- });
85
- });
86
- }
50
+ ruleNode
87
51
  );
88
52
 
89
- if (fixedSelector) {
53
+ if (!selectorTree) {
54
+ return;
55
+ }
56
+
57
+ selectorTree.walkPseudos((pseudoNode) => {
58
+ const pseudo = pseudoNode.value;
59
+
60
+ if (!isStandardSyntaxSelector(pseudo)) {
61
+ return;
62
+ }
63
+
64
+ if (
65
+ pseudo.includes('::') ||
66
+ levelOneAndTwoPseudoElements.has(pseudo.toLowerCase().slice(1))
67
+ ) {
68
+ return;
69
+ }
70
+
71
+ const expectedPseudo =
72
+ primary === 'lower' ? pseudo.toLowerCase() : pseudo.toUpperCase();
73
+
74
+ if (pseudo === expectedPseudo) {
75
+ return;
76
+ }
77
+
78
+ report({
79
+ message: messages.expected(pseudo, expectedPseudo),
80
+ node: ruleNode,
81
+ index: pseudoNode.sourceIndex,
82
+ endIndex: pseudoNode.sourceIndex,
83
+ ruleName,
84
+ result,
85
+ fix: () => {
86
+ hasFixed = true;
87
+ pseudoNode.value = expectedPseudo;
88
+ }
89
+ });
90
+ });
91
+
92
+ if (hasFixed) {
90
93
  if (ruleNode.raws.selector) {
91
- ruleNode.raws.selector.raw = fixedSelector;
94
+ ruleNode.raws.selector.raw = selectorTree.toString();
92
95
  }
93
96
  else {
94
- ruleNode.selector = fixedSelector;
97
+ ruleNode.selector = selectorTree.toString();
95
98
  }
96
99
  }
97
100
  });
@@ -43,87 +43,91 @@ const rule = (primary, _secondaryOptions) => (root, result) => {
43
43
 
44
44
  let hasFixed = false;
45
45
  const selector = ruleNode.raws.selector ? ruleNode.raws.selector.raw : ruleNode.selector;
46
- const fixedSelector = parseSelector(selector, result, ruleNode, (selectorTree) => {
47
- selectorTree.walkPseudos((pseudoNode) => {
48
- if (pseudoNode.length === 0) {
49
- return;
50
- }
51
-
52
- const paramString = pseudoNode.map((node) => String(node)).join(',');
53
- const nextCharIsSpace = paramString.startsWith(' ');
54
- const openIndex = pseudoNode.sourceIndex + pseudoNode.value.length + 1;
55
-
56
- if (nextCharIsSpace && primary === 'never') {
57
- report({
58
- message: messages.rejectedOpening,
59
- index: openIndex,
60
- endIndex: openIndex,
61
- result,
62
- ruleName,
63
- node: ruleNode,
64
- fix: () => {
65
- hasFixed = true;
66
- setFirstNodeSpaceBefore(pseudoNode, '');
67
- }
68
- });
69
- }
70
-
71
- if (!nextCharIsSpace && primary === 'always') {
72
- report({
73
- message: messages.expectedOpening,
74
- index: openIndex,
75
- endIndex: openIndex,
76
- result,
77
- ruleName,
78
- node: ruleNode,
79
- fix: () => {
80
- hasFixed = true;
81
- setFirstNodeSpaceBefore(pseudoNode, ' ');
82
- }
83
- });
84
- }
85
-
86
- const previousCharIsSpace = paramString.endsWith(' ');
87
- const closeIndex = openIndex + paramString.length - 1;
88
-
89
- if (previousCharIsSpace && primary === 'never') {
90
- report({
91
- message: messages.rejectedClosing,
92
- index: closeIndex,
93
- endIndex: closeIndex,
94
- result,
95
- ruleName,
96
- node: ruleNode,
97
- fix: () => {
98
- hasFixed = true;
99
- setLastNodeSpaceAfter(pseudoNode, '');
100
- }
101
- });
102
- }
103
-
104
- if (!previousCharIsSpace && primary === 'always') {
105
- report({
106
- message: messages.expectedClosing,
107
- index: closeIndex,
108
- endIndex: closeIndex,
109
- result,
110
- ruleName,
111
- node: ruleNode,
112
- fix: () => {
113
- hasFixed = true;
114
- setLastNodeSpaceAfter(pseudoNode, ' ');
115
- }
116
- });
117
- }
118
- });
46
+ const selectorTree = parseSelector(selector, result, ruleNode);
47
+
48
+ if (!selectorTree) {
49
+ return;
50
+ }
51
+
52
+ selectorTree.walkPseudos((pseudoNode) => {
53
+ if (pseudoNode.length === 0) {
54
+ return;
55
+ }
56
+
57
+ const paramString = pseudoNode.map((node) => String(node)).join(',');
58
+ const nextCharIsSpace = paramString.startsWith(' ');
59
+ const openIndex = pseudoNode.sourceIndex + pseudoNode.value.length + 1;
60
+
61
+ if (nextCharIsSpace && primary === 'never') {
62
+ report({
63
+ message: messages.rejectedOpening,
64
+ index: openIndex,
65
+ endIndex: openIndex,
66
+ result,
67
+ ruleName,
68
+ node: ruleNode,
69
+ fix: () => {
70
+ hasFixed = true;
71
+ setFirstNodeSpaceBefore(pseudoNode, '');
72
+ }
73
+ });
74
+ }
75
+
76
+ if (!nextCharIsSpace && primary === 'always') {
77
+ report({
78
+ message: messages.expectedOpening,
79
+ index: openIndex,
80
+ endIndex: openIndex,
81
+ result,
82
+ ruleName,
83
+ node: ruleNode,
84
+ fix: () => {
85
+ hasFixed = true;
86
+ setFirstNodeSpaceBefore(pseudoNode, ' ');
87
+ }
88
+ });
89
+ }
90
+
91
+ const previousCharIsSpace = paramString.endsWith(' ');
92
+ const closeIndex = openIndex + paramString.length - 1;
93
+
94
+ if (previousCharIsSpace && primary === 'never') {
95
+ report({
96
+ message: messages.rejectedClosing,
97
+ index: closeIndex,
98
+ endIndex: closeIndex,
99
+ result,
100
+ ruleName,
101
+ node: ruleNode,
102
+ fix: () => {
103
+ hasFixed = true;
104
+ setLastNodeSpaceAfter(pseudoNode, '');
105
+ }
106
+ });
107
+ }
108
+
109
+ if (!previousCharIsSpace && primary === 'always') {
110
+ report({
111
+ message: messages.expectedClosing,
112
+ index: closeIndex,
113
+ endIndex: closeIndex,
114
+ result,
115
+ ruleName,
116
+ node: ruleNode,
117
+ fix: () => {
118
+ hasFixed = true;
119
+ setLastNodeSpaceAfter(pseudoNode, ' ');
120
+ }
121
+ });
122
+ }
119
123
  });
120
124
 
121
- if (hasFixed && fixedSelector) {
125
+ if (hasFixed) {
122
126
  if (!ruleNode.raws.selector) {
123
- ruleNode.selector = fixedSelector;
127
+ ruleNode.selector = selectorTree.toString();
124
128
  }
125
129
  else {
126
- ruleNode.raws.selector.raw = fixedSelector;
130
+ ruleNode.raws.selector.raw = selectorTree.toString();
127
131
  }
128
132
  }
129
133
  });
@@ -30,30 +30,34 @@ export default function selectorAttributeOperatorSpaceChecker (options) {
30
30
  let hasFixed = false;
31
31
  const selector = rule.raws.selector ? rule.raws.selector.raw : rule.selector;
32
32
 
33
- const fixedSelector = parseSelector(selector, options.result, rule, (selectorTree) => {
34
- selectorTree.walkAttributes((attributeNode) => {
35
- const operator = attributeNode.operator;
33
+ const selectorTree = parseSelector(selector, options.result, rule);
36
34
 
37
- if (!operator) {
38
- return;
39
- }
35
+ if (!selectorTree) {
36
+ return;
37
+ }
38
+
39
+ selectorTree.walkAttributes((attributeNode) => {
40
+ const operator = attributeNode.operator;
41
+
42
+ if (!operator) {
43
+ return;
44
+ }
40
45
 
41
- const attributeNodeString = attributeNode.toString();
46
+ const attributeNodeString = attributeNode.toString();
42
47
 
43
- styleSearch({ source: attributeNodeString, target: operator }, (match) => {
44
- const index = options.checkBeforeOperator ? match.startIndex : match.endIndex - 1;
48
+ styleSearch({ source: attributeNodeString, target: operator }, (match) => {
49
+ const index = options.checkBeforeOperator ? match.startIndex : match.endIndex - 1;
45
50
 
46
- checkOperator(attributeNodeString, index, rule, attributeNode, operator);
47
- });
51
+ checkOperator(attributeNodeString, index, rule, attributeNode, operator);
48
52
  });
49
53
  });
50
54
 
51
- if (hasFixed && fixedSelector) {
55
+ if (hasFixed) {
52
56
  if (!rule.raws.selector) {
53
- rule.selector = fixedSelector;
57
+ rule.selector = selectorTree.toString();
54
58
  }
55
59
  else {
56
- rule.raws.selector.raw = fixedSelector;
60
+ rule.raws.selector.raw = selectorTree.toString();
57
61
  }
58
62
  }
59
63
 
@@ -28,47 +28,51 @@ export default function selectorCombinatorSpaceChecker (options) {
28
28
  hasFixed = false;
29
29
  const selector = rule.raws.selector ? rule.raws.selector.raw : rule.selector;
30
30
 
31
- const fixedSelector = parseSelector(selector, options.result, rule, (selectorTree) => {
32
- selectorTree.walkCombinators((node) => {
33
- // Ignore non-standard combinators
34
- if (!isStandardSyntaxCombinator(node)) {
35
- return;
36
- }
31
+ const selectorTree = parseSelector(selector, options.result, rule);
37
32
 
38
- // Ignore spaced descendant combinator
39
- if ((/\s/u).test(node.value)) {
40
- return;
41
- }
33
+ if (!selectorTree) {
34
+ return;
35
+ }
36
+
37
+ selectorTree.walkCombinators((node) => {
38
+ // Ignore non-standard combinators
39
+ if (!isStandardSyntaxCombinator(node)) {
40
+ return;
41
+ }
42
42
 
43
- // Check the exist of node in prev of the combinator.
44
- // in case some that aren't the first begin with combinators (nesting syntax)
45
- if (options.locationType === 'before' && !node.prev()) {
46
- return;
47
- }
43
+ // Ignore spaced descendant combinator
44
+ if ((/\s/u).test(node.value)) {
45
+ return;
46
+ }
47
+
48
+ // Check the exist of node in prev of the combinator.
49
+ // in case some that aren't the first begin with combinators (nesting syntax)
50
+ if (options.locationType === 'before' && !node.prev()) {
51
+ return;
52
+ }
48
53
 
49
- const parentParentNode = node.parent?.parent;
54
+ const parentParentNode = node.parent?.parent;
50
55
 
51
- // Ignore pseudo-classes selector like `.foo:nth-child(2n + 1) {}`
52
- if (parentParentNode && parentParentNode.type === 'pseudo') {
53
- return;
54
- }
56
+ // Ignore pseudo-classes selector like `.foo:nth-child(2n + 1) {}`
57
+ if (parentParentNode && parentParentNode.type === 'pseudo') {
58
+ return;
59
+ }
55
60
 
56
- const sourceIndex = node.sourceIndex;
57
- const index =
58
- node.value.length > 1 && options.locationType === 'before' ?
59
- sourceIndex
60
- : sourceIndex + node.value.length - 1;
61
+ const sourceIndex = node.sourceIndex;
62
+ const index =
63
+ node.value.length > 1 && options.locationType === 'before' ?
64
+ sourceIndex
65
+ : sourceIndex + node.value.length - 1;
61
66
 
62
- check(selector, node, index, rule, sourceIndex);
63
- });
67
+ check(selector, node, index, rule, sourceIndex);
64
68
  });
65
69
 
66
- if (hasFixed && fixedSelector) {
70
+ if (hasFixed) {
67
71
  if (!rule.raws.selector) {
68
- rule.selector = fixedSelector;
72
+ rule.selector = selectorTree.toString();
69
73
  }
70
74
  else {
71
- rule.raws.selector.raw = fixedSelector;
75
+ rule.raws.selector.raw = selectorTree.toString();
72
76
  }
73
77
  }
74
78
  });
@@ -86,7 +86,9 @@ const rule = (primary, secondaryOptions) => {
86
86
  /** @type {number[]} */
87
87
  const fixPositions = [];
88
88
 
89
- parseSelector(ruleNode.selector, result, ruleNode, (selectorTree) => {
89
+ const selectorTree = parseSelector(ruleNode.selector, result, ruleNode);
90
+
91
+ if (selectorTree) {
90
92
  let selectorFixed = false;
91
93
 
92
94
  selectorTree.walkAttributes((attributeNode) => {
@@ -165,7 +167,7 @@ const rule = (primary, secondaryOptions) => {
165
167
  if (selectorFixed) {
166
168
  ruleNode.selector = selectorTree.toString();
167
169
  }
168
- });
170
+ }
169
171
 
170
172
  for (const fixIndex of fixPositions) {
171
173
  ruleNode.selector = replaceQuote(ruleNode.selector, fixIndex, correctQuote);