dotfiles/vscode/.vscode/extensions/randomfractalsinc.vscode-data-preview-2.3.0/out/data.providers/markdown.data.provider.js
Errol Sancaktar ff17c17e23 vscode
2024-06-14 09:31:58 -06:00

295 lines
14 KiB
JavaScript

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MarkdownDataProvider = void 0;
const fs = require("fs");
const config = require("../config");
const fileUtils = require("../utils/file.utils");
const logger_1 = require("../logger");
const vscode_1 = require("vscode");
/**
* Markdown tables data provider.
*/
class MarkdownDataProvider {
/**
* Creates data provider for Excel data files.
*/
constructor() {
// TODO: add mime types later for http data loading
this.supportedDataFileTypes = ['.md'];
this.logger = new logger_1.Logger('markdown.data.provider:', config.logLevel);
// local table names cache with dataUrl/tableNames array key/values
this.dataTableNamesMap = {};
this.logger.debug('created for:', this.supportedDataFileTypes);
}
/**
* Gets local or remote markdown file table data.
* @param dataUrl Local data file path or remote data url.
* @param parseOptions Data parse options.
* @param loadData Load data callback.
*/
getData(dataUrl, parseOptions, loadData) {
return __awaiter(this, void 0, void 0, function* () {
let content = '';
try {
// read markdown file content
content = String(yield fileUtils.readDataFile(dataUrl, 'utf8'));
// convert it to to CSV for loading into data view
content = this.markdownToCsv(dataUrl, content, parseOptions.dataTable);
}
catch (error) {
this.logger.error(`getMarkdownData(): Error parsing '${dataUrl}'. \n\t Error: ${error.message}`);
vscode_1.window.showErrorMessage(`Unable to parse data file: '${dataUrl}'. \n\t Error: ${error.message}`);
}
loadData(content);
});
} // end of getData()
/**
* Gets data table names for data sources with multiple data sets.
* @param dataUrl Local data file path or remote data url.
*/
getDataTableNames(dataUrl) {
return this.dataTableNamesMap[dataUrl];
}
/**
* Gets data schema in json format for file types that provide it.
* @param dataUrl Local data file path or remote data url.
*/
getDataSchema(dataUrl) {
// TODO: return md table headers row later ???
return null; // none for .md data files
}
/**
* Saves CSV as markdown table data.
* @param filePath Local data file path.
* @param fileData Raw data to save.
* @param tableName Table name for data files with multiple tables support.
* @param showData Show saved data callback.
*/
saveData(filePath, fileData, tableName, showData) {
// convert CSV text to markdown table
fileData = this.csvToMarkdownTable(fileData);
if (fileData.length > 0) {
// TODO: change this to async later
fs.writeFile(filePath, fileData, (error) => showData(error));
}
}
/**
* Converts markdown content to csv data for display in data view.
* @param dataUrl Local data file path or remote data url.
* @param markdownContent Markdown file content to convert to csv string.
* @param dataTable Markdown data table name to load.
*/
markdownToCsv(dataUrl, markdownContent, dataTable) {
// extract markdown sections and tables
const sections = markdownContent.split('\n#');
const sectionMarker = new RegExp(/(#)/g);
const quotes = new RegExp(/(")/g);
const tableHeaderSeparator = new RegExp(/((\|)|(\:)|(\-)|(\s))+/g);
const tableRowMarkdown = new RegExp(/((\|[^|\r\n]*)+\|(\r?\n|\r)?)/g);
const tablesMap = {};
let tableNames = [];
sections.forEach(section => {
// get section title
let sectionTitle = '';
const sectionLines = section.split('\n');
if (sectionLines.length > 0) {
sectionTitle = sectionLines[0].replace(sectionMarker, '').trim(); // strip out #'s and trim
}
// create section text blocks
const textBlocks = [];
let textBlock = '';
sectionLines.forEach(textLine => {
if (textLine.trim().length === 0) {
// create new text block
textBlocks.push(textBlock);
textBlock = '';
}
else {
// append to the current text block
textBlock += textLine + '\n';
}
});
// extract section table data from each section text block
const tables = []; // two-dimensional array of table rows
textBlocks.forEach(textBlock => {
// extract markdown table data rows from a text block
const tableRows = textBlock.match(tableRowMarkdown);
if (tableRows) {
// add matching markdown table rows to the tables array
tables.push(tableRows);
this.logger.debug('markdownToCsv(): section:', sectionTitle);
this.logger.debug('markdownToCsv(): extractred markdown table rows:', tableRows);
}
});
// process markdown tables
tables.forEach((table, tableIndex) => {
// process markdown table row strings
const tableRows = [];
table.forEach(row => {
// trim markdown table text row lines
row = row.trim();
// strip out leading | table row sign
if (row.startsWith('| ')) {
row = row.slice(2);
}
// strip out trailing | table row sign
if (row.endsWith(' |')) {
row = row.slice(0, row.length - 2);
}
// check for a table header separator row
const isTableHeaderSeparator = (row.replace(tableHeaderSeparator, '').length === 0);
if (!isTableHeaderSeparator && row.length > 0) {
// add data table row
tableRows.push(row);
}
});
if (tableRows.length > 0) {
// create table title
let tableTitle = sectionTitle;
if (tables.length > 1) {
// append table index
tableTitle += '-table-' + (tableIndex + 1);
}
// update table list for data view display
tablesMap[tableTitle] = tableRows;
tableNames.push(tableTitle);
this.logger.debug(`markdownToCsv(): created data table: '${tableTitle}' rows: ${tableRows.length}`);
}
}); // end of tables.forEach(row)
}); // end of sections.forEach(textBlock/table)
// get requested table data
let table = tablesMap[tableNames[0]]; // default to 1st table in the loaded tables list
if (dataTable && dataTable.length > 0) {
table = tablesMap[dataTable];
this.logger.debug(`markdownToCsv(): requested data table: '${dataTable}'`);
}
if (tableNames.length === 1) {
// clear table names if only one markdown table is present
tableNames = [];
}
// update table names cache
this.dataTableNamesMap[dataUrl] = tableNames;
// convert requested markdown table to csv for data view display
let csvContent = '';
if (table) {
this.logger.debug('markdownToCsv(): markdown table rows:', table);
table.forEach(row => {
const cells = row.split(' | ');
const csvCells = [];
cells.forEach(cell => {
cell = cell.trim();
const cellHasQuotes = quotes.test(cell);
if (cellHasQuotes) {
// escape quotes for csv
cell = cell.replace(quotes, '""'); // double quote for csv quote escape
}
if (cellHasQuotes || cell.indexOf(',') >= 0) {
// quote cell string
cell = `"${cell}"`;
}
csvCells.push(cell);
});
const csvRow = csvCells.join(',');
csvContent += csvRow + '\n';
});
this.logger.debug('markdownToCsv(): final csv table content string for data.view load:\n', csvContent);
}
return csvContent;
} // end of markdownToCsv()
/**
* Converts CSV to markdown table.
* @param {string} csvContent Csv/tsv data content.
* @param {string} delimiter Csv/tsv delimiter.
* @param {boolean} hasTableHeaderRow Has table header row.
* @returns {string} Markdown table content.
*/
csvToMarkdownTable(csvContent, delimiter = ',', hasTableHeaderRow = true) {
if (delimiter !== '\t') {
// replace all tabs with spaces
csvContent = csvContent.replace(/\t/g, ' ');
}
// extract table rows and data from csv content
const csvRows = csvContent.split('\n');
const tableData = [];
const maxColumnLength = []; // for pretty markdown table cell spacing
const cellRegExp = new RegExp(delimiter + '(?![^"]*"\\B)');
const doubleQuotes = new RegExp(/("")/g);
this.logger.debug('csvToMarkdownTable(): csv rows:', csvRows);
csvRows.forEach((row, rowIndex) => {
if (typeof tableData[rowIndex] === 'undefined') {
// create new table row cells data array
tableData[rowIndex] = [];
}
// extract row cells data from csv text line
const cells = row.replace('\r', '').split(cellRegExp);
cells.forEach((cell, columnIndex) => {
if (typeof maxColumnLength[columnIndex] === 'undefined') {
// set initial column size to 0
maxColumnLength[columnIndex] = 0;
}
// strip out leading and trailing quotes
if (cell.startsWith('"')) {
cell = cell.substring(1);
}
if (cell.endsWith('"')) {
cell = cell.substring(0, cell.length - 1);
}
// replace escaped double quotes that come from csv text data format
cell = cell.replace(doubleQuotes, '"');
// update max column length for pretty markdwon table cells spacing
maxColumnLength[columnIndex] = Math.max(maxColumnLength[columnIndex], cell.length);
// save extracted cell data for table rows output
tableData[rowIndex][columnIndex] = cell;
});
});
// create markdown table header and separator text lines
let tableHeader = '';
let tableHeaderSeparator = '';
maxColumnLength.forEach((columnLength) => {
const columnHeader = Array(columnLength + 1 + 2);
tableHeader += '|' + columnHeader.join(' ');
tableHeaderSeparator += '|' + columnHeader.join('-');
});
// end table header and separator text lines
tableHeader += '| \n';
tableHeaderSeparator += '| \n';
if (hasTableHeaderRow) {
// reset: use table data instead
tableHeader = '';
}
// create markdown table data text lines
let tableRows = '';
tableData.forEach((row, rowIndex) => {
maxColumnLength.forEach((columnLength, columnIndex) => {
const cellData = typeof row[columnIndex] === 'undefined' ? '' : row[columnIndex];
const cellSpacing = Array((columnLength - cellData.length) + 1).join(' ');
const cellString = `| ${cellData}${cellSpacing} `;
if (hasTableHeaderRow && rowIndex === 0) {
tableHeader += cellString;
}
else {
tableRows += cellString;
}
});
// end table header or data row text line
if (hasTableHeaderRow && rowIndex === 0) {
tableHeader += '| \n';
}
else {
tableRows += '| \n';
}
});
return `${tableHeader}${tableHeaderSeparator}${tableRows}`;
} // end of csvToMarkdownTable()
}
exports.MarkdownDataProvider = MarkdownDataProvider;
//# sourceMappingURL=markdown.data.provider.js.map