Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | 2x 2x 2x 2x 2x 2x 1x 180x 90x 90x 1x 36x 36x 18x 348x 18x 306x 1x 216x 216x 36x 180x 1x 38x 38x 38x 216x 216x 38x 1x 90x 90x 90x 1x 2x 2x 2x 6x 6x 126x 126x 6x 2x 1x 2x 2x 1x 1x 3x 1x 2x 2x 2x 90x 2x 2x 1x | import * as fs from 'fs/promises';
import {ERRORS} from '@grnsft/if-core/utils';
import {STRINGS} from '../config';
import {Context} from '../types/manifest';
const {ExhaustOutputArgError, WriteFileError} = ERRORS;
const {OUTPUT_REQUIRED, WRITE_CSV_ERROR, EXPORTING_RAW_CSV_FILE} = STRINGS;
export const ExportCSVRaw = () => {
/**
* handle a tree leaf, where there are no child nodes, by adding it as key->value pair to the flat map
* and capturing key as a header
*/
const handleLeafValue = (
value: any,
fullPath: string,
key: any,
flatMap: {[key: string]: any},
headers: Set<string>
) => {
if (fullPath.includes('outputs')) {
headers.add(key);
flatMap[fullPath] = value;
}
};
/**
* handle a tree node, recursively traverse the children and append their results to the flat map and captured headers
*/
const handleNodeValue = (
value: any,
fullPath: string,
flatMap: Record<string, any>,
headers: Set<string>
) => {
const [subFlatMap, subHeaders] = extractFlatMapAndHeaders(value, fullPath);
if (Object.keys(subFlatMap).length > 0) {
Object.entries(subFlatMap).forEach(([subKey, value]) => {
flatMap[subKey] = value;
});
subHeaders.forEach(subHeader => {
headers.add(subHeader);
});
}
};
/**
* Handles a key at the top level of the tree
*/
const handleKey = (
value: any,
key: any,
prefix: string,
flatMap: Record<string, any>,
headers: Set<string>
) => {
const fullPath = prefix ? `${prefix}.${key}` : key;
if (value !== null && typeof value === 'object') {
return handleNodeValue(value, fullPath, flatMap, headers);
}
return handleLeafValue(value, fullPath, key, flatMap, headers);
};
/**
* Recursively extract a flat map and headers from the hierarcial tree.
*/
const extractFlatMapAndHeaders = (
tree: any,
prefix = ''
): [Record<string, any>, Set<string>] => {
const headers: Set<string> = new Set();
const flatMap: Record<string, any> = [];
for (const key in tree) {
if (key in tree) {
handleKey(tree[key], key, prefix, flatMap, headers);
}
}
return [flatMap, headers];
};
/**
* extract the id of the key, that is removing the last token (which is the index).
* in this manner, multiple keys that identical besides their index share the same id.
*/
const extractIdHelper = (key: string): string => {
const parts = key.split('.');
parts.pop();
return parts.join('.');
};
/**
* generate a CSV formatted string based on a flat key->value map, headers and ids
*/
const getCsvString = (
map: {[key: string]: any},
headers: Set<string>,
ids: Set<string>
): string => {
const csvRows: string[] = [];
csvRows.push(['id', ...headers].join(','));
ids.forEach(id => {
const rowData = [id];
headers.forEach(header => {
const value = map[`${id}.${header}`] ?? '';
rowData.push(value.toString());
});
csvRows.push(rowData.join(','));
});
return csvRows.join('\n');
};
/**
* write the given string content to a file at the provided path
*/
const writeOutputFile = async (content: string, outputPath: string) => {
try {
await fs.writeFile(`${outputPath}.csv`, content);
} catch (error) {
throw new WriteFileError(WRITE_CSV_ERROR(outputPath, error));
}
};
/**
* export the provided tree content to a CSV file, represented in a flat structure
*/
const execute = async (tree: any, _context: Context, outputPath: string) => {
if (!outputPath) {
throw new ExhaustOutputArgError(OUTPUT_REQUIRED);
}
console.debug(EXPORTING_RAW_CSV_FILE(outputPath));
const [extractredFlatMap, extractedHeaders] =
extractFlatMapAndHeaders(tree);
const ids = new Set(
Object.keys(extractredFlatMap).map(key => extractIdHelper(key))
);
const csvString = getCsvString(extractredFlatMap, extractedHeaders, ids);
await writeOutputFile(csvString, outputPath);
};
return {execute};
};
|