code-quality

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Code Quality Review

代码质量审查

Review $ARGUMENTS (or the whole app if no argument is given) for code quality issues. Work through every step below in order and report all findings with file paths and line numbers.

审查**$ARGUMENTS**(若未提供参数则审查整个应用)的代码质量问题。按顺序完成以下每一步,并附上文件路径和行号报告所有发现。

Step 1 — Run the linter first

步骤1 — 先运行代码检查工具

Before reading any code manually, get a baseline from the automated tools:
bash
pnpm run lint
List every error and warning. Fix all errors before proceeding — lint errors are not negotiable. Warnings should be reviewed and resolved unless there is a documented exception.
Also run the TypeScript compiler in strict mode to surface any hidden type issues:
bash
pnpm exec tsc --noEmit
List every type error. These must be fixed.

在手动阅读代码前,先用自动化工具获取基准结果:
bash
pnpm run lint
列出所有错误和警告。继续下一步前需修复所有错误——代码检查错误不可协商。警告应进行审查并解决,除非有文档记录的例外情况。
同时以严格模式运行TypeScript编译器,排查潜在的类型问题:
bash
pnpm exec tsc --noEmit
列出所有类型错误,这些必须修复。

Step 2 — Eliminate
any
types

步骤2 — 消除
any
类型

Search for
any
usage across the codebase:
bash
grep -rn --include="*.ts" --include="*.tsx" -E ": any|as any|<any>" src/
For each hit, replace with the correct type. Common substitutions:
Instead ofUse
any
for unknown external data
unknown
+ type guard or Zod parse
any
for event handlers
React.ChangeEvent<HTMLInputElement>
,
React.MouseEvent
, etc.
any
for CDF responses
The SDK's own response types (import from
@cognite/sdk
)
any[]
for arrays
T[]
with the correct generic
as any
casts
Proper type narrowing or explicit overloaded function signature
The goal is zero
any
in
src/
. If a third-party library forces it, wrap the call in a typed adapter function so
any
does not leak into the app.

在整个代码库中搜索
any
的用法:
bash
grep -rn --include="*.ts" --include="*.tsx" -E ": any|as any|<any>" src/
针对每个匹配项,替换为正确的类型。常见替换方案:
避免使用推荐使用
用于未知外部数据的
any
unknown
+ 类型守卫或Zod解析
用于事件处理器的
any
React.ChangeEvent<HTMLInputElement>
React.MouseEvent
用于CDF响应的
any
SDK自身的响应类型(从
@cognite/sdk
导入)
用于数组的
any[]
带有正确泛型的
T[]
as any
类型转换
正确的类型收窄或显式重载函数签名
目标是
src/
目录中零
any
类型。如果第三方库强制使用
any
,请将调用包装在类型适配器函数中,避免
any
泄漏到应用内部。

Step 3 — Check component size and single responsibility

步骤3 — 检查组件大小与单一职责

List all
.tsx
files with their line counts:
bash
node -e "const fs=require('fs'),path=require('path');function walk(d){return fs.readdirSync(d,{withFileTypes:true}).flatMap(e=>{const p=path.join(d,e.name);return e.isDirectory()?walk(p):p.endsWith('.tsx')?[p]:[]})}walk('src').map(p=>({p,l:fs.readFileSync(p,'utf8').split('\n').length})).sort((a,b)=>b.l-a.l).forEach(({l,p})=>console.log(l,p))"
Flag every component file over 150 lines. For each, read it and check:
  • Does it do more than one thing? (fetch data AND render UI AND handle form state)
  • Can the fetch logic move to a custom hook (
    useAssetData
    )?
  • Can sub-sections be extracted as named sub-components?
Apply the split only when it creates a genuinely cleaner separation — do not split for the sake of line count alone. A well-named 200-line component is better than three poorly-named 60-line ones.

列出所有
.tsx
文件及其行数:
bash
node -e "const fs=require('fs'),path=require('path');function walk(d){return fs.readdirSync(d,{withFileTypes:true}).flatMap(e=>{const p=path.join(d,e.name);return e.isDirectory()?walk(p):p.endsWith('.tsx')?[p]:[]})}walk('src').map(p=>({p,l:fs.readFileSync(p,'utf8').split('\n').length})).sort((a,b)=>b.l-a.l).forEach(({l,p})=>console.log(l,p))"
标记所有超过150行的组件文件。针对每个标记的文件,检查以下内容:
  • 它是否承担了多项职责?(同时获取数据、渲染UI、处理表单状态)
  • 是否可以将获取逻辑移至自定义Hook(如
    useAssetData
    )?
  • 是否可以将子部分提取为命名子组件?
