项目文件夹

文件
wehub-resource-sync 070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:00:47 +08:00

139 行
3.4 KiB
JavaScript
可执行文件

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
#!/usr/bin/env node
import fs from "node:fs";
import path from "node:path";
function usage() {
console.log(`Usage:
node scripts/init-clone.mjs <slug> [--url <url>] [--mode <mode>] [--level <L1-L6>] [--root <dir>] [--in-place]
Creates:
<root>/<slug>-clone/
<root>/<slug>-clone/NOTES.md
<root>/<slug>-clone/RECON/screenshots/
With --in-place, creates NOTES.md and RECON/screenshots/ in <root> itself.
`);
}
function parseArgs(argv) {
const out = { slug: null, url: "", mode: "", level: "", root: process.cwd(), inPlace: false };
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i];
if (arg === "--help" || arg === "-h") out.help = true;
else if (arg === "--url") out.url = argv[++i] || "";
else if (arg === "--mode") out.mode = argv[++i] || "";
else if (arg === "--level") out.level = argv[++i] || "";
else if (arg === "--root") out.root = argv[++i] || process.cwd();
else if (arg === "--in-place") out.inPlace = true;
else if (!out.slug) out.slug = arg;
else throw new Error(`Unexpected argument: ${arg}`);
}
return out;
}
function cleanSlug(input) {
return input
.trim()
.toLowerCase()
.replace(/https?:\/\//g, "")
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
}
function notesTemplate({ name, url, mode, level }) {
return `# ${name} · 克隆笔记
## 源信息
- 原站 URL: ${url}
- 源码仓库:
- 原作者:
- 许可证:
- 致谢要求:
## 技术栈
- 框架 / 关键库 / Node 版本:
## 复刻前预判
- 复杂度等级: ${level}
- 推荐模式: ${mode}
- 可高保真的部分:
- 需要近似或替代的部分:
- 不克隆的部分:
- 主要风险:
## 跑起来
\`\`\`bash
python3 -m http.server 8123
\`\`\`
## 改了什么(对照原版)
-
## 原站 vs 克隆站
| 模块 | 原站表现 | 克隆实现 | 差异 / 取舍 | 证据 |
|---|---|---|---|---|
| 首屏 | | | | |
| 导航 | | | | |
| 核心动效 | | | | |
| 内容区块 | | | | |
| 移动端 | | | | |
## 复刻评分
- 源证据: /5
- 结构保真: /5
- 视觉保真: /5
- 动效/交互: /5
- 响应式: /5
- 功能完整: /5
- 内容替换: /5
- 法务/部署风险: /5
- 总评:
## 替换地图(要换什么改哪)
- 文字 -> 文件 行
- 图片/媒体 -> 目录
- 配色 -> CSS 变量 / theme
- 3D 模型 / 字体 ->
## 验证
- [ ] 本地跑通、console 0 error
- [ ] 截图对照原站(RECON/screenshots/
- 验证不了的点(如实记,别伪造):
`;
}
try {
const args = parseArgs(process.argv.slice(2));
if (args.help || !args.slug) {
usage();
process.exit(args.help ? 0 : 1);
}
const slug = cleanSlug(args.slug);
if (!slug) throw new Error("Slug is empty after normalization.");
const name = slug.endsWith("-clone") ? slug : `${slug}-clone`;
const root = path.resolve(args.root || process.cwd());
const project = args.inPlace ? root : path.join(root, name);
if (!args.inPlace && fs.existsSync(project)) {
throw new Error(`Project already exists: ${project}`);
}
fs.mkdirSync(path.join(project, "RECON", "screenshots"), { recursive: true });
fs.writeFileSync(
path.join(project, "NOTES.md"),
notesTemplate({
name,
url: args.url,
mode: args.mode,
level: args.level,
})
);
fs.writeFileSync(path.join(project, ".gitignore"), "node_modules/\n.DS_Store\n");
console.log(project);
} catch (error) {
console.error(`init-clone failed: ${error.message}`);
process.exit(1);
}