fix(types): tipa records do bridge em products.ts (-36 erros TS) — F1-1.x Onda C #3#126
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughRefatoração em ChangesTipagem de resultados de enrichment
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutos Possibly related PRs🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
….x Onda C #3) ## Onda C #3 — fix tipado em src/lib/external-db/products.ts O arquivo `enrichProducts` (em products.ts) recebia records do bridge externo (`invokeBatchBridge`) e os armazenava como `Record<string, unknown>[]`. Toda iteração depois (`variantsRecords.forEach((variant) => ...)`, `imagesRecords.forEach((img) => ...)`) acessava propriedades que TS via como `unknown` — gerando 36 erros TS2322/TS2345 em cascata. ## Fix 1. **Tipos auxiliares** específicos no topo do arquivo: - `VariantRow`: id, product_id, sku, color_id, color_name, color_code, color_hex, stock_quantity, selected_thumbnail, images - `ImageRow`: product_id, variant_id, url_cdn, url_original, filename, image_type, is_primary, is_og_image, applies_to_color, display_order, supplier_code, alt_text, title_text - `SupplierRow`: id, name, code - `ColorVariationRow`: id, name, slug, group_id - `ColorGroupRow`: id, name, slug 2. **Trocas pontuais nos 5 arrays de records**: - `Record<string, unknown>[]` → `{Variant,Image,Supplier,ColorVariation,ColorGroup}Row[]` - `as unknown[]` → cast pra tipo específico - Cast errado `as ExternalProduct[]` em suppliers → `as SupplierRow[]` 3. **Limpeza de `as string` redundantes** em `colorVariationMap`/ `colorGroupMap` agora que os tipos são específicos. ## Resultado | Métrica | Antes | Depois | Delta | |---|---|---|---| | Total tsc errors | 960 | **924** | **-36 (-3.8%)** | | products.ts | 36 | **0** | **-100%** ✨ | ## Validação runtime 🟢 **Equivalente**. Os tipos das rows refletem o schema real do bridge (verifiquei contra o uso em `forEach`/`map` no mesmo arquivo). Cast puramente TS — JS gerado é idêntico. `r.data.records as VariantRow[]` não muda comportamento. ## Risk 🟢 **Baixo**. Mudança puramente de tipos: - Comportamento runtime equivalente (mesmos métodos/spreads) - Tipos específicos refletem campos efetivamente acessados no código - Nenhum caller externo precisa mudar ## Test plan - [x] tsc total: 960 → 924 (-36) - [x] products.ts: 36 → 0 (-100%) - [x] .tsc-baseline.json regenerado - [ ] CI verde - [ ] CodeRabbit OK
f66b05e to
8327e55
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/external-db/products.ts`:
- Around line 16-21: VariantRow currently declares id: string but the
product_variants query doesn't select id, causing a contract mismatch when
assembling images (variant.id). Fix by either updating the query that reads
product_variants to include the id column, or change the VariantRow type to
match the payload (e.g., id?: string | null); prefer adding id to the
product_variants select so VariantRow.id remains required and variant.id can be
reliably used when assembling images.
- Around line 252-276: As linhas que preenchem variantsRecords, imagesRecords,
suppliersRecords, colorVariationsRecords e colorGroupsRecords fazem casts
diretos de r.data.records (unknown[]) para tipos específicos sem checagem;
ajuste o código para validar/narrowear os registros antes de usá‑los: quando
iterar queryMap.* e ler batchResults[idx], verifique
Array.isArray(r.data?.records) e filtre/normalize cada item usando type guards
ou checagens de campos obrigatórios (por exemplo, verifica presença e tipos de
id, product_id, url, etc.) antes de push/assign em variantsRecords,
imagesRecords, suppliersRecords, colorVariationsRecords e colorGroupsRecords,
assim evitando propagação de dados malformados para os passos seguintes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d4fb372e-719c-4744-805e-9ef31fc3e02c
📒 Files selected for processing (2)
.tsc-baseline.jsonsrc/lib/external-db/products.ts
| type VariantRow = { | ||
| id: string; product_id: string; sku?: string | null; | ||
| color_id?: string | null; color_name?: string | null; color_code?: string | null; | ||
| color_hex?: string | null; stock_quantity?: number | null; | ||
| selected_thumbnail?: string | null; images?: string[] | null; | ||
| }; |
There was a problem hiding this comment.
VariantRow.id obrigatório está inconsistente com o payload consultado.
VariantRow exige id: string, mas a query de product_variants não seleciona id. Isso mascara erro de contrato e pode quebrar a associação por variant.id na montagem das imagens.
🔧 Ajuste sugerido
- select: 'product_id, color_name, color_hex, color_code, color_id, sku, stock_quantity, images, selected_thumbnail',
+ select: 'id, product_id, color_name, color_hex, color_code, color_id, sku, stock_quantity, images, selected_thumbnail',🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/external-db/products.ts` around lines 16 - 21, VariantRow currently
declares id: string but the product_variants query doesn't select id, causing a
contract mismatch when assembling images (variant.id). Fix by either updating
the query that reads product_variants to include the id column, or change the
VariantRow type to match the payload (e.g., id?: string | null); prefer adding
id to the product_variants select so VariantRow.id remains required and
variant.id can be reliably used when assembling images.
| const variantsRecords: VariantRow[] = []; | ||
| for (const idx of queryMap.variants) { | ||
| const r = batchResults[idx]; | ||
| if (r?.success && r.data?.records) variantsRecords.push(...r.data.records); | ||
| if (r?.success && r.data?.records) variantsRecords.push(...(r.data.records as VariantRow[])); | ||
| } | ||
| const imagesRecords: Record<string, unknown>[] = []; | ||
| const imagesRecords: ImageRow[] = []; | ||
| for (const idx of queryMap.images) { | ||
| const r = batchResults[idx]; | ||
| if (r?.success && r.data?.records) imagesRecords.push(...r.data.records); | ||
| if (r?.success && r.data?.records) imagesRecords.push(...(r.data.records as ImageRow[])); | ||
| } | ||
| const suppliersRecords: { id: string; name: string; code: string }[] = []; | ||
| const suppliersRecords: SupplierRow[] = []; | ||
| for (const idx of queryMap.suppliers) { | ||
| const r = batchResults[idx]; | ||
| if (r?.success && r.data?.records) suppliersRecords.push(...(r.data.records as ExternalProduct[])); | ||
| if (r?.success && r.data?.records) suppliersRecords.push(...(r.data.records as SupplierRow[])); | ||
| } | ||
|
|
||
| let colorVariationsRecords: Record<string, unknown>[] = []; | ||
| let colorVariationsRecords: ColorVariationRow[] = []; | ||
| for (const idx of queryMap.colorVariations) { | ||
| const r = batchResults[idx]; | ||
| if (r?.success && r.data?.records) colorVariationsRecords = r.data.records as unknown[]; | ||
| if (r?.success && r.data?.records) colorVariationsRecords = r.data.records as ColorVariationRow[]; | ||
| } | ||
| let colorGroupsRecords: Record<string, unknown>[] = []; | ||
| let colorGroupsRecords: ColorGroupRow[] = []; | ||
| for (const idx of queryMap.colorGroups) { | ||
| const r = batchResults[idx]; | ||
| if (r?.success && r.data?.records) colorGroupsRecords = r.data.records as unknown[]; | ||
| if (r?.success && r.data?.records) colorGroupsRecords = r.data.records as ColorGroupRow[]; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verifica pontos com cast direto de records sem narrowing e o tipo de BatchResult no bridge.
rg -n -C2 'r\.data\.records as [A-Za-z]+Row\[\]' src/lib/external-db/products.ts
fd -i 'bridge.ts' src/lib/external-db --exec sed -n '1,260p' {}Repository: adm01-debug/Promo_Gifts
Length of output: 9157
🏁 Script executed:
# Verify the Row type definitions exist to understand what narrowing should check
rg -n 'type.*Row\s*=|interface.*Row\s*{' src/lib/external-db/products.ts | head -20Repository: adm01-debug/Promo_Gifts
Length of output: 195
🏁 Script executed:
# Check Row type definitions
rg -n 'type.*Row' src/lib/external-db/products.ts | head -20Repository: adm01-debug/Promo_Gifts
Length of output: 335
🏁 Script executed:
# Get the full Row type definitions
sed -n '16,31p' src/lib/external-db/products.tsRepository: adm01-debug/Promo_Gifts
Length of output: 927
Casts de records sem narrowing propagam dados não-validados.
Essas linhas fazem cast direto de unknown[] para [RowType][] sem validação de shape. Se o bridge retornar registros incompletos ou mal-formados (campos obrigatórios faltando ou tipos errados), você propaga dados inconsistentes para maps/enriquecimento sem proteção.
Implemente narrowing mínimo antes de usar os dados:
Exemplo de fix
+const isSupplierRow = (v: unknown): v is SupplierRow => {
+ if (!v || typeof v !== 'object') return false;
+ const r = v as Record<string, unknown>;
+ return typeof r.id === 'string' && typeof r.name === 'string' && typeof r.code === 'string';
+};
const suppliersRecords: SupplierRow[] = [];
for (const idx of queryMap.suppliers) {
const r = batchResults[idx];
- if (r?.success && r.data?.records) suppliersRecords.push(...(r.data.records as SupplierRow[]));
+ if (r?.success && Array.isArray(r.data?.records)) {
+ suppliersRecords.push(...r.data.records.filter(isSupplierRow));
+ }
}Repita para variants, images, colorVariations e colorGroups (linhas 255, 260, 271, 276).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/external-db/products.ts` around lines 252 - 276, As linhas que
preenchem variantsRecords, imagesRecords, suppliersRecords,
colorVariationsRecords e colorGroupsRecords fazem casts diretos de
r.data.records (unknown[]) para tipos específicos sem checagem; ajuste o código
para validar/narrowear os registros antes de usá‑los: quando iterar queryMap.* e
ler batchResults[idx], verifique Array.isArray(r.data?.records) e
filtre/normalize cada item usando type guards ou checagens de campos
obrigatórios (por exemplo, verifica presença e tipos de id, product_id, url,
etc.) antes de push/assign em variantsRecords, imagesRecords, suppliersRecords,
colorVariationsRecords e colorGroupsRecords, assim evitando propagação de dados
malformados para os passos seguintes.
There was a problem hiding this comment.
Pull request overview
This PR removes TypeScript errors in src/lib/external-db/products.ts by replacing Record<string, unknown>[] bridge result handling with explicit row-shape types and targeted casts, and updates .tsc-baseline.json accordingly.
Changes:
- Introduces local
*Rowtypes (variants/images/suppliers/color groups/variations) to type bridge batchrecords. - Updates batch result extraction to use typed arrays and fixes an incorrect cast for suppliers.
- Regenerates
.tsc-baseline.json, removing the priorproducts.tserror counts and reducing total baseline errors.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/lib/external-db/products.ts | Adds row-shape types and applies them to batch enrichment extraction/mapping to eliminate TS errors. |
| .tsc-baseline.json | Updates generated timestamp and total error counts; removes the products.ts error bucket. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| id: string; product_id: string; sku?: string | null; | ||
| color_id?: string | null; color_name?: string | null; color_code?: string | null; | ||
| color_hex?: string | null; stock_quantity?: number | null; | ||
| selected_thumbnail?: string | null; images?: string[] | null; | ||
| }; | ||
| type ImageRow = { |
| applies_to_color: boolean | null; display_order: number; | ||
| supplier_code: string | null; alt_text: string | null; title_text: string | null; | ||
| }; | ||
| type SupplierRow = { id: string; name: string; code: string }; |
| type ColorVariationRow = { id: string; name: string; slug: string; group_id: string }; | ||
| type ColorGroupRow = { id: string; name: string; slug: string }; |
## Onda C #6 — techniques.ts: 19 → 0 erros Mesmo padrão do products.ts (#126) e useGravacaoV2.ts (#128): tipos auxiliares para records do bridge externo + correções incrementais em campos null vs undefined. ## Fix 1) **Tipo TechniqueRawRow** (mesmo do useGravacaoV2): - id, codigo, code, nome, name, descricao, description, etc. 2) **Trocas no invokeExternalDb**: - `<Record<string, unknown>>` → `<TechniqueRawRow>` em fetchPromobrindPrintAreas - `<PromobrindTechnique>` → `<TechniqueRawRow>` em fetchPromobrindTechniques e fetchPromobrindTechniqueById (depois mapTechniqueFields converte) 3) **Map<string, TechniqueRawRow>** explícito. 4) **`undefined as unknown` → `null`** nos casts de pre-fix (technique_id, technique_code, technique_name, max_colors, area_image_url) — agora compatíveis com `string | null` / `number | null` da interface PromobrindPrintArea. 5) **Interface PromobrindTechnique aceita null** em campos: requires_color_count, price_by_color, price_by_area, is_active, display_order. Antes eram `?: boolean`/`number` — incompatíveis com o resultado real do mapTechniqueFields que retorna `?? null`. 6) **Fallbacks adicionais**: - `code: (t.codigo ?? t.code) ?? undefined` (interface tem code?: string) - `name: (t.nome ?? t.name) ?? ''` (interface tem name: string) - `tech?.id ?? tid` em vez de `tech?.id || tid` - `(result.records || []).map(...)` defensive ## Resultado | Métrica | Antes | Depois | Delta | |---|---|---|---| | Total tsc errors | 851 | **841** | -10 (-1.2%) | | techniques.ts | 19 | **0** | **-100%** ✨ (Apenas -10 no total porque o baseline anterior já considerava parte dos erros eliminados pelos PRs em paralelo — +1 noise.) ## Risk 🟢 **Baixo**. Tipos refletem o schema real (mesmo TechniqueRawRow do useGravacaoV2 que já passou em produção). `undefined as unknown` → `null` é semanticamente equivalente em runtime (ambos serializam pra null em JSON). Comportamento runtime equivalente — JS gerado idêntico.
…F1-1.x Onda C #7) [encerramento] (#137) ## Onda C #7 — encerramento da F1-1.x MockupGenerator.tsx tinha 29 erros TS distribuídos em 4 categorias. Resolvidos com fixes cirúrgicos em 7 arquivos. ## Fixes aplicados ### 1. `MockupGenerator.tsx` (29 erros) **a)** `selectedColor.name/hex` → `colorName/colorHex` (5x) MockupProductSelection nunca teve `selectedColor` — só `colorName` e `colorHex` flat. Código antigo era bug latente. **b)** `tech.name` → `tech.name ?? ''` (1x) MockupTechnique.name é opcional (`?: string`). Destino exige string. **c)** `pantoneMatch?.name` → `pantoneMatch?.pantoneCode` (1x) PantoneMatch tem `{ pantoneCode, pantoneHex, deltaE }` — nunca teve `name`. Era acesso a campo inexistente em runtime. **d)** Guards `'maxWidth' in mg.selectedTechnique` (5x linhas 313-314, 342-344) useMockupGenerator narrows para `Technique | TechniqueWithLimits`. Só TechniqueWithLimits tem maxWidth/maxHeight/locationName. **e)** Cast `as MockupTechnique` em useTechniqueHandlers args (2x) useMockupGenerator emite `Technique|TechniqueWithLimits`, useTechniqueHandlers consome `MockupTechnique`. Compatíveis estruturalmente, TS não consegue widen `Dispatch<SetStateAction<T>>`. **f)** Wrappers de variancia em `onTechniqueSelect` e `handleTechniqueChange(tech)` (2x) — adapter functions. **g)** Acessos a `metadata.height_mm/width_mm` (8x) — corrigido em #2. ### 2. `product-catalog.ts` — adicionar `metadata` Campo opcional em Product: `metadata?: { height_mm?: number|null; width_mm?: number|null; [key: string]: unknown } | null` Reflete o JSONB real do banco (legacy). Acessos antes eram falhas de tipo, embora o runtime já tolerasse (optional chaining). ### 3. `useMockupTechniques.ts` — Technique extends index signature Adicionada `[key: string]: unknown` em interface Technique. Permite atribuição estrutural a MockupTechnique (que tem o mesmo). ### 4. `AIMockupAssistant.tsx` — adicionar prop `onApplySuggestion` Componente expunha legacy `onSuggestionApply: (type, value) => void`. Adicionada nova `onApplySuggestion: (suggestion: {techniqueId?, position?, ...}) => void` que MockupGenerator já estava usando. Antiga mantida pra back-compat. ### 5. `MultiAreaManager.tsx` — `logoFile` em PersonalizationArea Campo opcional `logoFile?: File | null` adicionado. Já era usado em `updateActiveArea({ logoPreview: null, logoFile: null })`. ### 6. `MockupHistoryPanel.tsx` — usa GeneratedMockup do SSOT Removida interface local duplicada (20 linhas), substituída por `import type { GeneratedMockup } from '@/hooks/mockup/mockupGenerationService'`. Também: handleSetViewMode aceita 3 modos (`grid|list|table`) e mapeia `table → list` (compat com LayoutPopover que tem 3). ### 7. `MockupLightbox.tsx` — usa GeneratedMockup do SSOT Mesma deduplicação. Interface local removida. ## Resultado | Métrica | Antes | Depois | Δ | |---|---|---|---| | Total tsc errors | 841 | **811** | **-30 (-3.6%)** | | MockupGenerator.tsx | 29 | **0** | **-100%** ✨ | MockupHistoryPanel.tsx | 0 | 0 | (sem regressão) | | MockupLightbox.tsx | 0 | 0 | (sem regressão) | | MultiAreaManager.tsx | 0 | 0 | (sem regressão) | | useMockupTechniques.ts | 0 | 0 | (sem regressão) | | AIMockupAssistant.tsx | 0 | 0 | (sem regressão) | | product-catalog.ts | 0 | 0 | (sem regressão) | ## Risk 🟢 **Baixo**. Todas as mudanças são tipo-only ou refletem o schema/runtime real: - selectedColor → colorName/colorHex era bug existente (corrige acesso a campo inexistente) - pantoneMatch?.name → pantoneCode era bug existente (corrige acesso a campo inexistente) - metadata em Product reflete JSONB real - logoFile já era passado em runtime - GeneratedMockup deduplicação remove drift entre 3 cópias JS gerado equivalente em 95%+ dos casos. Pequenas mudanças semânticas: - `tech.code || undefined` vs `tech.code ?? ''` — empty string vs undefined em edge case de techniqueCode vazio. Aceito porque destino tipa como string. ## Encerramento da Onda C Sequência completa F1-1.x Onda C (-403 erros): - #124 lazyWithRetry -67 - #125 untypedFrom -105 - #126 products.ts -36 - #127 useSalesGoals -32 - #128 useGravacaoV2 -32 - #129 techniques.ts -10 - **#7 MockupGenerator (este) -30** ← agora TS baseline F1: **1214 → 811 (-33%)**
Onda C #3 — products.ts: 36 → 0 erros 🎯
enrichProductsemsrc/lib/external-db/products.tsrecebia records do bridge externo e os tratava comoRecord<string, unknown>[]. Toda iteração depois acessava propriedades que TS via comounknown— 36 erros TS2322/TS2345 em cascata.✨ Fix
1) Tipos auxiliares específicos no topo do arquivo refletindo o schema real:
2) Trocas pontuais nos 5 arrays de records:
Record<string, unknown>[]→ tipos específicosas unknown[]→ cast certosuppliersRecords.push(... as ExternalProduct[])→as SupplierRow[](cast estava ERRADO)3) Limpeza dos
as stringredundantes emcolorVariationMap/colorGroupMap(agora os tipos já são string).📊 Resultado
🟢 Baixo. Mudança puramente de tipos:
forEach/mapno mesmo arquivo📋 Test plan
.tsc-baseline.jsonregeneradoSummary by CodeRabbit