UNPKG

yahoo-finance2

Version:
251 lines (249 loc) 8.82 kB
import byType from "./types/index.js"; export const getTypedDefinitions = (schema) => schema.definitions; export function set(dataCtx, value, instancePath) { if (dataCtx && dataCtx.parentData && dataCtx.parentDataProperty !== "") { // @ts-ignore: later dataCtx.parentData[dataCtx.parentDataProperty] = value; } else { throw new Error('In "' + instancePath + '", cannot set value ' + JSON.stringify(value) + " to context " + JSON.stringify(dataCtx)); } } /* function yahooFinanceType( data: unknown, schema: string, _definitions: JSONSchema["definitions"] | undefined, errors: ValidationError[], instancePath: string, dataCtx?: DataCtx, schemaPath: string = "", ) { if (schema === "DateInMs") { if (typeof data === "number") { return set(dataCtx, new Date(data), instancePath); } else { errors.push({ // keyword: "yahooFinanceType", instancePath, schemaPath, message: "yahooFinanceDate/dateInMs: Expected a number", // params: { schema, data }, schema, data, }); return false; } } else { errors.push({ instancePath, schemaPath, // keyword: "yahooFinanceType", message: "yahooFinanceType: no matching type", // params: { schema, data }, data, schema, }); return false; } // return true; } */ function schemaFromSchemaOrSchemaKey(schemaOrSchemaKey, definitions) { let schema; let path = ""; if (!definitions) { throw new Error("No definitions provided"); } if (typeof schemaOrSchemaKey === "string") { const definition = schemaOrSchemaKey.match(/^#\/definitions\/(.*)$/)?.[1]; if (!definition) { throw new Error("No such schema with key: " + schemaOrSchemaKey); } schema = definitions[definition]; path = schemaOrSchemaKey; if (!schema) { throw new Error(`No such schema with key: ${definition}`); } } else { schema = schemaOrSchemaKey; if (schema.$id) path = schema.$id; } let refs; while (schema.$ref) { if (!refs) refs = []; const ref = schema.$ref.replace("#/definitions/", ""); refs.push(ref); schema = definitions[ref]; path = schema.$ref; } return [schema, path, refs]; } export default function validateAndCoerce(input, schemaOrSchemaKey, ctx, errors = [], instancePath = "", dataCtx, schemaPath = null) { const [schema, foundSchemaPath, refs] = schemaFromSchemaOrSchemaKey(schemaOrSchemaKey, ctx.definitions); if (foundSchemaPath) schemaPath = foundSchemaPath; if (schema.anyOf) { const allErrors = []; let _errors = []; /// Since yahooFinanceType can mutate, we need to save unmodified state. const serializedInput = JSON.stringify(input); let i = 0; for (const subSchema of schema.anyOf) { const subSchemaPath = subSchema.$ref || schemaPath + "/anyOf/" + (i++).toString(); _errors = []; validateAndCoerce(input, subSchema, ctx, _errors, instancePath, dataCtx, subSchemaPath); if (!_errors.length) break; // allErrors.push(subSchema); allErrors.push(..._errors); if (dataCtx?.parentData) { input = serializedInput === undefined ? undefined : JSON.parse(serializedInput); // @ts-ignore: it's ok dataCtx.parentData[dataCtx.parentDataProperty] = input; } } if (_errors.length) { errors.push({ instancePath, schemaPath: schemaPath, // ! because of "if null" check above message: "should match some schema in anyOf", data: input, // schema, subErrors: allErrors, }); // return false; return errors; } /* } else if (schema.yahooFinanceType) { yahooFinanceType( input, schema.yahooFinanceType, definitions, errors, instancePath, dataCtx, schemaPath!, // ! because of "if null" check above ); */ } else if (schema.oneOf) { if (!("discriminator" in schema)) { throw new Error("oneOf without discriminator not supported yet"); } const discriminator = schema.discriminator ?.propertyName; const allErrors = []; let _errors = []; /// Since yahooFinanceType can mutate, we need to save unmodified state. const serializedInput = JSON.stringify(input); let i = 0; for (const subSchema of schema.oneOf) { const subSchemaPath = subSchema.$ref || schemaPath + "/oneOf/" + (i++).toString(); _errors = []; const _subSchema = schemaFromSchemaOrSchemaKey(subSchema, ctx.definitions)[0]; if (_subSchema.properties?.hasOwnProperty(discriminator)) { validateAndCoerce(input, subSchema, ctx, _errors, instancePath, dataCtx, subSchemaPath); } else { _errors.push({ instancePath, schemaPath: subSchemaPath, message: `Missing discriminator field "${discriminator}" in schema`, data: input, }); } if (!_errors.length) break; if (_errors.some((error) => error.instancePath === "/" + discriminator)) { // For now, let's exclude these errors // allErrors.push(..._errors); // It would be better to handle this at a later stage, but for now, the main // reason we're doing this is to make the errors easier to read so all we // really care about is not pushing superfluous errors. XXX } else { allErrors.push(..._errors); } if (dataCtx?.parentData) { input = serializedInput === undefined ? undefined : JSON.parse(serializedInput); // @ts-ignore: it's ok dataCtx.parentData[dataCtx.parentDataProperty] = input; } } if (_errors.length) { errors.push({ instancePath, schemaPath: schemaPath, // ! because of "if null" check above message: "should match some schema in oneOf", params: { discriminator }, data: input, // schema, subErrors: allErrors, }); // return false; return errors; } } else { if (schema.type === undefined) { // This is actually a no-op. With schema of {}, accept anything and everything. // console.log(`No type in ${instancePath}`); // throw new Error(`No type in ${instancePath}`); /* // TODO, need accesss to parent schema for this if (parentSchema.patternProperties) throw new Error( `patternProperties needed but not supported yet, ${instancePath}`, ); */ } else if (Array.isArray(schema.type)) { let _errors = []; for (const type of schema.type) { _errors = []; // @ts-ignore: another day const validator = byType[type]; if (!validator) { throw new Error(`No validator for type ${JSON.stringify(type)} in ${instancePath}`); } validator(input, schema, ctx, _errors, instancePath, dataCtx, schemaPath, refs); if (!_errors.length) break; } if (_errors.length) { errors.push({ instancePath, message: `Expected one of ${schema.type.join(", ")}`, data: input, }); // return false; return errors; } } else { // @ts-ignore: another day const validator = byType[schema.type]; if (!validator) { throw new Error(`No validator for type ${JSON.stringify(schema.type)} in ${instancePath}`); } validator(input, schema, ctx, errors, instancePath, dataCtx, schemaPath, refs); } } return errors; }