Skip to content

Commit 5f56b94

Browse files
author
Anton Eriksson
committed
fix(js): Validate parsed results and throw instead of returning null on failure
1 parent 51feb73 commit 5f56b94

File tree

1 file changed

+30
-31
lines changed

1 file changed

+30
-31
lines changed

interfaces/js/src/parser.ts

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ export function parse(file: string | string[], type?: Extension, parseLinks = fa
4343

4444
const nodeHeader = parseNodeHeader(file);
4545

46-
if (nodeHeader === null) {
47-
return null;
48-
}
49-
5046
if ((type && type === "clu") || nodeHeader.includes("module")) {
5147
if (nodeHeader[0] === "node_id") {
5248
return parseClu(file, nodeHeader);
@@ -77,7 +73,7 @@ const map = {
7773
export function parseClu<NodeType extends CluNode>(
7874
file: string | string[],
7975
nodeHeader?: string[]
80-
): Result<NodeType> | null {
76+
): Result<NodeType> {
8177
// First order
8278
// # node_id module flow
8379
// 10 1 0.0384615
@@ -101,22 +97,14 @@ export function parseClu<NodeType extends CluNode>(
10197
}
10298

10399
const header = parseHeader(file);
104-
if (!header) {
105-
console.warn("No header");
106-
return null;
107-
}
108100

109101
if (!nodeHeader) {
110-
nodeHeader = parseNodeHeader(file) ?? [];
111-
if (nodeHeader.length === 0) {
112-
console.warn("No node header");
113-
return null;
114-
}
102+
nodeHeader = parseNodeHeader(file);
115103
}
116104

117105
const nodes: NodeType[] = [];
118106

119-
for (const [_, line] of nodeSection(file)) {
107+
for (const [i, line] of nodeSection(file)) {
120108
const fields = line.split(" ").map(Number);
121109

122110
if (fields.length < nodeHeader.length) {
@@ -132,6 +120,10 @@ export function parseClu<NodeType extends CluNode>(
132120
node[key] = fields[i];
133121
}
134122

123+
if (node.id === undefined || node.moduleId === undefined || node.flow === undefined) {
124+
throw new Error(`Invalid node at line ${i + 1}: ${line}`);
125+
}
126+
135127
nodes.push(node as NodeType);
136128
}
137129

@@ -145,7 +137,7 @@ export function parseTree<NodeType extends TreeNode>(
145137
file: string | string[],
146138
nodeHeader?: string[],
147139
parseLinks = false
148-
): Result<NodeType> | null {
140+
): Result<NodeType> {
149141
// First order
150142
// # path flow name node_id
151143
// 1:1 0.166667 "i" 1
@@ -169,17 +161,9 @@ export function parseTree<NodeType extends TreeNode>(
169161
}
170162

171163
const header = parseHeader(file);
172-
if (!header) {
173-
console.warn("No header");
174-
return null;
175-
}
176164

177165
if (!nodeHeader) {
178-
nodeHeader = parseNodeHeader(file) ?? [];
179-
if (nodeHeader.length === 0) {
180-
console.warn("No node header");
181-
return null;
182-
}
166+
nodeHeader = parseNodeHeader(file);
183167
}
184168

185169
const nodes: NodeType[] = [];
@@ -223,6 +207,10 @@ export function parseTree<NodeType extends TreeNode>(
223207
}
224208
}
225209

210+
if (node.path === undefined || node.flow === undefined || node.name === undefined || node.id === undefined) {
211+
throw new Error(`Invalid node at line ${i + 1}: ${line}`);
212+
}
213+
226214
nodes.push(node as NodeType);
227215
}
228216

@@ -321,7 +309,7 @@ function* linkSection(lines: string[], start: number = 0) {
321309
}
322310
}
323311

324-
function parseNodeHeader(file: string | string[]): string[] | null {
312+
function parseNodeHeader(file: string | string[]): string[] {
325313
// First order tree
326314
// # path flow name node_id
327315

@@ -356,10 +344,10 @@ function parseNodeHeader(file: string | string[]): string[] | null {
356344
}
357345
}
358346

359-
return null;
347+
throw new Error("Could not parse node header");
360348
}
361349

362-
export function parseHeader(file: string | string[]): Header | null {
350+
export function parseHeader(file: string | string[]): Header {
363351
// # v1.7.3
364352
// # ./Infomap examples/networks/ninetriangles.net .
365353
// # started at 2021-11-02 13:56:33
@@ -376,22 +364,24 @@ export function parseHeader(file: string | string[]): Header | null {
376364
file = file.split("\n");
377365
}
378366

379-
if (file.length < 8) return null;
367+
if (file.length < 8) {
368+
throw new Error("Expected file header to have at least 8 lines");
369+
}
380370

381371
const version = file[0].match(/^# (v\d+\.\d+\.\d+)/)?.[1];
382372

383373
if (version) {
384374
result.version = version;
385375
} else {
386-
return null;
376+
throw new Error("Could not parse version");
387377
}
388378

389379
const args = file[1].match(/^# (.+)/)?.[1];
390380

391381
if (args) {
392382
result.args = args;
393383
} else {
394-
return null;
384+
throw new Error("Could not parse args");
395385
}
396386

397387
for (let i = 2; i < file.length; ++i) {
@@ -444,5 +434,14 @@ export function parseHeader(file: string | string[]): Header | null {
444434
}
445435
}
446436

437+
if (!result.startedAt ||
438+
!result.completedIn ||
439+
!result.numLevels ||
440+
!result.numTopModules ||
441+
!result.codelength ||
442+
!result.relativeCodelengthSavings) {
443+
throw new Error("Could not parse file header");
444+
}
445+
447446
return result as Header;
448447
}

0 commit comments

Comments
 (0)