diff --git a/home/modules/contribute/examples/example1.csv b/home/modules/contribute/examples/example1.csv new file mode 100644 index 0000000000..6933593e17 --- /dev/null +++ b/home/modules/contribute/examples/example1.csv @@ -0,0 +1,12 @@ +Issue Type,Priority,Issue key,Summary,Labels,Component/s,Component/s,Status,Fix Version/s +Bug,Critical,CBL-4922,Lithium: Failure in OkHttp authenticator,,Java-Android,Kotlin-Android,Closed,3.0.15 +Bug,Major,CBL-4921,Lithium: Lower the max size on the ClientTask thread pool to 8,,Java-Android,,Closed,3.0.15 +Bug,Major,CBL-4839,Attachments/Blobs got deleted after compaction&re-sync,,,,Closed,3.0.15 +Bug,Major,CBL-4799,Lithium: Database.exists should support the default directory,backport,Java-Android,,Closed,3.0.15 +Bug,Major,CBL-4139,Lithium build error on Linux,,,,Closed,3.0.15 +Bug,Major,CBL-4125,"Port Replicator test helpers, SG, SGTestUser, ReplParams to Lithium",,,,Closed,3.0.15 +Bug,Major,CBL-4111,Allow docs failed with property encryption / decryption to be retried,,,,Closed,3.0.15 +Bug,Major,CBL-3879,Failed test - testDoubleConflictResolutionOnSameConflicts,,,,Closed,3.0.15 +Bug,Major,CBL-3878,testStopContinuousReplicator inconsistent failure,,,,Closed,3.0.15 +Bug,Major,CBL-3877,testDeleteWithActiveReplicatorAndURLEndpointListeners failure,,,,Closed,3.0.15 +Bug,Critical,CBL-3871,QueryParams fails to decode bool,,,,Closed,3.0.15 \ No newline at end of file diff --git a/home/modules/contribute/pages/extensions-template.adoc b/home/modules/contribute/pages/extensions-template.adoc index 0b17b4ee6b..81c4c0f8fa 100644 --- a/home/modules/contribute/pages/extensions-template.adoc +++ b/home/modules/contribute/pages/extensions-template.adoc @@ -120,3 +120,25 @@ Description:: -- +== CSV parsing + +NOTE: The CSV function is designed to handle the export from JIRA which handles lists ("Components" etc.) by producing multiple columns each called "Component/s". + +[source,handlebars] +-- +{{#each this}} +{{this.[Issue key]}}:: +{{#each this.[Component/s]}}* {{.}} +{{/each}} +{{/each}} +-- + + +[template,example$example1.csv] +-- +{{#each this}} +{{this.[Issue key]}}:: +{{#each this.[Component/s]}}* {{.}} +{{/each}} +{{/each}} +-- diff --git a/lib/helpers/filter-by-component.js b/lib/helpers/filter-by-component.js new file mode 100644 index 0000000000..8c60b631bb --- /dev/null +++ b/lib/helpers/filter-by-component.js @@ -0,0 +1,13 @@ +'use strict' + +module.exports = filterByComponent + +function filterByComponent(arr, ...rest) { + const components = rest.slice(0,-1) // last item is Handlebars context + return arr.filter(item => intersects(item["Component/s"], components)) +} + +function intersects(a, b) { + const setB = new Set(b); + return a.some(x => setB.has(x)); +} diff --git a/lib/template-block.js b/lib/template-block.js index 2fabb11971..a48d7fce18 100644 --- a/lib/template-block.js +++ b/lib/template-block.js @@ -94,9 +94,9 @@ function setupHandlebars(attributes, config) { // get a resource from the Antora contentCatalog // This is called from the context of the current page, // and attempts to process known filetypes: -// .json / .yml (parse) -// .js (require) -// everything else (just return string) +// .json / .yml / .csv (parse) +// .js (require) +// everything else (just return string) // // function getResource (resourceId, config) { @@ -113,22 +113,62 @@ function getResource (resourceId, config) { else if (/\.ya?ml$/.test(resourceId)) { return YAML.parse(target.contents.toString(), {maxAliasCount: -1} ) } + else if (/\.csv$/.test(resourceId)) { + return parse_csv(target.contents) + } else if (/\.js$/.test(resourceId)) { return requireFromString(target.contents.toString(), resourceId) } else { + console.log(target.contents.toString()) return target.contents.toString() } } // Helper functions +/* This parse function is designed to handle the export from JIRA + * which will deal with lists ("Labels" etc.) by producing multiple columns + * each called "Label/s" + * + * `csv-parse` handles this with the `group_columns_by_name` option. + * However, in the case where there is only a *single* entry, the parser does + * not know to group the single result in an array. + * To make the output consistent each time, we post-process by wrapping the value + * of any fields named like "Foo/s" in an array if it is not already an array. + * Additionally, it's possible that not all rows will have the same number of items + * in the array. The handler will parse these as empty strings, so we will filter + * those out. + */ + +function parse_csv(contents) { + const { parse } = require('csv-parse/sync') + const records = parse( + contents, + { + columns: true, + group_columns_by_name: true, + } + ).map( + record => Object.fromEntries( + Object.entries(record).map(([key,val]) => { + if (key.endsWith("/s")) { + const arr = Array.isArray(val) ? val.filter(item => item !== '') : [val] + return [key, arr] + } + else { + return [key, val] + }}))) + + return records +} + // https://stackoverflow.com/questions/17581830/load-node-js-module-from-string-in-memory function requireFromString(src, filename) { var Module = module.constructor; var m = new Module(); m._compile(src, filename); return m.exports; - } +} module.exports = { register } diff --git a/package-lock.json b/package-lock.json index ef56986452..c31b71d848 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "antora": "~3.1", "asciidoctor-external-callout": "~1.2.0", "asciidoctor-kroki": "0.15.4", + "csv-parse": "5.5.0", "gulp": "~4.0", "gulp-connect": "~5.7", "js-yaml": "~4.1", @@ -1344,6 +1345,11 @@ "node": ">=0.8" } }, + "node_modules/csv-parse": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.5.0.tgz", + "integrity": "sha512-RxruSK3M4XgzcD7Trm2wEN+SJ26ChIb903+IWxNOcB5q4jT2Cs+hFr6QP39J05EohshRFEvyzEBoZ/466S2sbw==" + }, "node_modules/d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", diff --git a/package.json b/package.json index 31fe356cb1..da82d0d935 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "antora": "~3.1", "asciidoctor-external-callout": "~1.2.0", "asciidoctor-kroki": "0.15.4", + "csv-parse": "5.5.0", "gulp": "~4.0", "gulp-connect": "~5.7", "js-yaml": "~4.1",