@silvestv/migration-planificator 6.0.2 → 6.0.4
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/dist/src/core/ast/matchers/index.js +35 -1
- package/dist/src/core/ast/matchers/ts/host-binding-property-matcher.js +189 -31
- package/dist/src/core/ast/matchers/ts/host-binding-type-error-matcher.js +297 -0
- package/dist/src/core/ast/matchers/ts/host-binding-type-helpers.js +260 -0
- package/dist/src/core/ast/matchers/utils/matcher-helpers.js +8 -2
- package/dist/src/core/ast/scanner-ast.js +8 -4
- package/dist/src/data/rules/to21/rules-21-obligatoire.json +8 -6
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -34,6 +34,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.HtmlMatcher = exports.SymbolMatcher = exports.FileMatcher = exports.CollectionMatcher = exports.TypeMatcher = exports.ExpressionMatcher = exports.HierarchyMatcher = exports.DecoratorMatcher = exports.ImportMatcher = exports.ContextMatcher = exports.NodeMatcher = exports.clearTemplateCache = void 0;
|
|
37
|
+
exports.setOverrideNode = setOverrideNode;
|
|
38
|
+
exports.getOverrideNode = getOverrideNode;
|
|
39
|
+
exports.clearOverrideNode = clearOverrideNode;
|
|
37
40
|
exports.matchesAstPattern = matchesAstPattern;
|
|
38
41
|
const ts_morph_1 = require("ts-morph");
|
|
39
42
|
// Import matchers TypeScript (depuis ts/)
|
|
@@ -62,7 +65,26 @@ const HtmlMatcher = __importStar(require("./html"));
|
|
|
62
65
|
exports.HtmlMatcher = HtmlMatcher;
|
|
63
66
|
const html_pipe_variable_matcher_1 = require("./html/html-pipe-variable-matcher");
|
|
64
67
|
const host_binding_property_matcher_1 = require("./ts/host-binding-property-matcher");
|
|
68
|
+
const host_binding_type_error_matcher_1 = require("./ts/host-binding-type-error-matcher");
|
|
65
69
|
const mutation_matcher_1 = require("./ts/mutation-matcher");
|
|
70
|
+
/**
|
|
71
|
+
* Mécanisme "Override Node" pour localisation précise
|
|
72
|
+
* Permet aux matchers de retourner un nœud différent pour l'affichage
|
|
73
|
+
* Exemple: hostBindingProperty retourne le PropertyAssignment au lieu du @Component
|
|
74
|
+
*/
|
|
75
|
+
let currentOverrideNode = null;
|
|
76
|
+
/** Définit le nœud à utiliser pour la localisation (ligne, texte) */
|
|
77
|
+
function setOverrideNode(node) {
|
|
78
|
+
currentOverrideNode = node;
|
|
79
|
+
}
|
|
80
|
+
/** Récupère le nœud override ou null si non défini */
|
|
81
|
+
function getOverrideNode() {
|
|
82
|
+
return currentOverrideNode;
|
|
83
|
+
}
|
|
84
|
+
/** Nettoie le nœud override (à appeler après utilisation) */
|
|
85
|
+
function clearOverrideNode() {
|
|
86
|
+
currentOverrideNode = null;
|
|
87
|
+
}
|
|
66
88
|
/**
|
|
67
89
|
* Fonction principale : vérifie si un nœud correspond à un pattern AST
|
|
68
90
|
* OPTIMISÉ : excludeContext en premier (88% des règles l'utilisent)
|
|
@@ -393,10 +415,22 @@ function matchesAstPattern(node, pattern) {
|
|
|
393
415
|
}
|
|
394
416
|
}
|
|
395
417
|
// Vérifier hostBindingProperty (résolution host binding → TS property → vérification wrappers)
|
|
418
|
+
// Note: matchesHostBindingProperty retourne Node | null pour localisation précise
|
|
396
419
|
if (pattern.hostBindingProperty !== undefined) {
|
|
397
|
-
|
|
420
|
+
const problematicNode = (0, host_binding_property_matcher_1.matchesHostBindingProperty)(node, pattern.hostBindingProperty);
|
|
421
|
+
if (!problematicNode) {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
setOverrideNode(problematicNode);
|
|
425
|
+
}
|
|
426
|
+
// Vérifier hostBindingTypeError (erreurs de type dans host bindings pour Angular 21)
|
|
427
|
+
// Note: matchesHostBindingTypeError retourne Node | null pour localisation précise
|
|
428
|
+
if (pattern.hostBindingTypeError !== undefined) {
|
|
429
|
+
const errorNode = (0, host_binding_type_error_matcher_1.matchesHostBindingTypeError)(node, pattern.hostBindingTypeError);
|
|
430
|
+
if (!errorNode) {
|
|
398
431
|
return false;
|
|
399
432
|
}
|
|
433
|
+
setOverrideNode(errorNode);
|
|
400
434
|
}
|
|
401
435
|
// Vérifier fileMissing (identifiant absent de tout le fichier)
|
|
402
436
|
if (pattern.fileMissing !== undefined) {
|
|
@@ -38,7 +38,7 @@ function getHostObject(componentNode) {
|
|
|
38
38
|
/**
|
|
39
39
|
* Trouve les property bindings dans l'objet host
|
|
40
40
|
* Exemples: '[class.active]', '[attr.disabled]', '[style.color]'
|
|
41
|
-
* Retourne array de {key, value}
|
|
41
|
+
* Retourne array de {key, value, node} pour localisation précise
|
|
42
42
|
*/
|
|
43
43
|
function findPropertyBindings(hostObject) {
|
|
44
44
|
const bindings = [];
|
|
@@ -60,7 +60,7 @@ function findPropertyBindings(hostObject) {
|
|
|
60
60
|
const value = ts_morph_1.Node.isStringLiteral(initializer)
|
|
61
61
|
? initializer.getLiteralValue()
|
|
62
62
|
: initializer.getText();
|
|
63
|
-
bindings.push({ key, value });
|
|
63
|
+
bindings.push({ key, value, node: property });
|
|
64
64
|
}
|
|
65
65
|
return bindings;
|
|
66
66
|
}
|
|
@@ -79,6 +79,156 @@ function isWrappedInWrappers(propertyDecl, wrappers) {
|
|
|
79
79
|
}
|
|
80
80
|
return false;
|
|
81
81
|
}
|
|
82
|
+
/** Opérateurs d'assignation (réutilisé de mutation-matcher.ts) */
|
|
83
|
+
const ASSIGNMENT_OPERATORS = new Set([
|
|
84
|
+
ts_morph_1.SyntaxKind.EqualsToken,
|
|
85
|
+
ts_morph_1.SyntaxKind.PlusEqualsToken,
|
|
86
|
+
ts_morph_1.SyntaxKind.MinusEqualsToken,
|
|
87
|
+
ts_morph_1.SyntaxKind.AsteriskEqualsToken,
|
|
88
|
+
ts_morph_1.SyntaxKind.SlashEqualsToken
|
|
89
|
+
]);
|
|
90
|
+
/**
|
|
91
|
+
* Vérifie si un BinaryExpression est une assignation à this.propertyName
|
|
92
|
+
*/
|
|
93
|
+
function isAssignmentToThisProperty(expr, propertyName) {
|
|
94
|
+
if (!ts_morph_1.Node.isBinaryExpression(expr))
|
|
95
|
+
return false;
|
|
96
|
+
const operatorKind = expr.getOperatorToken().getKind();
|
|
97
|
+
if (!ASSIGNMENT_OPERATORS.has(operatorKind))
|
|
98
|
+
return false;
|
|
99
|
+
const left = expr.getLeft();
|
|
100
|
+
if (!ts_morph_1.Node.isPropertyAccessExpression(left))
|
|
101
|
+
return false;
|
|
102
|
+
const expression = left.getExpression();
|
|
103
|
+
const name = left.getName();
|
|
104
|
+
return expression.getText() === 'this' && name === propertyName;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Trouve la MethodDeclaration parente d'un nœud
|
|
108
|
+
*/
|
|
109
|
+
function findParentMethod(node) {
|
|
110
|
+
let current = node.getParent();
|
|
111
|
+
while (current) {
|
|
112
|
+
if (ts_morph_1.Node.isMethodDeclaration(current)) {
|
|
113
|
+
return current;
|
|
114
|
+
}
|
|
115
|
+
if (ts_morph_1.Node.isClassDeclaration(current)) {
|
|
116
|
+
return null; // Arrêter si on atteint la classe (initializer de propriété)
|
|
117
|
+
}
|
|
118
|
+
current = current.getParent();
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Trouve toutes les mutations d'une propriété dans une classe
|
|
124
|
+
* Détecte : this.prop = value, this.prop += value, etc.
|
|
125
|
+
*/
|
|
126
|
+
function findPropertyMutationsInClass(classDecl, propertyName) {
|
|
127
|
+
const mutations = [];
|
|
128
|
+
classDecl.forEachDescendant((descendant) => {
|
|
129
|
+
if (isAssignmentToThisProperty(descendant, propertyName)) {
|
|
130
|
+
mutations.push({
|
|
131
|
+
mutationNode: descendant,
|
|
132
|
+
containingMethod: findParentMethod(descendant)
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
return mutations;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Vérifie si un nœud contient un appel à markForCheck()
|
|
140
|
+
*/
|
|
141
|
+
function containsMarkForCheckCall(node) {
|
|
142
|
+
let found = false;
|
|
143
|
+
node.forEachDescendant((child) => {
|
|
144
|
+
if (found)
|
|
145
|
+
return;
|
|
146
|
+
if (!ts_morph_1.Node.isCallExpression(child))
|
|
147
|
+
return;
|
|
148
|
+
const expr = child.getExpression();
|
|
149
|
+
if (!ts_morph_1.Node.isPropertyAccessExpression(expr))
|
|
150
|
+
return;
|
|
151
|
+
if (expr.getName() === 'markForCheck') {
|
|
152
|
+
found = true;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
return found;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Trouve la position du premier appel markForCheck() dans un nœud
|
|
159
|
+
* Retourne -1 si non trouvé
|
|
160
|
+
*/
|
|
161
|
+
function findMarkForCheckPosition(node) {
|
|
162
|
+
let position = -1;
|
|
163
|
+
node.forEachDescendant((child) => {
|
|
164
|
+
if (position !== -1)
|
|
165
|
+
return;
|
|
166
|
+
if (!ts_morph_1.Node.isCallExpression(child))
|
|
167
|
+
return;
|
|
168
|
+
const expr = child.getExpression();
|
|
169
|
+
const isMarkForCheck = ts_morph_1.Node.isPropertyAccessExpression(expr) && expr.getName() === 'markForCheck';
|
|
170
|
+
if (isMarkForCheck) {
|
|
171
|
+
position = child.getStart();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
return position;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Vérifie si markForCheck() est appelé APRÈS une mutation dans la même méthode
|
|
178
|
+
*/
|
|
179
|
+
function hasMarkForCheckAfterMutation(method, mutationNode) {
|
|
180
|
+
const body = method.getBody();
|
|
181
|
+
if (!body || !ts_morph_1.Node.isBlock(body))
|
|
182
|
+
return false;
|
|
183
|
+
const statements = body.getStatements();
|
|
184
|
+
const mutationPos = mutationNode.getStart();
|
|
185
|
+
// Trouver l'index du statement contenant la mutation
|
|
186
|
+
let mutationIndex = -1;
|
|
187
|
+
for (let i = 0; i < statements.length; i++) {
|
|
188
|
+
const stmtStart = statements[i].getStart();
|
|
189
|
+
const stmtEnd = statements[i].getEnd();
|
|
190
|
+
if (mutationPos >= stmtStart && mutationPos <= stmtEnd) {
|
|
191
|
+
mutationIndex = i;
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (mutationIndex === -1)
|
|
196
|
+
return false;
|
|
197
|
+
// Chercher markForCheck() APRÈS la mutation (même statement ou suivants)
|
|
198
|
+
for (let i = mutationIndex; i < statements.length; i++) {
|
|
199
|
+
if (containsMarkForCheckCall(statements[i])) {
|
|
200
|
+
if (i === mutationIndex) {
|
|
201
|
+
// Même statement : vérifier que markForCheck est APRÈS mutation
|
|
202
|
+
const markForCheckPos = findMarkForCheckPosition(statements[i]);
|
|
203
|
+
if (markForCheckPos > mutationPos)
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
return true; // Statement suivant
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Vérifie si TOUTES les mutations d'une propriété ont markForCheck() appelé après
|
|
215
|
+
* Retourne true si :
|
|
216
|
+
* - La propriété n'est jamais mutée (seulement initialisée)
|
|
217
|
+
* - Toutes les mutations sont suivies de markForCheck()
|
|
218
|
+
*/
|
|
219
|
+
function allMutationsHaveMarkForCheck(classDecl, propertyName) {
|
|
220
|
+
const mutations = findPropertyMutationsInClass(classDecl, propertyName);
|
|
221
|
+
// Si aucune mutation → propriété jamais changée → PAS problématique
|
|
222
|
+
if (mutations.length === 0) {
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
// Vérifier que TOUTES les mutations ont markForCheck() après
|
|
226
|
+
return mutations.every(({ mutationNode, containingMethod }) => {
|
|
227
|
+
if (!containingMethod)
|
|
228
|
+
return false; // Mutation hors méthode = non protégée
|
|
229
|
+
return hasMarkForCheckAfterMutation(containingMethod, mutationNode);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
82
232
|
/**
|
|
83
233
|
* Vérifie si un getter utilise uniquement des propriétés signal/computed dans son body
|
|
84
234
|
* Retourne true si le getter est "safe" (ne nécessite pas markForCheck)
|
|
@@ -188,6 +338,31 @@ function findHostBindingDecorators(componentNode) {
|
|
|
188
338
|
extractHostBindings(parent.getGetAccessors());
|
|
189
339
|
return results;
|
|
190
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Vérifie si un membre résolu (PropertyDeclaration ou GetAccessor) est problématique
|
|
343
|
+
* Factorise la logique commune entre isProblematicBinding() et matchesHostBindingProperty()
|
|
344
|
+
* @returns true si problématique, false sinon
|
|
345
|
+
*/
|
|
346
|
+
function isResolvedMemberProblematic(resolved, propertyName, classDecl, notWrappedIn) {
|
|
347
|
+
// Si c'est un getter → Vérifier si son body utilise uniquement des signals
|
|
348
|
+
if (ts_morph_1.Node.isGetAccessorDeclaration(resolved)) {
|
|
349
|
+
if (classDecl && isGetterUsingOnlySignals(resolved, classDecl, notWrappedIn)) {
|
|
350
|
+
return false; // Getter safe (utilise uniquement des signals)
|
|
351
|
+
}
|
|
352
|
+
return true; // Getter problématique
|
|
353
|
+
}
|
|
354
|
+
// Si PropertyDeclaration, vérifier wrapper
|
|
355
|
+
if (ts_morph_1.Node.isPropertyDeclaration(resolved)) {
|
|
356
|
+
if (!isWrappedInWrappers(resolved, notWrappedIn)) {
|
|
357
|
+
// Propriété simple - vérifier si markForCheck() est appelé après chaque mutation
|
|
358
|
+
if (classDecl && allMutationsHaveMarkForCheck(classDecl, propertyName)) {
|
|
359
|
+
return false; // Toutes mutations protégées par markForCheck() → PAS problématique
|
|
360
|
+
}
|
|
361
|
+
return true; // Propriété simple sans markForCheck, PROBLÉMATIQUE
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
191
366
|
/**
|
|
192
367
|
* Vérifie si un binding est problématique (nécessite markForCheck)
|
|
193
368
|
* Vérifie TOUTES les variables dans l'expression
|
|
@@ -211,18 +386,8 @@ function isProblematicBinding(componentNode, bindingValue, notWrappedIn) {
|
|
|
211
386
|
if (!resolved) {
|
|
212
387
|
continue; // Variable non trouvée, skip
|
|
213
388
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (classDecl && isGetterUsingOnlySignals(resolved, classDecl, notWrappedIn)) {
|
|
217
|
-
continue; // Getter safe (utilise uniquement des signals)
|
|
218
|
-
}
|
|
219
|
-
return true; // Getter problématique
|
|
220
|
-
}
|
|
221
|
-
// Si PropertyDeclaration, vérifier wrapper
|
|
222
|
-
if (ts_morph_1.Node.isPropertyDeclaration(resolved)) {
|
|
223
|
-
if (!isWrappedInWrappers(resolved, notWrappedIn)) {
|
|
224
|
-
return true; // Propriété simple, PROBLÉMATIQUE
|
|
225
|
-
}
|
|
389
|
+
if (isResolvedMemberProblematic(resolved, variableName, classDecl, notWrappedIn)) {
|
|
390
|
+
return true;
|
|
226
391
|
}
|
|
227
392
|
}
|
|
228
393
|
return false;
|
|
@@ -234,19 +399,21 @@ function isProblematicBinding(componentNode, bindingValue, notWrappedIn) {
|
|
|
234
399
|
* Détecte 2 sources de host bindings:
|
|
235
400
|
* 1. Objet host dans @Component: host: { '[class.active]': 'isActive' }
|
|
236
401
|
* 2. @HostBinding() decorators sur properties/getters
|
|
402
|
+
*
|
|
403
|
+
* @returns Le nœud problématique (PropertyAssignment ou Decorator @HostBinding) ou null si pas de match
|
|
237
404
|
*/
|
|
238
405
|
function matchesHostBindingProperty(componentNode, pattern) {
|
|
239
406
|
if (!ts_morph_1.Node.isDecorator(componentNode)) {
|
|
240
|
-
return
|
|
407
|
+
return null;
|
|
241
408
|
}
|
|
242
409
|
const notWrappedIn = pattern.resolvedProperty.notWrappedIn || [];
|
|
243
410
|
// Source 1: Objet host dans @Component
|
|
244
411
|
const hostObject = getHostObject(componentNode);
|
|
245
412
|
if (hostObject) {
|
|
246
413
|
const bindings = findPropertyBindings(hostObject);
|
|
247
|
-
for (const { value } of bindings) {
|
|
414
|
+
for (const { value, node } of bindings) {
|
|
248
415
|
if (isProblematicBinding(componentNode, value, notWrappedIn)) {
|
|
249
|
-
return
|
|
416
|
+
return node; // Retourner le PropertyAssignment problématique
|
|
250
417
|
}
|
|
251
418
|
}
|
|
252
419
|
}
|
|
@@ -254,26 +421,17 @@ function matchesHostBindingProperty(componentNode, pattern) {
|
|
|
254
421
|
const parent = componentNode.getParent();
|
|
255
422
|
const classDecl = parent && ts_morph_1.Node.isClassDeclaration(parent) ? parent : null;
|
|
256
423
|
const hostBindingDecorators = findHostBindingDecorators(componentNode);
|
|
257
|
-
for (const { propertyName } of hostBindingDecorators) {
|
|
424
|
+
for (const { decorator, propertyName } of hostBindingDecorators) {
|
|
258
425
|
const resolved = resolveBindingVariable(componentNode, propertyName);
|
|
259
426
|
if (!resolved) {
|
|
260
427
|
continue;
|
|
261
428
|
}
|
|
262
|
-
//
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
continue; // Getter safe (utilise uniquement des signals)
|
|
266
|
-
}
|
|
267
|
-
return true; // Getter problématique
|
|
268
|
-
}
|
|
269
|
-
// Si PropertyDeclaration, vérifier wrapper
|
|
270
|
-
if (ts_morph_1.Node.isPropertyDeclaration(resolved)) {
|
|
271
|
-
if (!isWrappedInWrappers(resolved, notWrappedIn)) {
|
|
272
|
-
return true;
|
|
273
|
-
}
|
|
429
|
+
// Utiliser la fonction factorisée (DRY)
|
|
430
|
+
if (isResolvedMemberProblematic(resolved, propertyName, classDecl, notWrappedIn)) {
|
|
431
|
+
return decorator; // Retourner le @HostBinding decorator problématique
|
|
274
432
|
}
|
|
275
433
|
}
|
|
276
|
-
return
|
|
434
|
+
return null;
|
|
277
435
|
}
|
|
278
436
|
/**
|
|
279
437
|
* Vérifie si un composant a des @HostListener sur ses méthodes
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.matchesHostBindingTypeError = matchesHostBindingTypeError;
|
|
4
|
+
const ts_morph_1 = require("ts-morph");
|
|
5
|
+
const matcher_helpers_1 = require("../utils/matcher-helpers");
|
|
6
|
+
const host_binding_property_matcher_1 = require("./host-binding-property-matcher");
|
|
7
|
+
const host_binding_type_helpers_1 = require("./host-binding-type-helpers");
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Simple Reference Detection
|
|
10
|
+
// ============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Vérifie si la valeur est une référence simple à une variable/méthode
|
|
13
|
+
* Accepts: varName, varName(), varName($event)
|
|
14
|
+
*/
|
|
15
|
+
function isSimpleReference(value) {
|
|
16
|
+
const trimmed = value.trim();
|
|
17
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*(\(\s*(\$event)?\s*\))?$/.test(trimmed);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Extrait le nom de la variable/méthode d'une référence simple
|
|
21
|
+
*/
|
|
22
|
+
function extractReferenceName(value) {
|
|
23
|
+
const trimmed = value.trim();
|
|
24
|
+
const match = trimmed.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);
|
|
25
|
+
return match ? match[1] : trimmed;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Vérifie si c'est un appel de fonction (avec parenthèses)
|
|
29
|
+
*/
|
|
30
|
+
function isFunctionCall(value) {
|
|
31
|
+
return /\(\s*\)$/.test(value.trim()) || /\(\s*\$event\s*\)$/.test(value.trim());
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Vérifie si c'est un event binding
|
|
35
|
+
*/
|
|
36
|
+
function isEventBinding(key) {
|
|
37
|
+
return key.startsWith('(') && key.endsWith(')');
|
|
38
|
+
}
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// Event Handler Checking
|
|
41
|
+
// ============================================================================
|
|
42
|
+
/**
|
|
43
|
+
* Extrait le nom du handler d'une expression d'événement
|
|
44
|
+
*/
|
|
45
|
+
function extractHandlerName(expression) {
|
|
46
|
+
const match = expression.trim().match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);
|
|
47
|
+
return match ? match[1] : expression.trim();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Vérifie si l'expression utilise $event
|
|
51
|
+
*/
|
|
52
|
+
function usesEventParameter(expression) {
|
|
53
|
+
return expression.includes('$event');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Vérifie le type du paramètre d'un event handler
|
|
57
|
+
*/
|
|
58
|
+
function checkEventHandlerSignature(classDecl, handlerName, expectedEventType) {
|
|
59
|
+
const method = classDecl.getMethod(handlerName);
|
|
60
|
+
if (!method) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const params = method.getParameters();
|
|
64
|
+
if (params.length === 0) {
|
|
65
|
+
return 'event-signature';
|
|
66
|
+
}
|
|
67
|
+
const firstParam = params[0];
|
|
68
|
+
const typeNode = firstParam.getTypeNode();
|
|
69
|
+
let paramTypeText;
|
|
70
|
+
if (typeNode) {
|
|
71
|
+
paramTypeText = typeNode.getText();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const paramType = firstParam.getType();
|
|
75
|
+
paramTypeText = paramType.getText();
|
|
76
|
+
}
|
|
77
|
+
if (expectedEventType !== 'Event') {
|
|
78
|
+
if (paramTypeText === 'Event' || paramTypeText.endsWith('.Event')) {
|
|
79
|
+
return 'event-signature';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Extrait tous les bindings de l'objet host
|
|
86
|
+
*/
|
|
87
|
+
function extractHostBindings(hostObject) {
|
|
88
|
+
const bindings = [];
|
|
89
|
+
for (const property of hostObject.getProperties()) {
|
|
90
|
+
if (!ts_morph_1.Node.isPropertyAssignment(property)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const key = (0, matcher_helpers_1.stripQuotes)(property.getName());
|
|
94
|
+
const initializer = property.getInitializer();
|
|
95
|
+
if (!initializer) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (!key.startsWith('[') && !key.startsWith('(')) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const value = ts_morph_1.Node.isStringLiteral(initializer)
|
|
102
|
+
? initializer.getLiteralValue()
|
|
103
|
+
: initializer.getText();
|
|
104
|
+
bindings.push({
|
|
105
|
+
key,
|
|
106
|
+
value,
|
|
107
|
+
node: property,
|
|
108
|
+
isEvent: isEventBinding(key)
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return bindings;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Trouve les @HostBinding decorators dans la classe
|
|
115
|
+
*/
|
|
116
|
+
function findHostBindingDecorators(classDecl) {
|
|
117
|
+
const results = [];
|
|
118
|
+
for (const property of classDecl.getProperties()) {
|
|
119
|
+
for (const decorator of property.getDecorators()) {
|
|
120
|
+
if (decorator.getName() === 'HostBinding') {
|
|
121
|
+
results.push({
|
|
122
|
+
decorator,
|
|
123
|
+
propertyName: property.getName(),
|
|
124
|
+
bindingKey: extractDecoratorBindingKey(decorator)
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
for (const getter of classDecl.getGetAccessors()) {
|
|
130
|
+
for (const decorator of getter.getDecorators()) {
|
|
131
|
+
if (decorator.getName() === 'HostBinding') {
|
|
132
|
+
results.push({
|
|
133
|
+
decorator,
|
|
134
|
+
propertyName: getter.getName(),
|
|
135
|
+
bindingKey: extractDecoratorBindingKey(decorator)
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return results;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Extrait la clé de binding d'un @HostBinding decorator
|
|
144
|
+
*/
|
|
145
|
+
function extractDecoratorBindingKey(decorator) {
|
|
146
|
+
const callExpr = decorator.getCallExpression();
|
|
147
|
+
if (!callExpr) {
|
|
148
|
+
return '';
|
|
149
|
+
}
|
|
150
|
+
const args = callExpr.getArguments();
|
|
151
|
+
if (args.length === 0) {
|
|
152
|
+
return '';
|
|
153
|
+
}
|
|
154
|
+
const firstArg = args[0];
|
|
155
|
+
if (ts_morph_1.Node.isStringLiteral(firstArg)) {
|
|
156
|
+
const value = firstArg.getLiteralValue();
|
|
157
|
+
if (!value.startsWith('[')) {
|
|
158
|
+
return `[${value}]`;
|
|
159
|
+
}
|
|
160
|
+
return value;
|
|
161
|
+
}
|
|
162
|
+
return '';
|
|
163
|
+
}
|
|
164
|
+
// ============================================================================
|
|
165
|
+
// Detection Logic
|
|
166
|
+
// ============================================================================
|
|
167
|
+
/**
|
|
168
|
+
* Vérifie un property binding pour erreurs de type
|
|
169
|
+
*/
|
|
170
|
+
function checkPropertyBinding(classDecl, key, value, level) {
|
|
171
|
+
if (!isSimpleReference(value)) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const refName = extractReferenceName(value);
|
|
175
|
+
const isCall = isFunctionCall(value);
|
|
176
|
+
if (isCall) {
|
|
177
|
+
if (!(0, host_binding_type_helpers_1.methodExists)(classDecl, refName) && !(0, host_binding_type_helpers_1.propertyExists)(classDecl, refName)) {
|
|
178
|
+
return 'missing-method';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
if (!(0, host_binding_type_helpers_1.propertyExists)(classDecl, refName)) {
|
|
183
|
+
return 'missing-property';
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (level === 'existence') {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
const parsed = (0, host_binding_type_helpers_1.parseBindingKey)(key);
|
|
190
|
+
if (!parsed) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
const expectedType = (0, host_binding_type_helpers_1.getExpectedType)(parsed);
|
|
194
|
+
if (expectedType.kind === 'any') {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
if ((0, host_binding_type_helpers_1.isPropertySignalWrapper)(classDecl, refName)) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
const actualType = (0, host_binding_type_helpers_1.resolvePropertyType)(classDecl, refName);
|
|
201
|
+
if (!actualType) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
if (!(0, host_binding_type_helpers_1.isTypeCompatible)(actualType, expectedType)) {
|
|
205
|
+
return 'type-mismatch';
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Vérifie un event binding pour erreurs de type
|
|
211
|
+
*/
|
|
212
|
+
function checkEventBinding(classDecl, key, value, level) {
|
|
213
|
+
if (!isSimpleReference(value)) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
const handlerName = extractHandlerName(value);
|
|
217
|
+
if (!(0, host_binding_type_helpers_1.methodExists)(classDecl, handlerName)) {
|
|
218
|
+
return 'missing-method';
|
|
219
|
+
}
|
|
220
|
+
if (level !== 'full') {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
if (!usesEventParameter(value)) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
const eventName = (0, host_binding_type_helpers_1.parseEventKey)(key);
|
|
227
|
+
if (!eventName) {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
const expectedEventType = (0, host_binding_type_helpers_1.getExpectedEventType)(eventName);
|
|
231
|
+
return checkEventHandlerSignature(classDecl, handlerName, expectedEventType);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Vérifie un @HostBinding decorator pour erreurs de type
|
|
235
|
+
*/
|
|
236
|
+
function checkHostBindingDecorator(classDecl, bindingKey, propertyName, level) {
|
|
237
|
+
if (level === 'existence') {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
const parsed = (0, host_binding_type_helpers_1.parseBindingKey)(bindingKey);
|
|
241
|
+
if (!parsed) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const expectedType = (0, host_binding_type_helpers_1.getExpectedType)(parsed);
|
|
245
|
+
if (expectedType.kind === 'any') {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
const actualType = (0, host_binding_type_helpers_1.resolvePropertyType)(classDecl, propertyName);
|
|
249
|
+
if (!actualType) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
if (!(0, host_binding_type_helpers_1.isTypeCompatible)(actualType, expectedType)) {
|
|
253
|
+
return 'type-mismatch';
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
// ============================================================================
|
|
258
|
+
// Main Entry Point
|
|
259
|
+
// ============================================================================
|
|
260
|
+
/**
|
|
261
|
+
* Détecte les erreurs de type dans les host bindings d'un composant
|
|
262
|
+
* Retourne le nœud problématique ou null si aucune erreur
|
|
263
|
+
*/
|
|
264
|
+
function matchesHostBindingTypeError(componentNode, pattern) {
|
|
265
|
+
if (!ts_morph_1.Node.isDecorator(componentNode)) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
const classDecl = componentNode.getParent();
|
|
269
|
+
if (!classDecl || !ts_morph_1.Node.isClassDeclaration(classDecl)) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
const level = pattern.level || 'full';
|
|
273
|
+
const hostObject = (0, host_binding_property_matcher_1.getHostObject)(componentNode);
|
|
274
|
+
if (hostObject) {
|
|
275
|
+
const bindings = extractHostBindings(hostObject);
|
|
276
|
+
for (const binding of bindings) {
|
|
277
|
+
let error = null;
|
|
278
|
+
if (binding.isEvent) {
|
|
279
|
+
error = checkEventBinding(classDecl, binding.key, binding.value, level);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
error = checkPropertyBinding(classDecl, binding.key, binding.value, level);
|
|
283
|
+
}
|
|
284
|
+
if (error) {
|
|
285
|
+
return binding.node;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const hostBindings = findHostBindingDecorators(classDecl);
|
|
290
|
+
for (const { decorator, propertyName, bindingKey } of hostBindings) {
|
|
291
|
+
const error = checkHostBindingDecorator(classDecl, bindingKey, propertyName, level);
|
|
292
|
+
if (error) {
|
|
293
|
+
return decorator;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EVENT_TO_TYPE = void 0;
|
|
4
|
+
exports.parseBindingKey = parseBindingKey;
|
|
5
|
+
exports.parseEventKey = parseEventKey;
|
|
6
|
+
exports.getExpectedType = getExpectedType;
|
|
7
|
+
exports.getExpectedEventType = getExpectedEventType;
|
|
8
|
+
exports.resolvePropertyType = resolvePropertyType;
|
|
9
|
+
exports.methodExists = methodExists;
|
|
10
|
+
exports.propertyExists = propertyExists;
|
|
11
|
+
exports.isPropertySignalWrapper = isPropertySignalWrapper;
|
|
12
|
+
exports.unwrapSignalType = unwrapSignalType;
|
|
13
|
+
exports.isTypeCompatible = isTypeCompatible;
|
|
14
|
+
const ts_morph_1 = require("ts-morph");
|
|
15
|
+
/** Bindings qui attendent un boolean */
|
|
16
|
+
const BOOLEAN_BINDINGS = new Set(['hidden', 'disabled', 'readonly', 'checked', 'selected']);
|
|
17
|
+
/** Units de style qui attendent un number */
|
|
18
|
+
const NUMBER_STYLE_UNITS = new Set(['px', 'em', 'rem', '%', 'vh', 'vw', 'vmin', 'vmax', 'pt', 'pc', 'in', 'cm', 'mm']);
|
|
19
|
+
/** Mapping événements → type attendu */
|
|
20
|
+
exports.EVENT_TO_TYPE = {
|
|
21
|
+
'click': 'MouseEvent',
|
|
22
|
+
'dblclick': 'MouseEvent',
|
|
23
|
+
'mouseenter': 'MouseEvent',
|
|
24
|
+
'mouseleave': 'MouseEvent',
|
|
25
|
+
'mousedown': 'MouseEvent',
|
|
26
|
+
'mouseup': 'MouseEvent',
|
|
27
|
+
'mousemove': 'MouseEvent',
|
|
28
|
+
'mouseover': 'MouseEvent',
|
|
29
|
+
'mouseout': 'MouseEvent',
|
|
30
|
+
'contextmenu': 'MouseEvent',
|
|
31
|
+
'keydown': 'KeyboardEvent',
|
|
32
|
+
'keyup': 'KeyboardEvent',
|
|
33
|
+
'keypress': 'KeyboardEvent',
|
|
34
|
+
'focus': 'FocusEvent',
|
|
35
|
+
'blur': 'FocusEvent',
|
|
36
|
+
'focusin': 'FocusEvent',
|
|
37
|
+
'focusout': 'FocusEvent',
|
|
38
|
+
'input': 'InputEvent',
|
|
39
|
+
'change': 'Event',
|
|
40
|
+
'submit': 'SubmitEvent',
|
|
41
|
+
'reset': 'Event',
|
|
42
|
+
'scroll': 'Event',
|
|
43
|
+
'wheel': 'WheelEvent',
|
|
44
|
+
'drag': 'DragEvent',
|
|
45
|
+
'dragstart': 'DragEvent',
|
|
46
|
+
'dragend': 'DragEvent',
|
|
47
|
+
'dragenter': 'DragEvent',
|
|
48
|
+
'dragleave': 'DragEvent',
|
|
49
|
+
'dragover': 'DragEvent',
|
|
50
|
+
'drop': 'DragEvent',
|
|
51
|
+
'touchstart': 'TouchEvent',
|
|
52
|
+
'touchend': 'TouchEvent',
|
|
53
|
+
'touchmove': 'TouchEvent',
|
|
54
|
+
'touchcancel': 'TouchEvent',
|
|
55
|
+
'pointerdown': 'PointerEvent',
|
|
56
|
+
'pointerup': 'PointerEvent',
|
|
57
|
+
'pointermove': 'PointerEvent',
|
|
58
|
+
'pointerenter': 'PointerEvent',
|
|
59
|
+
'pointerleave': 'PointerEvent',
|
|
60
|
+
};
|
|
61
|
+
/** Signal wrapper functions that should be considered as valid reactive types */
|
|
62
|
+
const SIGNAL_WRAPPERS = new Set(['signal', 'computed', 'input', 'model', 'linkedSignal', 'toSignal']);
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// Binding Key Parsing
|
|
65
|
+
// ============================================================================
|
|
66
|
+
/**
|
|
67
|
+
* Parse une clé de binding pour extraire type, name et unit
|
|
68
|
+
* '[class.active]' → { type: 'class', name: 'active' }
|
|
69
|
+
* '[style.width.px]' → { type: 'style', name: 'width', unit: 'px' }
|
|
70
|
+
*/
|
|
71
|
+
function parseBindingKey(key) {
|
|
72
|
+
const match = key.match(/^\[([^.\]]+)(?:\.([^.\]]+))?(?:\.([^.\]]+))?\]$/);
|
|
73
|
+
if (!match) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const [, first, second, third] = match;
|
|
77
|
+
if (first === 'class') {
|
|
78
|
+
return { type: 'class', name: second || '' };
|
|
79
|
+
}
|
|
80
|
+
if (first === 'style') {
|
|
81
|
+
return { type: 'style', name: second || '', unit: third };
|
|
82
|
+
}
|
|
83
|
+
if (first === 'attr') {
|
|
84
|
+
return { type: 'attr', name: second || '' };
|
|
85
|
+
}
|
|
86
|
+
return { type: 'property', name: first };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Parse une clé d'événement pour extraire le nom de base
|
|
90
|
+
* '(click)' → 'click'
|
|
91
|
+
* '(keydown.enter)' → 'keydown'
|
|
92
|
+
*/
|
|
93
|
+
function parseEventKey(key) {
|
|
94
|
+
const match = key.match(/^\(([^.)]+)/);
|
|
95
|
+
return match ? match[1] : null;
|
|
96
|
+
}
|
|
97
|
+
// ============================================================================
|
|
98
|
+
// Type Expectations
|
|
99
|
+
// ============================================================================
|
|
100
|
+
/**
|
|
101
|
+
* Détermine le type attendu pour un property binding
|
|
102
|
+
*/
|
|
103
|
+
function getExpectedType(parsed) {
|
|
104
|
+
if (parsed.type === 'class') {
|
|
105
|
+
return { kind: 'boolean' };
|
|
106
|
+
}
|
|
107
|
+
if (parsed.type === 'style') {
|
|
108
|
+
if (parsed.unit && NUMBER_STYLE_UNITS.has(parsed.unit)) {
|
|
109
|
+
return { kind: 'number' };
|
|
110
|
+
}
|
|
111
|
+
return { kind: 'string' };
|
|
112
|
+
}
|
|
113
|
+
if (parsed.type === 'attr') {
|
|
114
|
+
return { kind: 'string-or-null' };
|
|
115
|
+
}
|
|
116
|
+
if (BOOLEAN_BINDINGS.has(parsed.name)) {
|
|
117
|
+
return { kind: 'boolean' };
|
|
118
|
+
}
|
|
119
|
+
return { kind: 'any' };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Retourne le type d'événement attendu
|
|
123
|
+
*/
|
|
124
|
+
function getExpectedEventType(eventName) {
|
|
125
|
+
return exports.EVENT_TO_TYPE[eventName] || 'Event';
|
|
126
|
+
}
|
|
127
|
+
// ============================================================================
|
|
128
|
+
// Type Resolution
|
|
129
|
+
// ============================================================================
|
|
130
|
+
/**
|
|
131
|
+
* Résout le type d'une propriété dans la classe
|
|
132
|
+
*/
|
|
133
|
+
function resolvePropertyType(classDecl, propName) {
|
|
134
|
+
const property = classDecl.getProperty(propName);
|
|
135
|
+
if (property) {
|
|
136
|
+
return property.getType();
|
|
137
|
+
}
|
|
138
|
+
const getter = classDecl.getGetAccessor(propName);
|
|
139
|
+
if (getter) {
|
|
140
|
+
return getter.getReturnType();
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Vérifie si une méthode existe dans la classe
|
|
146
|
+
*/
|
|
147
|
+
function methodExists(classDecl, methodName) {
|
|
148
|
+
return classDecl.getMethod(methodName) !== undefined;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Vérifie si une propriété existe dans la classe (property ou getter)
|
|
152
|
+
*/
|
|
153
|
+
function propertyExists(classDecl, propName) {
|
|
154
|
+
return classDecl.getProperty(propName) !== undefined ||
|
|
155
|
+
classDecl.getGetAccessor(propName) !== undefined;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Check if a property is initialized with a signal wrapper (signal(), computed(), etc.)
|
|
159
|
+
*/
|
|
160
|
+
function isPropertySignalWrapper(classDecl, propName) {
|
|
161
|
+
const property = classDecl.getProperty(propName);
|
|
162
|
+
if (!property) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
const initializer = property.getInitializer();
|
|
166
|
+
if (!initializer || !ts_morph_1.Node.isCallExpression(initializer)) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const callee = initializer.getExpression();
|
|
170
|
+
const calleeName = callee.getText();
|
|
171
|
+
return SIGNAL_WRAPPERS.has(calleeName);
|
|
172
|
+
}
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// Signal Type Unwrapping
|
|
175
|
+
// ============================================================================
|
|
176
|
+
/**
|
|
177
|
+
* Unwrap Signal<T>, WritableSignal<T>, InputSignal<T> → T
|
|
178
|
+
*/
|
|
179
|
+
function unwrapSignalType(type) {
|
|
180
|
+
const typeText = type.getText();
|
|
181
|
+
if (/Signal</.test(typeText)) {
|
|
182
|
+
const typeArgs = type.getTypeArguments();
|
|
183
|
+
if (typeArgs.length > 0) {
|
|
184
|
+
return typeArgs[0];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return type;
|
|
188
|
+
}
|
|
189
|
+
function isSignalOfBoolean(typeText) {
|
|
190
|
+
return /Signal<\s*(boolean|true|false)\s*>/.test(typeText);
|
|
191
|
+
}
|
|
192
|
+
function isSignalOfNumber(typeText) {
|
|
193
|
+
return /Signal<\s*(number|\d+)\s*>/.test(typeText);
|
|
194
|
+
}
|
|
195
|
+
function isSignalOfString(typeText) {
|
|
196
|
+
return /Signal<\s*(string|"[^"]*"|'[^']*')\s*>/.test(typeText);
|
|
197
|
+
}
|
|
198
|
+
// ============================================================================
|
|
199
|
+
// Type Compatibility
|
|
200
|
+
// ============================================================================
|
|
201
|
+
/**
|
|
202
|
+
* Vérifie si un type est compatible avec le type attendu
|
|
203
|
+
*/
|
|
204
|
+
function isTypeCompatible(actualType, expected) {
|
|
205
|
+
if (expected.kind === 'any') {
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
const unwrapped = unwrapSignalType(actualType);
|
|
209
|
+
switch (expected.kind) {
|
|
210
|
+
case 'boolean':
|
|
211
|
+
return isOrContainsBoolean(unwrapped);
|
|
212
|
+
case 'number':
|
|
213
|
+
return isOrContainsNumber(unwrapped);
|
|
214
|
+
case 'string':
|
|
215
|
+
return isOrContainsString(unwrapped);
|
|
216
|
+
case 'string-or-null':
|
|
217
|
+
return isOrContainsString(unwrapped) || unwrapped.isNull() || unwrapped.isUndefined();
|
|
218
|
+
default:
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function isOrContainsBoolean(type) {
|
|
223
|
+
const typeText = type.getText();
|
|
224
|
+
if (isSignalOfBoolean(typeText)) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
if (type.isBoolean() || type.isBooleanLiteral()) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
if (type.isUnion()) {
|
|
231
|
+
return type.getUnionTypes().some(t => t.isBoolean() || t.isBooleanLiteral());
|
|
232
|
+
}
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
function isOrContainsNumber(type) {
|
|
236
|
+
const typeText = type.getText();
|
|
237
|
+
if (isSignalOfNumber(typeText)) {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
if (type.isNumber() || type.isNumberLiteral()) {
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
if (type.isUnion()) {
|
|
244
|
+
return type.getUnionTypes().some(t => t.isNumber() || t.isNumberLiteral());
|
|
245
|
+
}
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
function isOrContainsString(type) {
|
|
249
|
+
const typeText = type.getText();
|
|
250
|
+
if (isSignalOfString(typeText)) {
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
if (type.isString() || type.isStringLiteral()) {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
if (type.isUnion()) {
|
|
257
|
+
return type.getUnionTypes().some(t => t.isString() || t.isStringLiteral());
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
@@ -56,13 +56,19 @@ function stripQuotes(str) {
|
|
|
56
56
|
* 'isActive' → ['isActive']
|
|
57
57
|
* 'count > 0' → ['count']
|
|
58
58
|
* 'count1 + count2' → ['count1', 'count2']
|
|
59
|
-
* 'sig() ? "a" : "b"' → ['sig']
|
|
59
|
+
* 'sig() ? "a" : "b"' → ['sig'] (strings littérales ignorées)
|
|
60
60
|
* 'obj.prop' → ['obj']
|
|
61
|
+
* '"search"' → [] (string littérale pure = pas de variable)
|
|
61
62
|
* @param expression Expression de binding
|
|
62
63
|
* @returns Array de noms de variables
|
|
63
64
|
*/
|
|
64
65
|
function extractVariableNames(expression) {
|
|
65
|
-
|
|
66
|
+
// Supprimer les strings littérales pour éviter les faux positifs
|
|
67
|
+
// '"search"' → '', 'sig() ? "a" : "b"' → 'sig() ? : '
|
|
68
|
+
const withoutStrings = expression
|
|
69
|
+
.replace(/"[^"]*"/g, '') // Supprimer strings double quotes
|
|
70
|
+
.replace(/'[^']*'/g, ''); // Supprimer strings single quotes
|
|
71
|
+
const cleaned = withoutStrings.trim();
|
|
66
72
|
const variables = new Set();
|
|
67
73
|
// Pattern pour extraire tous les identifiants valides
|
|
68
74
|
const identifierPattern = /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g;
|
|
@@ -131,18 +131,22 @@ function processNodeWithRules(node, rules, sourceFile, relativeFilePath, matches
|
|
|
131
131
|
// Vérifier testSetup si présent
|
|
132
132
|
if (rule.astPattern.testSetup &&
|
|
133
133
|
!matchers_1.FileMatcher.matchesTestSetup(sourceFile, rule.astPattern.testSetup)) {
|
|
134
|
+
(0, matchers_1.clearOverrideNode)(); // Nettoyer même si on skip
|
|
134
135
|
continue;
|
|
135
136
|
}
|
|
137
|
+
// Utiliser le nœud override si disponible (localisation précise)
|
|
138
|
+
const reportNode = (0, matchers_1.getOverrideNode)() || node;
|
|
139
|
+
(0, matchers_1.clearOverrideNode)(); // Toujours nettoyer après utilisation
|
|
136
140
|
// Optimisation getText() : vérifier width d'abord
|
|
137
|
-
const width =
|
|
141
|
+
const width = reportNode.getWidth();
|
|
138
142
|
const matchedText = width > 100
|
|
139
|
-
?
|
|
140
|
-
:
|
|
143
|
+
? reportNode.getText().substring(0, 100).trim()
|
|
144
|
+
: reportNode.getText().trim();
|
|
141
145
|
matches.push({
|
|
142
146
|
ruleKey: rule.key,
|
|
143
147
|
ruleSummary: rule.summary,
|
|
144
148
|
filePath: relativeFilePath,
|
|
145
|
-
lineNumber:
|
|
149
|
+
lineNumber: reportNode.getStartLineNumber(),
|
|
146
150
|
matchedText
|
|
147
151
|
});
|
|
148
152
|
}
|
|
@@ -210,17 +210,19 @@
|
|
|
210
210
|
"doc_url": "https://angular.dev/api/common/NgComponentOutlet"
|
|
211
211
|
},
|
|
212
212
|
{
|
|
213
|
-
"key": "
|
|
214
|
-
"summary": "
|
|
215
|
-
"description": "BREAKING CHANGE:
|
|
216
|
-
"estimated_time_per_occurrence":
|
|
213
|
+
"key": "host_binding_type_errors",
|
|
214
|
+
"summary": "Erreurs de type dans les host bindings (Angular 21)",
|
|
215
|
+
"description": "BREAKING CHANGE: Angular 21 active typeCheckHostBindings par defaut. Cette regle detecte les ERREURS DE TYPE REELLES: proprietes/methodes inexistantes, types incompatibles ([class.*] attend boolean, [style.*.px] attend number), signatures evenements incorrectes (Event au lieu de MouseEvent). Corriger ces erreurs avant migration ou desactiver temporairement via tsconfig.",
|
|
216
|
+
"estimated_time_per_occurrence": 10,
|
|
217
217
|
"onFile": null,
|
|
218
218
|
"fileTypes": ["*.ts"],
|
|
219
219
|
"regex": "host\\s*:\\s*\\{[^}]*[\\[\\(]|@Host(?:Binding|Listener)\\s*\\(",
|
|
220
220
|
"astPattern": {
|
|
221
221
|
"nodeType": "Decorator",
|
|
222
222
|
"name": ["Component", "Directive"],
|
|
223
|
-
"
|
|
223
|
+
"hostBindingTypeError": {
|
|
224
|
+
"level": "full"
|
|
225
|
+
},
|
|
224
226
|
"inFile": {
|
|
225
227
|
"tsconfig": {
|
|
226
228
|
"angularCompilerOptions": {
|
|
@@ -236,7 +238,7 @@
|
|
|
236
238
|
"isAutoFixable": false,
|
|
237
239
|
"migration_command": null,
|
|
238
240
|
"risk_level": "high",
|
|
239
|
-
"code_description": "//
|
|
241
|
+
"code_description": "// ERREUR: Propriete inexistante\n@Component({\n host: { '[style.color]': 'textColor' } // ERROR: 'textColor' n'existe pas\n})\nexport class Admin {\n color = 'red'; // Nom different!\n}\n\n// ERREUR: Type incompatible [class.*] attend boolean\n@Component({\n host: { '[class.active]': 'status' } // ERROR: boolean attendu\n})\nexport class MyComp {\n status = 'active'; // string fourni!\n}\n\n// ERREUR: Type incompatible [style.*.px] attend number\n@Component({\n host: { '[style.width.px]': 'width' } // ERROR: number attendu\n})\nexport class MyComp {\n width = '100'; // string fourni!\n}\n\n// ERREUR: Signature evenement incorrecte\n@Component({\n host: { '(click)': 'onClick($event)' }\n})\nexport class MyComp {\n onClick(e: Event) {} // ERROR: MouseEvent attendu!\n}\n\n// OK: Types corrects\n@Component({\n host: {\n '[class.active]': 'isActive', // boolean\n '[style.width.px]': 'width' // number\n }\n})\nexport class MyComp {\n isActive = true;\n width = 100;\n}",
|
|
240
242
|
"doc_url": "https://angular.dev/reference/migrations"
|
|
241
243
|
},
|
|
242
244
|
{
|
package/dist/styles.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! tailwindcss v4.1.14 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-orange-50:oklch(98% .016 73.684);--color-orange-100:oklch(95.4% .038 75.164);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-orange-700:oklch(55.3% .195 38.402);--color-yellow-50:oklch(98.7% .026 102.212);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-600:oklch(68.1% .162 75.834);--color-yellow-700:oklch(55.4% .135 66.442);--color-yellow-800:oklch(47.6% .114 61.907);--color-green-50:oklch(98.2% .018 155.826);--color-green-100:oklch(96.2% .044 156.743);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-teal-50:oklch(98.4% .014 180.72);--color-teal-400:oklch(77.7% .152 181.912);--color-teal-500:oklch(70.4% .14 182.503);--color-teal-600:oklch(60% .118 184.704);--color-teal-700:oklch(51.1% .096 186.391);--color-teal-800:oklch(43.7% .078 188.216);--color-cyan-50:oklch(98.4% .019 200.873);--color-cyan-400:oklch(78.9% .154 211.53);--color-cyan-600:oklch(60.9% .126 221.723);--color-cyan-800:oklch(45% .085 224.283);--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-800:oklch(42.4% .199 265.638);--color-blue-900:oklch(37.9% .146 265.522);--color-indigo-50:oklch(96.2% .018 272.314);--color-indigo-100:oklch(93% .034 272.788);--color-indigo-500:oklch(58.5% .233 277.117);--color-indigo-600:oklch(51.1% .262 276.966);--color-indigo-700:oklch(45.7% .24 277.023);--color-indigo-900:oklch(35.9% .144 278.697);--color-violet-50:oklch(96.9% .016 293.756);--color-violet-600:oklch(54.1% .281 293.009);--color-violet-700:oklch(49.1% .27 292.581);--color-purple-50:oklch(97.7% .014 308.299);--color-purple-100:oklch(94.6% .033 307.174);--color-purple-200:oklch(90.2% .063 306.703);--color-purple-500:oklch(62.7% .265 303.9);--color-purple-600:oklch(55.8% .288 302.321);--color-purple-700:oklch(49.6% .265 301.924);--color-purple-900:oklch(38.1% .176 304.987);--color-pink-50:oklch(97.1% .014 343.198);--color-pink-100:oklch(94.8% .028 342.258);--color-pink-500:oklch(65.6% .241 354.308);--color-pink-600:oklch(59.2% .249 .584);--color-pink-700:oklch(52.5% .223 3.958);--color-pink-900:oklch(40.8% .153 2.432);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-4xl:56rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5/2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wider:.05em;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.top-4{top:calc(var(--spacing)*4)}.right-0{right:calc(var(--spacing)*0)}.bottom-0{bottom:calc(var(--spacing)*0)}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-1{margin-inline:calc(var(--spacing)*1)}.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-6{margin-top:calc(var(--spacing)*6)}.mt-8{margin-top:calc(var(--spacing)*8)}.mt-12{margin-top:calc(var(--spacing)*12)}.mr-1{margin-right:calc(var(--spacing)*1)}.mr-1\.5{margin-right:calc(var(--spacing)*1.5)}.mr-2{margin-right:calc(var(--spacing)*2)}.mr-3{margin-right:calc(var(--spacing)*3)}.mr-4{margin-right:calc(var(--spacing)*4)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.mb-12{margin-bottom:calc(var(--spacing)*12)}.ml-0{margin-left:calc(var(--spacing)*0)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-2{margin-left:calc(var(--spacing)*2)}.ml-3{margin-left:calc(var(--spacing)*3)}.ml-4{margin-left:calc(var(--spacing)*4)}.ml-6{margin-left:calc(var(--spacing)*6)}.ml-8{margin-left:calc(var(--spacing)*8)}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.h-3{height:calc(var(--spacing)*3)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-16{height:calc(var(--spacing)*16)}.h-full{height:100%}.max-h-64{max-height:calc(var(--spacing)*64)}.max-h-\[90vh\]{max-height:90vh}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-screen{min-height:100vh}.w-3{width:calc(var(--spacing)*3)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-6{width:calc(var(--spacing)*6)}.w-8{width:calc(var(--spacing)*8)}.w-14{width:calc(var(--spacing)*14)}.w-16{width:calc(var(--spacing)*16)}.w-48{width:calc(var(--spacing)*48)}.w-64{width:calc(var(--spacing)*64)}.w-full{width:100%}.max-w-4xl{max-width:var(--container-4xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-32{max-width:calc(var(--spacing)*32)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-16{min-width:calc(var(--spacing)*16)}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.table-fixed{table-layout:fixed}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing)*1)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}.gap-8{gap:calc(var(--spacing)*8)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1.5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1.5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*2)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-3>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*3)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-4>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*4)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-x-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-200>:not(:last-child)){border-color:var(--color-gray-200)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-xl{border-top-left-radius:var(--radius-xl);border-top-right-radius:var(--radius-xl)}.rounded-b-xl{border-bottom-right-radius:var(--radius-xl);border-bottom-left-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-blue-200{border-color:var(--color-blue-200)}.border-blue-500{border-color:var(--color-blue-500)}.border-blue-600{border-color:var(--color-blue-600)}.border-cyan-400{border-color:var(--color-cyan-400)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-green-500{border-color:var(--color-green-500)}.border-indigo-500{border-color:var(--color-indigo-500)}.border-purple-200{border-color:var(--color-purple-200)}.border-purple-500{border-color:var(--color-purple-500)}.border-teal-400{border-color:var(--color-teal-400)}.border-transparent{border-color:#0000}.border-yellow-400{border-color:var(--color-yellow-400)}.bg-black{background-color:var(--color-black)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-blue-500{background-color:var(--color-blue-500)}.bg-blue-600{background-color:var(--color-blue-600)}.bg-cyan-50{background-color:var(--color-cyan-50)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-gray-500{background-color:var(--color-gray-500)}.bg-gray-600{background-color:var(--color-gray-600)}.bg-gray-800{background-color:var(--color-gray-800)}.bg-green-50{background-color:var(--color-green-50)}.bg-green-100{background-color:var(--color-green-100)}.bg-green-500{background-color:var(--color-green-500)}.bg-indigo-50{background-color:var(--color-indigo-50)}.bg-indigo-100{background-color:var(--color-indigo-100)}.bg-orange-50{background-color:var(--color-orange-50)}.bg-orange-100{background-color:var(--color-orange-100)}.bg-pink-50{background-color:var(--color-pink-50)}.bg-pink-100{background-color:var(--color-pink-100)}.bg-purple-50{background-color:var(--color-purple-50)}.bg-purple-100{background-color:var(--color-purple-100)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-500{background-color:var(--color-red-500)}.bg-teal-50{background-color:var(--color-teal-50)}.bg-violet-50{background-color:var(--color-violet-50)}.bg-white{background-color:var(--color-white)}.bg-yellow-50{background-color:var(--color-yellow-50)}.bg-yellow-100{background-color:var(--color-yellow-100)}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-gradient-to-r{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-blue-50{--tw-gradient-from:var(--color-blue-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-blue-600{--tw-gradient-from:var(--color-blue-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-green-500{--tw-gradient-from:var(--color-green-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-indigo-50{--tw-gradient-from:var(--color-indigo-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-orange-500{--tw-gradient-from:var(--color-orange-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-pink-50{--tw-gradient-from:var(--color-pink-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-purple-50{--tw-gradient-from:var(--color-purple-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-purple-600{--tw-gradient-from:var(--color-purple-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-red-500{--tw-gradient-from:var(--color-red-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-yellow-500{--tw-gradient-from:var(--color-yellow-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-blue-100{--tw-gradient-to:var(--color-blue-100);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-green-600{--tw-gradient-to:var(--color-green-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-indigo-50{--tw-gradient-to:var(--color-indigo-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-indigo-100{--tw-gradient-to:var(--color-indigo-100);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-indigo-600{--tw-gradient-to:var(--color-indigo-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-indigo-700{--tw-gradient-to:var(--color-indigo-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-orange-600{--tw-gradient-to:var(--color-orange-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-pink-100{--tw-gradient-to:var(--color-pink-100);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-purple-100{--tw-gradient-to:var(--color-purple-100);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-red-600{--tw-gradient-to:var(--color-red-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-yellow-600{--tw-gradient-to:var(--color-yellow-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.p-0\.5{padding:calc(var(--spacing)*.5)}.p-1\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.p-8{padding:calc(var(--spacing)*8)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-4{padding-block:calc(var(--spacing)*4)}.py-6{padding-block:calc(var(--spacing)*6)}.py-8{padding-block:calc(var(--spacing)*8)}.py-12{padding-block:calc(var(--spacing)*12)}.pt-0{padding-top:calc(var(--spacing)*0)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-6{padding-top:calc(var(--spacing)*6)}.pl-4{padding-left:calc(var(--spacing)*4)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.text-blue-100{color:var(--color-blue-100)}.text-blue-600{color:var(--color-blue-600)}.text-blue-700{color:var(--color-blue-700)}.text-blue-800{color:var(--color-blue-800)}.text-blue-900{color:var(--color-blue-900)}.text-cyan-600{color:var(--color-cyan-600)}.text-cyan-800{color:var(--color-cyan-800)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-100{color:var(--color-green-100)}.text-green-400{color:var(--color-green-400)}.text-green-600{color:var(--color-green-600)}.text-green-700{color:var(--color-green-700)}.text-indigo-600{color:var(--color-indigo-600)}.text-indigo-700{color:var(--color-indigo-700)}.text-indigo-900{color:var(--color-indigo-900)}.text-orange-100{color:var(--color-orange-100)}.text-orange-600{color:var(--color-orange-600)}.text-orange-700{color:var(--color-orange-700)}.text-pink-600{color:var(--color-pink-600)}.text-pink-700{color:var(--color-pink-700)}.text-pink-900{color:var(--color-pink-900)}.text-purple-100{color:var(--color-purple-100)}.text-purple-600{color:var(--color-purple-600)}.text-purple-700{color:var(--color-purple-700)}.text-purple-900{color:var(--color-purple-900)}.text-red-100{color:var(--color-red-100)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-teal-600{color:var(--color-teal-600)}.text-teal-700{color:var(--color-teal-700)}.text-teal-800{color:var(--color-teal-800)}.text-transparent{color:#0000}.text-violet-600{color:var(--color-violet-600)}.text-violet-700{color:var(--color-violet-700)}.text-white{color:var(--color-white)}.text-yellow-100{color:var(--color-yellow-100)}.text-yellow-600{color:var(--color-yellow-600)}.text-yellow-700{color:var(--color-yellow-700)}.text-yellow-800{color:var(--color-yellow-800)}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.underline{text-decoration-line:underline}.opacity-30{opacity:.3}.opacity-60{opacity:.6}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-300{--tw-duration:.3s;transition-duration:.3s}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:text-blue-600:is(:where(.group):hover *){color:var(--color-blue-600)}.group-hover\:text-green-600:is(:where(.group):hover *){color:var(--color-green-600)}.group-hover\:text-orange-600:is(:where(.group):hover *){color:var(--color-orange-600)}.group-hover\:text-pink-600:is(:where(.group):hover *){color:var(--color-pink-600)}.group-hover\:text-purple-600:is(:where(.group):hover *){color:var(--color-purple-600)}.group-hover\:text-red-600:is(:where(.group):hover *){color:var(--color-red-600)}.group-hover\:text-teal-600:is(:where(.group):hover *){color:var(--color-teal-600)}.group-hover\:text-yellow-600:is(:where(.group):hover *){color:var(--color-yellow-600)}.hover\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.hover\:bg-blue-50:hover{background-color:var(--color-blue-50)}.hover\:bg-blue-100:hover{background-color:var(--color-blue-100)}.hover\:bg-blue-200:hover{background-color:var(--color-blue-200)}.hover\:bg-blue-600:hover{background-color:var(--color-blue-600)}.hover\:bg-blue-700:hover{background-color:var(--color-blue-700)}.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-100:hover{background-color:var(--color-gray-100)}.hover\:bg-gray-200:hover{background-color:var(--color-gray-200)}.hover\:bg-gray-300:hover{background-color:var(--color-gray-300)}.hover\:bg-gray-600:hover{background-color:var(--color-gray-600)}.hover\:bg-gray-700:hover{background-color:var(--color-gray-700)}.hover\:bg-purple-50:hover{background-color:var(--color-purple-50)}.hover\:bg-purple-200:hover{background-color:var(--color-purple-200)}.hover\:bg-red-600:hover{background-color:var(--color-red-600)}.hover\:text-blue-600:hover{color:var(--color-blue-600)}.hover\:text-blue-800:hover{color:var(--color-blue-800)}.hover\:text-gray-600:hover{color:var(--color-gray-600)}.hover\:text-gray-800:hover{color:var(--color-gray-800)}.hover\:shadow-2xl:hover{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.hover\:shadow-xl:hover{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.focus\:border-transparent:focus{border-color:#0000}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-blue-500:focus{--tw-ring-color:var(--color-blue-500)}.focus\:ring-blue-600:focus{--tw-ring-color:var(--color-blue-600)}.focus\:ring-green-500:focus{--tw-ring-color:var(--color-green-500)}.focus\:ring-orange-500:focus{--tw-ring-color:var(--color-orange-500)}.focus\:ring-pink-500:focus{--tw-ring-color:var(--color-pink-500)}.focus\:ring-purple-500:focus{--tw-ring-color:var(--color-purple-500)}.focus\:ring-red-500:focus{--tw-ring-color:var(--color-red-500)}.focus\:ring-teal-500:focus{--tw-ring-color:var(--color-teal-500)}.focus\:ring-yellow-500:focus{--tw-ring-color:var(--color-yellow-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x)var(--tw-scale-y)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}@media (min-width:48rem){.md\:col-span-4{grid-column:span 4/span 4}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width:64rem){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}.filter-highlight{transition:box-shadow .3s ease-in-out;box-shadow:0 0 0 4px #3b82f680,0 0 20px #3b82f64d}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-orange-50:oklch(98% .016 73.684);--color-orange-100:oklch(95.4% .038 75.164);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-orange-700:oklch(55.3% .195 38.402);--color-yellow-50:oklch(98.7% .026 102.212);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-600:oklch(68.1% .162 75.834);--color-yellow-700:oklch(55.4% .135 66.442);--color-yellow-800:oklch(47.6% .114 61.907);--color-green-50:oklch(98.2% .018 155.826);--color-green-100:oklch(96.2% .044 156.743);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-teal-50:oklch(98.4% .014 180.72);--color-teal-400:oklch(77.7% .152 181.912);--color-teal-500:oklch(70.4% .14 182.503);--color-teal-600:oklch(60% .118 184.704);--color-teal-700:oklch(51.1% .096 186.391);--color-teal-800:oklch(43.7% .078 188.216);--color-cyan-50:oklch(98.4% .019 200.873);--color-cyan-400:oklch(78.9% .154 211.53);--color-cyan-600:oklch(60.9% .126 221.723);--color-cyan-800:oklch(45% .085 224.283);--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-800:oklch(42.4% .199 265.638);--color-blue-900:oklch(37.9% .146 265.522);--color-indigo-50:oklch(96.2% .018 272.314);--color-indigo-100:oklch(93% .034 272.788);--color-indigo-500:oklch(58.5% .233 277.117);--color-indigo-600:oklch(51.1% .262 276.966);--color-indigo-700:oklch(45.7% .24 277.023);--color-indigo-900:oklch(35.9% .144 278.697);--color-violet-50:oklch(96.9% .016 293.756);--color-violet-600:oklch(54.1% .281 293.009);--color-violet-700:oklch(49.1% .27 292.581);--color-purple-50:oklch(97.7% .014 308.299);--color-purple-100:oklch(94.6% .033 307.174);--color-purple-200:oklch(90.2% .063 306.703);--color-purple-500:oklch(62.7% .265 303.9);--color-purple-600:oklch(55.8% .288 302.321);--color-purple-700:oklch(49.6% .265 301.924);--color-purple-900:oklch(38.1% .176 304.987);--color-pink-50:oklch(97.1% .014 343.198);--color-pink-100:oklch(94.8% .028 342.258);--color-pink-500:oklch(65.6% .241 354.308);--color-pink-600:oklch(59.2% .249 .584);--color-pink-700:oklch(52.5% .223 3.958);--color-pink-900:oklch(40.8% .153 2.432);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-4xl:56rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5/2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wider:.05em;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.top-4{top:calc(var(--spacing)*4)}.right-0{right:calc(var(--spacing)*0)}.bottom-0{bottom:calc(var(--spacing)*0)}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-1{margin-inline:calc(var(--spacing)*1)}.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-6{margin-top:calc(var(--spacing)*6)}.mt-8{margin-top:calc(var(--spacing)*8)}.mt-12{margin-top:calc(var(--spacing)*12)}.mr-1{margin-right:calc(var(--spacing)*1)}.mr-1\.5{margin-right:calc(var(--spacing)*1.5)}.mr-2{margin-right:calc(var(--spacing)*2)}.mr-3{margin-right:calc(var(--spacing)*3)}.mr-4{margin-right:calc(var(--spacing)*4)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.mb-12{margin-bottom:calc(var(--spacing)*12)}.ml-0{margin-left:calc(var(--spacing)*0)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-2{margin-left:calc(var(--spacing)*2)}.ml-3{margin-left:calc(var(--spacing)*3)}.ml-4{margin-left:calc(var(--spacing)*4)}.ml-6{margin-left:calc(var(--spacing)*6)}.ml-8{margin-left:calc(var(--spacing)*8)}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.h-3{height:calc(var(--spacing)*3)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-16{height:calc(var(--spacing)*16)}.h-full{height:100%}.max-h-64{max-height:calc(var(--spacing)*64)}.max-h-\[90vh\]{max-height:90vh}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-screen{min-height:100vh}.w-3{width:calc(var(--spacing)*3)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-6{width:calc(var(--spacing)*6)}.w-8{width:calc(var(--spacing)*8)}.w-14{width:calc(var(--spacing)*14)}.w-16{width:calc(var(--spacing)*16)}.w-48{width:calc(var(--spacing)*48)}.w-64{width:calc(var(--spacing)*64)}.w-full{width:100%}.max-w-4xl{max-width:var(--container-4xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-32{max-width:calc(var(--spacing)*32)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-16{min-width:calc(var(--spacing)*16)}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.table-fixed{table-layout:fixed}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing)*1)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}.gap-8{gap:calc(var(--spacing)*8)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1.5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1.5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*2)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-3>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*3)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-4>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*4)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-x-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-200>:not(:last-child)){border-color:var(--color-gray-200)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-xl{border-top-left-radius:var(--radius-xl);border-top-right-radius:var(--radius-xl)}.rounded-b-xl{border-bottom-right-radius:var(--radius-xl);border-bottom-left-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-blue-200{border-color:var(--color-blue-200)}.border-blue-500{border-color:var(--color-blue-500)}.border-blue-600{border-color:var(--color-blue-600)}.border-cyan-400{border-color:var(--color-cyan-400)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-green-500{border-color:var(--color-green-500)}.border-indigo-500{border-color:var(--color-indigo-500)}.border-purple-200{border-color:var(--color-purple-200)}.border-purple-500{border-color:var(--color-purple-500)}.border-teal-400{border-color:var(--color-teal-400)}.border-transparent{border-color:#0000}.border-yellow-400{border-color:var(--color-yellow-400)}.bg-black{background-color:var(--color-black)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-blue-500{background-color:var(--color-blue-500)}.bg-blue-600{background-color:var(--color-blue-600)}.bg-cyan-50{background-color:var(--color-cyan-50)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-gray-500{background-color:var(--color-gray-500)}.bg-gray-600{background-color:var(--color-gray-600)}.bg-gray-800{background-color:var(--color-gray-800)}.bg-green-50{background-color:var(--color-green-50)}.bg-green-100{background-color:var(--color-green-100)}.bg-green-500{background-color:var(--color-green-500)}.bg-indigo-50{background-color:var(--color-indigo-50)}.bg-indigo-100{background-color:var(--color-indigo-100)}.bg-orange-50{background-color:var(--color-orange-50)}.bg-orange-100{background-color:var(--color-orange-100)}.bg-pink-50{background-color:var(--color-pink-50)}.bg-pink-100{background-color:var(--color-pink-100)}.bg-purple-50{background-color:var(--color-purple-50)}.bg-purple-100{background-color:var(--color-purple-100)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-500{background-color:var(--color-red-500)}.bg-teal-50{background-color:var(--color-teal-50)}.bg-violet-50{background-color:var(--color-violet-50)}.bg-white{background-color:var(--color-white)}.bg-yellow-50{background-color:var(--color-yellow-50)}.bg-yellow-100{background-color:var(--color-yellow-100)}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-gradient-to-r{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-blue-50{--tw-gradient-from:var(--color-blue-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-blue-600{--tw-gradient-from:var(--color-blue-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-green-500{--tw-gradient-from:var(--color-green-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-indigo-50{--tw-gradient-from:var(--color-indigo-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-orange-500{--tw-gradient-from:var(--color-orange-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-pink-50{--tw-gradient-from:var(--color-pink-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-purple-50{--tw-gradient-from:var(--color-purple-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-purple-600{--tw-gradient-from:var(--color-purple-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-red-500{--tw-gradient-from:var(--color-red-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-yellow-500{--tw-gradient-from:var(--color-yellow-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-blue-100{--tw-gradient-to:var(--color-blue-100);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-green-600{--tw-gradient-to:var(--color-green-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-indigo-50{--tw-gradient-to:var(--color-indigo-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-indigo-100{--tw-gradient-to:var(--color-indigo-100);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-indigo-600{--tw-gradient-to:var(--color-indigo-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-indigo-700{--tw-gradient-to:var(--color-indigo-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-orange-600{--tw-gradient-to:var(--color-orange-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-pink-100{--tw-gradient-to:var(--color-pink-100);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-purple-100{--tw-gradient-to:var(--color-purple-100);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-red-600{--tw-gradient-to:var(--color-red-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-yellow-600{--tw-gradient-to:var(--color-yellow-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.p-0\.5{padding:calc(var(--spacing)*.5)}.p-1\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.p-8{padding:calc(var(--spacing)*8)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-4{padding-block:calc(var(--spacing)*4)}.py-6{padding-block:calc(var(--spacing)*6)}.py-8{padding-block:calc(var(--spacing)*8)}.py-12{padding-block:calc(var(--spacing)*12)}.pt-0{padding-top:calc(var(--spacing)*0)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-6{padding-top:calc(var(--spacing)*6)}.pl-4{padding-left:calc(var(--spacing)*4)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.text-blue-100{color:var(--color-blue-100)}.text-blue-600{color:var(--color-blue-600)}.text-blue-700{color:var(--color-blue-700)}.text-blue-800{color:var(--color-blue-800)}.text-blue-900{color:var(--color-blue-900)}.text-cyan-600{color:var(--color-cyan-600)}.text-cyan-800{color:var(--color-cyan-800)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-100{color:var(--color-green-100)}.text-green-400{color:var(--color-green-400)}.text-green-600{color:var(--color-green-600)}.text-green-700{color:var(--color-green-700)}.text-indigo-600{color:var(--color-indigo-600)}.text-indigo-700{color:var(--color-indigo-700)}.text-indigo-900{color:var(--color-indigo-900)}.text-orange-100{color:var(--color-orange-100)}.text-orange-600{color:var(--color-orange-600)}.text-orange-700{color:var(--color-orange-700)}.text-pink-600{color:var(--color-pink-600)}.text-pink-700{color:var(--color-pink-700)}.text-pink-900{color:var(--color-pink-900)}.text-purple-100{color:var(--color-purple-100)}.text-purple-600{color:var(--color-purple-600)}.text-purple-700{color:var(--color-purple-700)}.text-purple-900{color:var(--color-purple-900)}.text-red-100{color:var(--color-red-100)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-teal-600{color:var(--color-teal-600)}.text-teal-700{color:var(--color-teal-700)}.text-teal-800{color:var(--color-teal-800)}.text-transparent{color:#0000}.text-violet-600{color:var(--color-violet-600)}.text-violet-700{color:var(--color-violet-700)}.text-white{color:var(--color-white)}.text-yellow-100{color:var(--color-yellow-100)}.text-yellow-600{color:var(--color-yellow-600)}.text-yellow-700{color:var(--color-yellow-700)}.text-yellow-800{color:var(--color-yellow-800)}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.underline{text-decoration-line:underline}.opacity-30{opacity:.3}.opacity-60{opacity:.6}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-300{--tw-duration:.3s;transition-duration:.3s}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:text-blue-600:is(:where(.group):hover *){color:var(--color-blue-600)}.group-hover\:text-green-600:is(:where(.group):hover *){color:var(--color-green-600)}.group-hover\:text-orange-600:is(:where(.group):hover *){color:var(--color-orange-600)}.group-hover\:text-pink-600:is(:where(.group):hover *){color:var(--color-pink-600)}.group-hover\:text-purple-600:is(:where(.group):hover *){color:var(--color-purple-600)}.group-hover\:text-red-600:is(:where(.group):hover *){color:var(--color-red-600)}.group-hover\:text-teal-600:is(:where(.group):hover *){color:var(--color-teal-600)}.group-hover\:text-yellow-600:is(:where(.group):hover *){color:var(--color-yellow-600)}.hover\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.hover\:bg-blue-50:hover{background-color:var(--color-blue-50)}.hover\:bg-blue-100:hover{background-color:var(--color-blue-100)}.hover\:bg-blue-200:hover{background-color:var(--color-blue-200)}.hover\:bg-blue-600:hover{background-color:var(--color-blue-600)}.hover\:bg-blue-700:hover{background-color:var(--color-blue-700)}.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-100:hover{background-color:var(--color-gray-100)}.hover\:bg-gray-200:hover{background-color:var(--color-gray-200)}.hover\:bg-gray-300:hover{background-color:var(--color-gray-300)}.hover\:bg-gray-600:hover{background-color:var(--color-gray-600)}.hover\:bg-gray-700:hover{background-color:var(--color-gray-700)}.hover\:bg-purple-50:hover{background-color:var(--color-purple-50)}.hover\:bg-purple-200:hover{background-color:var(--color-purple-200)}.hover\:bg-red-600:hover{background-color:var(--color-red-600)}.hover\:text-blue-600:hover{color:var(--color-blue-600)}.hover\:text-blue-800:hover{color:var(--color-blue-800)}.hover\:text-gray-600:hover{color:var(--color-gray-600)}.hover\:text-gray-800:hover{color:var(--color-gray-800)}.hover\:shadow-2xl:hover{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.hover\:shadow-xl:hover{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.focus\:border-transparent:focus{border-color:#0000}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-blue-500:focus{--tw-ring-color:var(--color-blue-500)}.focus\:ring-blue-600:focus{--tw-ring-color:var(--color-blue-600)}.focus\:ring-green-500:focus{--tw-ring-color:var(--color-green-500)}.focus\:ring-orange-500:focus{--tw-ring-color:var(--color-orange-500)}.focus\:ring-pink-500:focus{--tw-ring-color:var(--color-pink-500)}.focus\:ring-purple-500:focus{--tw-ring-color:var(--color-purple-500)}.focus\:ring-red-500:focus{--tw-ring-color:var(--color-red-500)}.focus\:ring-teal-500:focus{--tw-ring-color:var(--color-teal-500)}.focus\:ring-yellow-500:focus{--tw-ring-color:var(--color-yellow-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x)var(--tw-scale-y)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}@media (min-width:48rem){.md\:col-span-4{grid-column:span 4/span 4}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width:64rem){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}.filter-highlight{transition:box-shadow .3s ease-in-out;box-shadow:0 0 0 4px #3b82f680,0 0 20px #3b82f64d}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silvestv/migration-planificator",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.4",
|
|
4
4
|
"description": "Professional Angular migration analysis tool with AST precision for version upgrades (17→18, 18→19, 19→20, 20→21), Nx monorepo refactoring, workload estimation, and technical debt assessment. Interactive HTML reports with Gantt timeline and real-time editing.",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"publishConfig": {
|