Skip to content

Commit 585b6cb

Browse files
authored
同步最新代码 (#2)
* 修复禁用缓存也会写入缓存文件的BUG * 1.3.9 * Migrate to Jest testing framework and improve code quality - Replace old test files with comprehensive Jest test suite - Add Jest configuration and update ESLint for Jest environment - Enhance error handling with async/await and proper error propagation - Add circular inheritance detection for template safety - Improve parameter handling with argument overloading support - Update copyright and documentation formatting - Add block hide attribute functionality * Fix test file formatting and improve code readability Corrected spacing issues in multiple test files (index.test.js, lockfile.test.js, utils.test.js) to ensure consistent formatting and improved code readability. The changes include removing unnecessary blank lines and standardizing indentation for better maintainability. * Create workflow.yml * Remove GitHub Actions workflow for running tests and uploading coverage The workflow "Run tests and upload coverage" has been deleted as it is no longer needed in the repository. * Update README.md with codecov badge Add codecov badge to README.md to display test coverage status for the Node.js template engine project.
1 parent e484cc8 commit 585b6cb

File tree

17 files changed

+3213
-122
lines changed

17 files changed

+3213
-122
lines changed

.eslintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"node": true,
1111
"es6": true,
1212
"jasmine": true,
13-
"atomtest": true
13+
"atomtest": true,
14+
"jest": true
1415
},
1516
"extends": "eslint:recommended",
1617
"rules": {

.github/workflows/workflow.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Run tests and upload coverage
2+
3+
on:
4+
push
5+
6+
jobs:
7+
test:
8+
name: Run tests and collect coverage
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Checkout
12+
uses: actions/checkout@v4
13+
with:
14+
fetch-depth: 2
15+
16+
- name: Set up Node
17+
uses: actions/setup-node@v4
18+
19+
- name: Install dependencies
20+
run: npm install
21+
22+
- name: Run tests
23+
run: npx jest --coverage
24+
25+
- name: Upload results to Codecov
26+
uses: codecov/codecov-action@v5
27+
with:
28+
token: ${{ secrets.CODECOV_TOKEN }}
29+
slug: hex-ci/cbT

CLAUDE.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## 项目概述
6+
7+
cbT.js 是一个支持模板多级继承的 Node.js 服务端模板引擎。该引擎提供了丰富的模板语法,包括模板继承、变量输出、条件控制、循环遍历等功能。
8+
9+
## 开发命令
10+
11+
### 代码检查
12+
```bash
13+
npm run eslint
14+
```
15+
16+
### 测试相关
17+
```bash
18+
# 运行所有测试
19+
npm test
20+
21+
# 监听模式运行测试
22+
npm run test:watch
23+
24+
# 运行测试并生成覆盖率报告
25+
npm run test:coverage
26+
```
27+
28+
## 核心架构
29+
30+
### 主要文件结构
31+
- `index.js` - 模板引擎核心入口,包含编译和渲染逻辑
32+
- `lib/layout.js` - 模板继承系统,处理 extends、block 等指令
33+
- `lib/helper.js` - 辅助函数集合,包含 HTML 转义、数组处理等工具
34+
- `lib/lockfile.js` - 文件锁机制,用于缓存文件的并发安全
35+
- `lib/utils.js` - 通用工具函数,包含文件操作、哈希生成等
36+
37+
### 模板语法特性
38+
- **模板继承系统**: 支持 extends、block、parent、child、slot、call、use 指令
39+
- **变量输出**: 支持 HTML 转义、URL 转义、不转义等多种输出方式
40+
- **控制结构**: if/else、foreach 循环
41+
- **安全特性**: 默认 HTML 转义防止 XSS 攻击
42+
- **缓存机制**: 支持模板编译缓存,提升性能
43+
44+
### 关键配置
45+
- 默认分隔符: `<%``%>`
46+
- 默认扩展名: `.html`
47+
- 支持自定义 basePath 和 cachePath
48+
- 默认开启 HTML 转义
49+
50+
### 模板编译流程
51+
1. 解析模板语法,转换为 JavaScript 代码
52+
2. 处理模板继承关系(如果存在 extends)
53+
3. 合并 block 内容
54+
4. 生成最终的模板函数
55+
5. 缓存编译结果(可选)
56+
57+
### 缓存策略
58+
- 基于文件修改时间检测缓存有效性
59+
- 使用文件锁确保并发安全
60+
- 缓存文件包含版本信息和依赖文件时间戳
61+
62+
## 测试说明
63+
64+
测试文件位于 `test/` 目录,使用 Jest 作为测试框架。测试覆盖:
65+
- `index.test.js` - 核心功能测试
66+
- `helper.test.js` - 辅助函数测试
67+
- `layout.test.js` - 模板继承系统测试
68+
- `lockfile.test.js` - 文件锁机制测试
69+
- `utils.test.js` - 工具函数测试
70+
71+
## 代码风格
72+
73+
项目使用 ESLint 进行代码检查,主要规则:
74+
- 2 空格缩进
75+
- 禁用 console 检查
76+
- 强制使用 const(prefer-const)
77+
- Stroustrup 大括号风格
78+
- 严格的语法检查(无未使用变量、无未定义变量等)

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2019 ChangbaFE
3+
Copyright (c) 2019 Hex
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# cbT.js
22

3-
[![npm version](https://badgen.net/npm/v/cb-template)](https://www.npmjs.com/package/cb-template) [![Downloads](https://badgen.net/npm/dt/cb-template)](https://www.npmjs.com/package/cb-template)
3+
[![npm version](https://badgen.net/npm/v/cb-template)](https://www.npmjs.com/package/cb-template) [![Downloads](https://badgen.net/npm/dt/cb-template)](https://www.npmjs.com/package/cb-template) [![codecov](https://codecov.io/github/hex-ci/cbT/graph/badge.svg?token=HBHJLIG91R)](https://codecov.io/github/hex-ci/cbT)
44

55
一个支持模板多级继承的 Node.js 服务端模板引擎
66

@@ -247,6 +247,14 @@ myInstance.render(`<title><%=title%></title><p><%=nickname%></p>`, { title: '标
247247

248248
在子模板中使用 block 代表替换父模板中同名的 block。
249249

250+
```
251+
<% block 名称 hide %>
252+
内容...
253+
<% /block %>
254+
```
255+
256+
`hide` 属性表示在子模板中隐藏父模板中同名的 block。
257+
250258
#### parent 标签
251259

252260
```
@@ -463,7 +471,7 @@ myInstance.render(`<title><%=title%></title><p><%=nickname%></p>`, { title: '标
463471

464472
```html
465473
<div><%:a=listing%></div> <!-- 输出 <div>元素0<br>元素1<br>元素2<div> -->
466-
<div><%:a=listing | ,%></div> <!-- 输出 <div>元素0,元素1,元素2<div> -->
474+
<div><%:a=listing|,%></div> <!-- 输出 <div>元素0,元素1,元素2<div> -->
467475
```
468476

469477
#### 格式化钱数

index.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ const core = {
4646

4747
// 编译模板文件,支持模板继承
4848
compileFile(filename, options = {}, callback) {
49+
// Handle parameter overloading: check actual number of arguments
50+
if (arguments.length === 2) {
51+
callback = options;
52+
options = {};
53+
}
54+
4955
const instance = new Layout(this);
5056

5157
instance.make(filename, options, (err, content) => {
@@ -56,6 +62,12 @@ const core = {
5662

5763
// 渲染模板文件,支持模板继承
5864
renderFile(filename, data, options = {}, callback) {
65+
// Handle parameter overloading: check actual number of arguments
66+
if (arguments.length === 3) {
67+
callback = options;
68+
options = {};
69+
}
70+
5971
this.compileFile(filename, options, (err, func) => {
6072
// 返回渲染后的内容
6173
callback(err, func(data));
@@ -78,15 +90,15 @@ const core = {
7890
${TEMPLATE_VAR_NAME} = null;
7991
}
8092
let ${TEMPLATE_SUB} = {};
81-
let ${TEMPLATE_OUT} = '${str}';
93+
let ${TEMPLATE_OUT} /* init */ = '${str}';
8294
return ${TEMPLATE_OUT};
8395
`;
8496

85-
// console.log(funcBody.replace(/\\n/g, '\n'));
86-
8797
// 删除无效指令
8898
funcBody = funcBody.replace(new RegExp(`${TEMPLATE_OUT}\\s*\\+?=\\s*'';`, 'g'), '');
8999

100+
// console.log(funcBody.replace(/\\n/g, '\n'));
101+
90102
const func = new Function(TEMPLATE_HELPER, TEMPLATE_OBJECT, SUB_TEMPLATE, funcBody);
91103

92104
return (templateObject, subTemplate) => func(helpers, templateObject, subTemplate);
@@ -113,7 +125,7 @@ const core = {
113125
//去掉注释内容 <%* 这里可以任意的注释 *%>
114126
.replace(new RegExp(_left + '\\*[\\s\\S]*?\\*' + _right, 'gm'), '')
115127

116-
//用来处理非分隔符内部的内容中含有 斜杠 \ 单引号
128+
//用来处理非分隔符内部的内容中含有 斜杠 \ 单引号 '
117129
.replace(new RegExp(_left + "(?:(?!" + _right + ")[\\s\\S])*" + _right + "|((?:(?!" + _left + ")[\\s\\S])+)", "g"), (item, $1) => {
118130
let str = '';
119131
if ($1) {
@@ -201,7 +213,7 @@ const core = {
201213
if (this.escape) {
202214
str = str
203215

204-
//找到 \t=任意一个字符%> 替换为 ,任意字符,'
216+
//找到 \t=任意一个字符%> 替换为 ',任意字符,'
205217
//即替换简单变量 \t=data%> 替换为 ',data,'
206218
//默认HTML转义 也支持HTML转义写法<%:h=value%>
207219
.replace(new RegExp("\\t=(.*?)" + _right, "g"),
@@ -265,7 +277,7 @@ const core = {
265277
// 即去掉结尾符,生成字符串拼接
266278
.split(_right_).join(`${TEMPLATE_OUT}+='`);
267279

268-
//console.log(str);
280+
// console.log(str);
269281

270282
return str;
271283
}

jest.config.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module.exports = {
2+
testEnvironment: 'node',
3+
collectCoverageFrom: [
4+
'index.js',
5+
'lib/**/*.js',
6+
'!node_modules/**'
7+
],
8+
coverageDirectory: 'coverage',
9+
coverageReporters: ['text', 'lcov', 'html'],
10+
testMatch: [
11+
'<rootDir>/test/**/*.test.js'
12+
],
13+
testPathIgnorePatterns: [
14+
'/node_modules/'
15+
],
16+
moduleFileExtensions: ['js', 'json'],
17+
verbose: true
18+
};

lib/helper.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const helpers = {
4949
});
5050
}
5151

52-
return result.join(sep);
52+
return result.join(sep || '<br>');
5353
},
5454

5555
//判断是否是 Object 类型

0 commit comments

Comments
 (0)