-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathastericsValidator.ts
More file actions
110 lines (97 loc) · 3.26 KB
/
Copy pathastericsValidator.ts
File metadata and controls
110 lines (97 loc) · 3.26 KB
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
101
102
103
104
105
106
107
108
109
110
/* eslint-disable @typescript-eslint/require-await */
import { BaseValidator } from './baseValidator';
import { ValidationResult } from './validationTypes';
import { decodeText, getBasename, getFs, readBinaryFromInput, toUint8Array } from '../utils/io';
/**
* Validator for Asterics Grid (.grd) JSON files
*/
export class AstericsGridValidator extends BaseValidator {
/**
* Validate from disk
*/
static async validateFile(filePath: string): Promise<ValidationResult> {
const validator = new AstericsGridValidator();
const content = readBinaryFromInput(filePath);
const stats = getFs().statSync(filePath);
return validator.validate(content, getBasename(filePath), stats.size);
}
/**
* Identify whether the content appears to be an Asterics .grd file
*/
static async identifyFormat(content: any, filename: string): Promise<boolean> {
const name = filename.toLowerCase();
if (name.endsWith('.grd')) {
return true;
}
try {
if (
typeof content !== 'string' &&
!(content instanceof ArrayBuffer) &&
!(content instanceof Uint8Array)
) {
return false;
}
const str = typeof content === 'string' ? content : decodeText(toUint8Array(content));
const json = JSON.parse(str);
return Array.isArray(json?.grids);
} catch {
return false;
}
}
async validate(
content: Buffer | Uint8Array,
filename: string,
filesize: number
): Promise<ValidationResult> {
this.reset();
await this.add_check('filename', 'file extension', async () => {
if (!filename.toLowerCase().endsWith('.grd')) {
this.warn('filename should end with .grd');
}
});
let json: any = null;
await this.add_check('json_parse', 'valid JSON', async () => {
try {
let str = decodeText(content);
if (str.charCodeAt(0) === 0xfeff) {
str = str.slice(1);
}
json = JSON.parse(str);
} catch (e: any) {
this.err(`Failed to parse JSON: ${e.message}`, true);
}
});
if (!json) {
return this.buildResult(filename, filesize, 'asterics');
}
await this.add_check('grids', 'grids array', async () => {
if (!Array.isArray(json.grids) || json.grids.length === 0) {
this.err('missing grids array in file', true);
}
});
const grids = Array.isArray(json.grids) ? json.grids.slice(0, 5) : [];
grids.forEach((grid: any, idx: number) => {
const prefix = `grid[${idx}]`;
this.add_check_sync(`${prefix}_id`, `${prefix} id`, () => {
if (!grid?.id || typeof grid.id !== 'string') {
this.err('grid is missing an id');
}
});
this.add_check_sync(`${prefix}_rows`, `${prefix} rowCount`, () => {
if (typeof grid?.rowCount !== 'number' || grid.rowCount <= 0) {
this.err('rowCount must be a positive number');
}
});
this.add_check_sync(`${prefix}_elements`, `${prefix} elements`, () => {
if (!Array.isArray(grid?.gridElements)) {
this.err('gridElements must be an array');
return;
}
if (grid.gridElements.length === 0) {
this.warn('grid has no elements');
}
});
});
return this.buildResult(filename, filesize, 'asterics');
}
}