初始化项目

This commit is contained in:
2026-10-19 00:11:38 +08:00
commit 9545e48e4d
150 changed files with 9559 additions and 0 deletions
+103
View File
@@ -0,0 +1,103 @@
/**
* JSON 导入导出(1.8.5)。
*
* 导出行对象数组:[{"id":"1","name":"alice"}, …]。
* 导入要求为对象数组;缺列按空值补齐,并检查列集合一致性(不一致记为警告)。
* 解析失败返回错误而非抛异常。
*/
export interface JsonParseResult {
header: string[];
rows: string[][];
errors: string[];
warnings: string[];
}
export class JsonCodec {
static serialize(header: string[], rows: string[][]): string {
const objects: Map<string, string>[] = [];
for (let i = 0; i < rows.length; i++) {
const obj: Map<string, string> = new Map<string, string>();
for (let j = 0; j < header.length; j++) {
const value: string | undefined = rows[i][j];
obj.set(header[j], value === undefined ? '' : value);
}
objects.push(obj);
}
const plain: Record<string, string>[] = [];
for (let i = 0; i < objects.length; i++) {
const record: Record<string, string> = {};
objects[i].forEach((value: string, key: string) => {
record[key] = value;
});
plain.push(record);
}
return JSON.stringify(plain, null, 2);
}
static parse(text: string): JsonParseResult {
const errors: string[] = [];
const warnings: string[] = [];
let parsed: Object | null = null;
try {
parsed = JSON.parse(text) as Object;
} catch (e) {
const message: string = e instanceof Error ? e.message : String(e);
return { header: [], rows: [], errors: ['invalid JSON: ' + message], warnings: [] };
}
if (!Array.isArray(parsed)) {
return { header: [], rows: [], errors: ['top-level JSON value must be an array'], warnings: [] };
}
const array: Object[] = parsed as Object[];
if (array.length === 0) {
return { header: [], rows: [], errors: [], warnings: ['empty array'] };
}
const header: string[] = [];
const first: Object = array[0];
if (first === null || Array.isArray(first) || typeof first !== 'object') {
return { header: [], rows: [], errors: ['array items must be objects'], warnings: [] };
}
const firstRecord: Record<string, Object> = first as Record<string, Object>;
for (const key in firstRecord) {
header.push(key);
}
const rows: string[][] = [];
for (let i = 0; i < array.length; i++) {
const item: Object = array[i];
if (item === null || Array.isArray(item) || typeof item !== 'object') {
errors.push('item ' + i + ' is not an object');
continue;
}
const record: Record<string, Object> = item as Record<string, Object>;
const row: string[] = [];
for (let j = 0; j < header.length; j++) {
const value: Object = record[header[j]];
if (value === undefined) {
warnings.push('item ' + i + ' missing key ' + header[j]);
row.push('');
} else {
row.push(JsonCodec.stringifyValue(value));
}
}
for (const key in record) {
if (header.indexOf(key) < 0) {
warnings.push('item ' + i + ' has extra key ' + key + ' not in header');
}
}
rows.push(row);
}
return { header: header, rows: rows, errors: errors, warnings: warnings };
}
private static stringifyValue(value: Object): string {
if (value === null) {
return '';
}
if (typeof value === 'string') {
return value as string;
}
if (typeof value === 'number' || typeof value === 'boolean') {
return String(value);
}
return JSON.stringify(value);
}
}