import Tracker from "./main"; import { SearchType, BarInfo, CommonChartInfo, Query, RenderInfo, SummaryInfo, Margin, GraphType, LineInfo, PieInfo, MonthInfo, HeatmapInfo, BulletInfo, Dataset, CustomDatasetInfo, } from "./data"; import { TFolder, normalizePath } from "obsidian"; import { parseYaml } from "obsidian"; import * as helper from "./helper"; function strToBool(str: string): boolean | null { str = str.trim().toLowerCase(); switch (str) { case "true": case "1": case "on": case "yes": return true; case "false": case "0": case "off": case "no": return false; } return null; } function validateSearchType(searchType: string): boolean { if ( searchType.toLowerCase() === "tag" || searchType.toLowerCase() === "text" || searchType.toLowerCase() === "frontmatter" || searchType.toLowerCase() === "wiki" || searchType.toLowerCase() === "wiki.link" || searchType.toLowerCase() === "wiki.display" || searchType.toLowerCase() === "dvfield" || searchType.toLowerCase() === "table" || searchType.toLowerCase() === "filemeta" || searchType.toLowerCase() === "task" || searchType.toLowerCase() === "task.all" || searchType.toLowerCase() === "task.done" || searchType.toLowerCase() === "task.notdone" ) { return true; } return false; } function validateYAxisLocation(location: string): boolean { if (location === "left" || location === "right" || location === "none") { return true; } return false; } function validateColor(color: string): boolean { return true; } function splitInputByComma(input: string) { // Split string by ',' but not by '\,' // let splitted = input.split(/(?<!\\),/); // -->lookbehind not support in Safari for now const dummy = "::::::tracker::::::"; let temp = input.split("\\,").join(dummy); let splitted = temp.split(","); for (let ind = 0; ind < splitted.length; ind++) { splitted[ind] = splitted[ind].split(dummy).join(","); } return splitted; } function getBoolArrayFromInput( name: string, input: any, numDataset: number, defaultValue: boolean, allowNoValidValue: boolean ): Array<boolean> | string { let array: Array<boolean> = []; let errorMessage = ""; let numValidValue = 0; while (numDataset > array.length) { array.push(defaultValue); } if (typeof input === "undefined" || input === null) { // all defaultValue } else if (typeof input === "object" && input !== null) { if (Array.isArray(input)) { if (input.length > numDataset) { errorMessage = "Too many inputs for parameter '" + name + "'"; return errorMessage; } if (input.length === 0) { errorMessage = "Empty array not allowd for " + name; return errorMessage; } for (let ind = 0; ind < array.length; ind++) { if (ind < input.length) { let curr = input[ind]; let prev = null; if (ind > 0) { prev = input[ind - 1].trim(); } if (typeof curr === "string") { curr = curr.trim(); if (curr === "") { if (prev !== null) { array[ind] = prev; } else { array[ind] = defaultValue; } } else { errorMessage = "Invalid inputs for " + name; break; } } else if (typeof curr === "boolean") { array[ind] = curr; numValidValue++; } else { errorMessage = "Invalid inputs for " + name; break; } } else { // Exceeds the length of input, use prev value let last = input[input.length - 1]; if (numValidValue > 0) { array[ind] = last; } else { array[ind] = defaultValue; } } } } } else if (typeof input === "string") { let splitted = splitInputByComma(input); if (splitted.length > 1) { if (splitted.length > numDataset) { errorMessage = "Too many inputs for parameter '" + name + "'"; return errorMessage; } for (let ind = 0; ind < array.length; ind++) { if (ind < splitted.length) { let curr = splitted[ind].trim(); let prev = null; if (ind > 0) { prev = strToBool(splitted[ind - 1].trim()); } if (curr === "") { if (prev !== null) { array[ind] = prev; } else { array[ind] = defaultValue; } } else { let currBool = strToBool(curr); if (currBool !== null) { array[ind] = currBool; numValidValue++; } else { errorMessage = "Invalid inputs for " + name; break; } } } else { // Exceeds the length of input, use prev value let last = strToBool(splitted[splitted.length - 1].trim()); if (numValidValue > 0 && last !== null) { array[ind] = last; } else { array[ind] = defaultValue; } } } } else { if (input === "") { // all defaultValue } else { let inputBool = strToBool(input); if (inputBool !== null) { array[0] = inputBool; numValidValue++; for (let ind = 1; ind < array.length; ind++) { array[ind] = inputBool; } } else { errorMessage = "Invalid inputs for " + name; } } } } else if (typeof input === "boolean") { array[0] = input; numValidValue++; for (let ind = 1; ind < array.length; ind++) { array[ind] = input; } } else { errorMessage = "Invalid inputs for " + name; } if (!allowNoValidValue && numValidValue === 0) { errorMessage = "No valid input for " + name; } if (errorMessage !== "") { return errorMessage; } return array; } function getNumberArrayFromInput( name: string, input: any, numDataset: number, defaultValue: number, allowNoValidValue: boolean ): Array<number> | string { // console.log("getNumberArrayFromInput"); let array: Array<number> = []; let errorMessage = ""; let numValidValue = 0; while (numDataset > array.length) { array.push(defaultValue); } if (typeof input === "undefined" || input === null) { // all defaultValue } else if (typeof input === "object" && input !== null) { if (Array.isArray(input)) { if (input.length > numDataset) { errorMessage = "Too many inputs for parameter '" + name + "'"; return errorMessage; } if (input.length === 0) { errorMessage = "Empty array not allowd for " + name; return errorMessage; } for (let ind = 0; ind < array.length; ind++) { if (ind < input.length) { let curr = input[ind]; let prev = null; if (ind > 0) { prev = input[ind - 1].trim(); } if (typeof curr === "string") { curr = curr.trim(); if (curr === "") { if (prev !== null) { array[ind] = prev; } else { array[ind] = defaultValue; } } else { errorMessage = "Invalid inputs for " + name; break; } } else if (typeof curr === "number") { array[ind] = curr; numValidValue++; } else { errorMessage = "Invalid inputs for " + name; break; } } else { // Exceeds the length of input, use prev value let last = input[input.length - 1]; if (numValidValue > 0) { array[ind] = last; } else { array[ind] = defaultValue; } } } } } else if (typeof input === "string") { let splitted = splitInputByComma(input); if (splitted.length > 1) { if (splitted.length > numDataset) { errorMessage = "Too many inputs for parameter '" + name + "'"; return errorMessage; } for (let ind = 0; ind < array.length; ind++) { if (ind < splitted.length) { let curr = splitted[ind].trim(); let prev = null; if (ind > 0) { prev = helper.parseFloatFromAny( splitted[ind - 1].trim() ).value; } if (curr === "") { if (prev !== null && Number.isNumber(prev)) { array[ind] = prev; } else { array[ind] = defaultValue; } } else { let currNum = helper.parseFloatFromAny(curr).value; if (currNum !== null) { array[ind] = currNum; numValidValue++; } else { errorMessage = "Invalid inputs for " + name; break; } } } else { // Exceeds the length of input, use prev value let last = helper.parseFloatFromAny( splitted[input.length - 1].trim() ).value; if (numValidValue > 0 && last !== null) { array[ind] = last; } else { array[ind] = defaultValue; } } } } else { if (input === "") { // all defaultValue } else { let inputNum = helper.parseFloatFromAny(input).value; if (inputNum !== null) { array[0] = inputNum; numValidValue++; for (let ind = 1; ind < array.length; ind++) { array[ind] = inputNum; } } else { errorMessage = "Invalid inputs for " + name; } } } } else if (typeof input === "number") { if (Number.isNumber(input)) { array[0] = input; numValidValue++; for (let ind = 1; ind < array.length; ind++) { array[ind] = input; } } else { errorMessage = "Invalid inputs for " + name; } } else { errorMessage = "Invalid inputs for " + name; } if (!allowNoValidValue && numValidValue === 0) { errorMessage = "No valid input for " + name; } if (errorMessage !== "") { return errorMessage; } return array; } function getStringFromInput(input: any, defaultValue: string): string { if (typeof input === "string") { return helper.replaceImgTagByAlt(input); } else if (typeof input === "number") { return input.toString(); } return defaultValue; } function getStringArrayFromInput( name: string, input: any, numDataset: number, defaultValue: string, validator: Function, allowNoValidValue: boolean ): Array<string> | string { let array: Array<string> = []; let errorMessage = ""; let numValidValue = 0; while (numDataset > array.length) { array.push(defaultValue); } if (typeof input === "undefined" || input === null) { // all defaultValue } else if (typeof input === "object" && input !== null) { if (Array.isArray(input)) { if (input.length > numDataset) { errorMessage = "Too many inputs for parameter '" + name + "'"; return errorMessage; } if (input.length === 0) { errorMessage = "Empty array not allowd for " + name; return errorMessage; } for (let ind = 0; ind < array.length; ind++) { if (ind < input.length) { let curr = input[ind]; let prev = null; if (ind > 0) { prev = input[ind - 1].trim(); } if (typeof curr === "string") { curr = curr.trim(); if (curr === "") { if (prev !== null) { array[ind] = prev; } else { array[ind] = defaultValue; } } else { if (validator) { if (validator(curr)) { array[ind] = curr; numValidValue++; } else { errorMessage = "Invalid inputs for " + name; break; } } else { array[ind] = curr; numValidValue++; } } } else { errorMessage = "Invalid inputs for " + name; break; } } else { // Exceeds the length of input, use prev value let last = input[input.length - 1].trim(); if (numValidValue > 0) { array[ind] = last; } else { array[ind] = defaultValue; } } } } } else if (typeof input === "string") { let splitted = splitInputByComma(input); if (splitted.length > 1) { if (splitted.length > numDataset) { errorMessage = "Too many inputs for parameter '" + name + "'"; return errorMessage; } for (let ind = 0; ind < array.length; ind++) { if (ind < splitted.length) { let curr = splitted[ind].trim(); let prev = null; if (ind > 0) { prev = splitted[ind - 1].trim(); } if (curr === "") { if (prev !== null) { array[ind] = prev; } else { array[ind] = defaultValue; } } else { if (validator) { if (validator(curr)) { array[ind] = curr; numValidValue++; } else { errorMessage = "Invalid inputs for " + name; break; } } else { array[ind] = curr; numValidValue++; } } } else { // Exceeds the length of input, use prev value let last = splitted[splitted.length - 1].trim(); if (numValidValue > 0) { array[ind] = last; } else { array[ind] = defaultValue; } } } } else { if (input === "") { // all defaultValue } else { if (validator) { if (validator(input)) { array[0] = input; numValidValue++; for (let ind = 1; ind < array.length; ind++) { array[ind] = input; } } else { errorMessage = "Invalid inputs for " + name; } } else { array[0] = input; numValidValue++; for (let ind = 1; ind < array.length; ind++) { array[ind] = input; } } } } } else if (typeof input === "number") { let strNumber = input.toString(); if (validator) { if (validator(strNumber)) { array[0] = strNumber; numValidValue++; for (let ind = 1; ind < array.length; ind++) { array[ind] = strNumber; } } else { errorMessage = "Invalid inputs for " + name; } } else { array[0] = strNumber; numValidValue++; for (let ind = 1; ind < array.length; ind++) { array[ind] = strNumber; } } } else { errorMessage = "Invalid inputs for " + name; } if (!allowNoValidValue && numValidValue === 0) { errorMessage = "No valid input for " + name; } if (errorMessage !== "") { return errorMessage; } for (let ind = 0; ind < array.length; ind++) { array[ind] = helper.replaceImgTagByAlt(array[ind]); } return array; } function getNumberArray(name: string, input: any): Array<number> | string { let numArray: Array<number> = []; if (typeof input === "undefined" || input === null) return numArray; if (typeof input === "object") { if (Array.isArray(input)) { for (let elem of input) { if (typeof elem === "string") { let v = parseFloat(elem); if (Number.isNumber(v)) { numArray.push(v); } else { let errorMessage = `Parameter '${name}' accepts only numbers`; return errorMessage; } } } } } else if (typeof input === "string") { let splitted = splitInputByComma(input); if (splitted.length > 1) { for (let piece of splitted) { let v = parseFloat(piece.trim()); if (!Number.isNaN(v)) { // Number.isNumber(NaN) --> true numArray.push(v); } else { let errorMessage = `Parameter '${name}' accepts only numbers`; return errorMessage; } } } else if (input === "") { let errorMessage = `Empty ${name} is not allowed.`; return errorMessage; } else { let v = parseFloat(input); if (Number.isNumber(v)) { numArray.push(v); } else { let errorMessage = `Parameter '${name}' accepts only numbers`; return errorMessage; } } } else if (typeof input === "number") { numArray.push(input); } else { let errorMessage = `Invalid ${name}`; return errorMessage; } return numArray; } function getStringArray(name: string, input: any): Array<string> | string { let strArray: Array<string> = []; if (typeof input === "undefined" || input === null) return strArray; if (typeof input === "object") { if (Array.isArray(input)) { for (let elem of input) { if (typeof elem === "string") { strArray.push(elem.trim()); } } } } else if (typeof input === "string") { let splitted = splitInputByComma(input); // console.log(splitted); if (splitted.length > 1) { for (let piece of splitted) { strArray.push(piece.trim()); } } else if (input === "") { let errorMessage = `Empty ${name} is not allowed.`; return errorMessage; } else { strArray.push(input); } } else { let errorMessage = `Invalid ${name}`; return errorMessage; } for (let ind = 0; ind < strArray.length; ind++) { strArray[ind] = helper.replaceImgTagByAlt(strArray[ind]); } return strArray; } function parseCommonChartInfo(yaml: any, renderInfo: CommonChartInfo) { // console.log("parseCommonChartInfo"); // single value, use default value if no value from YAML if (yaml) { // title renderInfo.title = getStringFromInput(yaml?.title, renderInfo.title); // xAxisLabel renderInfo.xAxisLabel = getStringFromInput( yaml?.xAxisLabel, renderInfo.xAxisLabel ); // xAxisColor renderInfo.xAxisColor = getStringFromInput( yaml?.xAxisColor, renderInfo.xAxisColor ); // xAxisLabelColor renderInfo.xAxisLabelColor = getStringFromInput( yaml?.xAxisLabelColor, renderInfo.xAxisLabelColor ); // allowInspectData if (typeof yaml.allowInspectData === "boolean") { renderInfo.allowInspectData = yaml.allowInspectData; } // showLegend if (typeof yaml.showLegend === "boolean") { renderInfo.showLegend = yaml.showLegend; } // legendPosition if (typeof yaml.legendPosition === "string") { renderInfo.legendPosition = yaml.legendPosition; } else { renderInfo.legendPosition = "bottom"; } // legendOrient if (typeof yaml.legendOrientation === "string") { renderInfo.legendOrientation = yaml.legendOrientation; } else { if ( renderInfo.legendPosition === "top" || renderInfo.legendPosition === "bottom" ) { renderInfo.legendOrientation = "horizontal"; } else if ( renderInfo.legendPosition === "left" || renderInfo.legendPosition === "right" ) { renderInfo.legendOrientation = "vertical"; } else { renderInfo.legendOrientation = "horizontal"; } } // console.log(renderInfo.legendPosition); // console.log(renderInfo.legendOrientation); // legendBgColor renderInfo.legendBgColor = getStringFromInput( yaml?.legendBgColor, renderInfo.legendBgColor ); // legendBorderColor renderInfo.legendBorderColor = getStringFromInput( yaml?.legendBorderColor, renderInfo.legendBorderColor ); } // yAxisLabel let retYAxisLabel = getStringArrayFromInput( "yAxisLabel", yaml?.yAxisLabel, 2, "Value", null, true ); if (typeof retYAxisLabel === "string") { return retYAxisLabel; // errorMessage } if (retYAxisLabel.length > 2) { return "yAxisLabel accepts not more than two values for left and right y-axes"; } renderInfo.yAxisLabel = retYAxisLabel; // console.log(renderInfo.yAxisLabel); // yAxisColor let retYAxisColor = getStringArrayFromInput( "yAxisColor", yaml?.yAxisColor, 2, "", validateColor, true ); if (typeof retYAxisColor === "string") { return retYAxisColor; // errorMessage } if (retYAxisColor.length > 2) { return "yAxisColor accepts not more than two values for left and right y-axes"; } renderInfo.yAxisColor = retYAxisColor; // console.log(renderInfo.yAxisColor); // yAxisLabelColor let retYAxisLabelColor = getStringArrayFromInput( "yAxisLabelColor", yaml?.yAxisLabelColor, 2, "", validateColor, true ); if (typeof retYAxisLabelColor === "string") { return retYAxisLabelColor; // errorMessage } if (retYAxisLabelColor.length > 2) { return "yAxisLabelColor accepts not more than two values for left and right y-axes"; } renderInfo.yAxisLabelColor = retYAxisLabelColor; // console.log(renderInfo.yAxisLabelColor); // yAxisUnit let retYAxisUnit = getStringArrayFromInput( "yAxisUnit", yaml?.yAxisUnit, 2, "", null, true ); if (typeof retYAxisUnit === "string") { return retYAxisUnit; // errorMessage } if (retYAxisUnit.length > 2) { return "yAxisUnit accepts not more than two values for left and right y-axes"; } renderInfo.yAxisUnit = retYAxisUnit; // console.log(renderInfo.yAxisUnit); // xAxisTickInterval renderInfo.xAxisTickInterval = getStringFromInput( yaml?.xAxisTickInterval, renderInfo.xAxisTickInterval ); // console.log(renderInfo.xAxisTickInterval); // yAxisTickInterval let retYAxisTickInterval = getStringArrayFromInput( "yAxisTickInterval", yaml?.yAxisTickInterval, 2, null, null, true ); if (typeof retYAxisTickInterval === "string") { return retYAxisTickInterval; // errorMessage } if (retYAxisTickInterval.length > 2) { return "yAxisTickInterval accepts not more than two values for left and right y-axes"; } renderInfo.yAxisTickInterval = retYAxisTickInterval; // console.log(renderInfo.yAxisTickInterval); // xAxisTickLabelFormat renderInfo.xAxisTickLabelFormat = getStringFromInput( yaml?.xAxisTickLabelFormat, renderInfo.xAxisTickLabelFormat ); // console.log(renderInfo.xAxisTickLabelFormat); // yAxisTickLabelFormat let retYAxisTickLabelFormat = getStringArrayFromInput( "yAxisTickLabelFormat", yaml?.yAxisTickLabelFormat, 2, null, null, true ); if (typeof retYAxisTickLabelFormat === "string") { return retYAxisTickLabelFormat; // errorMessage } if (retYAxisTickLabelFormat.length > 2) { return "yAxisTickLabelFormat accepts not more than two values for left and right y-axes"; } renderInfo.yAxisTickLabelFormat = retYAxisTickLabelFormat; // console.log(renderInfo.yAxisTickLabelFormat); // yMin let retYMin = getNumberArrayFromInput("yMin", yaml?.yMin, 2, null, true); if (typeof retYMin === "string") { return retYMin; // errorMessage } if (retYMin.length > 2) { return "yMin accepts not more than two values for left and right y-axes"; } renderInfo.yMin = retYMin; // console.log(renderInfo.yMin); // yMax let retYMax = getNumberArrayFromInput("yMax", yaml?.yMax, 2, null, true); if (typeof retYMax === "string") { return retYMax; // errorMessage } if (retYMax.length > 2) { return "yMax accepts not more than two values for left and right y-axes"; } renderInfo.yMax = retYMax; // console.log(renderInfo.yMax); // reverseYAxis let retReverseYAxis = getBoolArrayFromInput( "reverseYAxis", yaml?.reverseYAxis, 2, false, true ); if (typeof retReverseYAxis === "string") { return retReverseYAxis; // errorMessage } if (retReverseYAxis.length > 2) { return "reverseYAxis accepts not more than two values for left and right y-axes"; } renderInfo.reverseYAxis = retReverseYAxis; // console.log(renderInfo.reverseYAxis); } function getAvailableKeysOfClass(obj: object): string[] { let keys: string[] = []; if (obj !== null) { const objectKeys = Object.keys(obj) as Array<keyof string>; for (let key of objectKeys) { keys.push(key.toString()); } } return keys; } export function getRenderInfoFromYaml( yamlText: string, plugin: Tracker ): RenderInfo | string { let yaml; try { // console.log(yamlText); yaml = parseYaml(yamlText); } catch (err) { let errorMessage = "Error parsing YAML"; console.log(err); return errorMessage; } if (!yaml) { let errorMessage = "Error parsing YAML"; return errorMessage; } // console.log(yaml); let keysFoundInYAML = getAvailableKeysOfClass(yaml); // console.log(keysFoundInYAML); let errorMessage = ""; // Search target if (!keysFoundInYAML.includes("searchTarget")) { let errorMessage = "Parameter 'searchTarget' not found in YAML"; return errorMessage; } let searchTarget: Array<string> = []; if (typeof yaml.searchTarget === "object" && yaml.searchTarget !== null) { if (Array.isArray(yaml.searchTarget)) { for (let target of yaml.searchTarget) { if (typeof target === "string") { if (target !== "") { searchTarget.push(target); } else { errorMessage = "Empty search target is not allowed."; break; } } } } } else if (typeof yaml.searchTarget === "string") { let splitted = splitInputByComma(yaml.searchTarget); // console.log(splitted); if (splitted.length > 1) { for (let piece of splitted) { piece = piece.trim(); if (piece !== "") { searchTarget.push(piece); } else { errorMessage = "Empty search target is not allowed."; break; } } } else if (yaml.searchTarget === "") { errorMessage = "Empty search target is not allowed."; } else { searchTarget.push(yaml.searchTarget); } } else { errorMessage = "Invalid search target (searchTarget)"; } for (let ind = 0; ind < searchTarget.length; ind++) { searchTarget[ind] = helper.replaceImgTagByAlt(searchTarget[ind]); } // console.log(searchTarget); if (errorMessage !== "") { return errorMessage; } let numDatasets = searchTarget.length; // Search type if (!keysFoundInYAML.includes("searchType")) { let errorMessage = "Parameter 'searchType' not found in YAML"; return errorMessage; } let searchType: Array<SearchType> = []; let retSearchType = getStringArrayFromInput( "searchType", yaml.searchType, numDatasets, "", validateSearchType, false ); if (typeof retSearchType === "string") { return retSearchType; // errorMessage } for (let strType of retSearchType) { switch (strType.toLowerCase()) { case "tag": searchType.push(SearchType.Tag); break; case "frontmatter": searchType.push(SearchType.Frontmatter); break; case "wiki": searchType.push(SearchType.Wiki); break; case "wiki.link": searchType.push(SearchType.WikiLink); break; case "wiki.display": searchType.push(SearchType.WikiDisplay); break; case "text": searchType.push(SearchType.Text); break; case "dvfield": searchType.push(SearchType.dvField); break; case "table": searchType.push(SearchType.Table); break; case "filemeta": searchType.push(SearchType.FileMeta); break; case "task": searchType.push(SearchType.Task); break; case "task.all": searchType.push(SearchType.Task); break; case "task.done": searchType.push(SearchType.TaskDone); break; case "task.notdone": searchType.push(SearchType.TaskNotDone); break; } } // Currently, we don't allow type 'table' used with other types if ( searchType.includes(SearchType.Table) && searchType.filter((t) => t !== SearchType.Table).length > 0 ) { let errorMessage = "searchType 'table' doestn't work with other types for now"; return errorMessage; } // console.log(searchType); // separator let multipleValueSparator: Array<string> = []; let retMultipleValueSparator = getStringArrayFromInput( "separator", yaml.separator, numDatasets, "", // set the default value later null, true ); if (typeof retMultipleValueSparator === "string") { return retMultipleValueSparator; // errorMessage } multipleValueSparator = retMultipleValueSparator.map((sep) => { if (sep === "comma" || sep === "\\,") { return ","; } return sep; }); // console.log(multipleValueSparator); // xDataset let retXDataset = getNumberArrayFromInput( "xDataset", yaml.xDataset, numDatasets, -1, true ); if (typeof retXDataset === "string") { return retXDataset; // errorMessage } let xDataset = retXDataset.map((d: number) => { if (d < 0 || d >= numDatasets) { return -1; } return d; }); // assign this to renderInfo later // Create queries let queries: Array<Query> = []; for (let ind = 0; ind < searchTarget.length; ind++) { let query = new Query( queries.length, searchType[ind], searchTarget[ind] ); query.setSeparator(multipleValueSparator[ind]); if (xDataset.includes(ind)) query.usedAsXDataset = true; queries.push(query); } // console.log(queries); // Create grarph info let renderInfo = new RenderInfo(queries); let keysOfRenderInfo = getAvailableKeysOfClass(renderInfo); let additionalAllowedKeys = ["searchType", "searchTarget", "separator"]; // console.log(keysOfRenderInfo); let yamlLineKeys = []; let yamlBarKeys = []; let yamlPieKeys = []; let yamlSummaryKeys = []; let yamlMonthKeys = []; let yamlHeatmapKeys = []; let yamlBulletKeys = []; for (let key of keysFoundInYAML) { if (/^line[0-9]*$/.test(key)) { yamlLineKeys.push(key); additionalAllowedKeys.push(key); } if (/^bar[0-9]*$/.test(key)) { yamlBarKeys.push(key); additionalAllowedKeys.push(key); } if (/^pie[0-9]*$/.test(key)) { yamlPieKeys.push(key); additionalAllowedKeys.push(key); } if (/^summary[0-9]*$/.test(key)) { yamlSummaryKeys.push(key); additionalAllowedKeys.push(key); } if (/^bullet[0-9]*$/.test(key)) { yamlBulletKeys.push(key); additionalAllowedKeys.push(key); } if (/^month[0-9]*$/.test(key)) { yamlMonthKeys.push(key); additionalAllowedKeys.push(key); } if (/^heatmap[0-9]*$/.test(key)) { yamlHeatmapKeys.push(key); additionalAllowedKeys.push(key); } } // Custom dataset let yamlCustomDatasetKeys = []; for (let key of keysFoundInYAML) { if (/^dataset[0-9]*$/.test(key)) { // Check the id of custom dataset is not duplicated let customDatasetId = -1; let strCustomDatasetId = key.replace("dataset", ""); if (strCustomDatasetId === "") { customDatasetId = 0; } else { customDatasetId = parseFloat(strCustomDatasetId); } if ( queries.some((q) => { return q.getId() === customDatasetId; }) ) { errorMessage = "Duplicated dataset id for key '" + key + "'"; return errorMessage; } yamlCustomDatasetKeys.push(key); additionalAllowedKeys.push(key); } } // console.log(additionalAllowedKeys); for (let key of keysFoundInYAML) { if ( !keysOfRenderInfo.includes(key) && !additionalAllowedKeys.includes(key) ) { errorMessage = "'" + key + "' is not an available key"; return errorMessage; } } let totalNumOutputs = yamlLineKeys.length + yamlBarKeys.length + yamlPieKeys.length + yamlSummaryKeys.length + yamlBulletKeys.length + yamlMonthKeys.length + yamlHeatmapKeys.length; if (totalNumOutputs === 0) { return "No output parameter provided, please place line, bar, pie, month, bullet, or summary."; } // Root folder to search renderInfo.folder = getStringFromInput( yaml?.folder, plugin.settings.folder ); if (renderInfo.folder.trim() === "") { renderInfo.folder = plugin.settings.folder; } // console.log("renderInfo folder: " + renderInfo.folder); let abstractFolder = plugin.app.vault.getAbstractFileByPath( normalizePath(renderInfo.folder) ); if (!abstractFolder || !(abstractFolder instanceof TFolder)) { let errorMessage = "Folder '" + renderInfo.folder + "' doesn't exist"; return errorMessage; } // file if (typeof yaml.file === "string") { let retFiles = getStringArray("file", yaml.file); if (typeof retFiles === "string") { return retFiles; // error message } renderInfo.file = retFiles; } // console.log(renderInfo.file); // specifiedFilesOnly if (typeof yaml.specifiedFilesOnly === "boolean") { renderInfo.specifiedFilesOnly = yaml.specifiedFilesOnly; } // console.log(renderInfo.specifiedFilesOnly); // fileContainsLinkedFiles if (typeof yaml.fileContainsLinkedFiles === "string") { let retFiles = getStringArray( "fileContainsLinkedFiles", yaml.fileContainsLinkedFiles ); if (typeof retFiles === "string") { return retFiles; } renderInfo.fileContainsLinkedFiles = retFiles; } // console.log(renderInfo.fileContainsLinkedFiles); // fileMultiplierAfterLink renderInfo.fileMultiplierAfterLink = getStringFromInput( yaml?.fileMultiplierAfterLink, renderInfo.fileMultiplierAfterLink ); // console.log(renderInfo.fileMultiplierAfterLink); // Date format const dateFormat = yaml.dateFormat; //?? not sure why I need this to make it works, // without that, the assigned the renderInfo.dateFormat will become undefined if (typeof yaml.dateFormat === "string") { if (yaml.dateFormat === "") { renderInfo.dateFormat = plugin.settings.dateFormat; } else { renderInfo.dateFormat = dateFormat; } } else { renderInfo.dateFormat = plugin.settings.dateFormat; } // console.log("renderInfo dateFormat: " + renderInfo.dateFormat); // Date format prefix renderInfo.dateFormatPrefix = getStringFromInput( yaml?.dateFormatPrefix, renderInfo.dateFormatPrefix ); // Date fromat suffix renderInfo.dateFormatSuffix = getStringFromInput( yaml?.dateFormatSuffix, renderInfo.dateFormatSuffix ); // startDate, endDate // console.log("Parsing startDate"); if (typeof yaml.startDate === "string") { if (/^([\-]?[0-9]+[\.][0-9]+|[\-]?[0-9]+)m$/.test(yaml.startDate)) { let errorMessage = "'m' for 'minute' is too small for parameter startDate, please use 'd' for 'day' or 'M' for month"; return errorMessage; } let strStartDate = helper.getDateStringFromInputString( yaml.startDate, renderInfo.dateFormatPrefix, renderInfo.dateFormatSuffix ); // console.log(strStartDate); // relative date let startDate = null; let isStartDateValid = false; startDate = helper.getDateByDurationToToday( strStartDate, renderInfo.dateFormat ); // console.log(startDate); if (startDate) { isStartDateValid = true; } else { startDate = helper.strToDate(strStartDate, renderInfo.dateFormat); if (startDate.isValid()) { isStartDateValid = true; } } // console.log(startDate); if (!isStartDateValid || startDate === null) { let errorMessage = "Invalid startDate, the format of startDate may not match your dateFormat " + renderInfo.dateFormat; return errorMessage; } renderInfo.startDate = startDate; } // console.log("Parsing endDate"); if (typeof yaml.endDate === "string") { if (/^([\-]?[0-9]+[\.][0-9]+|[\-]?[0-9]+)m$/.test(yaml.endDate)) { let errorMessage = "'m' for 'minute' is too small for parameter endDate, please use 'd' for 'day' or 'M' for month"; return errorMessage; } let strEndDate = helper.getDateStringFromInputString( yaml.endDate, renderInfo.dateFormatPrefix, renderInfo.dateFormatSuffix ); let endDate = null; let isEndDateValid = false; endDate = helper.getDateByDurationToToday( strEndDate, renderInfo.dateFormat ); if (endDate) { isEndDateValid = true; } else { endDate = helper.strToDate(strEndDate, renderInfo.dateFormat); if (endDate.isValid()) { isEndDateValid = true; } } // console.log(endDate); if (!isEndDateValid || endDate === null) { let errorMessage = "Invalid endDate, the format of endDate may not match your dateFormat " + renderInfo.dateFormat; return errorMessage; } renderInfo.endDate = endDate; } if ( renderInfo.startDate !== null && renderInfo.startDate.isValid() && renderInfo.endDate !== null && renderInfo.endDate.isValid() ) { // Make sure endDate > startDate if (renderInfo.endDate < renderInfo.startDate) { let errorMessage = "Invalid date range (startDate larger than endDate)"; return errorMessage; } } // console.log(renderInfo.startDate); // console.log(renderInfo.endDate); // xDataset renderInfo.xDataset = xDataset; // console.log(renderInfo.xDataset); // Dataset name (need xDataset to set default name) let retDatasetName = getStringArrayFromInput( "datasetName", yaml.datasetName, numDatasets, "untitled", null, true ); if (typeof retDatasetName === "string") { return retDatasetName; // errorMessage } // rename untitled let indUntitled = 0; for (let ind = 0; ind < retDatasetName.length; ind++) { if (renderInfo.xDataset.includes(ind)) continue; if (retDatasetName[ind] === "untitled") { retDatasetName[ind] = "untitled" + indUntitled.toString(); indUntitled++; } } // Check duplicated names if (new Set(retDatasetName).size === retDatasetName.length) { renderInfo.datasetName = retDatasetName; } else { let errorMessage = "Not enough dataset names or duplicated names"; return errorMessage; } // console.log(renderInfo.datasetName); // constValue let retConstValue = getNumberArrayFromInput( "constValue", yaml.constValue, numDatasets, 1.0, true ); if (typeof retConstValue === "string") { return retConstValue; // errorMessage } renderInfo.constValue = retConstValue; // console.log(renderInfo.constValue); // ignoreAttachedValue let retIgnoreAttachedValue = getBoolArrayFromInput( "ignoreAttachedValue", yaml.ignoreAttachedValue, numDatasets, false, true ); if (typeof retIgnoreAttachedValue === "string") { return retIgnoreAttachedValue; } renderInfo.ignoreAttachedValue = retIgnoreAttachedValue; // console.log(renderInfo.ignoreAttachedValue); // ignoreZeroValue let retIgnoreZeroValue = getBoolArrayFromInput( "ignoreZeroValue", yaml.ignoreZeroValue, numDatasets, false, true ); if (typeof retIgnoreZeroValue === "string") { return retIgnoreZeroValue; } renderInfo.ignoreZeroValue = retIgnoreZeroValue; // console.log(renderInfo.ignoreAttachedValue); // accum let retAccum = getBoolArrayFromInput( "accum", yaml.accum, numDatasets, false, true ); if (typeof retAccum === "string") { return retAccum; } renderInfo.accum = retAccum; // console.log(renderInfo.accum); // penalty let retPenalty = getNumberArrayFromInput( "penalty", yaml.penalty, numDatasets, null, true ); if (typeof retPenalty === "string") { return retPenalty; } renderInfo.penalty = retPenalty; // console.log(renderInfo.penalty); // valueShift let retValueShift = getNumberArrayFromInput( "valueShift", yaml.valueShift, numDatasets, 0, true ); if (typeof retValueShift === "string") { return retValueShift; } renderInfo.valueShift = retValueShift; // console.log(renderInfo.valueShift); // shiftOnlyValueLargerThan let retShiftOnlyValueLargerThan = getNumberArrayFromInput( "shiftOnlyValueLargerThan", yaml.shiftOnlyValueLargerThan, numDatasets, null, true ); if (typeof retShiftOnlyValueLargerThan === "string") { return retShiftOnlyValueLargerThan; } renderInfo.shiftOnlyValueLargerThan = retShiftOnlyValueLargerThan; // console.log(renderInfo.shiftOnlyValueLargerThan); // textValueMap if (typeof yaml.textValueMap !== "undefined") { let keys = getAvailableKeysOfClass(yaml.textValueMap); // console.log(texts); for (let key of keys) { let text = key.trim(); renderInfo.textValueMap[text] = yaml.textValueMap[text]; } } // console.log(renderInfo.textValueMap); // fixedScale if (typeof yaml.fixedScale === "number") { renderInfo.fixedScale = yaml.fixedScale; } // fitPanelWidth if (typeof yaml.fitPanelWidth === "boolean") { renderInfo.fitPanelWidth = yaml.fitPanelWidth; } // margin let retMargin = getNumberArrayFromInput("margin", yaml.margin, 4, 10, true); if (typeof retMargin === "string") { return retMargin; // errorMessage } if (retMargin.length > 4) { return "margin accepts not more than four values for top, right, bottom, and left margins."; } renderInfo.margin = new Margin( retMargin[0], retMargin[1], retMargin[2], retMargin[3] ); // console.log(renderInfo.margin); // customDataset related parameters for (let datasetKey of yamlCustomDatasetKeys) { let customDataset = new CustomDatasetInfo(); let yamlCustomDataset = yaml[datasetKey]; let keysOfCustomDatasetInfo = getAvailableKeysOfClass(customDataset); let keysFoundInYAML = getAvailableKeysOfClass(yamlCustomDataset); // console.log(keysOfCustomDatasetInfo); // console.log(keysFoundInYAML); for (let key of keysFoundInYAML) { if (!keysOfCustomDatasetInfo.includes(key)) { errorMessage = "'" + key + "' is not an available key"; return errorMessage; } } // id let customDatasetId = -1; let strCustomDatasetId = datasetKey.replace("dataset", ""); if (strCustomDatasetId === "") { customDatasetId = 0; } else { customDatasetId = parseFloat(strCustomDatasetId); } customDataset.id = customDatasetId; // name customDataset.name = getStringFromInput( yamlCustomDataset?.name, customDataset.name ); // xData let retXData = getStringArray("xData", yamlCustomDataset?.xData); if (typeof retXData === "string") { return retXData; } customDataset.xData = retXData; // console.log(customDataset.xData); let numXData = customDataset.xData.length; // yData let retYData = getStringArray("yData", yamlCustomDataset?.yData); if (typeof retYData === "string") { return retYData; } customDataset.yData = retYData; // console.log(customDataset.yData); if (customDataset.yData.length !== numXData) { let errorMessage = "Number of elements in xData and yData not matched"; return errorMessage; } renderInfo.customDataset.push(customDataset); } // customDataset related parameters // console.log(renderInfo.customDataset); // line related parameters for (let lineKey of yamlLineKeys) { let line = new LineInfo(); let yamlLine = yaml[lineKey]; let keysOfLineInfo = getAvailableKeysOfClass(line); let keysFoundInYAML = getAvailableKeysOfClass(yamlLine); // console.log(keysOfLineInfo); // console.log(keysFoundInYAML); for (let key of keysFoundInYAML) { if (!keysOfLineInfo.includes(key)) { errorMessage = "'" + key + "' is not an available key"; return errorMessage; } } let retParseCommonChartInfo = parseCommonChartInfo(yamlLine, line); if (typeof retParseCommonChartInfo === "string") { return retParseCommonChartInfo; } // lineColor let retLineColor = getStringArrayFromInput( "lineColor", yamlLine?.lineColor, numDatasets, "", validateColor, true ); if (typeof retLineColor === "string") { return retLineColor; // errorMessage } line.lineColor = retLineColor; // console.log(line.lineColor); // lineWidth let retLineWidth = getNumberArrayFromInput( "lineWidth", yamlLine?.lineWidth, numDatasets, 1.5, true ); if (typeof retLineWidth === "string") { return retLineWidth; // errorMessage } line.lineWidth = retLineWidth; // console.log(line.lineWidth); // showLine let retShowLine = getBoolArrayFromInput( "showLine", yamlLine?.showLine, numDatasets, true, true ); if (typeof retShowLine === "string") { return retShowLine; } line.showLine = retShowLine; // console.log(line.showLine); // showPoint let retShowPoint = getBoolArrayFromInput( "showPoint", yamlLine?.showPoint, numDatasets, true, true ); if (typeof retShowPoint === "string") { return retShowPoint; } line.showPoint = retShowPoint; // console.log(line.showPoint); // pointColor let retPointColor = getStringArrayFromInput( "pointColor", yamlLine?.pointColor, numDatasets, "#69b3a2", validateColor, true ); if (typeof retPointColor === "string") { return retPointColor; } line.pointColor = retPointColor; // console.log(line.pointColor); // pointBorderColor let retPointBorderColor = getStringArrayFromInput( "pointBorderColor", yamlLine?.pointBorderColor, numDatasets, "#69b3a2", validateColor, true ); if (typeof retPointBorderColor === "string") { return retPointBorderColor; } line.pointBorderColor = retPointBorderColor; // console.log(line.pointBorderColor); // pointBorderWidth let retPointBorderWidth = getNumberArrayFromInput( "pointBorderWidth", yamlLine?.pointBorderWidth, numDatasets, 0.0, true ); if (typeof retPointBorderWidth === "string") { return retPointBorderWidth; // errorMessage } line.pointBorderWidth = retPointBorderWidth; // console.log(line.pointBorderWidth); // pointSize let retPointSize = getNumberArrayFromInput( "pointSize", yamlLine?.pointSize, numDatasets, 3.0, true ); if (typeof retPointSize === "string") { return retPointSize; // errorMessage } line.pointSize = retPointSize; // console.log(line.pointSize); // fillGap let retFillGap = getBoolArrayFromInput( "fillGap", yamlLine?.fillGap, numDatasets, false, true ); if (typeof retFillGap === "string") { return retFillGap; } line.fillGap = retFillGap; // console.log(line.fillGap); // yAxisLocation let retYAxisLocation = getStringArrayFromInput( "yAxisLocation", yamlLine?.yAxisLocation, numDatasets, "left", validateYAxisLocation, true ); if (typeof retYAxisLocation === "string") { return retYAxisLocation; // errorMessage } line.yAxisLocation = retYAxisLocation; // console.log(line.yAxisLocation); renderInfo.line.push(line); } // line related parameters // console.log(renderInfo.line); // bar related parameters for (let barKey of yamlBarKeys) { let bar = new BarInfo(); let yamlBar = yaml[barKey]; let keysOfBarInfo = getAvailableKeysOfClass(bar); let keysFoundInYAML = getAvailableKeysOfClass(yamlBar); // console.log(keysOfBarInfo); // console.log(keysFoundInYAML); for (let key of keysFoundInYAML) { if (!keysOfBarInfo.includes(key)) { errorMessage = "'" + key + "' is not an available key"; return errorMessage; } } let retParseCommonChartInfo = parseCommonChartInfo(yamlBar, bar); if (typeof retParseCommonChartInfo === "string") { return retParseCommonChartInfo; } // barColor let retBarColor = getStringArrayFromInput( "barColor", yamlBar?.barColor, numDatasets, "", validateColor, true ); if (typeof retBarColor === "string") { return retBarColor; // errorMessage } bar.barColor = retBarColor; // console.log(bar.barColor); // yAxisLocation let retYAxisLocation = getStringArrayFromInput( "yAxisLocation", yamlBar?.yAxisLocation, numDatasets, "left", validateYAxisLocation, true ); if (typeof retYAxisLocation === "string") { return retYAxisLocation; // errorMessage } bar.yAxisLocation = retYAxisLocation; // console.log(bar.yAxisLocation); renderInfo.bar.push(bar); } // bar related parameters // console.log(renderInfo.bar); // pie related parameters for (let pieKey of yamlPieKeys) { let pie = new PieInfo(); let yamlPie = yaml[pieKey]; let keysOfPieInfo = getAvailableKeysOfClass(pie); let keysFoundInYAML = getAvailableKeysOfClass(yamlPie); // console.log(keysOfPieInfo); // console.log(keysFoundInYAML); for (let key of keysFoundInYAML) { if (!keysOfPieInfo.includes(key)) { errorMessage = "'" + key + "' is not an available key"; return errorMessage; } } // title pie.title = getStringFromInput(yamlPie?.title, pie.title); // console.log(pie.title); // data let retData = getStringArray("data", yamlPie?.data); if (typeof retData === "string") { return retData; } pie.data = retData; // console.log(pie.data); let numData = pie.data.length; // dataColor let retDataColor = getStringArrayFromInput( "dataColor", yamlPie?.dataColor, numData, null, validateColor, true ); if (typeof retDataColor === "string") { return retDataColor; // errorMessage } pie.dataColor = retDataColor; // console.log(pie.dataColor); // dataName let retDataName = getStringArrayFromInput( "dataName", yamlPie?.dataName, numData, "", null, true ); if (typeof retDataName === "string") { return retDataName; // errorMessage } pie.dataName = retDataName; // console.log(pie.dataName); // label let retLabel = getStringArrayFromInput( "label", yamlPie?.label, numData, "", null, true ); if (typeof retLabel === "string") { return retLabel; // errorMessage } pie.label = retLabel; // console.log(pie.label); // hideLabelLessThan if (typeof yamlPie?.hideLabelLessThan === "number") { pie.hideLabelLessThan = yamlPie.hideLabelLessThan; } // console.log(pie.hideLabelLessThan); // extLabel let retExtLabel = getStringArrayFromInput( "extLabel", yamlPie?.extLabel, numData, "", null, true ); if (typeof retExtLabel === "string") { return retExtLabel; // errorMessage } pie.extLabel = retExtLabel; // console.log(pie.extLabel); // showExtLabelOnlyIfNoLabel if (typeof yamlPie?.showExtLabelOnlyIfNoLabel === "boolean") { pie.showExtLabelOnlyIfNoLabel = yamlPie.showExtLabelOnlyIfNoLabel; } // console.log(pie.showExtLabelOnlyIfNoLabel); // ratioInnerRadius if (typeof yamlPie?.ratioInnerRadius === "number") { pie.ratioInnerRadius = yamlPie.ratioInnerRadius; } // console.log(pie.ratioInnerRadius); // showLegend if (typeof yamlPie?.showLegend === "boolean") { pie.showLegend = yamlPie.showLegend; } // legendPosition pie.legendPosition = getStringFromInput( yamlPie?.legendPosition, "right" ); // legendOrient let defaultLegendOrientation = "horizontal"; if (pie.legendPosition === "top" || pie.legendPosition === "bottom") { defaultLegendOrientation = "horizontal"; } else if ( pie.legendPosition === "left" || pie.legendPosition === "right" ) { defaultLegendOrientation = "vertical"; } else { defaultLegendOrientation = "horizontal"; } pie.legendOrientation = getStringFromInput( yamlPie?.legendOrientation, defaultLegendOrientation ); // console.log(pie.legendPosition); // console.log(pie.legendOrientation); // legendBgColor pie.legendBgColor = getStringFromInput( yamlPie?.legendBgColor, pie.legendBgColor ); // legendBorderColor pie.legendBorderColor = getStringFromInput( yamlPie?.legendBorderColor, pie.legendBorderColor ); renderInfo.pie.push(pie); } // pie related parameters // console.log(renderInfo.pie); // summary related parameters for (let summaryKey of yamlSummaryKeys) { let summary = new SummaryInfo(); let yamlSummary = yaml[summaryKey]; let keysOfSummaryInfo = getAvailableKeysOfClass(summary); let keysFoundInYAML = getAvailableKeysOfClass(yamlSummary); // console.log(keysOfSummaryInfo); // console.log(keysFoundInYAML); for (let key of keysFoundInYAML) { if (!keysOfSummaryInfo.includes(key)) { errorMessage = "'" + key + "' is not an available key"; return errorMessage; } } // template summary.template = getStringFromInput( yamlSummary?.template, summary.template ); // style summary.style = getStringFromInput(yamlSummary?.style, summary.style); renderInfo.summary.push(summary); } // summary related parameters // Month related parameters for (let monthKey of yamlMonthKeys) { let month = new MonthInfo(); let yamlMonth = yaml[monthKey]; let keysOfMonthInfo = getAvailableKeysOfClass(month); let keysFoundInYAML = getAvailableKeysOfClass(yamlMonth); // console.log(keysOfSummaryInfo); // console.log(keysFoundInYAML); for (let key of keysFoundInYAML) { if (!keysOfMonthInfo.includes(key)) { errorMessage = "'" + key + "' is not an available key"; return errorMessage; } } // mode month.mode = getStringFromInput(yamlMonth?.mode, month.mode); // console.log(month.mode); // dataset let retDataset = getNumberArray("dataset", yamlMonth?.dataset); if (typeof retDataset === "string") { return retDataset; } if (retDataset.length === 0) { // insert y dataset given for (let q of queries) { retDataset.push(q.getId()); } } month.dataset = retDataset; // console.log(month.dataset); let numDataset = month.dataset.length; // startWeekOn month.startWeekOn = getStringFromInput( yamlMonth?.startWeekOn, month.startWeekOn ); // console.log(month.startWeekOn); // showCircle if (typeof yamlMonth?.showCircle === "boolean") { month.showCircle = yamlMonth.showCircle; } // console.log(month.showCircle); // threshold let retThreshold = getNumberArray("threshold", yamlMonth?.threshold); if (typeof retThreshold === "string") { return retThreshold; } month.threshold = retThreshold; if (month.threshold.length === 0) { for (let indDataset = 0; indDataset < numDataset; indDataset++) { month.threshold.push(0); } } if (month.threshold.length !== month.dataset.length) { // console.log(month.threshold); // console.log(month.dataset); const errorMessage = "The number of inputs of threshold and dataset not matched"; return errorMessage; } // console.log(month.threshold); // yMin let retYMin = getNumberArray("yMin", yamlMonth?.yMin); if (typeof retYMin === "string") { return retYMin; } month.yMin = retYMin; if (month.yMin.length === 0) { for (let indDataset = 0; indDataset < numDataset; indDataset++) { month.yMin.push(null); } } if (month.yMin.length !== month.dataset.length) { const errorMessage = "The number of inputs of yMin and dataset not matched"; return errorMessage; } // console.log(month.yMin); // yMax let retYMax = getNumberArray("yMax", yamlMonth?.yMax); if (typeof retYMax === "string") { return retYMax; } month.yMax = retYMax; if (month.yMax.length === 0) { for (let indDataset = 0; indDataset < numDataset; indDataset++) { month.yMax.push(null); } } if (month.yMax.length !== month.dataset.length) { const errorMessage = "The number of inputs of yMin and dataset not matched"; return errorMessage; } // console.log(month.yMax); // color month.color = getStringFromInput(yamlMonth?.color, month.color); // console.log(month.color); // dimNotInMonth if (typeof yamlMonth?.dimNotInMonth === "boolean") { month.dimNotInMonth = yamlMonth.dimNotInMonth; } // console.log(month.dimNotInMonth); // showStreak if (typeof yamlMonth?.showStreak === "boolean") { month.showStreak = yamlMonth.showStreak; } // console.log(month.showStreak); // showTodayRing if (typeof yamlMonth?.showTodayRing === "boolean") { month.showTodayRing = yamlMonth.showTodayRing; } // console.log(month.showTodayRing); // showSelectedValue if (typeof yamlMonth?.showSelectedValue === "boolean") { month.showSelectedValue = yamlMonth.showSelectedValue; } // console.log(month.showSelectedValue); // showSelectedRing if (typeof yamlMonth?.showSelectedRing === "boolean") { month.showSelectedRing = yamlMonth.showSelectedRing; } // console.log(month.showSelectedRing); // circleColor month.circleColor = getStringFromInput( yamlMonth?.circleColor, month.circleColor ); // console.log(month.circleColor); // circleColorByValue if (typeof yamlMonth?.circleColorByValue === "boolean") { month.circleColorByValue = yamlMonth.circleColorByValue; } // console.log(month.circleColorByValue); // headerYearColor month.headerYearColor = getStringFromInput( yamlMonth?.headerYearColor, month.headerYearColor ); // console.log(month.headerYearColor); // headerMonthColor month.headerMonthColor = getStringFromInput( yamlMonth?.headerMonthColor, month.headerMonthColor ); // console.log(month.headerMonthColor); // dividingLineColor month.dividingLineColor = getStringFromInput( yamlMonth?.dividingLineColor, month.dividingLineColor ); // console.log(month.dividingLineColor); // todayRingColor month.todayRingColor = getStringFromInput( yamlMonth?.todayRingColor, month.todayRingColor ); // console.log(month.todayRingColor); // selectedRingColor month.selectedRingColor = getStringFromInput( yamlMonth?.selectedRingColor, month.selectedRingColor ); // console.log(month.selectedRingColor); // initMonth month.initMonth = getStringFromInput( yamlMonth?.initMonth, month.initMonth ); // console.log(month.initMonth); // showAnnotation if (typeof yamlMonth?.showAnnotation === "boolean") { month.showAnnotation = yamlMonth.showAnnotation; } // console.log(month.showAnnotation); // annotation let retAnnotation = getStringArray("annotation", yamlMonth?.annotation); if (typeof retAnnotation === "string") { return retAnnotation; } month.annotation = retAnnotation; if (month.annotation.length === 0) { for (let indDataset = 0; indDataset < numDataset; indDataset++) { month.annotation.push(null); } } if (month.annotation.length !== month.dataset.length) { const errorMessage = "The number of inputs of annotation and dataset not matched"; return errorMessage; } // console.log(month.annotation); // showAnnotationOfAllTargets if (typeof yamlMonth?.showAnnotationOfAllTargets === "boolean") { month.showAnnotationOfAllTargets = yamlMonth.showAnnotationOfAllTargets; } // console.log(month.showAnnotationOfAllTargets); renderInfo.month.push(month); } // Month related parameters // console.log(renderInfo.month); // Heatmap related parameters for (let heatmapKey of yamlHeatmapKeys) { let heatmap = new HeatmapInfo(); let yamlHeatmap = yaml[heatmapKey]; let keysOfHeatmapInfo = getAvailableKeysOfClass(heatmap); let keysFoundInYAML = getAvailableKeysOfClass(yamlHeatmap); // console.log(keysOfHeatmapInfo); // console.log(keysFoundInYAML); for (let key of keysFoundInYAML) { if (!keysOfHeatmapInfo.includes(key)) { errorMessage = "'" + key + "' is not an available key"; return errorMessage; } } renderInfo.heatmap.push(heatmap); } // console.log(renderInfo.heatmap); // Bullet related parameters for (let bulletKey of yamlBulletKeys) { let bullet = new BulletInfo(); let yamlBullet = yaml[bulletKey]; let keysOfBulletInfo = getAvailableKeysOfClass(bullet); let keysFoundInYAML = getAvailableKeysOfClass(yamlBullet); // console.log(keysOfSummaryInfo); // console.log(keysFoundInYAML); for (let key of keysFoundInYAML) { if (!keysOfBulletInfo.includes(key)) { errorMessage = "'" + key + "' is not an available key"; return errorMessage; } } // title bullet.title = getStringFromInput(yamlBullet?.title, bullet.title); // console.log(bullet.title); // dataset bullet.dataset = getStringFromInput( yamlBullet?.dataset, bullet.dataset ); // console.log(bullet.dataset); // orientation bullet.orientation = getStringFromInput( yamlBullet?.orientation, bullet.orientation ); // console.log(bullet.orientation); // range let retRange = getNumberArray("range", yamlBullet?.range); if (typeof retRange === "string") { return retRange; } let range = retRange as Array<number>; // Check the value is monotonically increasing // Check the value is not negative if (range.length === 1) { if (range[0] < 0) { errorMessage = "Negative range value is not allowed"; return errorMessage; } } else if (range.length > 1) { let lastBound = range[0]; if (lastBound < 0) { errorMessage = "Negative range value is not allowed"; return errorMessage; } else { for (let ind = 1; ind < range.length; ind++) { if (range[ind] <= lastBound) { errorMessage = "Values in parameter 'range' should be monotonically increasing"; return errorMessage; } } } } else { errorMessage = "Empty range is not allowed"; return errorMessage; } bullet.range = range; let numRange = range.length; // console.log(renderInfo.bullet.range); // range color let retRangeColor = getStringArrayFromInput( "rangeColor", yamlBullet?.rangeColor, numRange, "", validateColor, true ); if (typeof retRangeColor === "string") { return retRangeColor; // errorMessage } bullet.rangeColor = retRangeColor; // console.log(bullet.rangeColor); // actual value, can possess template variable bullet.value = getStringFromInput(yamlBullet?.value, bullet.value); // console.log(bullet.value); // value unit bullet.valueUnit = getStringFromInput( yamlBullet?.valueUnit, bullet.valueUnit ); // console.log(bullet.valueUnit); // value color bullet.valueColor = getStringFromInput( yamlBullet?.valueColor, bullet.valueColor ); // console.log(bullet.valueColor); // show mark if (typeof yamlBullet?.showMarker === "boolean") { bullet.showMarker = yamlBullet.showMarker; } // console.log(bullet.showMark); // mark value if (typeof yamlBullet?.markerValue === "number") { bullet.markerValue = yamlBullet.markerValue; } // console.log(bullet.markValue); // mark color bullet.markerColor = getStringFromInput( yamlBullet?.markerColor, bullet.markerColor ); // console.log(bullet.markValue); renderInfo.bullet.push(bullet); } // Bullet related parameters // console.log(renderInfo.bullet); return renderInfo; }