@clhaas/palette-kit 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +80 -87
- package/dist/contrast/contrast.d.ts +16 -0
- package/dist/contrast/contrast.js +102 -0
- package/dist/core/intent-registry.d.ts +11 -0
- package/dist/core/intent-registry.js +70 -0
- package/dist/core/oklch.d.ts +16 -0
- package/dist/core/oklch.js +56 -0
- package/dist/create-palette-kit.d.ts +9 -0
- package/dist/create-palette-kit.js +67 -0
- package/dist/engine/context/context.d.ts +13 -0
- package/dist/engine/context/context.js +37 -0
- package/dist/engine/level/curves.d.ts +17 -0
- package/dist/engine/level/curves.js +49 -0
- package/dist/engine/level/level.d.ts +4 -0
- package/dist/engine/level/level.js +13 -0
- package/dist/engine/relation/relation.d.ts +105 -0
- package/dist/engine/relation/relation.js +137 -0
- package/dist/engine/resolve/resolve.d.ts +36 -0
- package/dist/engine/resolve/resolve.js +116 -0
- package/dist/engine/state/state.d.ts +46 -0
- package/dist/engine/state/state.js +68 -0
- package/dist/engine/usage/fill.d.ts +9 -0
- package/dist/engine/usage/fill.js +9 -0
- package/dist/engine/usage/lines.d.ts +9 -0
- package/dist/engine/usage/lines.js +9 -0
- package/dist/engine/usage/overlays.d.ts +9 -0
- package/dist/engine/usage/overlays.js +9 -0
- package/dist/engine/usage/strategy.d.ts +56 -0
- package/dist/engine/usage/strategy.js +30 -0
- package/dist/engine/usage/visualVocabulary.d.ts +9 -0
- package/dist/engine/usage/visualVocabulary.js +9 -0
- package/dist/export/serialize.d.ts +14 -0
- package/dist/export/serialize.js +89 -0
- package/dist/export/types.d.ts +37 -0
- package/dist/export/types.js +31 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/operators/convert.d.ts +32 -0
- package/dist/operators/convert.js +80 -0
- package/dist/presets/presets.d.ts +95 -0
- package/dist/presets/presets.js +308 -0
- package/dist/types/index.d.ts +111 -187
- package/dist/utils/errors/errors.d.ts +17 -0
- package/dist/utils/errors/errors.js +22 -0
- package/docs/API.md +167 -0
- package/docs/Alpha.md +14 -0
- package/docs/Architecture.md +56 -0
- package/docs/CLI.md +22 -0
- package/docs/Concepts.md +73 -0
- package/docs/Config.md +144 -0
- package/docs/Diagnostics.md +22 -0
- package/docs/Exporters.md +33 -0
- package/docs/FAQ.md +59 -0
- package/docs/Migration.md +61 -0
- package/docs/Overlays.md +33 -0
- package/docs/README.md +60 -0
- package/docs/Text.md +41 -0
- package/docs/Tokens.md +42 -0
- package/docs/Usage-JSON.md +39 -0
- package/docs/Usage-ReactNative.md +63 -0
- package/docs/Usage-Web.md +66 -0
- package/docs/Validation.md +97 -0
- package/docs/Why.md +37 -0
- package/docs/_api-surface.md +53 -0
- package/docs/snippets/serialize-oklch.md +9 -0
- package/docs/spec.md +98 -0
- package/package.json +74 -59
- package/.codex/skills/color-pipeline-implementer/SKILL.md +0 -23
- package/.codex/skills/commit-message-crafter/SKILL.md +0 -63
- package/.codex/skills/commit-message-crafter/references/benchmarks.md +0 -20
- package/.codex/skills/contrast-solver-helper/SKILL.md +0 -20
- package/.codex/skills/exporters-builder/SKILL.md +0 -20
- package/.codex/skills/markdownlint-writer/SKILL.md +0 -32
- package/.codex/skills/phase-implementation-runbook/SKILL.md +0 -92
- package/.codex/skills/type-contract-auditor/SKILL.md +0 -21
- package/.github/skills/review-guide/SKILL.md +0 -23
- package/.github/skills/review-guide/references/review-guide-v0.3.md +0 -629
- package/.markdownlint.json +0 -4
- package/AGENTS.md +0 -16
- package/biome.json +0 -43
- package/dist/cli/args.d.ts +0 -12
- package/dist/cli/args.js +0 -56
- package/dist/cli/args.test.d.ts +0 -1
- package/dist/cli/args.test.js +0 -22
- package/dist/cli/codegen/__snapshots__/tokens.test.js.snap +0 -87
- package/dist/cli/codegen/tokens.d.ts +0 -12
- package/dist/cli/codegen/tokens.js +0 -139
- package/dist/cli/codegen/tokens.test.d.ts +0 -1
- package/dist/cli/codegen/tokens.test.js +0 -51
- package/dist/cli/config.d.ts +0 -40
- package/dist/cli/config.js +0 -34
- package/dist/cli/validate.d.ts +0 -2
- package/dist/cli/validate.js +0 -33
- package/dist/cli/validate.test.d.ts +0 -1
- package/dist/cli/validate.test.js +0 -40
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -148
- package/dist/contrast/apca.d.ts +0 -2
- package/dist/contrast/apca.js +0 -15
- package/dist/contrast/apca.test.d.ts +0 -1
- package/dist/contrast/apca.test.js +0 -16
- package/dist/contrast/index.d.ts +0 -4
- package/dist/contrast/index.js +0 -4
- package/dist/contrast/scoring.d.ts +0 -4
- package/dist/contrast/scoring.js +0 -31
- package/dist/contrast/scoring.test.d.ts +0 -1
- package/dist/contrast/scoring.test.js +0 -148
- package/dist/contrast/solver.d.ts +0 -13
- package/dist/contrast/solver.js +0 -170
- package/dist/contrast/solver.test.d.ts +0 -1
- package/dist/contrast/solver.test.js +0 -75
- package/dist/contrast/types.d.ts +0 -17
- package/dist/contrast/types.js +0 -1
- package/dist/contrast/utils.d.ts +0 -4
- package/dist/contrast/utils.js +0 -18
- package/dist/contrast/wcag2.d.ts +0 -3
- package/dist/contrast/wcag2.js +0 -19
- package/dist/contrast/wcag2.test.d.ts +0 -1
- package/dist/contrast/wcag2.test.js +0 -17
- package/dist/core/createTheme.d.ts +0 -35
- package/dist/core/createTheme.js +0 -24
- package/dist/core/dx-helpers.test.d.ts +0 -1
- package/dist/core/dx-helpers.test.js +0 -61
- package/dist/core/index.d.ts +0 -2
- package/dist/core/index.js +0 -2
- package/dist/core/onSolid.test.d.ts +0 -1
- package/dist/core/onSolid.test.js +0 -118
- package/dist/core/qa.v1.test.d.ts +0 -1
- package/dist/core/qa.v1.test.js +0 -112
- package/dist/core/resolve.d.ts +0 -3
- package/dist/core/resolve.js +0 -8
- package/dist/core/resolve.test.d.ts +0 -1
- package/dist/core/resolve.test.js +0 -89
- package/dist/core/resolveMany.d.ts +0 -8
- package/dist/core/resolveMany.js +0 -17
- package/dist/core/tokenRegistry.d.ts +0 -23
- package/dist/core/tokenRegistry.js +0 -83
- package/dist/core/tokenRegistry.test.d.ts +0 -1
- package/dist/core/tokenRegistry.test.js +0 -133
- package/dist/engine/applyOperators.d.ts +0 -3
- package/dist/engine/applyOperators.js +0 -23
- package/dist/engine/context.d.ts +0 -4
- package/dist/engine/context.js +0 -1
- package/dist/engine/gamut.d.ts +0 -13
- package/dist/engine/gamut.js +0 -101
- package/dist/engine/gamut.test.d.ts +0 -1
- package/dist/engine/gamut.test.js +0 -23
- package/dist/engine/generateScale.d.ts +0 -15
- package/dist/engine/generateScale.js +0 -29
- package/dist/engine/generateScale.test.d.ts +0 -1
- package/dist/engine/generateScale.test.js +0 -32
- package/dist/engine/index.d.ts +0 -8
- package/dist/engine/index.js +0 -4
- package/dist/engine/normalize.d.ts +0 -43
- package/dist/engine/normalize.js +0 -403
- package/dist/engine/normalize.test.d.ts +0 -1
- package/dist/engine/normalize.test.js +0 -136
- package/dist/engine/onSolid.d.ts +0 -3
- package/dist/engine/onSolid.js +0 -110
- package/dist/engine/resolveBaseColor.d.ts +0 -25
- package/dist/engine/resolveBaseColor.js +0 -127
- package/dist/engine/resolveBaseColor.test.d.ts +0 -1
- package/dist/engine/resolveBaseColor.test.js +0 -97
- package/dist/export/__snapshots__/exportTheme.test.js.snap +0 -74
- package/dist/export/exportTheme.d.ts +0 -47
- package/dist/export/exportTheme.js +0 -170
- package/dist/export/exportTheme.test.d.ts +0 -1
- package/dist/export/exportTheme.test.js +0 -118
- package/dist/export/index.d.ts +0 -1
- package/dist/export/index.js +0 -1
- package/dist/export/serializeColor.d.ts +0 -1
- package/dist/export/serializeColor.js +0 -1
- package/dist/export/serializeColor.test.d.ts +0 -1
- package/dist/export/serializeColor.test.js +0 -54
- package/dist/export.d.ts +0 -1
- package/dist/export.js +0 -1
- package/dist/operators/emphasis.d.ts +0 -3
- package/dist/operators/emphasis.js +0 -113
- package/dist/operators/emphasis.test.d.ts +0 -1
- package/dist/operators/emphasis.test.js +0 -69
- package/dist/operators/index.d.ts +0 -3
- package/dist/operators/index.js +0 -2
- package/dist/operators/state.d.ts +0 -3
- package/dist/operators/state.js +0 -102
- package/dist/operators/state.test.d.ts +0 -1
- package/dist/operators/state.test.js +0 -48
- package/dist/operators/types.d.ts +0 -13
- package/dist/operators/types.js +0 -1
- package/dist/operators/utils.d.ts +0 -16
- package/dist/operators/utils.js +0 -23
- package/dist/presets/curves.d.ts +0 -28
- package/dist/presets/curves.js +0 -145
- package/dist/presets/index.d.ts +0 -2
- package/dist/presets/index.js +0 -1
- package/dist/presets/tokens/index.d.ts +0 -3
- package/dist/presets/tokens/index.js +0 -3
- package/dist/presets/tokens/minimal-ui.d.ts +0 -6
- package/dist/presets/tokens/minimal-ui.js +0 -53
- package/dist/presets/tokens/modern-ui.d.ts +0 -5
- package/dist/presets/tokens/modern-ui.js +0 -83
- package/dist/presets/tokens/presets.test.d.ts +0 -1
- package/dist/presets/tokens/presets.test.js +0 -31
- package/dist/presets/tokens/radixLike-ui.d.ts +0 -6
- package/dist/presets/tokens/radixLike-ui.js +0 -77
- package/dist/serialize/index.d.ts +0 -1
- package/dist/serialize/index.js +0 -1
- package/dist/serialize/normalizeOutput.d.ts +0 -6
- package/dist/serialize/normalizeOutput.js +0 -45
- package/dist/serialize/serializeColor.d.ts +0 -21
- package/dist/serialize/serializeColor.js +0 -178
- package/dist/serialize/serializeResolved.test.d.ts +0 -1
- package/dist/serialize/serializeResolved.test.js +0 -45
- package/dist/serialize.d.ts +0 -1
- package/dist/serialize.js +0 -1
- package/dist/utils/clamp.d.ts +0 -1
- package/dist/utils/clamp.js +0 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/lerp.d.ts +0 -1
- package/dist/utils/lerp.js +0 -1
- package/dist/utils/parseColor.d.ts +0 -6
- package/dist/utils/parseColor.js +0 -67
- package/dist/utils/parseColor.test.d.ts +0 -1
- package/dist/utils/parseColor.test.js +0 -51
- package/dist/utils/smoothstep.d.ts +0 -1
- package/dist/utils/smoothstep.js +0 -5
- package/planning/phase-10-review.md +0 -550
- package/planning/phase-7-review.md +0 -411
- package/planning/phase-8-review.md +0 -669
- package/planning/phase-9-review.md +0 -564
- package/planning/roadmap-v0.3.md +0 -284
- package/planning/spec-serializer-v0.3.md +0 -324
- package/planning/spec-v0.3.md +0 -305
- package/src/cli/args.test.ts +0 -28
- package/src/cli/args.ts +0 -66
- package/src/cli/codegen/__snapshots__/tokens.test.ts.snap +0 -87
- package/src/cli/codegen/tokens.test.ts +0 -61
- package/src/cli/codegen/tokens.ts +0 -191
- package/src/cli/config.ts +0 -71
- package/src/cli/validate.test.ts +0 -49
- package/src/cli/validate.ts +0 -38
- package/src/cli.ts +0 -183
- package/src/contrast/apca.test.ts +0 -20
- package/src/contrast/apca.ts +0 -26
- package/src/contrast/index.ts +0 -4
- package/src/contrast/scoring.test.ts +0 -188
- package/src/contrast/scoring.ts +0 -48
- package/src/contrast/solver.test.ts +0 -147
- package/src/contrast/solver.ts +0 -235
- package/src/contrast/types.ts +0 -20
- package/src/contrast/utils.ts +0 -28
- package/src/contrast/wcag2.test.ts +0 -21
- package/src/contrast/wcag2.ts +0 -24
- package/src/core/createTheme.ts +0 -78
- package/src/core/dx-helpers.test.ts +0 -82
- package/src/core/index.ts +0 -7
- package/src/core/onSolid.test.ts +0 -146
- package/src/core/qa.v1.test.ts +0 -149
- package/src/core/resolve.test.ts +0 -99
- package/src/core/resolve.ts +0 -11
- package/src/core/resolveMany.ts +0 -22
- package/src/core/tokenRegistry.test.ts +0 -153
- package/src/core/tokenRegistry.ts +0 -114
- package/src/engine/applyOperators.ts +0 -32
- package/src/engine/context.ts +0 -8
- package/src/engine/gamut.test.ts +0 -30
- package/src/engine/gamut.ts +0 -144
- package/src/engine/generateScale.test.ts +0 -46
- package/src/engine/generateScale.ts +0 -48
- package/src/engine/index.ts +0 -8
- package/src/engine/normalize.test.ts +0 -222
- package/src/engine/normalize.ts +0 -550
- package/src/engine/onSolid.ts +0 -178
- package/src/engine/resolveBaseColor.test.ts +0 -117
- package/src/engine/resolveBaseColor.ts +0 -203
- package/src/export/__snapshots__/exportTheme.test.ts.snap +0 -74
- package/src/export/exportTheme.test.ts +0 -144
- package/src/export/exportTheme.ts +0 -251
- package/src/export/index.ts +0 -1
- package/src/export/serializeColor.test.ts +0 -73
- package/src/export/serializeColor.ts +0 -1
- package/src/export.ts +0 -1
- package/src/index.ts +0 -3
- package/src/operators/emphasis.test.ts +0 -85
- package/src/operators/emphasis.ts +0 -132
- package/src/operators/index.ts +0 -3
- package/src/operators/state.test.ts +0 -66
- package/src/operators/state.ts +0 -122
- package/src/operators/types.ts +0 -14
- package/src/operators/utils.ts +0 -44
- package/src/presets/curves.ts +0 -168
- package/src/presets/index.ts +0 -2
- package/src/presets/tokens/index.ts +0 -3
- package/src/presets/tokens/minimal-ui.ts +0 -55
- package/src/presets/tokens/modern-ui.ts +0 -85
- package/src/presets/tokens/presets.test.ts +0 -46
- package/src/presets/tokens/radixLike-ui.ts +0 -79
- package/src/serialize/index.ts +0 -1
- package/src/serialize/normalizeOutput.ts +0 -63
- package/src/serialize/serializeColor.ts +0 -260
- package/src/serialize/serializeResolved.test.ts +0 -57
- package/src/serialize.ts +0 -1
- package/src/types/index.ts +0 -207
- package/src/utils/clamp.ts +0 -2
- package/src/utils/index.ts +0 -1
- package/src/utils/lerp.ts +0 -1
- package/src/utils/parseColor.test.ts +0 -66
- package/src/utils/parseColor.ts +0 -87
- package/src/utils/smoothstep.ts +0 -6
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -15
|
@@ -1,669 +0,0 @@
|
|
|
1
|
-
# Revisão Fase 8 — Inferência e Validações
|
|
2
|
-
|
|
3
|
-
**Data**: 18 de janeiro de 2026
|
|
4
|
-
**Revisor**: GitHub Copilot (usando review-guide-v0.3.md)
|
|
5
|
-
**Status**: ✅ **APROVADO COM OBSERVAÇÃO CRÍTICA**
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 📋 Resumo Executivo
|
|
10
|
-
|
|
11
|
-
A implementação da Fase 8 (Inferência e Validações) está **funcionalmente completa** com inferência robusta de `usage`, `surface` e `variant`. O código:
|
|
12
|
-
|
|
13
|
-
- ✅ Infere `usage` de prefixos de role
|
|
14
|
-
- ✅ Infere `surface` de padrões de naming
|
|
15
|
-
- ✅ Infere `variant` de tokens semânticos
|
|
16
|
-
- ✅ Strict mode com mensagens didáticas
|
|
17
|
-
- ✅ Warnings únicos (não repetidos)
|
|
18
|
-
- ✅ Testes abrangentes
|
|
19
|
-
|
|
20
|
-
**⚠️ OBSERVAÇÃO CRÍTICA**:
|
|
21
|
-
|
|
22
|
-
- **Warnings globais com estado mutável** (`inferenceWarnings` Set) pode causar vazamento de memória em long-running processes
|
|
23
|
-
- **Sugestão**: Mover para contexto ou adicionar método de reset
|
|
24
|
-
|
|
25
|
-
**Sugestões menores**:
|
|
26
|
-
|
|
27
|
-
1. Documentar estratégia de deduplicação de warnings
|
|
28
|
-
2. Adicionar teste para variant inference
|
|
29
|
-
3. JSDoc em funções helper de inferência
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## ✅ CRITÉRIOS GERAIS (Todos aprovados)
|
|
34
|
-
|
|
35
|
-
### 1. Contratos e tipos ✅
|
|
36
|
-
|
|
37
|
-
- ✅ **Nenhum `any` ou `unknown` injustificado**
|
|
38
|
-
- ✅ **Tipos exportados**: `NormalizedQuery` mantido
|
|
39
|
-
- ✅ **Sem circular imports**: `normalize.ts` → `types` apenas
|
|
40
|
-
- ✅ **Hierarquia respeitada**: `types` → `engine`
|
|
41
|
-
- ✅ **Breaking changes documentados**: JSDoc atualizado em `normalizeQuery`
|
|
42
|
-
|
|
43
|
-
**Evidência**:
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
/**
|
|
47
|
-
* Normalize a user-facing ColorQuery into a fully populated, validated structure.
|
|
48
|
-
*
|
|
49
|
-
* - Applies defaults for missing fields (context, surface, state, emphasis, output).
|
|
50
|
-
* - Infers usage and surface from role naming patterns when not provided.
|
|
51
|
-
* - In strict mode, missing required fields throw actionable errors.
|
|
52
|
-
* - In non-strict mode, safe defaults are applied with explicit warnings.
|
|
53
|
-
*/
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
### 2. Qualidade de código ✅
|
|
59
|
-
|
|
60
|
-
- ✅ **Build**: Código bem estruturado
|
|
61
|
-
- ✅ **Testes**: 19 testes em `normalize.test.ts` (6 novos)
|
|
62
|
-
- ✅ **Sem TODO/FIXME**: Nenhum encontrado
|
|
63
|
-
- ⚠️ **Comentários**: Faltam em funções helper de inferência
|
|
64
|
-
- ✅ **Style**: Formatação consistente
|
|
65
|
-
|
|
66
|
-
**Testes adicionados**:
|
|
67
|
-
|
|
68
|
-
1. `infers surface when obvious` ✅
|
|
69
|
-
2. `requires surface when strict and inference fails` ✅
|
|
70
|
-
3. `warns when surface cannot be inferred in non-strict mode` ✅
|
|
71
|
-
4. Atualização de testes existentes com mock de warnings ✅
|
|
72
|
-
|
|
73
|
-
**Sugestão de comentários**:
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
/**
|
|
77
|
-
* Infer surface intent from role naming patterns.
|
|
78
|
-
* Recognizes: "app.*", "surface.*", "bg.app", "bg.surface", etc.
|
|
79
|
-
*/
|
|
80
|
-
const inferSurfaceFromRole = (role: string): SurfaceIntent | undefined => {
|
|
81
|
-
// ... implementation
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Infer semantic variant from role token.
|
|
86
|
-
* Recognizes: "success", "warning", "danger", "category:*", "chart:*"
|
|
87
|
-
*/
|
|
88
|
-
const inferVariantFromRole = (role: string): SemanticVariant | undefined => {
|
|
89
|
-
// ... implementation
|
|
90
|
-
};
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
### 3. DX (Developer Experience) ✅
|
|
96
|
-
|
|
97
|
-
- ✅ **Mensagens de erro acionáveis**:
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
`Usage is required for role: "${role}". Provide usage explicitly (e.g. { usage: "text" }) or use a role prefix like "text.", "icon.", "bg.", "border.", "ring."`
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
- ✅ **Warnings explícitos**:
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
`Defaulting surface to "surface" for role: "${role}". Surface is required for role: "${role}". Provide surface explicitly (e.g. { surface: "surface" }) or use a role pattern like "bg.app", "bg.surface", "app.*"`
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
- ✅ **Sem magia**: Inferência é explícita e testável
|
|
110
|
-
- ✅ **Autocomplete**: Enums mantidos
|
|
111
|
-
|
|
112
|
-
**Pontos positivos**:
|
|
113
|
-
|
|
114
|
-
- Mensagens incluem exemplos práticos de correção
|
|
115
|
-
- Warnings mostram caminho de solução
|
|
116
|
-
- Deduplicação evita spam de logs
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
### 4. Princípios da v0.3 ✅
|
|
121
|
-
|
|
122
|
-
- ✅ **Runtime-first**: Inferência no engine, não na CLI
|
|
123
|
-
- ✅ **Serializer independente**: Não afetado
|
|
124
|
-
- ✅ **Resolver com inferência**: Decisões explícitas via strict mode
|
|
125
|
-
- ✅ **Sem magia oculta**: Warnings revelam inferência
|
|
126
|
-
- ✅ **Determinismo**: Mesma entrada → mesma saída (warnings são side-effect)
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## ✅ CRITÉRIOS ESPECÍFICOS DA FASE 8
|
|
131
|
-
|
|
132
|
-
### Inferência implementada ✅
|
|
133
|
-
|
|
134
|
-
#### `usage` inferido por prefixo ✅
|
|
135
|
-
|
|
136
|
-
**Evidência** (`inferUsageFromRole`, linhas 125-167):
|
|
137
|
-
|
|
138
|
-
```typescript
|
|
139
|
-
if (normalizedRole.startsWith("bg.")) return "bg";
|
|
140
|
-
if (normalizedRole.startsWith("text.")) return "text";
|
|
141
|
-
if (normalizedRole.startsWith("icon.")) return "icon";
|
|
142
|
-
// ... mais prefixos
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
**Testes**:
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
expect(normalizeQuery({ role: "icon.primary" }).usage).toBe("icon");
|
|
149
|
-
expect(normalizeQuery({ role: "border.muted" }).usage).toBe("border");
|
|
150
|
-
expect(normalizeQuery({ role: "bg.canvas" }).usage).toBe("bg");
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
#### `surface` inferido quando óbvio ✅
|
|
154
|
-
|
|
155
|
-
**Evidência** (`inferSurfaceFromRole`, linhas 169-184):
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
// Padrão: "app.*", "surface.*"
|
|
159
|
-
if (first && surfaces.includes(first as SurfaceIntent)) {
|
|
160
|
-
return first as SurfaceIntent;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Padrão: "bg.app", "bg.surface"
|
|
164
|
-
if (first === "bg" && second && surfaces.includes(second as SurfaceIntent)) {
|
|
165
|
-
return second as SurfaceIntent;
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
**Testes**:
|
|
170
|
-
|
|
171
|
-
```typescript
|
|
172
|
-
expect(normalizeQuery({ role: "bg.app" }).surface).toBe("app");
|
|
173
|
-
expect(normalizeQuery({ role: "bg.surface" }).surface).toBe("surface");
|
|
174
|
-
expect(normalizeQuery({ role: "app.bg", usage: "bg" }).surface).toBe("app");
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
#### `variant` inferido se omitido ✅
|
|
178
|
-
|
|
179
|
-
**Evidência** (`inferVariantFromRole`, linhas 186-202):
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
// Reconhece variantes semânticas
|
|
183
|
-
if (semanticVariants.includes(normalized as SemanticVariant)) {
|
|
184
|
-
return normalized as SemanticVariant;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Reconhece padrões especiais: "category:*", "chart:*"
|
|
188
|
-
if (/^(category|chart):.+/.test(normalized)) {
|
|
189
|
-
return normalized as SemanticVariant;
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
**⚠️ Teste faltando**:
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
it("infers variant from role token", () => {
|
|
197
|
-
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
|
|
198
|
-
|
|
199
|
-
try {
|
|
200
|
-
expect(normalizeQuery({ role: "success.bg" }).variant).toBe("success");
|
|
201
|
-
expect(normalizeQuery({ role: "warning.text" }).variant).toBe("warning");
|
|
202
|
-
expect(normalizeQuery({ role: "danger.border" }).variant).toBe("danger");
|
|
203
|
-
expect(normalizeQuery({ role: "category:sales.fill" }).variant).toBe("category:sales");
|
|
204
|
-
expect(normalizeQuery({ role: "chart:revenue.stroke" }).variant).toBe("chart:revenue");
|
|
205
|
-
} finally {
|
|
206
|
-
warnSpy.mockRestore();
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
---
|
|
212
|
-
|
|
213
|
-
### Strict mode ✅
|
|
214
|
-
|
|
215
|
-
#### `strict: false` - warnings + fallback ✅
|
|
216
|
-
|
|
217
|
-
**Evidência** (linhas 446-456):
|
|
218
|
-
|
|
219
|
-
```typescript
|
|
220
|
-
if (!usageValue) {
|
|
221
|
-
if (output.strict) {
|
|
222
|
-
throw new Error(missingUsageMessage(role));
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
warnInferenceOnce(
|
|
226
|
-
`usage:${role}`,
|
|
227
|
-
`Defaulting usage to "bg" for role: "${role}". ${missingUsageMessage(role)}`,
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
**Testes**:
|
|
233
|
-
|
|
234
|
-
```typescript
|
|
235
|
-
it("warns when usage cannot be inferred in non-strict mode", () => {
|
|
236
|
-
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
|
|
237
|
-
|
|
238
|
-
expect(normalizeQuery({ role: "brand.primary" }).usage).toBe("bg");
|
|
239
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
240
|
-
expect.stringContaining('Defaulting usage to "bg"'),
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
warnSpy.mockRestore();
|
|
244
|
-
});
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
#### `strict: true` - erros claros ✅
|
|
248
|
-
|
|
249
|
-
**Evidência**:
|
|
250
|
-
|
|
251
|
-
```typescript
|
|
252
|
-
it("requires usage when strict and inference fails", () => {
|
|
253
|
-
expect(() =>
|
|
254
|
-
normalizeQuery({ role: "brand.primary", output: { strict: true } }),
|
|
255
|
-
).toThrowError(/Provide usage explicitly/i);
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it("requires surface when strict and inference fails", () => {
|
|
259
|
-
expect(() =>
|
|
260
|
-
normalizeQuery({ role: "text.primary", output: { strict: true } }),
|
|
261
|
-
).toThrowError(/Provide surface explicitly/i);
|
|
262
|
-
});
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
#### Mensagens didáticas ✅
|
|
266
|
-
|
|
267
|
-
**Evidência** (linhas 235-238):
|
|
268
|
-
|
|
269
|
-
```typescript
|
|
270
|
-
const missingUsageMessage = (role: string) =>
|
|
271
|
-
`Usage is required for role: "${role}". Provide usage explicitly (e.g. { usage: "text" }) or use a role prefix like "text.", "icon.", "bg.", "border.", "ring."`;
|
|
272
|
-
|
|
273
|
-
const missingSurfaceMessage = (role: string) =>
|
|
274
|
-
`Surface is required for role: "${role}". Provide surface explicitly (e.g. { surface: "surface" }) or use a role pattern like "bg.app", "bg.surface", "app.*"`;
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
**Pontos positivos**:
|
|
278
|
-
|
|
279
|
-
- ✅ Explica o problema
|
|
280
|
-
- ✅ Mostra exemplo de correção
|
|
281
|
-
- ✅ Lista padrões válidos
|
|
282
|
-
|
|
283
|
-
#### Sugestões de correção ✅
|
|
284
|
-
|
|
285
|
-
Todas as mensagens incluem exemplos práticos:
|
|
286
|
-
|
|
287
|
-
- `{ usage: "text" }` ✅
|
|
288
|
-
- `{ surface: "surface" }` ✅
|
|
289
|
-
- Padrões de naming válidos ✅
|
|
290
|
-
|
|
291
|
-
---
|
|
292
|
-
|
|
293
|
-
### Validações ✅
|
|
294
|
-
|
|
295
|
-
#### Queries inválidos detectados ✅
|
|
296
|
-
|
|
297
|
-
**Evidência**:
|
|
298
|
-
|
|
299
|
-
- Strict mode valida `usage` obrigatório
|
|
300
|
-
- Strict mode valida `surface` obrigatório
|
|
301
|
-
- Testes cobrem casos de erro
|
|
302
|
-
|
|
303
|
-
#### Conflitos de inferência apontados ✅
|
|
304
|
-
|
|
305
|
-
**Evidência** (warnings explícitos):
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
warnInferenceOnce(
|
|
309
|
-
`usage:${role}`,
|
|
310
|
-
`Defaulting usage to "bg" for role: "${role}". ${missingUsageMessage(role)}`,
|
|
311
|
-
);
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
#### Fallbacks documentados ✅
|
|
315
|
-
|
|
316
|
-
**Evidência** (JSDoc atualizado):
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
/**
|
|
320
|
-
* - In strict mode, missing required fields throw actionable errors.
|
|
321
|
-
* - In non-strict mode, safe defaults are applied with explicit warnings.
|
|
322
|
-
*/
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
---
|
|
326
|
-
|
|
327
|
-
### Testes ✅
|
|
328
|
-
|
|
329
|
-
#### Inferência correta em casos comuns ✅
|
|
330
|
-
|
|
331
|
-
**Testes presentes**:
|
|
332
|
-
|
|
333
|
-
1. `infers usage from role prefixes` - 8 casos ✅
|
|
334
|
-
2. `infers surface when obvious` - 3 casos ✅
|
|
335
|
-
3. Background hint normalization mantida ✅
|
|
336
|
-
|
|
337
|
-
#### Inferência falha gracefully ✅
|
|
338
|
-
|
|
339
|
-
**Testes presentes**:
|
|
340
|
-
|
|
341
|
-
1. `warns when usage cannot be inferred in non-strict mode` ✅
|
|
342
|
-
2. `warns when surface cannot be inferred in non-strict mode` ✅
|
|
343
|
-
3. Mock de `console.warn` em testes relevantes ✅
|
|
344
|
-
|
|
345
|
-
#### Strict mode valida edge cases ✅
|
|
346
|
-
|
|
347
|
-
**Testes presentes**:
|
|
348
|
-
|
|
349
|
-
1. `requires usage when strict and inference fails` ✅
|
|
350
|
-
2. `requires surface when strict and inference fails` ✅
|
|
351
|
-
|
|
352
|
-
#### Mensagens de erro testadas ✅
|
|
353
|
-
|
|
354
|
-
**Evidência**:
|
|
355
|
-
|
|
356
|
-
```typescript
|
|
357
|
-
.toThrowError(/Provide usage explicitly/i);
|
|
358
|
-
.toThrowError(/Provide surface explicitly/i);
|
|
359
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
360
|
-
expect.stringContaining('Defaulting surface to "surface"'),
|
|
361
|
-
);
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
---
|
|
365
|
-
|
|
366
|
-
## ⚠️ OBSERVAÇÃO CRÍTICA
|
|
367
|
-
|
|
368
|
-
### Estado global mutável (`inferenceWarnings`)
|
|
369
|
-
|
|
370
|
-
**Localização**: `src/engine/normalize.ts` linha 227
|
|
371
|
-
|
|
372
|
-
**Problema**:
|
|
373
|
-
|
|
374
|
-
```typescript
|
|
375
|
-
const inferenceWarnings = new Set<string>();
|
|
376
|
-
|
|
377
|
-
const warnInferenceOnce = (key: string, message: string) => {
|
|
378
|
-
if (inferenceWarnings.has(key)) return;
|
|
379
|
-
inferenceWarnings.add(key); // ⚠️ Cresce indefinidamente
|
|
380
|
-
console.warn(message);
|
|
381
|
-
};
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
**Impacto**:
|
|
385
|
-
|
|
386
|
-
- ✅ Funciona bem em builds CLI (processo curto)
|
|
387
|
-
- ⚠️ **Memory leak** em long-running processes (servers, watch modes)
|
|
388
|
-
- ⚠️ Warnings nunca são resetados entre builds
|
|
389
|
-
|
|
390
|
-
**Cenários problemáticos**:
|
|
391
|
-
|
|
392
|
-
1. Server-side rendering com multiple renders
|
|
393
|
-
2. Dev server em watch mode
|
|
394
|
-
3. Testes com múltiplas execuções
|
|
395
|
-
|
|
396
|
-
**Sugestão 1** - Reset público:
|
|
397
|
-
|
|
398
|
-
```typescript
|
|
399
|
-
/**
|
|
400
|
-
* Clear inference warning cache.
|
|
401
|
-
* Call this between independent builds or test runs.
|
|
402
|
-
*/
|
|
403
|
-
export const resetInferenceWarnings = () => {
|
|
404
|
-
inferenceWarnings.clear();
|
|
405
|
-
};
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
**Sugestão 2** - Context-based (melhor):
|
|
409
|
-
|
|
410
|
-
```typescript
|
|
411
|
-
// Mover Set para dentro de createTheme ou normalizeQuery context
|
|
412
|
-
// Evitar estado global compartilhado
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
**Sugestão 3** - LRU cache:
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
// Limitar tamanho do Set (ex: máximo 1000 keys)
|
|
419
|
-
const MAX_WARNINGS = 1000;
|
|
420
|
-
|
|
421
|
-
const warnInferenceOnce = (key: string, message: string) => {
|
|
422
|
-
if (inferenceWarnings.size >= MAX_WARNINGS) {
|
|
423
|
-
inferenceWarnings.clear(); // Reset quando cheio
|
|
424
|
-
}
|
|
425
|
-
if (inferenceWarnings.has(key)) return;
|
|
426
|
-
inferenceWarnings.add(key);
|
|
427
|
-
console.warn(message);
|
|
428
|
-
};
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
**Decisão**: Não bloqueante para merge, mas deve ser endereçado em PR futuro.
|
|
432
|
-
|
|
433
|
-
---
|
|
434
|
-
|
|
435
|
-
## ⚠️ SUGESTÕES DE MELHORIA (Não bloqueantes)
|
|
436
|
-
|
|
437
|
-
### 1. JSDoc em funções helper de inferência
|
|
438
|
-
|
|
439
|
-
**Localização**: `src/engine/normalize.ts` linhas 169-202
|
|
440
|
-
|
|
441
|
-
**Código atual**:
|
|
442
|
-
|
|
443
|
-
```typescript
|
|
444
|
-
const inferSurfaceFromRole = (role: string): SurfaceIntent | undefined => {
|
|
445
|
-
// Sem JSDoc
|
|
446
|
-
};
|
|
447
|
-
|
|
448
|
-
const inferVariantFromRole = (role: string): SemanticVariant | undefined => {
|
|
449
|
-
// Sem JSDoc
|
|
450
|
-
};
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
**Sugestão**:
|
|
454
|
-
|
|
455
|
-
```typescript
|
|
456
|
-
/**
|
|
457
|
-
* Infer surface intent from role naming patterns.
|
|
458
|
-
*
|
|
459
|
-
* Recognizes:
|
|
460
|
-
* - Direct surface tokens: "app.*", "surface.*", "solid.*"
|
|
461
|
-
* - Background patterns: "bg.app", "bg.surface", "bg.solid"
|
|
462
|
-
*
|
|
463
|
-
* @example
|
|
464
|
-
* inferSurfaceFromRole("bg.app") // → "app"
|
|
465
|
-
* inferSurfaceFromRole("app.bg") // → "app"
|
|
466
|
-
* inferSurfaceFromRole("text.primary") // → undefined
|
|
467
|
-
*/
|
|
468
|
-
const inferSurfaceFromRole = (role: string): SurfaceIntent | undefined => {
|
|
469
|
-
// ... implementation
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* Infer semantic variant from role token.
|
|
474
|
-
*
|
|
475
|
-
* Recognizes:
|
|
476
|
-
* - Semantic variants: "success", "warning", "danger", "info"
|
|
477
|
-
* - Custom categories: "category:sales", "category:marketing"
|
|
478
|
-
* - Chart variants: "chart:revenue", "chart:expenses"
|
|
479
|
-
*
|
|
480
|
-
* @example
|
|
481
|
-
* inferVariantFromRole("success.bg") // → "success"
|
|
482
|
-
* inferVariantFromRole("category:sales.fill") // → "category:sales"
|
|
483
|
-
* inferVariantFromRole("text.primary") // → undefined
|
|
484
|
-
*/
|
|
485
|
-
const inferVariantFromRole = (role: string): SemanticVariant | undefined => {
|
|
486
|
-
// ... implementation
|
|
487
|
-
};
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
---
|
|
491
|
-
|
|
492
|
-
### 2. Teste para variant inference
|
|
493
|
-
|
|
494
|
-
**Motivação**: Código existe mas não há teste específico
|
|
495
|
-
|
|
496
|
-
**Sugestão**:
|
|
497
|
-
|
|
498
|
-
```typescript
|
|
499
|
-
it("infers variant from role token", () => {
|
|
500
|
-
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
|
|
501
|
-
|
|
502
|
-
try {
|
|
503
|
-
// Semantic variants
|
|
504
|
-
expect(normalizeQuery({ role: "success.bg" }).variant).toBe("success");
|
|
505
|
-
expect(normalizeQuery({ role: "warning.text" }).variant).toBe("warning");
|
|
506
|
-
expect(normalizeQuery({ role: "danger.border" }).variant).toBe("danger");
|
|
507
|
-
expect(normalizeQuery({ role: "info.icon" }).variant).toBe("info");
|
|
508
|
-
|
|
509
|
-
// Custom categories
|
|
510
|
-
expect(normalizeQuery({ role: "category:sales.fill" }).variant).toBe("category:sales");
|
|
511
|
-
expect(normalizeQuery({ role: "category:marketing.bg" }).variant).toBe("category:marketing");
|
|
512
|
-
|
|
513
|
-
// Chart variants
|
|
514
|
-
expect(normalizeQuery({ role: "chart:revenue.stroke" }).variant).toBe("chart:revenue");
|
|
515
|
-
expect(normalizeQuery({ role: "chart:expenses.fill" }).variant).toBe("chart:expenses");
|
|
516
|
-
|
|
517
|
-
// No inference
|
|
518
|
-
expect(normalizeQuery({ role: "text.primary" }).variant).toBeUndefined();
|
|
519
|
-
} finally {
|
|
520
|
-
warnSpy.mockRestore();
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
---
|
|
526
|
-
|
|
527
|
-
### 3. Documentar estratégia de deduplicação
|
|
528
|
-
|
|
529
|
-
**Localização**: `src/engine/normalize.ts` linha 227-233
|
|
530
|
-
|
|
531
|
-
**Sugestão**:
|
|
532
|
-
|
|
533
|
-
```typescript
|
|
534
|
-
/**
|
|
535
|
-
* Global cache to avoid duplicate inference warnings.
|
|
536
|
-
*
|
|
537
|
-
* WARNING: This Set grows indefinitely in long-running processes.
|
|
538
|
-
* Consider calling resetInferenceWarnings() between independent builds
|
|
539
|
-
* or moving to a context-based approach.
|
|
540
|
-
*
|
|
541
|
-
* @internal
|
|
542
|
-
*/
|
|
543
|
-
const inferenceWarnings = new Set<string>();
|
|
544
|
-
|
|
545
|
-
/**
|
|
546
|
-
* Emit a warning only once per unique key.
|
|
547
|
-
* Uses global cache to deduplicate across multiple normalizeQuery calls.
|
|
548
|
-
*
|
|
549
|
-
* @param key - Unique identifier for this warning (e.g., "usage:text.primary")
|
|
550
|
-
* @param message - Warning message to display
|
|
551
|
-
*/
|
|
552
|
-
const warnInferenceOnce = (key: string, message: string) => {
|
|
553
|
-
if (inferenceWarnings.has(key)) return;
|
|
554
|
-
inferenceWarnings.add(key);
|
|
555
|
-
console.warn(message);
|
|
556
|
-
};
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
---
|
|
560
|
-
|
|
561
|
-
### 4. Teste de integração com `createTheme`
|
|
562
|
-
|
|
563
|
-
**Motivação**: Inferência foi movida de `createTheme` para `normalize`, validar integração
|
|
564
|
-
|
|
565
|
-
**Sugestão**:
|
|
566
|
-
|
|
567
|
-
```typescript
|
|
568
|
-
// Em src/core/createTheme.test.ts
|
|
569
|
-
it("theme.color() uses inference from normalizeQuery", () => {
|
|
570
|
-
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
|
|
571
|
-
|
|
572
|
-
try {
|
|
573
|
-
const theme = createTheme({
|
|
574
|
-
seeds: { light: { neutral: "#111827", accent: "#3d63dd" }, dark: { neutral: "#111827", accent: "#3d63dd" } },
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
// Inferência de usage
|
|
578
|
-
const color1 = theme.color("text.primary");
|
|
579
|
-
expect(color1).toBeDefined();
|
|
580
|
-
|
|
581
|
-
// Inferência de surface
|
|
582
|
-
const color2 = theme.color("bg.app");
|
|
583
|
-
expect(color2).toBeDefined();
|
|
584
|
-
|
|
585
|
-
// Strict mode
|
|
586
|
-
expect(() =>
|
|
587
|
-
theme.color("brand.primary", { output: { strict: true } })
|
|
588
|
-
).toThrow(/Provide usage explicitly/i);
|
|
589
|
-
} finally {
|
|
590
|
-
warnSpy.mockRestore();
|
|
591
|
-
}
|
|
592
|
-
});
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
---
|
|
596
|
-
|
|
597
|
-
## ✅ VALIDAÇÕES NEGATIVAS
|
|
598
|
-
|
|
599
|
-
### O que NÃO deve acontecer ✅
|
|
600
|
-
|
|
601
|
-
- ✅ **Inferência silenciosa incorreta**: Warnings explícitos em non-strict
|
|
602
|
-
- ✅ **Erros crípticos**: Mensagens didáticas com exemplos
|
|
603
|
-
- ✅ **Strict mode permissivo**: Valida corretamente
|
|
604
|
-
- ✅ **Fallbacks inesperados**: Documentados em JSDoc e warnings
|
|
605
|
-
|
|
606
|
-
---
|
|
607
|
-
|
|
608
|
-
## 🎯 CHECKLIST FINAL
|
|
609
|
-
|
|
610
|
-
### Critérios Gerais
|
|
611
|
-
|
|
612
|
-
- ✅ Contratos e tipos (JSDoc atualizado)
|
|
613
|
-
- ✅ Qualidade de código (com sugestão de comentários)
|
|
614
|
-
- ✅ DX (mensagens acionáveis)
|
|
615
|
-
- ✅ Princípios v0.3
|
|
616
|
-
|
|
617
|
-
### Critérios Fase 8
|
|
618
|
-
|
|
619
|
-
- ✅ Inferência implementada (`usage`, `surface`, `variant`)
|
|
620
|
-
- ✅ Strict mode (`false`: warnings, `true`: errors)
|
|
621
|
-
- ✅ Validações (queries inválidos, conflitos, fallbacks)
|
|
622
|
-
- ✅ Testes (19 testes, cobertura abrangente)
|
|
623
|
-
|
|
624
|
-
### O que NÃO deve acontecer (Checklist) ✅
|
|
625
|
-
|
|
626
|
-
- ✅ Sem inferência silenciosa incorreta
|
|
627
|
-
- ✅ Sem erros crípticos
|
|
628
|
-
- ✅ Strict mode não permissivo
|
|
629
|
-
- ✅ Sem fallbacks inesperados
|
|
630
|
-
|
|
631
|
-
---
|
|
632
|
-
|
|
633
|
-
## 📊 VEREDICTO FINAL
|
|
634
|
-
|
|
635
|
-
**Status**: ✅ **APROVADO PARA MERGE** (com observação para PR futuro)
|
|
636
|
-
|
|
637
|
-
**Implementação robusta** que:
|
|
638
|
-
|
|
639
|
-
- Atende todos os critérios obrigatórios da Fase 8
|
|
640
|
-
- Possui testes abrangentes (19 testes, 6 novos)
|
|
641
|
-
- Mensagens de erro didáticas e acionáveis
|
|
642
|
-
- Inferência inteligente de `usage`, `surface` e `variant`
|
|
643
|
-
- Strict mode funcional com validações claras
|
|
644
|
-
|
|
645
|
-
**⚠️ Para endereçar em PR futuro** (não bloqueante):
|
|
646
|
-
|
|
647
|
-
1. **Crítico**: Resolver memory leak do `inferenceWarnings` Set global
|
|
648
|
-
- Sugestão: Adicionar método de reset ou mover para contexto
|
|
649
|
-
- Impacto: Long-running processes (SSR, dev servers)
|
|
650
|
-
|
|
651
|
-
**Sugestões opcionais**:
|
|
652
|
-
|
|
653
|
-
2. JSDoc em funções helper de inferência
|
|
654
|
-
3. Teste específico para variant inference
|
|
655
|
-
4. Documentar estratégia de deduplicação
|
|
656
|
-
5. Teste de integração com `createTheme`
|
|
657
|
-
|
|
658
|
-
**Parabéns pela implementação completa e bem testada!** 🎉
|
|
659
|
-
|
|
660
|
-
---
|
|
661
|
-
|
|
662
|
-
## 📚 Referências
|
|
663
|
-
|
|
664
|
-
- Guia de revisão: `.github/skills/review-guide/references/review-guide-v0.3.md`
|
|
665
|
-
- Fase 8 checklist: Linhas 439-469 do guia
|
|
666
|
-
- Arquivos revisados:
|
|
667
|
-
- `src/engine/normalize.ts` (+67 linhas, refactor de inferência)
|
|
668
|
-
- `src/engine/normalize.test.ts` (+58 linhas, 6 novos testes)
|
|
669
|
-
- `src/core/createTheme.ts` (-76 linhas, simplificação)
|