仅当拆分能真正实现更清晰的职责分离时才进行拆分——不要单纯为了行数而拆分。一个命名规范的200行组件比三个命名混乱的60行组件更好。

Step 4 — Find and remove duplicate logic (DRY)

步骤4 — 查找并移除重复逻辑(遵循DRY原则)

Search for copy-pasted patterns across hooks, utilities, and components:
bash
undefined
在Hook、工具函数和组件中搜索复制粘贴的模式:
bash
undefined

Find repeated fetch patterns

查找重复的获取数据模式

grep -rn --include=".ts" --include=".tsx" -E "sdk.(assets|timeseries|events|files).(list|retrieve)" src/
grep -rn --include=".ts" --include=".tsx" -E "sdk.(assets|timeseries|events|files).(list|retrieve)" src/

Find repeated formatting functions

查找重复的格式化函数

grep -rn --include=".ts" --include=".tsx" -E "toLocaleDateString|toLocaleString|new Date(" src/
grep -rn --include=".ts" --include=".tsx" -E "toLocaleDateString|toLocaleString|new Date(" src/

Find repeated className strings longer than 40 chars

查找超过40字符的重复className字符串

grep -rn --include="*.tsx" -E 'className="[^"]{40,}"' src/

For each set of duplicates:
- Extract to `src/utils/` if it is a pure function
- Extract to `src/hooks/` if it contains React state or effects
- Extract to a shared component if it is JSX

---
grep -rn --include="*.tsx" -E 'className="[^"]{40,}"' src/

针对每组重复逻辑:
- 如果是纯函数,提取至`src/utils/`目录
- 如果包含React状态或副作用,提取至`src/hooks/`目录
- 如果是JSX代码,提取为共享组件

---

Step 5 — Enforce dependency injection for external calls

步骤5 — 强制外部调用使用依赖注入

Components and hooks must not import the CDF client directly. The SDK client must be obtained from context (via
useCogniteClient()
or a prop) so the component is testable in isolation.
bash
grep -rn --include="*.ts" --include="*.tsx" -E "new CogniteClient|createCogniteClient" src/
Flag any direct client construction outside of the app's bootstrap / auth setup file. The pattern should always be:
ts
// GOOD — client comes from context
export function useMyData() {
  const sdk = useCogniteClient(); // from Dune auth context
  // ...
}

// BAD — direct construction inside a hook or component
const sdk = new CogniteClient({ project: "my-project", ... });
Similarly, Atlas tools should receive their dependencies via
execute
's closure over a hook-provided ref, not by importing a global singleton.

组件和Hook不得直接导入CDF客户端。SDK客户端必须从上下文获取(通过
useCogniteClient()
或props),以便组件可独立测试。
bash
grep -rn --include="*.ts" --include="*.tsx" -E "new CogniteClient|createCogniteClient" src/
标记所有在应用启动/认证设置文件之外直接构造客户端的情况。正确的模式应始终为:
ts
// 良好实践 — 客户端来自上下文
export function useMyData() {
  const sdk = useCogniteClient(); // 来自Dune认证上下文
  // ...
}

// 不良实践 — 在Hook或组件内部直接构造客户端
const sdk = new CogniteClient({ project: "my-project", ... });
类似地,Atlas工具应通过
execute
的闭包从Hook提供的ref获取依赖,而非导入全局单例。

Step 6 — Check naming conventions

步骤6 — 检查命名规范

