@udt/parser-utils 0.1.0 → 0.3.0

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/README.md CHANGED
@@ -16,7 +16,7 @@ const fileData = { /* ... */ };
16
16
  // relevant properties of each group and design token
17
17
  // object it encounters to the functions you provide in
18
18
  // the config:
19
- const parsedData = parseData(fileData, {
19
+ const parsedGroup = parseData(fileData, {
20
20
  /* Parser config */
21
21
 
22
22
  // A function that checks whether an object is
@@ -39,7 +39,18 @@ const parsedData = parseData(fileData, {
39
39
  // format properties
40
40
  groupPropsToExtract: [ /* ... */ ];
41
41
 
42
- // Function which is called for each group data object
42
+ // Function which is called for each design token
43
+ // data object that is encountered.
44
+ //
45
+ // Is given the design token data and its path, and
46
+ // should parse that data into whatever structure is
47
+ // desired.
48
+ parseDesignTokenData: (data, path, contextFromParent) => {
49
+ /* ... */
50
+ return parsedDesignToken;
51
+ },
52
+
53
+ // OPTIONAL function which is called for each group data object
43
54
  // that is encountered.
44
55
  //
45
56
  // Is given the extracted properties of that group and its
@@ -50,24 +61,17 @@ const parsedData = parseData(fileData, {
50
61
  return {
51
62
  group: parsedGroup,
52
63
 
53
- // optional:
54
- addChild: (childName, childGroupOrToken) => { /*... */ },
55
-
56
- // optional:
64
+ // OPTIONAL:
57
65
  contextForChildren: /* anything you like */,
58
66
  }
59
67
  },
60
68
 
61
- // Function which is called for each design token
62
- // data object that is encountered.
69
+ // OPTIONAL function which is called for each design token and/or
70
+ // nested group found within a group.
63
71
  //
64
- // Is given the design token data and its path, and
65
- // should parse that data into whatever structure is
66
- // desired.
67
- parseDesignTokenData: (data, path, contextFromParent) => {
68
- /* ... */
69
- return parsedDesignToken;
70
- },
72
+ // Useful if your parsed groups and design tokens need to be assembled into
73
+ // a tree structure.
74
+ addChildToGroup: (parsedParentGroup, childName, parsedChildGroupOrToken) => { /*... */ },
71
75
  });
72
76
  ```
73
77
 
@@ -16,15 +16,15 @@ import { type PlainObject } from "./isJsonObject.js";
16
16
  * and their values, and an array of all property
17
17
  * names of the input object that were not extracted.
18
18
  */
19
- export declare function extractProperties(object: PlainObject, propsToExtract: (string | RegExp)[]): {
19
+ export declare function extractProperties(object: PlainObject, propsToExtract: readonly (string | RegExp)[]): {
20
20
  /**
21
21
  * Object containg the extract properties
22
22
  * and their respective values.
23
23
  */
24
24
  extracted: PlainObject;
25
25
  /**
26
- * Array of property names of the input
27
- * object that were not extracted.
26
+ * Object containing the remaining, unextracted
27
+ * properties and their respective values.
28
28
  */
29
- remainingProps: string[];
29
+ rest: PlainObject;
30
30
  };
@@ -19,18 +19,18 @@ export function extractProperties(object, propsToExtract) {
19
19
  const propNamesToExtract = propsToExtract.filter((prop) => typeof prop === "string");
20
20
  const propRegexesToExtract = propsToExtract.filter((prop) => prop instanceof RegExp);
21
21
  const extracted = {};
22
- const remainingProps = [];
22
+ const rest = {};
23
23
  Object.getOwnPropertyNames(object).forEach((prop) => {
24
24
  if (propNamesToExtract.some((propNameToExtract) => propNameToExtract === prop) ||
25
25
  propRegexesToExtract.some((propRegexToExtract) => propRegexToExtract.test(prop))) {
26
26
  extracted[prop] = object[prop];
27
27
  }
28
28
  else {
29
- remainingProps.push(prop);
29
+ rest[prop] = object[prop];
30
30
  }
31
31
  });
32
32
  return {
33
33
  extracted,
34
- remainingProps,
34
+ rest,
35
35
  };
36
36
  }
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ /* v8 ignore start */
1
2
  export * from "./parseData.js";
2
3
  export * from "./isJsonObject.js";
3
4
  export * from "./extractProperties.js";
5
+ /* v8 ignore end */
@@ -31,33 +31,25 @@ export type IsDesignTokenDataFn = (data: PlainObject) => boolean;
31
31
  export type ParseDesignTokenDataFn<ParsedDesignToken, T> = (data: PlainObject, path: string[], contextFromParent?: T) => ParsedDesignToken;
32
32
  /**
33
33
  * A function that adds a parsed group or design token
34
- * as a child of a parsed group.
34
+ * as a child of the given parsed group.
35
35
  *
36
+ * @param parent The parent group to add a child to
36
37
  * @param name The name of the child group or design token
37
- * @param child The group or desing token to add
38
+ * @param child The group or design token to add
38
39
  */
39
- export type AddChildFn<ParsedGroup, ParsedDesignToken> = (name: string, child: ParsedGroup | ParsedDesignToken) => void;
40
+ export type AddChildFn<ParsedGroup, ParsedDesignToken> = (parent: ParsedGroup, name: string, child: ParsedGroup | ParsedDesignToken) => void;
40
41
  /**
41
42
  * The return value of a `ParseGroupDataFn`.
42
43
  */
43
- export interface ParseGroupResult<ParsedGroup, ParsedDesignToken, T> {
44
+ export interface ParseGroupResult<ParsedGroup, T> {
44
45
  /**
45
46
  * The parsed representation of the group.
46
47
  *
47
- * May be `undefined` if there is no useful result
48
- * to return from `parseData()` - e.g. if just
49
- * logging group info or something like that.
48
+ * May be omitted if there is no useful result to
49
+ * return and we only need to pass along context
50
+ * data.
50
51
  */
51
- group: ParsedGroup;
52
- /**
53
- * Optional function that will add other parsed groups
54
- * or design tokens as children of this parsed group.
55
- *
56
- * Intended for cases where the parsed representation
57
- * of a group needs to contain its children. If not
58
- * needed, this property can be omitted.
59
- */
60
- addChild?: AddChildFn<ParsedGroup, ParsedDesignToken>;
52
+ group?: ParsedGroup;
61
53
  /**
62
54
  * Optional context data to be passed into the
63
55
  * `parseGroupData()` and `parseDesignTokenData()` calls
@@ -81,11 +73,10 @@ export interface ParseGroupResult<ParsedGroup, ParsedDesignToken, T> {
81
73
  * parsed the group containing this group.
82
74
  *
83
75
  * @returns The parsed representation of the group and,
84
- * optionally, a function to add child groups or
85
- * design tokens to it and some context data to
86
- * pass down when child data is parsed.
76
+ * optionally, some context data to pass down
77
+ * when child data is parsed.
87
78
  */
88
- export type ParseGroupDataFn<ParsedGroup, ParsedDesignToken, T> = (data: PlainObject, path: string[], contextFromParent?: T) => ParseGroupResult<ParsedGroup, ParsedDesignToken, T>;
79
+ export type ParseGroupDataFn<ParsedGroup, T> = (data: PlainObject, path: string[], contextFromParent?: T) => ParseGroupResult<ParsedGroup, T>;
89
80
  export interface ParserConfig<ParsedDesignToken, ParsedGroup, T> {
90
81
  /**
91
82
  * A function that determines whether an object in the input
@@ -110,7 +101,7 @@ export interface ParserConfig<ParsedDesignToken, ParsedGroup, T> {
110
101
  * path, and should parse that data into whatever structure
111
102
  * is desired.
112
103
  */
113
- parseGroupData: ParseGroupDataFn<ParsedGroup, ParsedDesignToken, T>;
104
+ parseGroupData?: ParseGroupDataFn<ParsedGroup, T>;
114
105
  /**
115
106
  * Function which is called for each design token
116
107
  *data object that is encountered.
@@ -120,6 +111,15 @@ export interface ParserConfig<ParsedDesignToken, ParsedGroup, T> {
120
111
  * desired.
121
112
  */
122
113
  parseDesignTokenData: ParseDesignTokenDataFn<ParsedDesignToken, T>;
114
+ /**
115
+ * Optional function that will add parsed groups
116
+ * or design tokens as children of another parsed group.
117
+ *
118
+ * Intended for cases where the parsed representation
119
+ * of a group needs to contain its children. If not
120
+ * needed, this property can be omitted.
121
+ */
122
+ addChildToGroup?: AddChildFn<ParsedGroup, ParsedDesignToken>;
123
123
  }
124
124
  /**
125
125
  * Thrown when `parseData()` encounters group or design token
@@ -136,6 +136,17 @@ export declare class InvalidDataError extends Error {
136
136
  data: unknown;
137
137
  constructor(path: string[], data: unknown);
138
138
  }
139
+ /**
140
+ * Thrown when the outermost object in the data passed to `parseData()`
141
+ * is not a group.
142
+ */
143
+ export declare class InvalidStructureError extends Error {
144
+ /**
145
+ * The offending value.
146
+ */
147
+ data: unknown;
148
+ constructor(data: unknown);
149
+ }
139
150
  /**
140
151
  * Parses a nested object structure representing groups
141
152
  * and design tokens, such as the data obtained by reading
@@ -156,4 +167,4 @@ export declare class InvalidDataError extends Error {
156
167
  * or group parser function call.
157
168
  * @returns The outermost parsed group or design token
158
169
  */
159
- export declare function parseData<ParsedDesignToken, ParsedGroup, T>(data: unknown, config: ParserConfig<ParsedDesignToken, ParsedGroup, T>, contextFromParent?: T): ParsedDesignToken | ParsedGroup;
170
+ export declare function parseData<ParsedDesignToken, ParsedGroup, T>(data: unknown, config: ParserConfig<ParsedDesignToken, ParsedGroup, T>, contextFromParent?: T): ParsedGroup | undefined;
package/dist/parseData.js CHANGED
@@ -20,6 +20,21 @@ export class InvalidDataError extends Error {
20
20
  this.data = data;
21
21
  }
22
22
  }
23
+ /**
24
+ * Thrown when the outermost object in the data passed to `parseData()`
25
+ * is not a group.
26
+ */
27
+ export class InvalidStructureError extends Error {
28
+ /**
29
+ * The offending value.
30
+ */
31
+ data;
32
+ constructor(data) {
33
+ super(`Expected a group at the root level, but encountered a design token instead`);
34
+ this.name = "InvalidDataError";
35
+ this.data = data;
36
+ }
37
+ }
23
38
  /**
24
39
  * The internal data parsing implementation.
25
40
  *
@@ -35,29 +50,39 @@ export class InvalidDataError extends Error {
35
50
  * to the parent group.
36
51
  * @returns The parsed design token or group.
37
52
  */
38
- function parseDataImpl(data, config, contextFromParent, path = [], addToParent) {
53
+ function parseDataImpl(data, config, contextFromParent, path = [], parentGroup) {
39
54
  if (!isPlainObject(data)) {
40
55
  throw new InvalidDataError(path, data);
41
56
  }
42
- const { isDesignTokenData, groupPropsToExtract, parseGroupData, parseDesignTokenData, } = config;
43
- let groupOrToken;
57
+ const { isDesignTokenData, groupPropsToExtract, parseGroupData, parseDesignTokenData, addChildToGroup, } = config;
58
+ let groupOrToken = undefined;
44
59
  if (isDesignTokenData(data)) {
45
60
  // looks like a token
61
+ if (path.length === 0) {
62
+ throw new InvalidStructureError(data);
63
+ }
46
64
  groupOrToken = parseDesignTokenData(data, path, contextFromParent);
47
- if (addToParent && path.length > 0) {
48
- addToParent(path[path.length - 1], groupOrToken);
65
+ if (addChildToGroup && path.length > 0 && parentGroup !== undefined) {
66
+ addChildToGroup(parentGroup, path[path.length - 1], groupOrToken);
49
67
  }
50
68
  }
51
69
  else {
52
70
  // must be a group
53
- const { extracted: groupData, remainingProps: childNames } = extractProperties(data, groupPropsToExtract);
54
- const { group, addChild, contextForChildren } = parseGroupData(groupData, path, contextFromParent);
55
- groupOrToken = group;
56
- if (addToParent && path.length > 0) {
57
- addToParent(path[path.length - 1], groupOrToken);
71
+ const { extracted: groupData, rest: children } = extractProperties(data, groupPropsToExtract);
72
+ let contextForChildren;
73
+ if (parseGroupData) {
74
+ const parseResult = parseGroupData(groupData, path, contextFromParent);
75
+ contextForChildren = parseResult.contextForChildren;
76
+ groupOrToken = parseResult.group;
77
+ }
78
+ if (addChildToGroup &&
79
+ path.length > 0 &&
80
+ parentGroup !== undefined &&
81
+ groupOrToken !== undefined) {
82
+ addChildToGroup(parentGroup, path[path.length - 1], groupOrToken);
58
83
  }
59
- for (const childName of childNames) {
60
- parseDataImpl(data[childName], config, contextForChildren, [...path, childName], addChild);
84
+ for (const childName in children) {
85
+ parseDataImpl(children[childName], config, contextForChildren, [...path, childName], groupOrToken);
61
86
  }
62
87
  }
63
88
  return groupOrToken;
@@ -83,5 +108,7 @@ function parseDataImpl(data, config, contextFromParent, path = [], addToParent)
83
108
  * @returns The outermost parsed group or design token
84
109
  */
85
110
  export function parseData(data, config, contextFromParent) {
111
+ // parseDataImpl() called with an empty path will never return
112
+ // a ParsedDesignToken
86
113
  return parseDataImpl(data, config, contextFromParent);
87
114
  }
package/package.json CHANGED
@@ -1,10 +1,18 @@
1
1
  {
2
2
  "name": "@udt/parser-utils",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Low-level logic and utilities for parsing DTCG and DTCG-like files",
5
- "main": "dist/index.js",
6
5
  "type": "module",
7
- "types": "dist/index.d.ts",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/index.js",
9
+ "types": "./dist/index.d.ts"
10
+ }
11
+ },
12
+ "sideEffects": false,
13
+ "files": [
14
+ "dist/"
15
+ ],
8
16
  "scripts": {
9
17
  "clean": "del-cli dist/*",
10
18
  "build": "tsc -p tsconfig.build.json",
@@ -25,5 +33,8 @@
25
33
  "bugs": {
26
34
  "url": "https://github.com/universal-design-tokens/udt/issues"
27
35
  },
36
+ "engines": {
37
+ "node": ">= 18"
38
+ },
28
39
  "homepage": "https://github.com/universal-design-tokens/udt/tree/master/packages/parser-utils#readme"
29
40
  }
package/CHANGELOG.md DELETED
@@ -1,13 +0,0 @@
1
- # @udt/parser-utils
2
-
3
- ## 0.1.0
4
-
5
- ### Minor Changes
6
-
7
- - aa0e5ce: Initial release of `@udt/parser-utils` package.
8
-
9
- ### Patch Changes
10
-
11
- - aa0e5ce: Added `extractProperties()` function for extracting specified properties and their values from an obejct.
12
- - aa0e5ce: Added `parseData()` function for parsing design token data
13
- - aa0e5ce: Added `isPlainObject()` function for checking if a value is a plain object.
package/coverage/base.css DELETED
@@ -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
- // Selecter 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);