@funkai/cli 0.1.0 → 0.1.2
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 +15 -16
- package/CHANGELOG.md +15 -0
- package/README.md +1 -1
- package/dist/index.mjs +5018 -298
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/commands/generate.ts +4 -62
- package/src/commands/prompts/generate.ts +75 -48
- package/src/commands/prompts/lint.ts +62 -44
- package/src/commands/prompts/setup.ts +2 -7
- package/src/commands/validate.ts +4 -27
- package/src/index.ts +6 -1
- package/src/lib/prompts/codegen.ts +12 -16
- package/src/lib/prompts/flatten.ts +2 -7
- package/src/lib/prompts/frontmatter.ts +28 -33
- package/src/lib/prompts/lint.ts +8 -8
- package/src/lib/prompts/paths.ts +5 -5
- package/src/lib/prompts/pipeline.ts +6 -7
- package/.turbo/turbo-test$colon$coverage.log +0 -36
- package/.turbo/turbo-test.log +0 -26
- package/.turbo/turbo-typecheck.log +0 -4
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/commands/create.ts.html +0 -208
- package/coverage/lcov-report/commands/generate.ts.html +0 -388
- package/coverage/lcov-report/commands/index.html +0 -161
- package/coverage/lcov-report/commands/lint.ts.html +0 -331
- package/coverage/lcov-report/commands/setup.ts.html +0 -493
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -131
- package/coverage/lcov-report/lib/codegen.ts.html +0 -805
- package/coverage/lcov-report/lib/extract-variables.ts.html +0 -181
- package/coverage/lcov-report/lib/flatten.ts.html +0 -385
- package/coverage/lcov-report/lib/frontmatter.ts.html +0 -487
- package/coverage/lcov-report/lib/index.html +0 -191
- package/coverage/lcov-report/lib/lint.ts.html +0 -307
- package/coverage/lcov-report/lib/paths.ts.html +0 -487
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -749
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { match } from "ts-pattern";
|
|
2
1
|
import { parse as parseYaml } from "yaml";
|
|
3
2
|
|
|
4
|
-
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
5
|
-
const NAME_RE = /^[a-z0-9-]+$/;
|
|
3
|
+
export const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
4
|
+
export const NAME_RE = /^[a-z0-9-]+$/;
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Parse raw YAML content into a record, wrapping parse errors
|
|
@@ -26,20 +25,20 @@ function parseYamlContent(yaml: string, filePath: string): Record<string, unknow
|
|
|
26
25
|
* A variable declared in the frontmatter `schema` block.
|
|
27
26
|
*/
|
|
28
27
|
export interface SchemaVariable {
|
|
29
|
-
name: string;
|
|
30
|
-
type: string;
|
|
31
|
-
required: boolean;
|
|
32
|
-
description?: string;
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly type: string;
|
|
30
|
+
readonly required: boolean;
|
|
31
|
+
readonly description?: string;
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
/**
|
|
36
35
|
* Parsed frontmatter from a `.prompt` file.
|
|
37
36
|
*/
|
|
38
37
|
export interface ParsedFrontmatter {
|
|
39
|
-
name: string;
|
|
40
|
-
group?: string;
|
|
41
|
-
version?: string;
|
|
42
|
-
schema: SchemaVariable[];
|
|
38
|
+
readonly name: string;
|
|
39
|
+
readonly group?: string;
|
|
40
|
+
readonly version?: string;
|
|
41
|
+
readonly schema: readonly SchemaVariable[];
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
/**
|
|
@@ -77,22 +76,21 @@ export function parseFrontmatter(content: string, filePath: string): ParsedFront
|
|
|
77
76
|
);
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
const group =
|
|
81
|
-
.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
.otherwise(() => undefined);
|
|
79
|
+
const group =
|
|
80
|
+
typeof parsed.group === "string"
|
|
81
|
+
? (() => {
|
|
82
|
+
const g = parsed.group as string;
|
|
83
|
+
const invalidSegment = g.split("/").find((segment) => !NAME_RE.test(segment));
|
|
84
|
+
if (invalidSegment !== undefined) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Invalid group segment "${invalidSegment}" in ${filePath}. ` +
|
|
87
|
+
"Group segments must be lowercase alphanumeric with hyphens only.",
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return g;
|
|
91
|
+
})()
|
|
92
|
+
: undefined;
|
|
93
|
+
const version = parsed.version != null ? String(parsed.version) : undefined;
|
|
96
94
|
|
|
97
95
|
const schema = parseSchemaBlock(parsed.schema, filePath);
|
|
98
96
|
|
|
@@ -124,13 +122,10 @@ function parseSchemaBlock(raw: unknown, filePath: string): SchemaVariable[] {
|
|
|
124
122
|
|
|
125
123
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
126
124
|
const def = value as Record<string, unknown>;
|
|
127
|
-
const type =
|
|
128
|
-
.with(true, () => def.type as string)
|
|
129
|
-
.otherwise(() => "string");
|
|
125
|
+
const type = typeof def.type === "string" ? (def.type as string) : "string";
|
|
130
126
|
const required = def.required !== false;
|
|
131
|
-
const description =
|
|
132
|
-
.
|
|
133
|
-
.otherwise(() => undefined);
|
|
127
|
+
const description =
|
|
128
|
+
typeof def.description === "string" ? (def.description as string) : undefined;
|
|
134
129
|
|
|
135
130
|
return { name: varName, type, required, description };
|
|
136
131
|
}
|
package/src/lib/prompts/lint.ts
CHANGED
|
@@ -4,17 +4,17 @@ import type { SchemaVariable } from "./frontmatter.js";
|
|
|
4
4
|
* A single lint diagnostic.
|
|
5
5
|
*/
|
|
6
6
|
export interface LintDiagnostic {
|
|
7
|
-
level: "error" | "warn";
|
|
8
|
-
message: string;
|
|
7
|
+
readonly level: "error" | "warn";
|
|
8
|
+
readonly message: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Result of linting a single prompt file.
|
|
13
13
|
*/
|
|
14
14
|
export interface LintResult {
|
|
15
|
-
name: string;
|
|
16
|
-
filePath: string;
|
|
17
|
-
diagnostics: LintDiagnostic[];
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly filePath: string;
|
|
17
|
+
readonly diagnostics: readonly LintDiagnostic[];
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -33,8 +33,8 @@ export interface LintResult {
|
|
|
33
33
|
export function lintPrompt(
|
|
34
34
|
name: string,
|
|
35
35
|
filePath: string,
|
|
36
|
-
schemaVars: SchemaVariable[],
|
|
37
|
-
templateVars: string[],
|
|
36
|
+
schemaVars: readonly SchemaVariable[],
|
|
37
|
+
templateVars: readonly string[],
|
|
38
38
|
): LintResult {
|
|
39
39
|
const diagnostics: LintDiagnostic[] = [];
|
|
40
40
|
const declared = new Set(schemaVars.map((v) => v.name));
|
|
@@ -69,6 +69,6 @@ export function lintPrompt(
|
|
|
69
69
|
/**
|
|
70
70
|
* Check whether any lint results contain errors.
|
|
71
71
|
*/
|
|
72
|
-
export function hasLintErrors(results: LintResult[]): boolean {
|
|
72
|
+
export function hasLintErrors(results: readonly LintResult[]): boolean {
|
|
73
73
|
return results.some((r) => r.diagnostics.some((d) => d.level === "error"));
|
|
74
74
|
}
|
package/src/lib/prompts/paths.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { existsSync, lstatSync, readdirSync, readFileSync } from "node:fs";
|
|
2
2
|
import { basename, extname, join, resolve } from "node:path";
|
|
3
3
|
|
|
4
|
+
import { FRONTMATTER_RE, NAME_RE } from "./frontmatter.js";
|
|
5
|
+
|
|
4
6
|
const MAX_DEPTH = 5;
|
|
5
7
|
const PROMPT_EXT = ".prompt";
|
|
6
|
-
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
7
|
-
const NAME_RE = /^[a-z0-9-]+$/;
|
|
8
8
|
|
|
9
9
|
export interface DiscoveredPrompt {
|
|
10
|
-
name: string;
|
|
11
|
-
filePath: string;
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly filePath: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -102,7 +102,7 @@ function scanDirectory(dir: string, depth: number): DiscoveredPrompt[] {
|
|
|
102
102
|
* @returns Sorted, deduplicated list of discovered prompts.
|
|
103
103
|
* @throws If duplicate prompt names are found across roots.
|
|
104
104
|
*/
|
|
105
|
-
export function discoverPrompts(roots: string[]): DiscoveredPrompt[] {
|
|
105
|
+
export function discoverPrompts(roots: readonly string[]): DiscoveredPrompt[] {
|
|
106
106
|
const all = roots.flatMap((root) => scanDirectory(resolve(root), 0));
|
|
107
107
|
|
|
108
108
|
const byName = Map.groupBy(all, (prompt) => prompt.name);
|
|
@@ -2,7 +2,6 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
|
|
4
4
|
import { clean, PARTIALS_DIR } from "@funkai/prompts";
|
|
5
|
-
import { match } from "ts-pattern";
|
|
6
5
|
|
|
7
6
|
import { type ParsedPrompt } from "./codegen.js";
|
|
8
7
|
import { extractVariables } from "./extract-variables.js";
|
|
@@ -37,9 +36,9 @@ export function runLintPipeline(options: LintPipelineOptions): LintPipelineResul
|
|
|
37
36
|
const discovered = discoverPrompts([...options.roots]);
|
|
38
37
|
const customPartialsDir = resolve(options.partials ?? ".prompts/partials");
|
|
39
38
|
// oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: checking custom partials directory from CLI config
|
|
40
|
-
const partialsDirs =
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
const partialsDirs = existsSync(customPartialsDir)
|
|
40
|
+
? [customPartialsDir, PARTIALS_DIR]
|
|
41
|
+
: [PARTIALS_DIR];
|
|
43
42
|
|
|
44
43
|
const results = discovered.map((d) => {
|
|
45
44
|
// oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: reading discovered prompt file
|
|
@@ -83,9 +82,9 @@ export function runGeneratePipeline(options: GeneratePipelineOptions): GenerateP
|
|
|
83
82
|
const discovered = discoverPrompts([...options.roots]);
|
|
84
83
|
const customPartialsDir = resolve(options.partials ?? resolve(options.out, "../partials"));
|
|
85
84
|
// oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: checking custom partials directory from CLI config
|
|
86
|
-
const partialsDirs =
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
const partialsDirs = existsSync(customPartialsDir)
|
|
86
|
+
? [customPartialsDir, PARTIALS_DIR]
|
|
87
|
+
: [PARTIALS_DIR];
|
|
89
88
|
|
|
90
89
|
const processed = discovered.map((d) => {
|
|
91
90
|
// oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: reading discovered prompt file
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @funkai/cli@0.4.0 test:coverage /Users/zacrosenbauer/Code/joggr/funkai/packages/cli
|
|
3
|
-
> vitest run --coverage
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[1m[46m RUN [49m[22m [36mv4.1.0 [39m[90m/Users/zacrosenbauer/Code/joggr/funkai/packages/cli[39m
|
|
7
|
-
[2mCoverage enabled with [22m[33mv8[39m
|
|
8
|
-
|
|
9
|
-
[32m✓[39m src/lib/__tests__/lint.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
10
|
-
[32m✓[39m src/lib/__tests__/frontmatter.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
11
|
-
[32m✓[39m src/lib/__tests__/extract-variables.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 15[2mms[22m[39m
|
|
12
|
-
[32m✓[39m src/lib/__tests__/flatten.test.ts [2m([22m[2m27 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
|
13
|
-
|
|
14
|
-
[2m Test Files [22m [1m[32m4 passed[39m[22m[90m (4)[39m
|
|
15
|
-
[2m Tests [22m [1m[32m55 passed[39m[22m[90m (55)[39m
|
|
16
|
-
[2m Start at [22m 20:28:56
|
|
17
|
-
[2m Duration [22m 173ms[2m (transform 89ms, setup 0ms, import 139ms, tests 47ms, environment 0ms)[22m
|
|
18
|
-
|
|
19
|
-
[34m % [39m[2mCoverage report from [22m[33mv8[39m
|
|
20
|
-
-------------------|---------|----------|---------|---------|-------------------
|
|
21
|
-
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
|
22
|
-
-------------------|---------|----------|---------|---------|-------------------
|
|
23
|
-
All files | 28.3 | 26.31 | 34.11 | 27.8 |
|
|
24
|
-
commands | 0 | 0 | 0 | 0 |
|
|
25
|
-
create.ts | 0 | 0 | 0 | 0 | 8-39
|
|
26
|
-
generate.ts | 0 | 0 | 0 | 0 | 25-98
|
|
27
|
-
lint.ts | 0 | 0 | 0 | 0 | 23-79
|
|
28
|
-
setup.ts | 0 | 0 | 0 | 0 | 7-134
|
|
29
|
-
lib | 48.83 | 42.16 | 50 | 48.29 |
|
|
30
|
-
codegen.ts | 0 | 0 | 0 | 0 | 25-239
|
|
31
|
-
...-variables.ts | 100 | 75 | 100 | 100 | 21
|
|
32
|
-
flatten.ts | 100 | 100 | 100 | 100 |
|
|
33
|
-
frontmatter.ts | 90.38 | 88.88 | 91.66 | 90.19 | 48,53,99,117,127
|
|
34
|
-
lint.ts | 100 | 100 | 100 | 100 |
|
|
35
|
-
paths.ts | 0 | 0 | 0 | 0 | 4-133
|
|
36
|
-
-------------------|---------|----------|---------|---------|-------------------
|
package/.turbo/turbo-test.log
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
> @funkai/cli@0.4.0 test /Users/zacrosenbauer/Code/joggr/funkai/packages/cli
|
|
4
|
-
> vitest run
|
|
5
|
-
|
|
6
|
-
[?25l
|
|
7
|
-
[1m[46m RUN [49m[22m [36mv4.1.0 [39m[90m/Users/zacrosenbauer/Code/joggr/funkai/packages/cli[39m
|
|
8
|
-
|
|
9
|
-
[?2026h
|
|
10
|
-
[1m[33m ❯ [39m[22msrc/lib/prompts/__tests__/extract-variables.test.ts[2m [queued][22m
|
|
11
|
-
|
|
12
|
-
[2m Test Files [22m[1m[32m0 passed[39m[22m[90m (4)[39m
|
|
13
|
-
[2m Tests [22m[1m[32m0 passed[39m[22m[90m (0)[39m
|
|
14
|
-
[2m Start at [22m21:15:41
|
|
15
|
-
[2m Duration [22m102ms
|
|
16
|
-
[?2026l[K[1A[K[1A[K[1A[K[1A[K[1A[K[1A[K[1A[K [32m✓[39m src/lib/prompts/__tests__/lint.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
17
|
-
[32m✓[39m src/lib/prompts/__tests__/extract-variables.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 18[2mms[22m[39m
|
|
18
|
-
[32m✓[39m src/lib/prompts/__tests__/frontmatter.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
19
|
-
[32m✓[39m src/lib/prompts/__tests__/flatten.test.ts [2m([22m[2m27 tests[22m[2m)[22m[32m 34[2mms[22m[39m
|
|
20
|
-
|
|
21
|
-
[2m Test Files [22m [1m[32m4 passed[39m[22m[90m (4)[39m
|
|
22
|
-
[2m Tests [22m [1m[32m55 passed[39m[22m[90m (55)[39m
|
|
23
|
-
[2m Start at [22m 21:15:41
|
|
24
|
-
[2m Duration [22m 233ms[2m (transform 140ms, setup 0ms, import 222ms, tests 66ms, environment 0ms)[22m
|
|
25
|
-
|
|
26
|
-
[?25h
|
|
@@ -1,224 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
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);
|