Read a representative sample of files and verify:
ArtifactConventionExamples
Files & directories
kebab-case
asset-panel.tsx
,
use-asset-data.ts
React components
PascalCase
AssetPanel
,
NavigationBar
Variables, functions, hooks
camelCase
isLoading
,
fetchAssets
,
useAssetData
Constants (module-level)
SCREAMING_SNAKE_CASE
MAX_ITEMS
,
AGENT_EXTERNAL_ID
TypeScript types & interfaces
PascalCase
AssetNode
,
ChartConfig
Boolean variablesAuxiliary verb prefix
isLoading
,
hasError
,
canEdit
Search for common violations:
bash
undefined
读取代表性的文件样本,验证以下规范:
类型规范示例
文件与目录
kebab-case
(短横线分隔)
asset-panel.tsx
use-asset-data.ts
React组件
PascalCase
(大驼峰)
AssetPanel
NavigationBar
变量、函数、Hook
camelCase
(小驼峰)
isLoading
fetchAssets
useAssetData
常量(模块级)
SCREAMING_SNAKE_CASE
(大写蛇形)
MAX_ITEMS
AGENT_EXTERNAL_ID
TypeScript类型与接口
PascalCase
(大驼峰)
AssetNode
ChartConfig
布尔变量辅助动词前缀
isLoading
hasError
canEdit
搜索常见违规情况:
bash
undefined

TSX components not in PascalCase (filename starts with lowercase)

未使用大驼峰命名的TSX组件(文件名以小写开头)

node -e "const fs=require('fs'),path=require('path');function walk(d){return fs.readdirSync(d,{withFileTypes:true}).flatMap(e=>{const p=path.join(d,e.name);return e.isDirectory()?walk(p):p.endsWith('.tsx')?[p]:[]})}walk('src').filter(p=>/^[a-z]/.test(path.basename(p))).forEach(p=>console.log(p))"
node -e "const fs=require('fs'),path=require('path');function walk(d){return fs.readdirSync(d,{withFileTypes:true}).flatMap(e=>{const p=path.join(d,e.name);return e.isDirectory()?walk(p):p.endsWith('.tsx')?[p]:[]})}walk('src').filter(p=>/^[a-z]/.test(path.basename(p))).forEach(p=>console.log(p))"

Hook files not prefixed with "use"

未以"use"开头的Hook文件

node -e "const fs=require('fs');fs.readdirSync('src/hooks').filter(f=>f.endsWith('.ts')&&!f.startsWith('use')).forEach(f=>console.log('src/hooks/'+f))"

---
node -e "const fs=require('fs');fs.readdirSync('src/hooks').filter(f=>f.endsWith('.ts')&&!f.startsWith('use')).forEach(f=>console.log('src/hooks/'+f))"

---

Step 7 — Remove dead code

步骤7 — 移除死代码

powershell
undefined
powershell
undefined

Find commented-out code blocks (3+ consecutive commented lines)

查找注释掉的代码块(连续3行及以上注释)

Get-ChildItem -Recurse -Include ".ts",".tsx" src | ForEach-Object { $file = $_; $lines = Get-Content $file.FullName $count = 0; $startLine = 0 for ($i = 0; $i -lt $lines.Count; $i++) { if ($lines[$i] -match '^\s*//') { if ($count -eq 0) { $startLine = $i + 1 } $count++ } else { if ($count -ge 3) { "$($file.FullName):$startLine — $count consecutive comment lines" } $count = 0 } } if ($count -ge 3) { "$($file.FullName):$startLine — $count consecutive comment lines" } }
Get-ChildItem -Recurse -Include ".ts",".tsx" src | ForEach-Object { $file = $_; $lines = Get-Content $file.FullName $count = 0; $startLine = 0 for ($i = 0; $i -lt $lines.Count; $i++) { if ($lines[$i] -match '^\s*//') { if ($count -eq 0) { $startLine = $i + 1 } $count++ } else { if ($count -ge 3) { "$($file.FullName):$startLine — $count consecutive comment lines" } $count = 0 } } if ($count -ge 3) { "$($file.FullName):$startLine — $count consecutive comment lines" } }

Find console.log/debug statements

查找console.log/debug语句

grep -rn --include=".tsx" --include=".ts" -E "console.(log|debug|warn|error|info)" src/
grep -rn --include=".tsx" --include=".ts" -E "console.(log|debug|warn|error|info)" src/

Find TODO/FIXME/HACK comments

查找TODO/FIXME/HACK注释

grep -rn --include=".tsx" --include=".ts" -E "(TODO|FIXME|HACK|XXX):" src/

