/
index.ts
100 lines (82 loc) · 2.7 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { Input, Output, ActionStep, Json } from "@shanzhai/interfaces";
/**
* An {@link ActionStep} which converts the result of parsing a CSV to
* values which can be included in the TypeScript global scope.
*/
export class ConvertParsedCsvToStructOfArraysStep extends ActionStep {
/**
* @param name A description of the operation being performed.
* @param keyPrefix The prefix of any generated TypeScript global variables.
* @param input An {@link Input} which supplies the parsed CSV.
* @param output An {@link Output} which accepts the generated TypeScript
* global variables.
*/
constructor(
name: string,
public readonly keyPrefix: string,
public readonly input: Input<ReadonlyArray<ReadonlyArray<string>>>,
public readonly output: Output<{ readonly [key: string]: Json }>
) {
super(name, output.effects);
}
/**
* @inheritdoc
*/
async execute(): Promise<void> {
const input = await this.input.get();
if (input.length < 1) {
throw new Error(`The file contains no rows.`);
}
const headerRow = input[0];
const populatedHeaders = headerRow.filter((header) => header !== ``);
if (populatedHeaders.length === 0) {
throw new Error(`The file contains no columns.`);
}
const invalidColumnNames = populatedHeaders.filter(
(header) => !/^[a-zA-Z_0-9$]+$/.test(header)
);
if (invalidColumnNames.length > 0) {
throw new Error(
`Column ${JSON.stringify(invalidColumnNames[0])} is invalidly named.`
);
}
const duplicateColumnNames = populatedHeaders.filter(
(header) =>
populatedHeaders.indexOf(header) !==
populatedHeaders.lastIndexOf(header)
);
if (duplicateColumnNames.length > 0) {
throw new Error(
`Column ${JSON.stringify(duplicateColumnNames[0])} is not unique.`
);
}
const output: { [key: string]: ReadonlyArray<Json> } = {};
for (let column = 0; column < headerRow.length; column++) {
const header = headerRow[column];
if (header === ``) {
if (
input
.slice(1)
.map((row) => row[column])
.some((cell) => cell !== ``)
) {
throw new Error(`The file contains a column without a header.`);
}
} else {
const items: Json[] = [];
for (const row of input.slice(1)) {
const cell = row[column];
let converted: Json;
try {
converted = JSON.parse(cell);
} catch {
converted = cell;
}
items.push(converted);
}
output[`${this.keyPrefix}${header}`] = items;
}
}
await this.output.set(output);
}
}