FreeDatas2HTML/src/ParserForJSON.ts

152 lines
6.0 KiB
TypeScript

const errors=require("./errors.js");
import { RemoteSource } from "./RemoteSource";
import { ParseErrors, ParseResults, Parsers, RemoteSources, RemoteSourceSettings } from "./interfaces";
export class ParserForJSON implements Parsers
{
private _datasRemoteSource: RemoteSources;
private _datas2Parse: string="";
private _parseResults: ParseResults|undefined=undefined;
// L'instance d'une autre classe que RemoteSource peut être passée au constructeur
constructor(datasRemoteSource?: RemoteSources)
{
if(datasRemoteSource !== undefined)
this._datasRemoteSource=datasRemoteSource;
else
this._datasRemoteSource=new RemoteSource({ url:"" });
}
public setRemoteSource(source: RemoteSourceSettings)
{
this._datasRemoteSource=new RemoteSource(source);
}
get datasRemoteSource() : RemoteSources
{
return this._datasRemoteSource;
}
set datas2Parse(datas: string)
{
if(datas.trim().length === 0)
throw new Error(errors.parserNeedDatas);
else
this._datas2Parse=datas.trim();
}
get datas2Parse() : string
{
return this._datas2Parse;
}
get parseResults() : ParseResults|undefined
{
return this._parseResults;
}
public async parse(): Promise<any>
{
const parser=this;
let parseContent="";
if(parser._datasRemoteSource.url !== "")
{
const settings: {}=parser._datasRemoteSource.getFetchSettings();
const response=await fetch(parser._datasRemoteSource.url, settings);
if (! response.ok)
throw new Error(errors.parserRemoteFail);
parseContent=await response.text(); // doit en fait retourner du JSON, mais il est parsé plus loin.
}
else if(parser._datas2Parse !== "")
parseContent=parser._datas2Parse;
else
throw new Error(errors.parserNeedSource);
const datasParsed=JSON.parse(parseContent);
const typesOkForValue=["boolean","number","string"];
let fields: string[]=[], datas: {[index: string]:string}[]=[], parseErrors: ParseErrors[]=[];
// Je peux recevoir 2 tableaux contenant respectivement la liste de champs : string[] + celle des données : any[][]
if(Array.isArray(datasParsed.fields) && Array.isArray(datasParsed.datas))
{
const nbFields=datasParsed.fields.length, nbDatas=datasParsed.datas.length;
// Traitement des noms de champs reçus :
const goodFields: string[]=[];
fields=datasParsed.fields;
for(let i=0; i < nbFields; i++)
{
if(typeof fields[i] !== "string")
parseErrors.push({ row:-1, message: errors.parserTypeError+typeof fields[i] });
else
{
fields[i]=fields[i].trim();
if(fields[i] !== "" && goodFields.indexOf(fields[i]) === -1)
goodFields.push(fields[i]);
else
parseErrors.push({ row:-1, message: errors.parserFieldNameFail});
}
}
fields=goodFields;
if(fields.length === 0)
throw new Error(errors.parserFail);
// Puis les données :
for(let i=0; i < nbDatas; i++)
{
const dataObject: {[index: string]: string}={}, nbObjFields=datasParsed.datas[i].length;
if( nbObjFields !== nbFields)
parseErrors.push({ row:i, message:errors.parserNumberOfFieldsFail});
for(let j=0; j < nbObjFields && j < nbFields; j++)
{
if(typesOkForValue.indexOf(typeof datasParsed.datas[i][j]) === -1)
parseErrors.push({ row:i, message:errors.parserTypeError+typeof datasParsed.datas[i][j]});
else
dataObject[fields[j]]=datasParsed.datas[i][j]+""; // force le type String
}
if(Object.keys(dataObject).length !== 0)
datas.push(dataObject);
else
parseErrors.push({ row:i, message: errors.parserLineWithoutDatas});
}
}
else // Ou un tableau d'objets {}[], dont les attributs sont les noms des champs
{
let i=0;
for(let data of datasParsed)
{
// Ici les champs sont découverts au fur et à mesure,
// Leur ordre peut être différent d'une ligne à l'autre
// Et tous les champs ne sont pas systématiquement présents
let dataObject: {[index: string]: string} = {}
for(let field in data)
{
field=field.trim();
if(field === "")
parseErrors.push({ row:-1, message: errors.parserFieldNameFail});
else if (typesOkForValue.indexOf(typeof data[field]) === -1)
parseErrors.push({ row:i, message:errors.parserTypeError+typeof data[field]});
else
{
if(fields.indexOf(field) === -1)
fields.push(field);
if(dataObject[field] !== undefined) // = doublon
parseErrors.push({ row:i, message:errors.parserFieldNameFail});
else
dataObject[field]=data[field]+""; // force le type String
}
}
if(Object.keys(dataObject).length !== 0)
datas.push(dataObject);
else
parseErrors.push({ row:i, message: errors.parserLineWithoutDatas});
i++;
}
if(fields.length === 0)
throw new Error(errors.parserFail);
}
parser._parseResults =
{
datas: datas,
errors: parseErrors,
fields: fields,
};
}
}