@longzai-intelligence/pagination 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +22 -0
- package/.turbo/turbo-lint.log +1 -0
- package/.turbo/turbo-test$colon$coverage.log +36 -0
- package/.turbo/turbo-test.log +14 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +11 -0
- package/README.md +218 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/coverage-final.json +12 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +161 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/src/adapters/index.html +131 -0
- package/coverage/src/adapters/index.ts.html +118 -0
- package/coverage/src/adapters/typeorm.adapter.ts.html +940 -0
- package/coverage/src/index.html +116 -0
- package/coverage/src/index.ts.html +253 -0
- package/coverage/src/types/index.html +176 -0
- package/coverage/src/types/index.ts.html +133 -0
- package/coverage/src/types/pagination.types.ts.html +292 -0
- package/coverage/src/types/result.types.ts.html +415 -0
- package/coverage/src/types/sort.types.ts.html +265 -0
- package/coverage/src/types/typeorm.d.ts.html +196 -0
- package/coverage/src/utils/index.html +146 -0
- package/coverage/src/utils/index.ts.html +178 -0
- package/coverage/src/utils/pagination.util.ts.html +703 -0
- package/coverage/src/utils/validation.util.ts.html +535 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +117 -0
- package/dist/index.d.mts +117 -0
- package/dist/index.mjs +1 -0
- package/eslint.config.ts +3 -0
- package/package.json +62 -0
- package/src/__tests__/index.test.ts +66 -0
- package/src/__tests__/pagination.util.test.ts +253 -0
- package/src/__tests__/typeorm.adapter.test.ts +214 -0
- package/src/__tests__/validation.util.test.ts +122 -0
- package/src/adapters/index.ts +11 -0
- package/src/adapters/typeorm.adapter.ts +285 -0
- package/src/index.ts +56 -0
- package/src/types/index.ts +16 -0
- package/src/types/pagination.types.ts +69 -0
- package/src/types/result.types.ts +110 -0
- package/src/types/sort.types.ts +60 -0
- package/src/types/typeorm.d.ts +37 -0
- package/src/utils/index.ts +31 -0
- package/src/utils/pagination.util.ts +206 -0
- package/src/utils/validation.util.ts +150 -0
- package/tsconfig/.cache/app.tsbuildinfo +1 -0
- package/tsconfig/.cache/build.tsbuildinfo +1 -0
- package/tsconfig/.cache/node.tsbuildinfo +1 -0
- package/tsconfig/.cache/test.tsbuildinfo +1 -0
- package/tsconfig/app.json +12 -0
- package/tsconfig/node.json +11 -0
- package/tsconfig/test.json +14 -0
- package/tsconfig.json +9 -0
- package/tsdown.config.ts +6 -0
- package/vitest.config.ts +3 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
$ tsdown
|
|
2
|
+
ℹ tsdown v0.21.7 powered by rolldown v1.0.0-rc.12
|
|
3
|
+
ℹ config file: /Volumes/JZAO/j-projects/workspaces/longzai/longzai-intelligence/longzai-intelligence/packages/pagination/tsdown.config.ts
|
|
4
|
+
(node:62059) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
|
|
5
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
6
|
+
ℹ entry: src/index.ts
|
|
7
|
+
ℹ tsconfig: tsconfig/app.json
|
|
8
|
+
ℹ Build start
|
|
9
|
+
ℹ Cleaning 8 files
|
|
10
|
+
ℹ [CJS] dist/index.cjs 9.63 kB │ gzip: 2.45 kB
|
|
11
|
+
ℹ [CJS] dist/index.cjs.map 19.04 kB │ gzip: 4.55 kB
|
|
12
|
+
ℹ [CJS] 2 files, total: 28.66 kB
|
|
13
|
+
ℹ [CJS] dist/index.d.cts.map 2.74 kB │ gzip: 0.82 kB
|
|
14
|
+
ℹ [CJS] dist/index.d.cts 5.36 kB │ gzip: 1.21 kB
|
|
15
|
+
ℹ [CJS] 2 files, total: 8.10 kB
|
|
16
|
+
✔ Build complete in 679ms
|
|
17
|
+
ℹ [ESM] dist/index.mjs 9.02 kB │ gzip: 2.33 kB
|
|
18
|
+
ℹ [ESM] dist/index.mjs.map 19.04 kB │ gzip: 4.55 kB
|
|
19
|
+
ℹ [ESM] dist/index.d.mts.map 2.74 kB │ gzip: 0.82 kB
|
|
20
|
+
ℹ [ESM] dist/index.d.mts 5.36 kB │ gzip: 1.21 kB
|
|
21
|
+
ℹ [ESM] 4 files, total: 36.16 kB
|
|
22
|
+
✔ Build complete in 680ms
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$ eslint .
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
$ vitest run --coverage
|
|
2
|
+
|
|
3
|
+
[1m[46m RUN [49m[22m [36mv4.1.3 [39m[90m/Volumes/JZAO/j-projects/workspaces/longzai/longzai-intelligence/longzai-intelligence/packages/pagination[39m
|
|
4
|
+
[2mCoverage enabled with [22m[33mv8[39m
|
|
5
|
+
|
|
6
|
+
[32m✓[39m src/__tests__/pagination.util.test.ts [2m([22m[2m41 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
7
|
+
[32m✓[39m src/__tests__/index.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
8
|
+
[32m✓[39m src/__tests__/validation.util.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
9
|
+
[32m✓[39m src/__tests__/typeorm.adapter.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
10
|
+
|
|
11
|
+
[2m Test Files [22m [1m[32m4 passed[39m[22m[90m (4)[39m
|
|
12
|
+
[2m Tests [22m [1m[32m68 passed[39m[22m[90m (68)[39m
|
|
13
|
+
[2m Start at [22m 01:27:15
|
|
14
|
+
[2m Duration [22m 162ms[2m (transform 99ms, setup 0ms, import 126ms, tests 24ms, environment 0ms)[22m
|
|
15
|
+
|
|
16
|
+
[34m % [39m[2mCoverage report from [22m[33mv8[39m
|
|
17
|
+
-------------------|---------|----------|---------|---------|-------------------
|
|
18
|
+
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
|
19
|
+
-------------------|---------|----------|---------|---------|-------------------
|
|
20
|
+
All files | 100 | 100 | 100 | 100 |
|
|
21
|
+
src | 0 | 0 | 0 | 0 |
|
|
22
|
+
index.ts | 0 | 0 | 0 | 0 |
|
|
23
|
+
src/adapters | 100 | 100 | 100 | 100 |
|
|
24
|
+
index.ts | 0 | 0 | 0 | 0 |
|
|
25
|
+
...rm.adapter.ts | 100 | 100 | 100 | 100 |
|
|
26
|
+
src/types | 100 | 100 | 100 | 100 |
|
|
27
|
+
index.ts | 0 | 0 | 0 | 0 |
|
|
28
|
+
...tion.types.ts | 100 | 100 | 100 | 100 |
|
|
29
|
+
result.types.ts | 0 | 0 | 0 | 0 |
|
|
30
|
+
sort.types.ts | 0 | 0 | 0 | 0 |
|
|
31
|
+
typeorm.d.ts | 0 | 0 | 0 | 0 |
|
|
32
|
+
src/utils | 100 | 100 | 100 | 100 |
|
|
33
|
+
index.ts | 0 | 0 | 0 | 0 |
|
|
34
|
+
...ation.util.ts | 100 | 100 | 100 | 100 |
|
|
35
|
+
...ation.util.ts | 100 | 100 | 100 | 100 |
|
|
36
|
+
-------------------|---------|----------|---------|---------|-------------------
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
$ vitest run
|
|
2
|
+
|
|
3
|
+
[1m[46m RUN [49m[22m [36mv4.1.3 [39m[90m/Volumes/JZAO/j-projects/workspaces/longzai/longzai-intelligence/longzai-intelligence/packages/pagination[39m
|
|
4
|
+
|
|
5
|
+
[32m✓[39m src/__tests__/validation.util.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
6
|
+
[32m✓[39m src/__tests__/pagination.util.test.ts [2m([22m[2m41 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
7
|
+
[32m✓[39m src/__tests__/typeorm.adapter.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
8
|
+
[32m✓[39m src/__tests__/index.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 22[2mms[22m[39m
|
|
9
|
+
|
|
10
|
+
[2m Test Files [22m [1m[32m4 passed[39m[22m[90m (4)[39m
|
|
11
|
+
[2m Tests [22m [1m[32m68 passed[39m[22m[90m (68)[39m
|
|
12
|
+
[2m Start at [22m 01:27:13
|
|
13
|
+
[2m Duration [22m 162ms[2m (transform 133ms, setup 0ms, import 153ms, tests 38ms, environment 0ms)[22m
|
|
14
|
+
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.0.1] - 2026-04-10
|
|
4
|
+
|
|
5
|
+
### 功能
|
|
6
|
+
|
|
7
|
+
- 分页类型定义:PaginationParams、OffsetPaginationParams、CursorPaginationParams
|
|
8
|
+
- 排序类型定义:SortOrder、SortParams、MultiSortParams
|
|
9
|
+
- 分页工具函数:normalizePagination、calculateOffset、hasNextPage 等
|
|
10
|
+
- 校验工具函数:isValidPage、isValidPageSize、isValidOffset 等
|
|
11
|
+
- TypeORM 适配器:paginateWithRepository、paginateWithQueryBuilder、createPaginationQueryBuilder
|
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# @longzai-intelligence/pagination
|
|
2
|
+
|
|
3
|
+
统一的分页功能包,提供类型安全的分页参数、结果类型和工具函数。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @longzai-intelligence/pagination
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 特性
|
|
12
|
+
|
|
13
|
+
- 类型安全的分页参数定义
|
|
14
|
+
- 支持 page/pageSize 和 limit/offset 两种分页风格
|
|
15
|
+
- 支持游标分页
|
|
16
|
+
- 提供参数验证工具
|
|
17
|
+
- 提供 TypeORM 适配器(可选)
|
|
18
|
+
|
|
19
|
+
## 快速开始
|
|
20
|
+
|
|
21
|
+
### 基本使用
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import {
|
|
25
|
+
normalizePagination,
|
|
26
|
+
calculateOffset,
|
|
27
|
+
createPaginatedResult,
|
|
28
|
+
type PaginationParams,
|
|
29
|
+
type PaginatedResult,
|
|
30
|
+
} from '@longzai-intelligence/pagination';
|
|
31
|
+
|
|
32
|
+
// 规范化分页参数
|
|
33
|
+
const params: PaginationParams = { page: 2, pageSize: 20 };
|
|
34
|
+
const { page, pageSize } = normalizePagination(params);
|
|
35
|
+
|
|
36
|
+
// 计算偏移量
|
|
37
|
+
const offset = calculateOffset(page, pageSize);
|
|
38
|
+
|
|
39
|
+
// 创建分页结果
|
|
40
|
+
const result: PaginatedResult<User> = createPaginatedResult(
|
|
41
|
+
users,
|
|
42
|
+
total,
|
|
43
|
+
page,
|
|
44
|
+
pageSize,
|
|
45
|
+
);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 参数验证
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import {
|
|
52
|
+
isValidPage,
|
|
53
|
+
isValidPageSize,
|
|
54
|
+
isValidPagination,
|
|
55
|
+
} from '@longzai-intelligence/pagination';
|
|
56
|
+
|
|
57
|
+
if (isValidPagination(params)) {
|
|
58
|
+
// 参数有效
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (isValidPage(1) && isValidPageSize(20)) {
|
|
62
|
+
// 页码和页面大小有效
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### TypeORM 适配器
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import {
|
|
70
|
+
paginateWithRepository,
|
|
71
|
+
paginateWithQueryBuilder,
|
|
72
|
+
} from '@longzai-intelligence/pagination';
|
|
73
|
+
|
|
74
|
+
// 使用 Repository 分页
|
|
75
|
+
const result = await paginateWithRepository(userRepository, {
|
|
76
|
+
page: 1,
|
|
77
|
+
pageSize: 20,
|
|
78
|
+
}, {
|
|
79
|
+
where: { active: true },
|
|
80
|
+
order: { createdAt: 'DESC' },
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// 使用 QueryBuilder 分页
|
|
84
|
+
const qb = userRepository.createQueryBuilder('user');
|
|
85
|
+
const result = await paginateWithQueryBuilder(qb, { page: 1, pageSize: 20 });
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## API 文档
|
|
89
|
+
|
|
90
|
+
### 类型
|
|
91
|
+
|
|
92
|
+
#### PaginationParams
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface PaginationParams {
|
|
96
|
+
page?: number; // 页码,从 1 开始
|
|
97
|
+
pageSize?: number; // 每页数量
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### OffsetPaginationParams
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
interface OffsetPaginationParams {
|
|
105
|
+
limit?: number; // 每页数量
|
|
106
|
+
offset?: number; // 偏移量
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### PaginatedResult
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
interface PaginatedResult<T> {
|
|
114
|
+
items: T[]; // 数据项
|
|
115
|
+
total: number; // 总记录数
|
|
116
|
+
page: number; // 当前页码
|
|
117
|
+
pageSize: number; // 每页数量
|
|
118
|
+
totalPages: number; // 总页数
|
|
119
|
+
hasNextPage: boolean; // 是否有下一页
|
|
120
|
+
hasPreviousPage: boolean; // 是否有上一页
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### SortParams
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
interface SortParams<T extends string = string> {
|
|
128
|
+
sortBy?: T; // 排序字段
|
|
129
|
+
sortOrder?: 'asc' | 'desc'; // 排序方向
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 常量
|
|
134
|
+
|
|
135
|
+
#### PAGINATION_DEFAULTS
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const PAGINATION_DEFAULTS = {
|
|
139
|
+
page: 1,
|
|
140
|
+
pageSize: 20,
|
|
141
|
+
maxPageSize: 100,
|
|
142
|
+
minPageSize: 1,
|
|
143
|
+
} as const;
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 工具函数
|
|
147
|
+
|
|
148
|
+
#### normalizePagination(params?)
|
|
149
|
+
|
|
150
|
+
规范化分页参数,确保参数在有效范围内。
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
const { page, pageSize } = normalizePagination({ page: 2, pageSize: 50 });
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### calculateOffset(page, pageSize)
|
|
157
|
+
|
|
158
|
+
计算偏移量。
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const offset = calculateOffset(2, 20); // 20
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### calculateTotalPages(total, pageSize)
|
|
165
|
+
|
|
166
|
+
计算总页数。
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
const totalPages = calculateTotalPages(100, 20); // 5
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### hasNextPage(page, totalPages) / hasPreviousPage(page)
|
|
173
|
+
|
|
174
|
+
判断是否有下一页/上一页。
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
hasNextPage(1, 5); // true
|
|
178
|
+
hasPreviousPage(1); // false
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### offsetToPage(offset, limit) / pageToOffset(page, pageSize)
|
|
182
|
+
|
|
183
|
+
分页风格转换。
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
offsetToPage(20, 20); // { page: 2, pageSize: 20 }
|
|
187
|
+
pageToOffset(2, 20); // { offset: 20, limit: 20 }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 验证函数
|
|
191
|
+
|
|
192
|
+
#### isValidPage(page)
|
|
193
|
+
|
|
194
|
+
验证页码是否有效(正整数)。
|
|
195
|
+
|
|
196
|
+
#### isValidPageSize(pageSize)
|
|
197
|
+
|
|
198
|
+
验证每页数量是否有效(1-100 之间的整数)。
|
|
199
|
+
|
|
200
|
+
#### isValidOffset(offset)
|
|
201
|
+
|
|
202
|
+
验证偏移量是否有效(非负整数)。
|
|
203
|
+
|
|
204
|
+
#### isValidLimit(limit)
|
|
205
|
+
|
|
206
|
+
验证限制数量是否有效(1-100 之间的整数)。
|
|
207
|
+
|
|
208
|
+
#### isValidPagination(params)
|
|
209
|
+
|
|
210
|
+
验证分页参数对象是否有效。
|
|
211
|
+
|
|
212
|
+
#### isValidOffsetPagination(params)
|
|
213
|
+
|
|
214
|
+
验证 offset 分页参数对象是否有效。
|
|
215
|
+
|
|
216
|
+
## 许可证
|
|
217
|
+
|
|
218
|
+
MIT
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
body, html {
|
|
2
|
+
margin:0; padding: 0;
|
|
3
|
+
height: 100%;
|
|
4
|
+
}
|
|
5
|
+
body {
|
|
6
|
+
font-family: Helvetica Neue, Helvetica, Arial;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
color:#333;
|
|
9
|
+
}
|
|
10
|
+
.small { font-size: 12px; }
|
|
11
|
+
*, *:after, *:before {
|
|
12
|
+
-webkit-box-sizing:border-box;
|
|
13
|
+
-moz-box-sizing:border-box;
|
|
14
|
+
box-sizing:border-box;
|
|
15
|
+
}
|
|
16
|
+
h1 { font-size: 20px; margin: 0;}
|
|
17
|
+
h2 { font-size: 14px; }
|
|
18
|
+
pre {
|
|
19
|
+
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 0;
|
|
22
|
+
-moz-tab-size: 2;
|
|
23
|
+
-o-tab-size: 2;
|
|
24
|
+
tab-size: 2;
|
|
25
|
+
}
|
|
26
|
+
a { color:#0074D9; text-decoration:none; }
|
|
27
|
+
a:hover { text-decoration:underline; }
|
|
28
|
+
.strong { font-weight: bold; }
|
|
29
|
+
.space-top1 { padding: 10px 0 0 0; }
|
|
30
|
+
.pad2y { padding: 20px 0; }
|
|
31
|
+
.pad1y { padding: 10px 0; }
|
|
32
|
+
.pad2x { padding: 0 20px; }
|
|
33
|
+
.pad2 { padding: 20px; }
|
|
34
|
+
.pad1 { padding: 10px; }
|
|
35
|
+
.space-left2 { padding-left:55px; }
|
|
36
|
+
.space-right2 { padding-right:20px; }
|
|
37
|
+
.center { text-align:center; }
|
|
38
|
+
.clearfix { display:block; }
|
|
39
|
+
.clearfix:after {
|
|
40
|
+
content:'';
|
|
41
|
+
display:block;
|
|
42
|
+
height:0;
|
|
43
|
+
clear:both;
|
|
44
|
+
visibility:hidden;
|
|
45
|
+
}
|
|
46
|
+
.fl { float: left; }
|
|
47
|
+
@media only screen and (max-width:640px) {
|
|
48
|
+
.col3 { width:100%; max-width:100%; }
|
|
49
|
+
.hide-mobile { display:none!important; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.quiet {
|
|
53
|
+
color: #7f7f7f;
|
|
54
|
+
color: rgba(0,0,0,0.5);
|
|
55
|
+
}
|
|
56
|
+
.quiet a { opacity: 0.7; }
|
|
57
|
+
|
|
58
|
+
.fraction {
|
|
59
|
+
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
|
60
|
+
font-size: 10px;
|
|
61
|
+
color: #555;
|
|
62
|
+
background: #E8E8E8;
|
|
63
|
+
padding: 4px 5px;
|
|
64
|
+
border-radius: 3px;
|
|
65
|
+
vertical-align: middle;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
div.path a:link, div.path a:visited { color: #333; }
|
|
69
|
+
table.coverage {
|
|
70
|
+
border-collapse: collapse;
|
|
71
|
+
margin: 10px 0 0 0;
|
|
72
|
+
padding: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
table.coverage td {
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 0;
|
|
78
|
+
vertical-align: top;
|
|
79
|
+
}
|
|
80
|
+
table.coverage td.line-count {
|
|
81
|
+
text-align: right;
|
|
82
|
+
padding: 0 5px 0 20px;
|
|
83
|
+
}
|
|
84
|
+
table.coverage td.line-coverage {
|
|
85
|
+
text-align: right;
|
|
86
|
+
padding-right: 10px;
|
|
87
|
+
min-width:20px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
table.coverage td span.cline-any {
|
|
91
|
+
display: inline-block;
|
|
92
|
+
padding: 0 5px;
|
|
93
|
+
width: 100%;
|
|
94
|
+
}
|
|
95
|
+
.missing-if-branch {
|
|
96
|
+
display: inline-block;
|
|
97
|
+
margin-right: 5px;
|
|
98
|
+
border-radius: 3px;
|
|
99
|
+
position: relative;
|
|
100
|
+
padding: 0 4px;
|
|
101
|
+
background: #333;
|
|
102
|
+
color: yellow;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.skip-if-branch {
|
|
106
|
+
display: none;
|
|
107
|
+
margin-right: 10px;
|
|
108
|
+
position: relative;
|
|
109
|
+
padding: 0 4px;
|
|
110
|
+
background: #ccc;
|
|
111
|
+
color: white;
|
|
112
|
+
}
|
|
113
|
+
.missing-if-branch .typ, .skip-if-branch .typ {
|
|
114
|
+
color: inherit !important;
|
|
115
|
+
}
|
|
116
|
+
.coverage-summary {
|
|
117
|
+
border-collapse: collapse;
|
|
118
|
+
width: 100%;
|
|
119
|
+
}
|
|
120
|
+
.coverage-summary tr { border-bottom: 1px solid #bbb; }
|
|
121
|
+
.keyline-all { border: 1px solid #ddd; }
|
|
122
|
+
.coverage-summary td, .coverage-summary th { padding: 10px; }
|
|
123
|
+
.coverage-summary tbody { border: 1px solid #bbb; }
|
|
124
|
+
.coverage-summary td { border-right: 1px solid #bbb; }
|
|
125
|
+
.coverage-summary td:last-child { border-right: none; }
|
|
126
|
+
.coverage-summary th {
|
|
127
|
+
text-align: left;
|
|
128
|
+
font-weight: normal;
|
|
129
|
+
white-space: nowrap;
|
|
130
|
+
}
|
|
131
|
+
.coverage-summary th.file { border-right: none !important; }
|
|
132
|
+
.coverage-summary th.pct { }
|
|
133
|
+
.coverage-summary th.pic,
|
|
134
|
+
.coverage-summary th.abs,
|
|
135
|
+
.coverage-summary td.pct,
|
|
136
|
+
.coverage-summary td.abs { text-align: right; }
|
|
137
|
+
.coverage-summary td.file { white-space: nowrap; }
|
|
138
|
+
.coverage-summary td.pic { min-width: 120px !important; }
|
|
139
|
+
.coverage-summary tfoot td { }
|
|
140
|
+
|
|
141
|
+
.coverage-summary .sorter {
|
|
142
|
+
height: 10px;
|
|
143
|
+
width: 7px;
|
|
144
|
+
display: inline-block;
|
|
145
|
+
margin-left: 0.5em;
|
|
146
|
+
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
|
|
147
|
+
}
|
|
148
|
+
.coverage-summary .sorted .sorter {
|
|
149
|
+
background-position: 0 -20px;
|
|
150
|
+
}
|
|
151
|
+
.coverage-summary .sorted-desc .sorter {
|
|
152
|
+
background-position: 0 -10px;
|
|
153
|
+
}
|
|
154
|
+
.status-line { height: 10px; }
|
|
155
|
+
/* yellow */
|
|
156
|
+
.cbranch-no { background: yellow !important; color: #111; }
|
|
157
|
+
/* dark red */
|
|
158
|
+
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
|
|
159
|
+
.low .chart { border:1px solid #C21F39 }
|
|
160
|
+
.highlighted,
|
|
161
|
+
.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
|
|
162
|
+
background: #C21F39 !important;
|
|
163
|
+
}
|
|
164
|
+
/* medium red */
|
|
165
|
+
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
|
|
166
|
+
/* light red */
|
|
167
|
+
.low, .cline-no { background:#FCE1E5 }
|
|
168
|
+
/* light green */
|
|
169
|
+
.high, .cline-yes { background:rgb(230,245,208) }
|
|
170
|
+
/* medium green */
|
|
171
|
+
.cstat-yes { background:rgb(161,215,106) }
|
|
172
|
+
/* dark green */
|
|
173
|
+
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
|
|
174
|
+
.high .chart { border:1px solid rgb(77,146,33) }
|
|
175
|
+
/* dark yellow (gold) */
|
|
176
|
+
.status-line.medium, .medium .cover-fill { background: #f9cd0b; }
|
|
177
|
+
.medium .chart { border:1px solid #f9cd0b; }
|
|
178
|
+
/* light yellow */
|
|
179
|
+
.medium { background: #fff4c2; }
|
|
180
|
+
|
|
181
|
+
.cstat-skip { background: #ddd; color: #111; }
|
|
182
|
+
.fstat-skip { background: #ddd; color: #111 !important; }
|
|
183
|
+
.cbranch-skip { background: #ddd !important; color: #111; }
|
|
184
|
+
|
|
185
|
+
span.cline-neutral { background: #eaeaea; }
|
|
186
|
+
|
|
187
|
+
.coverage-summary td.empty {
|
|
188
|
+
opacity: .5;
|
|
189
|
+
padding-top: 4px;
|
|
190
|
+
padding-bottom: 4px;
|
|
191
|
+
line-height: 1;
|
|
192
|
+
color: #888;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.cover-fill, .cover-empty {
|
|
196
|
+
display:inline-block;
|
|
197
|
+
height: 12px;
|
|
198
|
+
}
|
|
199
|
+
.chart {
|
|
200
|
+
line-height: 0;
|
|
201
|
+
}
|
|
202
|
+
.cover-empty {
|
|
203
|
+
background: white;
|
|
204
|
+
}
|
|
205
|
+
.cover-full {
|
|
206
|
+
border-right: none !important;
|
|
207
|
+
}
|
|
208
|
+
pre.prettyprint {
|
|
209
|
+
border: none !important;
|
|
210
|
+
padding: 0 !important;
|
|
211
|
+
margin: 0 !important;
|
|
212
|
+
}
|
|
213
|
+
.com { color: #999 !important; }
|
|
214
|
+
.ignore-none { color: #999; font-weight: normal; }
|
|
215
|
+
|
|
216
|
+
.wrapper {
|
|
217
|
+
min-height: 100%;
|
|
218
|
+
height: auto !important;
|
|
219
|
+
height: 100%;
|
|
220
|
+
margin: 0 auto -48px;
|
|
221
|
+
}
|
|
222
|
+
.footer, .push {
|
|
223
|
+
height: 48px;
|
|
224
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
var jumpToCode = (function init() {
|
|
3
|
+
// Classes of code we would like to highlight in the file view
|
|
4
|
+
var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
|
|
5
|
+
|
|
6
|
+
// Elements to highlight in the file listing view
|
|
7
|
+
var fileListingElements = ['td.pct.low'];
|
|
8
|
+
|
|
9
|
+
// We don't want to select elements that are direct descendants of another match
|
|
10
|
+
var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
|
|
11
|
+
|
|
12
|
+
// Selector that finds elements on the page to which we can jump
|
|
13
|
+
var selector =
|
|
14
|
+
fileListingElements.join(', ') +
|
|
15
|
+
', ' +
|
|
16
|
+
notSelector +
|
|
17
|
+
missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
|
|
18
|
+
|
|
19
|
+
// The NodeList of matching elements
|
|
20
|
+
var missingCoverageElements = document.querySelectorAll(selector);
|
|
21
|
+
|
|
22
|
+
var currentIndex;
|
|
23
|
+
|
|
24
|
+
function toggleClass(index) {
|
|
25
|
+
missingCoverageElements
|
|
26
|
+
.item(currentIndex)
|
|
27
|
+
.classList.remove('highlighted');
|
|
28
|
+
missingCoverageElements.item(index).classList.add('highlighted');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function makeCurrent(index) {
|
|
32
|
+
toggleClass(index);
|
|
33
|
+
currentIndex = index;
|
|
34
|
+
missingCoverageElements.item(index).scrollIntoView({
|
|
35
|
+
behavior: 'smooth',
|
|
36
|
+
block: 'center',
|
|
37
|
+
inline: 'center'
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function goToPrevious() {
|
|
42
|
+
var nextIndex = 0;
|
|
43
|
+
if (typeof currentIndex !== 'number' || currentIndex === 0) {
|
|
44
|
+
nextIndex = missingCoverageElements.length - 1;
|
|
45
|
+
} else if (missingCoverageElements.length > 1) {
|
|
46
|
+
nextIndex = currentIndex - 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
makeCurrent(nextIndex);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function goToNext() {
|
|
53
|
+
var nextIndex = 0;
|
|
54
|
+
|
|
55
|
+
if (
|
|
56
|
+
typeof currentIndex === 'number' &&
|
|
57
|
+
currentIndex < missingCoverageElements.length - 1
|
|
58
|
+
) {
|
|
59
|
+
nextIndex = currentIndex + 1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
makeCurrent(nextIndex);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return function jump(event) {
|
|
66
|
+
if (
|
|
67
|
+
document.getElementById('fileSearch') === document.activeElement &&
|
|
68
|
+
document.activeElement != null
|
|
69
|
+
) {
|
|
70
|
+
// if we're currently focused on the search input, we don't want to navigate
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
switch (event.which) {
|
|
75
|
+
case 78: // n
|
|
76
|
+
case 74: // j
|
|
77
|
+
goToNext();
|
|
78
|
+
break;
|
|
79
|
+
case 66: // b
|
|
80
|
+
case 75: // k
|
|
81
|
+
case 80: // p
|
|
82
|
+
goToPrevious();
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
})();
|
|
87
|
+
window.addEventListener('keydown', jumpToCode);
|