chore: 安全升级并完善 CI/测试
- 升级 js-yaml 修复生产依赖漏洞 - 新增 CI:lint/test/build - 增加书签处理单测与可测性导出"- 生成器补充 config/user 缺失提示 - 增加 lint/format/check 脚本与 Prettier 配置 - 统一行尾策略并支持书签确定性输出"
This commit is contained in:
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
15
.gitattributes
vendored
15
.gitattributes
vendored
@@ -1,2 +1,15 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
|
||||||
* text=auto
|
* text=auto
|
||||||
|
|
||||||
|
*.js text eol=lf
|
||||||
|
*.json text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.css text eol=lf
|
||||||
|
*.html text eol=lf
|
||||||
|
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.ico binary
|
||||||
|
|||||||
31
.github/workflows/ci.yml
vendored
Normal file
31
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '18'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
- name: Unit tests
|
||||||
|
run: npm test
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: npm run build
|
||||||
13
.github/workflows/deploy.yml
vendored
13
.github/workflows/deploy.yml
vendored
@@ -50,6 +50,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Process bookmark files
|
- name: Process bookmark files
|
||||||
if: steps.check_bookmark_files.outputs.found == 'true'
|
if: steps.check_bookmark_files.outputs.found == 'true'
|
||||||
|
env:
|
||||||
|
MENAV_BOOKMARKS_DETERMINISTIC: '1'
|
||||||
run: |
|
run: |
|
||||||
echo "Processing bookmark files..."
|
echo "Processing bookmark files..."
|
||||||
node src/bookmark-processor.js
|
node src/bookmark-processor.js
|
||||||
@@ -98,7 +100,16 @@ jobs:
|
|||||||
git commit -m "Add bookmarks configuration from imported bookmarks"
|
git commit -m "Add bookmarks configuration from imported bookmarks"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Also check for navigation file changes
|
# Also check for site.yml changes(导航已合并到 site.yml)
|
||||||
|
if [ -f config/user/site.yml ]; then
|
||||||
|
if ! git diff --quiet config/user/site.yml; then
|
||||||
|
echo "config/user/site.yml has changes, committing..."
|
||||||
|
git add config/user/site.yml
|
||||||
|
git commit -m "Update site configuration for bookmarks"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Also check for legacy navigation file changes
|
||||||
if [ -f config/user/navigation.yml ]; then
|
if [ -f config/user/navigation.yml ]; then
|
||||||
if ! git diff --quiet config/user/navigation.yml; then
|
if ! git diff --quiet config/user/navigation.yml; then
|
||||||
echo "config/user/navigation.yml has changes, committing..."
|
echo "config/user/navigation.yml has changes, committing..."
|
||||||
|
|||||||
7
.prettierrc.json
Normal file
7
.prettierrc.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 100,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false
|
||||||
|
}
|
||||||
22
README.md
22
README.md
@@ -265,6 +265,10 @@ npm install
|
|||||||
```bash
|
```bash
|
||||||
npm run import-bookmarks
|
npm run import-bookmarks
|
||||||
```
|
```
|
||||||
|
- 若希望生成结果保持确定性(便于版本管理,减少时间戳导致的无意义 diff):
|
||||||
|
```bash
|
||||||
|
MENAV_BOOKMARKS_DETERMINISTIC=1 npm run import-bookmarks
|
||||||
|
```
|
||||||
- 系统会自动将书签转换为配置文件保存到`config/user/pages/bookmarks.yml`
|
- 系统会自动将书签转换为配置文件保存到`config/user/pages/bookmarks.yml`
|
||||||
- **注意**:`npm run dev`命令不会自动处理书签文件,必须先手动运行上述命令
|
- **注意**:`npm run dev`命令不会自动处理书签文件,必须先手动运行上述命令
|
||||||
|
|
||||||
@@ -281,6 +285,19 @@ npm run build
|
|||||||
|
|
||||||
构建后的文件位于`dist`目录
|
构建后的文件位于`dist`目录
|
||||||
|
|
||||||
|
6. 提交前检查(推荐)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 一键检查(语法检查 + 单元测试 + 构建)
|
||||||
|
npm run check
|
||||||
|
```
|
||||||
|
|
||||||
|
(可选)格式化代码:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run format
|
||||||
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## 部署方式
|
## 部署方式
|
||||||
@@ -413,7 +430,8 @@ MeNav使用模块化配置方式,将配置分散到多个文件中,更易于
|
|||||||
* **创建配置目录**:
|
* **创建配置目录**:
|
||||||
- 在`config/user/`目录下创建您的自定义配置文件
|
- 在`config/user/`目录下创建您的自定义配置文件
|
||||||
- 可以参考项目结构中的`config/_default/`目录结构
|
- 可以参考项目结构中的`config/_default/`目录结构
|
||||||
- 至少需要创建`site.yml`
|
- 至少需要创建`site.yml`(缺失时构建会直接报错退出,避免生成空白站点)
|
||||||
|
- 首次使用建议先完整复制 `config/_default/` 到 `config/user/`,再按需修改(因为配置采用“完全替换”策略,不会从默认配置补齐缺失项)
|
||||||
|
|
||||||
### 配置详解
|
### 配置详解
|
||||||
|
|
||||||
@@ -745,6 +763,8 @@ MeNav支持从浏览器导入书签,快速批量添加网站链接,无需手
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
> 💡 *版本管理建议*:若你希望每次导入书签生成的 `bookmarks.yml` 内容保持确定性(避免因时间戳导致的无意义 diff),可在运行导入时设置环境变量:`MENAV_BOOKMARKS_DETERMINISTIC=1`。
|
||||||
|
|
||||||
> 生成的配置可在`config/user/pages/bookmarks.yml`中查看和编辑
|
> 生成的配置可在`config/user/pages/bookmarks.yml`中查看和编辑
|
||||||
|
|
||||||
## 常见问题
|
## 常见问题
|
||||||
|
|||||||
31
package-lock.json
generated
31
package-lock.json
generated
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "menav",
|
"name": "menav",
|
||||||
"version": "1.2.3",
|
"version": "1.3.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "menav",
|
"name": "menav",
|
||||||
"version": "1.2.3",
|
"version": "1.3.0",
|
||||||
"license": "MIT",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^6.0.1",
|
"ansi-regex": "^6.0.1",
|
||||||
"ansi-styles": "^6.2.1",
|
"ansi-styles": "^6.2.1",
|
||||||
@@ -15,11 +15,12 @@
|
|||||||
"color-name": "^2.0.0",
|
"color-name": "^2.0.0",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.8",
|
||||||
"has-flag": "^5.0.1",
|
"has-flag": "^5.0.1",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.1",
|
||||||
"mime-db": "^1.52.0",
|
"mime-db": "^1.52.0",
|
||||||
"supports-color": "^9.4.0"
|
"supports-color": "^9.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"prettier": "^3.4.2",
|
||||||
"serve": "^14.2.1"
|
"serve": "^14.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -646,9 +647,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
@@ -821,6 +822,22 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "3.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
|
||||||
|
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin/prettier.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -9,7 +9,12 @@
|
|||||||
"dev": "node src/generator.js && serve dist -l 5173",
|
"dev": "node src/generator.js && serve dist -l 5173",
|
||||||
"clean": "node ./scripts/clean.js",
|
"clean": "node ./scripts/clean.js",
|
||||||
"build": "npm run clean && npm run generate",
|
"build": "npm run clean && npm run generate",
|
||||||
"import-bookmarks": "node src/bookmark-processor.js"
|
"import-bookmarks": "node src/bookmark-processor.js",
|
||||||
|
"test": "node --test test/*.js",
|
||||||
|
"lint": "node --check \"src/generator.js\" && node --check \"src/bookmark-processor.js\" && node --check \"src/script.js\"",
|
||||||
|
"format": "prettier --write \"src/**/*.js\" \"scripts/**/*.js\" \"test/**/*.js\" \".github/**/*.yml\" \"*.{md,json}\" \"config/**/*.md\" \"config/**/*.yml\"",
|
||||||
|
"format:check": "prettier --check \"src/**/*.js\" \"scripts/**/*.js\" \"test/**/*.js\" \".github/**/*.yml\" \"*.{md,json}\" \"config/**/*.md\" \"config/**/*.yml\"",
|
||||||
|
"check": "npm run lint && npm test && npm run build"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"navigation",
|
"navigation",
|
||||||
@@ -19,7 +24,7 @@
|
|||||||
"author": "Your Name",
|
"author": "Your Name",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.1",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.8",
|
||||||
"ansi-regex": "^6.0.1",
|
"ansi-regex": "^6.0.1",
|
||||||
"ansi-styles": "^6.2.1",
|
"ansi-styles": "^6.2.1",
|
||||||
@@ -30,6 +35,7 @@
|
|||||||
"mime-db": "^1.52.0"
|
"mime-db": "^1.52.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"prettier": "^3.4.2",
|
||||||
"serve": "^14.2.1"
|
"serve": "^14.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -714,11 +714,15 @@ function generateBookmarksYaml(bookmarks) {
|
|||||||
quotingType: '"'
|
quotingType: '"'
|
||||||
});
|
});
|
||||||
|
|
||||||
// 添加注释
|
// 添加注释(可选确定性输出,方便版本管理)
|
||||||
|
const deterministic = process.env.MENAV_BOOKMARKS_DETERMINISTIC === '1';
|
||||||
|
const timestampLine = deterministic
|
||||||
|
? ''
|
||||||
|
: `# 由bookmark-processor.js生成于 ${new Date().toISOString()}\n`;
|
||||||
|
|
||||||
const yamlWithComment =
|
const yamlWithComment =
|
||||||
`# 自动生成的书签配置文件
|
`# 自动生成的书签配置文件
|
||||||
# 由bookmark-processor.js生成于 ${new Date().toISOString()}
|
${timestampLine}# 若要更新,请将新的书签HTML文件放入bookmarks/目录
|
||||||
# 若要更新,请将新的书签HTML文件放入bookmarks/目录
|
|
||||||
# 此文件使用模块化配置格式,位于config/user/pages/目录下
|
# 此文件使用模块化配置格式,位于config/user/pages/目录下
|
||||||
|
|
||||||
${yamlString}`;
|
${yamlString}`;
|
||||||
@@ -915,3 +919,12 @@ if (require.main === module) {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
ensureUserConfigInitialized,
|
||||||
|
ensureUserSiteYmlExists,
|
||||||
|
upsertBookmarksNavInSiteYml,
|
||||||
|
parseBookmarks,
|
||||||
|
generateBookmarksYaml,
|
||||||
|
updateNavigationWithBookmarks,
|
||||||
|
};
|
||||||
|
|||||||
@@ -519,6 +519,19 @@ function loadConfig() {
|
|||||||
|
|
||||||
// 根据优先级顺序选择最高优先级的配置
|
// 根据优先级顺序选择最高优先级的配置
|
||||||
if (hasUserModularConfig) {
|
if (hasUserModularConfig) {
|
||||||
|
// 配置采用“完全替换”策略:一旦存在 config/user/,将不会回退到 config/_default/
|
||||||
|
if (!fs.existsSync('config/user/site.yml')) {
|
||||||
|
console.error('[ERROR] 检测到 config/user/ 目录,但缺少 config/user/site.yml。');
|
||||||
|
console.error('[ERROR] 由于配置采用“完全替换”策略,系统不会从 config/_default/ 补齐缺失配置。');
|
||||||
|
console.error('[ERROR] 解决方法:先完整复制 config/_default/ 到 config/user/,再按需修改。');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync('config/user/pages')) {
|
||||||
|
console.warn('[WARN] 检测到 config/user/ 目录,但缺少 config/user/pages/。部分页面内容可能为空。');
|
||||||
|
console.warn('[WARN] 建议:复制 config/_default/pages/ 到 config/user/pages/,再按需修改。');
|
||||||
|
}
|
||||||
|
|
||||||
// 1. 最高优先级: config/user/ 目录
|
// 1. 最高优先级: config/user/ 目录
|
||||||
config = loadModularConfig('config/user');
|
config = loadModularConfig('config/user');
|
||||||
} else if (hasDefaultModularConfig) {
|
} else if (hasDefaultModularConfig) {
|
||||||
|
|||||||
125
test/bookmark-processor.node-test.js
Normal file
125
test/bookmark-processor.node-test.js
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
const os = require('node:os');
|
||||||
|
|
||||||
|
const {
|
||||||
|
ensureUserConfigInitialized,
|
||||||
|
ensureUserSiteYmlExists,
|
||||||
|
upsertBookmarksNavInSiteYml,
|
||||||
|
parseBookmarks,
|
||||||
|
generateBookmarksYaml,
|
||||||
|
} = require('../src/bookmark-processor.js');
|
||||||
|
|
||||||
|
function stripYamlComments(yamlText) {
|
||||||
|
return yamlText
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.filter(line => !/^\s*#/.test(line))
|
||||||
|
.join('\n')
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
test('parseBookmarks:解析书签栏、根目录书签与图标映射', () => {
|
||||||
|
const html = `
|
||||||
|
<!DOCTYPE NETSCAPE-Bookmark-file-1>
|
||||||
|
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
|
||||||
|
<TITLE>Bookmarks</TITLE>
|
||||||
|
<H1>Bookmarks</H1>
|
||||||
|
<DL><p>
|
||||||
|
<DT><H3 PERSONAL_TOOLBAR_FOLDER="true">书签栏</H3>
|
||||||
|
<DL><p>
|
||||||
|
<DT><A HREF="https://github.com/">GitHub</A>
|
||||||
|
<DT><H3>工具</H3>
|
||||||
|
<DL><p>
|
||||||
|
<DT><A HREF="https://www.google.com/">Google</A>
|
||||||
|
</DL><p>
|
||||||
|
</DL><p>
|
||||||
|
</DL><p>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const bookmarks = parseBookmarks(html);
|
||||||
|
assert.ok(bookmarks);
|
||||||
|
assert.ok(Array.isArray(bookmarks.categories));
|
||||||
|
assert.ok(bookmarks.categories.length >= 2);
|
||||||
|
|
||||||
|
// 根目录书签应该插入到首位
|
||||||
|
assert.equal(bookmarks.categories[0].name, '根目录书签');
|
||||||
|
assert.ok(Array.isArray(bookmarks.categories[0].sites));
|
||||||
|
assert.equal(bookmarks.categories[0].sites[0].name, 'GitHub');
|
||||||
|
assert.equal(bookmarks.categories[0].sites[0].icon, 'fab fa-github');
|
||||||
|
|
||||||
|
const tools = bookmarks.categories.find(c => c.name === '工具');
|
||||||
|
assert.ok(tools, '应解析出“工具”分类');
|
||||||
|
assert.ok(Array.isArray(tools.sites));
|
||||||
|
assert.equal(tools.sites[0].name, 'Google');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generateBookmarksYaml:生成 YAML 且可被解析', () => {
|
||||||
|
const bookmarks = {
|
||||||
|
categories: [
|
||||||
|
{
|
||||||
|
name: '示例分类',
|
||||||
|
icon: 'fas fa-folder',
|
||||||
|
sites: [{ name: 'Example', url: 'https://example.com', icon: 'fas fa-link', description: '' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const yamlText = generateBookmarksYaml(bookmarks);
|
||||||
|
assert.ok(typeof yamlText === 'string');
|
||||||
|
assert.ok(yamlText.includes('# 自动生成的书签配置文件'));
|
||||||
|
assert.ok(yamlText.includes('categories:'));
|
||||||
|
|
||||||
|
const yaml = require('js-yaml');
|
||||||
|
const parsed = yaml.load(stripYamlComments(yamlText));
|
||||||
|
assert.equal(parsed.title, '我的书签');
|
||||||
|
assert.ok(Array.isArray(parsed.categories));
|
||||||
|
assert.equal(parsed.categories[0].name, '示例分类');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('upsertBookmarksNavInSiteYml:无 navigation 时追加并幂等', () => {
|
||||||
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'menav-test-'));
|
||||||
|
const filePath = path.join(tmp, 'site.yml');
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
filePath,
|
||||||
|
`title: Test Site\n`,
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
|
||||||
|
const r1 = upsertBookmarksNavInSiteYml(filePath);
|
||||||
|
assert.equal(r1.updated, true);
|
||||||
|
|
||||||
|
const updated1 = fs.readFileSync(filePath, 'utf8');
|
||||||
|
assert.ok(updated1.includes('navigation:'));
|
||||||
|
assert.ok(updated1.includes('- name: 书签'));
|
||||||
|
assert.ok(updated1.includes('id: bookmarks'));
|
||||||
|
|
||||||
|
const r2 = upsertBookmarksNavInSiteYml(filePath);
|
||||||
|
assert.equal(r2.updated, false);
|
||||||
|
assert.equal(r2.reason, 'already_present');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ensureUserConfigInitialized/ensureUserSiteYmlExists:可在空目录初始化用户配置', () => {
|
||||||
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'menav-test-'));
|
||||||
|
const originalCwd = process.cwd();
|
||||||
|
process.chdir(tmp);
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.mkdirSync('config/_default/pages', { recursive: true });
|
||||||
|
fs.writeFileSync('config/_default/site.yml', 'title: Default\n', 'utf8');
|
||||||
|
fs.writeFileSync('config/_default/pages/home.yml', 'categories: []\n', 'utf8');
|
||||||
|
|
||||||
|
const init = ensureUserConfigInitialized();
|
||||||
|
assert.equal(init.initialized, true);
|
||||||
|
assert.ok(fs.existsSync('config/user/site.yml'));
|
||||||
|
assert.ok(fs.existsSync('config/user/pages/home.yml'));
|
||||||
|
|
||||||
|
// 若 site.yml 已存在,应直接返回 true
|
||||||
|
assert.equal(ensureUserSiteYmlExists(), true);
|
||||||
|
} finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Reference in New Issue
Block a user