重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
component-flattening-analysis by tech-leads-club/agent-skills
npx skills add https://github.com/tech-leads-club/agent-skills --skill component-flattening-analysis此技能用于识别组件层次结构问题,确保组件仅作为目录/命名空间结构中的叶节点存在,并从根命名空间中移除孤立的类。
请求分析您的代码库:
示例 1:查找孤立类
User: "查找根命名空间中的孤立类"
该技能将:
1. 扫描组件命名空间以发现层次结构问题
2. 识别根命名空间中的孤立类
3. 检测构建在其他组件之上的组件
4. 建议扁平化策略
5. 创建重构计划
示例 2:扁平化组件
User: "扁平化此代码库中的组件层次结构"
该技能将:
1. 识别存在层次结构问题的组件
2. 分析孤立类
3. 建议合并或拆分策略
4. 创建重构计划
5. 估算工作量
示例 3:组件结构分析
User: "分析组件结构以发现层次结构问题"
该技能将:
1. 映射组件命名空间结构
2. 识别包含代码的根命名空间
3. 查找构建在组件之上的组件
4. 标记违反层次结构的情况
5. 提供建议
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
在以下情况下应用此技能:
组件由目录/命名空间结构中的叶节点标识:
关键规则:组件仅作为叶节点存在。如果一个命名空间被扩展,父级将变为子域,而不是组件。
根命名空间是一个已被扩展的命名空间节点:
ss.survey 扩展为 ss.survey.templatesss.survey 变为根命名空间(子域)孤立类是位于根命名空间中的源文件:
示例:
ss.survey/ ← 根命名空间(被 .templates 扩展)
├── Survey.js ← 孤立类(位于根命名空间)
└── templates/ ← 组件(叶节点)
└── Template.js
策略 1:向下合并
ss.survey.templates → ss.survey策略 2:向上拆分
ss.survey → ss.survey.create + ss.survey.process策略 3:移动共享代码
.shared 组件ss.survey 共享代码 → ss.survey.shared扫描目录/命名空间结构以识别层次结构:
映射命名空间树
识别根命名空间
定位源文件
示例结构映射:
## 组件结构映射
ss.survey/ ← 根命名空间(已扩展) ├── Survey.js ← 孤立类 ├── SurveyProcessor.js ← 孤立类 └── templates/ ← 组件(叶节点) ├── EmailTemplate.js └── SMSTemplate.js
ss.ticket/ ← 根命名空间(已扩展) ├── Ticket.js ← 孤立类 ├── assign/ ← 组件(叶节点) │ └── TicketAssign.js └── route/ ← 组件(叶节点) └── TicketRoute.js
查找根命名空间中的源文件:
扫描根命名空间
分类孤立类
评估影响
示例孤立类检测:
## 发现的孤立类
### 根命名空间:ss.survey
**孤立文件**(5 个文件):
- Survey.js(领域代码 - 调查创建)
- SurveyProcessor.js(领域代码 - 调查处理)
- SurveyValidator.js(共享代码 - 验证)
- SurveyFormatter.js(共享代码 - 格式化)
- SurveyConstants.js(共享代码 - 常量)
**分类**:
- 领域代码:2 个文件(应位于组件中)
- 共享代码:3 个文件(应位于 .shared 组件中)
**依赖关系**:被 ss.survey.templates 组件使用
为每个根命名空间确定最佳扁平化策略:
选项 1:向下合并
选项 2:向上拆分
选项 3:移动共享代码
.shared 组件示例扁平化分析:
## 扁平化选项分析
### 根命名空间:ss.survey
**当前状态**:
- 根命名空间:5 个孤立文件
- 叶组件:ss.survey.templates(7 个文件)
**选项 1:向下合并** ✅ 推荐
- 将模板代码移动到 ss.survey
- 结果:单一组件 ss.survey
- 工作量:低(移动 7 个文件)
- 理由:模板较小,与调查功能相关
**选项 2:向上拆分**
- 创建 ss.survey.create(2 个文件)
- 创建 ss.survey.process(1 个文件)
- 创建 ss.survey.shared(3 个文件)
- 保留 ss.survey.templates(7 个文件)
- 工作量:高(需要创建多个组件)
- 理由:更细粒度,但可能过度设计
**选项 3:移动共享代码**
- 创建 ss.survey.shared(3 个共享文件)
- 将领域代码保留在根命名空间(2 个文件)
- 保留 ss.survey.templates(7 个文件)
- 工作量:中等
- 理由:将共享代码与领域代码分离,但仍存在层次结构
为每个根命名空间生成重构计划:
选择策略
规划重构步骤
估算工作量
示例扁平化计划:
## 扁平化计划
### 优先级:高
**根命名空间:ss.survey**
**策略**:向下合并
**步骤**:
1. 将文件从 ss.survey.templates/ 移动到 ss.survey/
- EmailTemplate.js
- SMSTemplate.js
- [其他 5 个文件]
2. 更新依赖组件中的导入
- 将引用从 ss.survey.templates._ 更新为 ss.survey._
3. 删除 ss.survey.templates/ 目录
4. 更新命名空间声明
- 将命名空间从 ss.survey.templates 更改为 ss.survey
5. 运行测试以验证更改
**工作量**:2-3 天
**风险**:低(模板是自包含的)
**依赖关系**:无
执行重构:
移动文件
更新引用
验证更改
## 孤立类分析
### 根命名空间:ss.survey
**状态**:⚠️ 存在孤立类
**孤立文件**(5 个文件):
- Survey.js(领域代码)
- SurveyProcessor.js(领域代码)
- SurveyValidator.js(共享代码)
- SurveyFormatter.js(共享代码)
- SurveyConstants.js(共享代码)
**叶组件**:
- ss.survey.templates(7 个文件)
**问题**:根命名空间包含代码但被叶组件扩展
**建议**:将模板合并到根命名空间
## 组件层次结构问题
| 根命名空间 | 孤立文件 | 叶组件 | 问题 | 建议 |
| -------------- | -------------- | ------------------------------- | -------------------- | ---------------- |
| ss.survey | 5 | 1 (templates) | 存在孤立类 | 向下合并 |
| ss.ticket | 45 | 2 (assign, route) | 大量孤立代码 | 向上拆分 |
| ss.reporting | 0 | 3 (tickets, experts, financial) | 无问题 | ✅ 正常 |
## 扁平化计划
### 优先级:高
**ss.survey** → 向下合并
- 将 7 个文件从 templates 移动到根目录
- 工作量:2-3 天
- 风险:低
### 优先级:中等
**ss.ticket** → 向上拆分
- 创建 ss.ticket.maintenance(30 个文件)
- 创建 ss.ticket.completion(10 个文件)
- 创建 ss.ticket.shared(5 个文件)
- 工作量:1 周
- 风险:中等
结构映射:
孤立类检测:
扁平化分析:
计划创建:
执行:
组件通常位于 services/ 目录中:
services/
├── survey/ ← 根命名空间(已扩展)
│ ├── Survey.js ← 孤立类
│ └── templates/ ← 组件(叶节点)
│ └── Template.js
扁平化:
templates/ 文件移动到 survey/survey/create/ 和 survey/process/survey/shared/ 用于工具组件通过包结构标识:
com.company.survey ← 根包(已扩展)
├── Survey.java ← 孤立类
└── templates/ ← 组件(叶包)
└── Template.java
扁平化:
templates 类移动到 survey 包survey.create 和 survey.process 包survey.shared 包查找包含代码的根命名空间:
// 查找包含源文件的根命名空间
function findRootNamespacesWithCode(namespaces, sourceFiles) {
const rootNamespaces = namespaces.filter((ns) => {
// 检查命名空间是否已被扩展
const hasChildren = namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))
// 检查命名空间是否包含源文件
const hasFiles = sourceFiles.some((f) => f.namespace === ns)
return hasChildren && hasFiles
})
return rootNamespaces
}
查找孤立类:
// 查找根命名空间中的孤立类
function findOrphanedClasses(rootNamespaces, sourceFiles) {
const orphaned = []
rootNamespaces.forEach((rootNs) => {
const files = sourceFiles.filter((f) => f.namespace === rootNs)
orphaned.push({
rootNamespace: rootNs,
files: files,
count: files.length,
})
})
return orphaned
}
扁平化组件后,创建自动化检查:
// 如果根命名空间中存在源代码则发出警报
function checkRootNamespaceCode(namespaces, sourceFiles) {
const violations = []
namespaces.forEach((ns) => {
// 检查命名空间是否已被扩展
const hasChildren = namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))
if (hasChildren) {
// 检查命名空间是否包含源文件
const files = sourceFiles.filter((f) => f.namespace === ns)
if (files.length > 0) {
violations.push({
namespace: ns,
files: files.map((f) => f.name),
issue: '根命名空间包含源文件(孤立类)',
})
}
}
})
return violations
}
// 确保组件仅作为叶节点存在
function validateComponentStructure(namespaces, sourceFiles) {
const violations = []
// 查找所有叶节点(组件)
const leafNodes = namespaces.filter((ns) => {
return !namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))
})
// 检查所有源文件是否都在叶节点中
sourceFiles.forEach((file) => {
if (!leafNodes.includes(file.namespace)) {
violations.push({
file: file.name,
namespace: file.namespace,
issue: '源文件不在叶节点(组件)中',
})
}
})
return violations
}
.shared 组件之前:
ss.survey/
├── Survey.js ← 孤立类
└── templates/ ← 组件
└── Template.js
之后:
ss.survey/ ← 组件(叶节点)
├── Survey.js
└── Template.js
之前:
ss.ticket/ ← 根命名空间
├── Ticket.js ← 孤立类(45 个文件)
├── assign/ ← 组件
└── route/ ← 组件
之后:
ss.ticket/ ← 子域
├── maintenance/ ← 组件
│ └── Ticket.js
├── completion/ ← 组件
│ └── TicketCompletion.js
├── assign/ ← 组件
└── route/ ← 组件
之前:
ss.survey/ ← 根命名空间
├── Survey.js ← 领域代码
├── SurveyValidator.js ← 共享代码
└── templates/ ← 组件
之后:
ss.survey/ ← 组件
├── Survey.js
└── shared/ ← 组件
└── SurveyValidator.js
扁平化组件后:
每周安装次数
57
代码仓库
GitHub 星标数
2.0K
首次出现
2026年2月7日
安全审计
已安装于
opencode55
gemini-cli53
github-copilot53
codex53
cursor52
amp51
This skill identifies component hierarchy issues and ensures components exist only as leaf nodes in directory/namespace structures, removing orphaned classes from root namespaces.
Request analysis of your codebase:
Example 1: Find Orphaned Classes
User: "Find orphaned classes in root namespaces"
The skill will:
1. Scan component namespaces for hierarchy issues
2. Identify orphaned classes in root namespaces
3. Detect components built on top of other components
4. Suggest flattening strategies
5. Create refactoring plan
Example 2: Flatten Components
User: "Flatten component hierarchies in this codebase"
The skill will:
1. Identify components with hierarchy issues
2. Analyze orphaned classes
3. Suggest consolidation or splitting strategies
4. Create refactoring plan
5. Estimate effort
Example 3: Component Structure Analysis
User: "Analyze component structure for hierarchy issues"
The skill will:
1. Map component namespace structure
2. Identify root namespaces with code
3. Find components built on components
4. Flag hierarchy violations
5. Provide recommendations
Apply this skill when:
A component is identified by a leaf node in directory/namespace structure:
Key Rule : Components exist only as leaf nodes. If a namespace is extended, the parent becomes a subdomain, not a component.
A root namespace is a namespace node that has been extended:
ss.survey extended to ss.survey.templatesss.survey becomes a root namespace (subdomain)Orphaned classes are source files in root namespaces:
Example :
ss.survey/ ← Root namespace (extended by .templates)
├── Survey.js ← Orphaned class (in root namespace)
└── templates/ ← Component (leaf node)
└── Template.js
Strategy 1: Consolidate Down
ss.survey.templates → ss.surveyStrategy 2: Split Up
ss.survey → ss.survey.create + ss.survey.processStrategy 3: Move Shared Code
.shared componentss.survey shared code → ss.survey.sharedScan directory/namespace structure to identify hierarchy:
Map Namespace Tree
Identify Root Namespaces
Locate Source Files
Example Structure Mapping :
## Component Structure Map
ss.survey/ ← Root namespace (extended) ├── Survey.js ← Orphaned class ├── SurveyProcessor.js ← Orphaned class └── templates/ ← Component (leaf node) ├── EmailTemplate.js └── SMSTemplate.js
ss.ticket/ ← Root namespace (extended) ├── Ticket.js ← Orphaned class ├── assign/ ← Component (leaf node) │ └── TicketAssign.js └── route/ ← Component (leaf node) └── TicketRoute.js
Find source files in root namespaces:
Scan Root Namespaces
Classify Orphaned Classes
Assess Impact
Example Orphaned Class Detection :
## Orphaned Classes Found
### Root Namespace: ss.survey
**Orphaned Files** (5 files):
- Survey.js (domain code - survey creation)
- SurveyProcessor.js (domain code - survey processing)
- SurveyValidator.js (shared code - validation)
- SurveyFormatter.js (shared code - formatting)
- SurveyConstants.js (shared code - constants)
**Classification**:
- Domain Code: 2 files (should be in components)
- Shared Code: 3 files (should be in .shared component)
**Dependencies**: Used by ss.survey.templates component
Determine best flattening strategy for each root namespace:
Option 1: Consolidate Down
Option 2: Split Up
Option 3: Move Shared Code
.shared componentExample Flattening Analysis :
## Flattening Options Analysis
### Root Namespace: ss.survey
**Current State**:
- Root namespace: 5 orphaned files
- Leaf component: ss.survey.templates (7 files)
**Option 1: Consolidate Down** ✅ Recommended
- Move templates code into ss.survey
- Result: Single component ss.survey
- Effort: Low (7 files to move)
- Rationale: Templates are small, related to survey functionality
**Option 2: Split Up**
- Create ss.survey.create (2 files)
- Create ss.survey.process (1 file)
- Create ss.survey.shared (3 files)
- Keep ss.survey.templates (7 files)
- Effort: High (multiple components to create)
- Rationale: More granular, but may be over-engineering
**Option 3: Move Shared Code**
- Create ss.survey.shared (3 shared files)
- Keep domain code in root (2 files)
- Keep ss.survey.templates (7 files)
- Effort: Medium
- Rationale: Separates shared from domain, but still has hierarchy
Generate refactoring plan for each root namespace:
Select Strategy
Plan Refactoring Steps
Estimate Effort
Example Flattening Plan :
## Flattening Plan
### Priority: High
**Root Namespace: ss.survey**
**Strategy**: Consolidate Down
**Steps**:
1. Move files from ss.survey.templates/ to ss.survey/
- EmailTemplate.js
- SMSTemplate.js
- [5 more files]
2. Update imports in dependent components
- Update references from ss.survey.templates._ to ss.survey._
3. Remove ss.survey.templates/ directory
4. Update namespace declarations
- Change namespace from ss.survey.templates to ss.survey
5. Run tests to verify changes
**Effort**: 2-3 days
**Risk**: Low (templates are self-contained)
**Dependencies**: None
Perform the refactoring:
Move Files
Update References
Verify Changes
## Orphaned Classes Analysis
### Root Namespace: ss.survey
**Status**: ⚠️ Has Orphaned Classes
**Orphaned Files** (5 files):
- Survey.js (domain code)
- SurveyProcessor.js (domain code)
- SurveyValidator.js (shared code)
- SurveyFormatter.js (shared code)
- SurveyConstants.js (shared code)
**Leaf Components**:
- ss.survey.templates (7 files)
**Issue**: Root namespace contains code but is extended by leaf component
**Recommendation**: Consolidate templates into root namespace
## Component Hierarchy Issues
| Root Namespace | Orphaned Files | Leaf Components | Issue | Recommendation |
| -------------- | -------------- | ------------------------------- | -------------------- | ---------------- |
| ss.survey | 5 | 1 (templates) | Has orphaned classes | Consolidate down |
| ss.ticket | 45 | 2 (assign, route) | Large orphaned code | Split up |
| ss.reporting | 0 | 3 (tickets, experts, financial) | No issue | ✅ OK |
## Flattening Plan
### Priority: High
**ss.survey** → Consolidate Down
- Move 7 files from templates to root
- Effort: 2-3 days
- Risk: Low
### Priority: Medium
**ss.ticket** → Split Up
- Create ss.ticket.maintenance (30 files)
- Create ss.ticket.completion (10 files)
- Create ss.ticket.shared (5 files)
- Effort: 1 week
- Risk: Medium
Structure Mapping :
Orphaned Class Detection :
Flattening Analysis :
Plan Creation :
Execution :
Components typically in services/ directory:
services/
├── survey/ ← Root namespace (extended)
│ ├── Survey.js ← Orphaned class
│ └── templates/ ← Component (leaf node)
│ └── Template.js
Flattening :
templates/ files to survey/survey/create/ and survey/process/survey/shared/ for utilitiesComponents identified by package structure:
com.company.survey ← Root package (extended)
├── Survey.java ← Orphaned class
└── templates/ ← Component (leaf package)
└── Template.java
Flattening :
templates classes to survey packagesurvey.create and survey.process packagessurvey.shared packageFind Root Namespaces with Code :
// Find root namespaces containing source files
function findRootNamespacesWithCode(namespaces, sourceFiles) {
const rootNamespaces = namespaces.filter((ns) => {
// Check if namespace has been extended
const hasChildren = namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))
// Check if namespace contains source files
const hasFiles = sourceFiles.some((f) => f.namespace === ns)
return hasChildren && hasFiles
})
return rootNamespaces
}
Find Orphaned Classes :
// Find orphaned classes in root namespaces
function findOrphanedClasses(rootNamespaces, sourceFiles) {
const orphaned = []
rootNamespaces.forEach((rootNs) => {
const files = sourceFiles.filter((f) => f.namespace === rootNs)
orphaned.push({
rootNamespace: rootNs,
files: files,
count: files.length,
})
})
return orphaned
}
After flattening components, create automated checks:
// Alert if source code exists in root namespace
function checkRootNamespaceCode(namespaces, sourceFiles) {
const violations = []
namespaces.forEach((ns) => {
// Check if namespace has been extended
const hasChildren = namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))
if (hasChildren) {
// Check if namespace contains source files
const files = sourceFiles.filter((f) => f.namespace === ns)
if (files.length > 0) {
violations.push({
namespace: ns,
files: files.map((f) => f.name),
issue: 'Root namespace contains source files (orphaned classes)',
})
}
}
})
return violations
}
// Ensure components exist only as leaf nodes
function validateComponentStructure(namespaces, sourceFiles) {
const violations = []
// Find all leaf nodes (components)
const leafNodes = namespaces.filter((ns) => {
return !namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))
})
// Check that all source files are in leaf nodes
sourceFiles.forEach((file) => {
if (!leafNodes.includes(file.namespace)) {
violations.push({
file: file.name,
namespace: file.namespace,
issue: 'Source file not in leaf node (component)',
})
}
})
return violations
}
.shared componentsBefore :
ss.survey/
├── Survey.js ← Orphaned
└── templates/ ← Component
└── Template.js
After :
ss.survey/ ← Component (leaf node)
├── Survey.js
└── Template.js
Before :
ss.ticket/ ← Root namespace
├── Ticket.js ← Orphaned (45 files)
├── assign/ ← Component
└── route/ ← Component
After :
ss.ticket/ ← Subdomain
├── maintenance/ ← Component
│ └── Ticket.js
├── completion/ ← Component
│ └── TicketCompletion.js
├── assign/ ← Component
└── route/ ← Component
Before :
ss.survey/ ← Root namespace
├── Survey.js ← Domain code
├── SurveyValidator.js ← Shared code
└── templates/ ← Component
After :
ss.survey/ ← Component
├── Survey.js
└── shared/ ← Component
└── SurveyValidator.js
After flattening components:
Weekly Installs
57
Repository
GitHub Stars
2.0K
First Seen
Feb 7, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode55
gemini-cli53
github-copilot53
codex53
cursor52
amp51
Flutter/Dart代码审查最佳实践:提升应用性能与质量的完整检查清单
1,200 周安装