Rules:
- `console.log` and `console.debug` must be removed before shipping (use proper error logging for `console.error`).
- Commented-out code blocks must be removed — version control preserves history.
- `TODO` and `FIXME` comments older than the current sprint should be resolved or converted to tracked issues.
- Unused imports are caught by the linter (Step 1); confirm they are gone.

---
grep -rn --include=".tsx" --include=".ts" -E "(TODO|FIXME|HACK|XXX):" src/

规则:
- 上线前必须移除`console.log`和`console.debug`(`console.error`需使用正规错误日志工具)。
- 注释掉的代码块必须移除——版本控制会保留历史记录。
- 早于当前迭代的`TODO`和`FIXME`注释应被解决或转换为跟踪工单。
- 未使用的导入会被代码检查工具(步骤1)捕获;确认已移除。

---

Step 8 — Verify file and export structure

步骤8 — 验证文件与导出结构

Every feature area should follow a consistent structure. Check that the app's layout matches this pattern:
src/
├── components/         # Shared presentational components
│   └── <name>/
│       ├── <name>.tsx
│       └── index.ts    # re-exports the public API
├── hooks/              # Custom hooks (each file = one hook)
├── utils/              # Pure utility functions (no React)
├── contexts/           # React context providers
├── pages/ or views/    # Route-level components
└── types/              # Shared TypeScript types
Flag:
  • Business logic sitting directly in page components (should be in hooks)
  • Utility functions living inside component files (should be in
    utils/
    )
  • Types defined inline in component files when they are used across multiple files (should be in
    types/
    )
  • Missing
    index.ts
    barrel files for component directories (makes imports verbose)

每个功能区域应遵循一致的结构。检查应用布局是否符合以下模式:
src/
├── components/         # 共享展示组件
│   └── <name>/
│       ├── <name>.tsx
│       └── index.ts    # 重导出公共API
├── hooks/              # 自定义Hook(每个文件对应一个Hook)
├── utils/              # 纯工具函数(无React依赖)
├── contexts/           # React上下文提供者
├── pages/ or views/    # 路由级组件
└── types/              # 共享TypeScript类型
标记以下问题:
  • 业务逻辑直接写在页面组件中(应移至Hook)
  • 工具函数存放在组件文件内(应移至
    utils/
  • 跨多个文件使用的类型在组件文件内定义(应移至
    types/
  • 组件目录缺少
    index.ts
    桶文件(会导致导入语句冗长)

Step 9 — Report findings

步骤9 — 报告发现结果

Produce a structured report grouped by category:
CategoryFileLineIssueRecommendation
TypeScript
src/hooks/useData.ts
18
response as any
cast
Import and use
NodeItem
type from
@cognite/sdk
Size
src/components/Dashboard.tsx
340 lines, mixes fetch and render logicExtract
useDashboardData
hook (~120 lines)
DRY
src/components/A.tsx
,
src/components/B.tsx
45, 62Identical date formatterExtract to
src/utils/formatDate.ts
Naming
src/hooks/data.ts
File name does not start with
use
Rename to
useData.ts
Dead code
src/App.tsx
88
console.log("debug response", data)
Remove
If no issues are found in a step, state "No issues found" for that step. Do not skip steps silently.

生成按类别分组的结构化报告:
问题类别文件路径行号问题描述修复建议
TypeScript
src/hooks/useData.ts
18使用
response as any
类型转换
@cognite/sdk
导入并使用
NodeItem
类型
组件大小
src/components/Dashboard.tsx
共340行,混合了数据获取与渲染逻辑提取
useDashboardData
Hook(约120行)
DRY原则
src/components/A.tsx
,
src/components/B.tsx
45, 62存在相同的日期格式化函数提取至
src/utils/formatDate.ts
命名规范
src/hooks/data.ts
文件名未以
use
开头
重命名为
useData.ts
死代码
src/App.tsx
88存在
console.log("debug response", data)
移除该语句
若某一步未发现问题,需明确标注“未发现问题”,不得跳过步骤不说明。

Done

完成

Summarize the total number of findings by category and list the highest-impact items to address first. Any
any
type and lint error must be treated as blocking — list these separately.
按类别总结发现的问题总数,并列出需优先处理的高影响项。所有
any
类型和代码检查错误必须视为阻塞性问题——单独列出这些问题。