@web-atoms/core
Version:
152 lines (138 loc) • 5.19 kB
text/typescript
import { IValueConverter } from "../core/IValueConverter";
import { StringHelper } from "../core/StringHelper";
import { RegisterSingleton } from "../di/RegisterSingleton";
import DateTime from "@web-atoms/date-time/dist/DateTime";
export const dateFormatISORegEx = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/;
export const dateFormatMSRegEx = /^\/Date\((d|-|.*)\)[\/|\\]$/;
export type JsonKeysNamingStrategy = "underscore" | "hyphen" | "pascal" | "none";
export interface IJsonParserOptions {
namingStrategy?: JsonKeysNamingStrategy;
dateConverter?: Array<{
regex?: RegExp;
valueConverter: IValueConverter;
}>;
indent?: number;
}
const timeZoneDiff = (new Date()).getTimezoneOffset();
export class JsonService {
public options: IJsonParserOptions = {
indent: 2,
namingStrategy: "none",
dateConverter: [
{
regex: dateFormatISORegEx,
valueConverter: {
fromSource(v: string): DateTime {
const d = new DateTime(v);
// if (/z$/i.test(v)) {
// d.setMinutes( d.getMinutes() - timeZoneDiff );
// }
return d;
},
fromTarget(v: Date): any {
return v.toISOString();
}
}
}, {
regex: dateFormatMSRegEx,
valueConverter: {
fromSource(v: string): DateTime {
const a = dateFormatMSRegEx.exec(v);
const b = a[1].split(/[-+,.]/);
return new DateTime(b[0] ? +b[0] : 0 - +b[1]);
},
fromTarget(v: Date): any {
return v.toISOString();
}
}
}
]
};
public transformKeys(t: (ins: string) => string, v: any): any {
if (!v) {
return v;
}
if (typeof v !== "object") {
return v;
}
if (v instanceof Date) {
return v;
}
if (typeof v === "object" && v.length !== undefined && typeof v.length === "number") {
const a = v as any[];
if (a.map) {
return a.map( (x) => this.transformKeys(t, x));
}
const ra = [];
// tslint:disable-next-line: prefer-for-of
for (let i = 0; i < a.length; i++) {
const iterator = a[i];
ra.push(this.transformKeys(t, iterator));
}
return ra;
}
const r = {};
for (const key in v) {
if (v.hasOwnProperty(key)) {
const element = v[key];
r[ t(key) ] = this.transformKeys(t, element);
}
}
return r;
}
public parse(text: string, options?: IJsonParserOptions): any {
const { dateConverter, namingStrategy } = {
... this.options,
... options
};
const result = JSON.parse(text, (key, value) => {
// transform date...
if (typeof value === "string") {
for (const iterator of dateConverter) {
const a = iterator.regex.test(value);
if (a) {
const dv = iterator.valueConverter.fromSource(value);
return dv;
}
}
}
return value;
} );
switch (namingStrategy) {
case "hyphen":
return this.transformKeys(StringHelper.fromHyphenToCamel, result);
case "underscore":
return this.transformKeys(StringHelper.fromUnderscoreToCamel, result);
case "pascal":
return this.transformKeys(StringHelper.fromPascalToCamel, result);
}
return result;
}
public stringify(v: any, options?: IJsonParserOptions): string {
const { namingStrategy, dateConverter, indent } = {
... this.options,
... options
};
switch (namingStrategy) {
case "hyphen":
v = this.transformKeys(StringHelper.fromCamelToHyphen, v);
break;
case "underscore":
v = this.transformKeys(StringHelper.fromCamelToUnderscore, v);
break;
case "pascal":
v = this.transformKeys(StringHelper.fromCamelToPascal, v);
break;
}
return JSON.stringify(v, (key, value) => {
if (key && /^\_\$\_/.test(key)) {
return undefined;
}
if (dateConverter && (value instanceof Date)) {
return dateConverter[0].valueConverter.fromTarget(value);
}
return value;
}, indent);
}
}