yahoo-finance2
Version:
JS API for Yahoo Finance
235 lines (222 loc) • 9.51 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolvePath = resolvePath;
exports.disallowAdditionalProps = disallowAdditionalProps;
const deno_js_1 = __importDefault(require("../../deno.js"));
const errors_js_1 = require("./errors.js");
const index_js_1 = __importDefault(require("./validate/index.js"));
const consts_js_1 = require("../consts.js");
const versions_js_1 = require("./versions.js");
function resolvePath(obj, instancePath) {
const path = instancePath.split("/");
let ref = obj;
for (let i = 1; i < path.length; i++) {
ref = ref[path[i]];
}
return ref;
}
const doneAlready = new Map();
function disallowAdditionalProps(definitions, show = false) {
if (doneAlready.has(definitions))
return;
doneAlready.set(definitions, true);
const disallowed = new Set();
for (const key of Object.keys(definitions)) {
if (key.match(/Options$/)) {
continue;
}
const def = definitions[key];
if (def.type === "object") {
if (def.additionalProperties === undefined ||
typeof def.additionalProperties === "object" &&
Object.keys(def.additionalProperties).length === 0) {
def.additionalProperties = false;
disallowed.add(key);
}
}
}
/* istanbul ignore next */
if (show) {
console.log("Disallowed additional props in " + Array.from(disallowed).join(", "));
}
}
function aggregateErrors(inputErrors) {
const missingMap = new Map();
const additionalMap = new Map();
const errors = inputErrors.filter((error) => {
if (error.subErrors) {
error.subErrors = aggregateErrors(error.subErrors);
}
if (error.schemaPath) {
const key = error.schemaPath + "|" + error.instancePath;
if (error.message === "Missing required property") {
let arr;
if (missingMap.has(key)) {
arr = missingMap.get(key);
}
else {
arr = [];
missingMap.set(key, arr);
}
arr.push(error);
return false;
}
else if (error.message === "should NOT have additional properties") {
let arr;
if (additionalMap.has(key)) {
arr = additionalMap.get(key);
}
else {
arr = [];
additionalMap.set(key, arr);
}
arr.push(error);
return false;
}
}
return true;
});
for (const arr of missingMap.values()) {
const missing = [];
for (const error of arr) {
missing.push(error.data || "somethingWentWrong(tm)");
}
errors.push({
schemaPath: arr[0].schemaPath,
instancePath: arr[0].instancePath,
message: "Missing required properties",
params: { missing },
});
}
for (const arr of additionalMap.values()) {
const additionalProperties = {};
for (const error of arr) {
const additionalProperty = error.params?.additionalProperty ||
"somethingWentWrong(tm)";
additionalProperties[additionalProperty] = error.data[additionalProperty];
}
errors.push({
schemaPath: arr[0].schemaPath,
instancePath: arr[0].instancePath,
message: "should NOT have additional properties",
params: { additionalProperties },
});
}
return errors;
}
function validate({ source, type, object, schemaOrSchemaKey, definitions, options, logger, logObj, versionCheck, }) {
const _errors = (0, index_js_1.default)(object, schemaOrSchemaKey, { definitions, logger, logObj });
// if (_errors === false || !_errors.length) return;
if (_errors.length === 0)
return;
const errors = aggregateErrors(_errors);
if (type === "result") {
/* istanbul ignore else */
/*
if (errors) {
let origData: any = false;
errors.forEach((error) => {
// For now let's ignore the base object which could be huge.
/* istanbul ignore else */
/*
if (error.instancePath !== "")
// Note, not the regular ajv data value from verbose:true
error.data = resolvePath(object, error.instancePath);
if (error.schemaPath === "#/anyOf") {
if (origData === false) {
origData = error.data;
} else if (origData === error.data) {
error.data = "[shortened by validateAndCoerceTypes]";
}
}
});
// Becaue of the "anyOf" in quote, errors are huuuuge and mostly
// irrelevant... so let's filter out (some of) the latter
errors = errors.filter((error) => {
if (error.schemaPath.startsWith("#/definitions/Quote")) {
const schemaQuoteType = error.schemaPath
.substring(19)
.split("/")[0]
.toUpperCase();
/*
* Filter out entries for non-matching schema type, i.e.
* {
* schemaPath: '#/definitions/QuoteCryptoCurrency/properties...'
* data: {
* quoteType: "EQUITY"
* }
* }
*/
/*
if (
typeof error.data === "object" &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Properrty "quoteType" does not exist on type "object"
error.data?.quoteType !== schemaQuoteType
)
return false;
/*
* Filter out the non-matching "const" for the above.
* {
* schemaPath: '#/definitions/QuoteCryptoCurrency/properties/quoteType/const'
* keyword: "const",
* params: { allowedValue: "CRYPTOCURRENCY"}},
* data: "EQUITY"
* }
*/
/*
if (
typeof error.data === "string" &&
error.params?.allowedValue === schemaQuoteType
)
return false;
}
return true;
});
// In the case of there being NO match in #anyOf, bring back the data
if (errors.length === 1 && errors[0].schemaPath === "#/anyOf")
errors[0].data = origData;
}
*/
if (options.logErrors === true) {
const title = encodeURIComponent("Failed validation: " + schemaOrSchemaKey);
logger.error("The following result did not validate with schema: " +
schemaOrSchemaKey);
logObj(errors, { depth: 5 });
// logObj(object);
logger.error(`
This may happen intermittently and you should catch errors appropriately. However: 1) if this recently started happening on every request for a symbol that used to work, Yahoo may have changed their API. 2) If this happens on every request for a symbol you've never used before, but not for other symbols, you've found an edge-case (OR, we may just be protecting you from "bad" data sometimes stored for e.g. misspelt symbols on Yahoo's side).
Please see if anyone has reported this previously:
${consts_js_1.repository}/issues?q=is%3Aissue+${title}
or open a new issue (and mention the symbol): ${deno_js_1.default.name} v${deno_js_1.default.version}
${consts_js_1.repository}/issues/new?labels=bug%2C+validation&template=validation.md&title=${title}
For information on how to turn off the above logging or skip these errors, see https://github.com/gadicc/yahoo-finance2/tree/devel/docs/validation.md.
At the end of the doc, there's also a section on how to "Help Fix Validation Errors" in case you'd like to contribute to the project. Most of the time, these fixes are very quick and easy; it's just hard for our small core team to keep up, so help is always appreciated!
`);
if (versionCheck) {
(0, versions_js_1.versionCheck)().then((result) => {
if (!result.isLatest) {
logger.info(`Additionally, your yahoo-finance2 version out of date: ${result.current} < ${result.latest} (latest)`);
}
}).catch((error) => {
logger.error(`Failed to check version: ${error.message}`);
});
}
} /* if (logErrors) */
throw new errors_js_1.FailedYahooValidationError("Failed Yahoo Schema validation", {
result: object,
errors: errors,
});
} /* if (type === 'options') */
else {
if (options.logOptionsErrors === true) {
logger.error(`[yahooFinance.${source}] Invalid options ("${schemaOrSchemaKey}")`);
logObj({ errors, input: object });
}
throw new errors_js_1.InvalidOptionsError(`yahooFinance.${source} called with invalid options.`);
}
}
exports.default = validate;