diff --git a/forms-parser/README.md b/forms-parser/README.md new file mode 100644 index 00000000..d89d454e --- /dev/null +++ b/forms-parser/README.md @@ -0,0 +1,8 @@ +Install dependencies +```js +pnpm install +``` +Running the app +```js +node form-parser.js -f "forms-2023-10-11.xlsx" -s 1 -o "output" +``` \ No newline at end of file diff --git a/forms-parser/form-parser.js b/forms-parser/form-parser.js new file mode 100644 index 00000000..f5750158 --- /dev/null +++ b/forms-parser/form-parser.js @@ -0,0 +1,120 @@ +#!/usr/bin/env node +import yargs from 'yargs' +import readXlsxFile from 'read-excel-file/node' +import { forIn } from 'lodash-es'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { hideBin } from 'yargs/helpers'; + +const options = yargs(hideBin(process.argv)) + .usage('Usage: -f -s 1 -o -v 1') + .option('f', { alias: 'filePath', describe: 'Excel file to be parsed', type: 'string', demandOption: true }) + .option('s', { alias: 'sheetIndex', describe: 'Sheet index to parse (1 indexed)', type: 'number', demandOption: true }) + .option('o', { alias: 'outputDirectory', describe: 'Output folder where to write imported forms.', type: 'string', demandOption: true }) + .argv; + +if (!fs.existsSync(options.outputDirectory)) { + throw new Error(`Specified output directory does not exist!outputDirectory= ${options.outputDirectory}`) +} + +readXlsxFile(fs.readFileSync(options.filePath), { sheet: options.sheetIndex }).then((rows) => { + // remove header + rows = rows.slice(1); + const forms = {}; + + rows.forEach(row => { + let form = undefined; + + if (!(row[0] in forms)) { + form = { + code: row[0], + currentVersion: 1, + description: row[0], + formSections: [], + }; + + forms[row[0]] = form; + } else { + form = forms[row[0]] + } + + let section = form.formSections.find(fs=>fs.code == row[1]); + + if (section === undefined) { + section = { + uniqueId: row[1], + code: row[1].toString(), + description: '', + orderNumber: Object.keys(form.formSections).length + 1, + questions: [] + }; + + form.formSections.push(section); + } + + section.questions.push({ + formCode: form.code, + code: row[2].toString(), + questionType: mapQuestionType(row[4]), + text: row[3], + orderNumber: section.questions.length + 1, + optionsToQuestions: getOptions(row.slice(5)) + }); + }); + + + const generatedFiles = []; + + let formIndex = 1; + forIn(forms,f => { + f.order = formIndex; + const content = JSON.stringify(f, null, 4); + + const outputFilePath = path.join(options.outputDirectory, f.code + '.json'); + generatedFiles.push(outputFilePath); + + fs.writeFileSync(outputFilePath, content); + formIndex++; + }) + + + console.log(`All done!`); + console.log(`Generated files:`); + generatedFiles.forEach(f=>console.log(f)) +}); + +function getOptions(options) { + return options + .filter(o=>o) + .map(o => o.toString()) + .map(parseOption); +} + +function parseOption(option, index) { + const isFlagged = option.indexOf('$flag') !== -1; + const isFreeText = option.indexOf('$text') !== -1; + + option = option.replace('$text', '').replace('$flag', ''); + + return { + isFreeText, + isFlagged, + text: option, + orderNumber: index+1 + }; +} + +function mapQuestionType(excelQuestionType) { + switch (excelQuestionType) { + case 'multiple choice': + return 0; + case 'single choice': + return 1; + case 'single choice with text': + return 2; + case 'multiple choice with text': + return 3; + default: + throw new Error(`Unknown question type: ${excelQuestionType}`); + } +} diff --git a/forms-parser/package.json b/forms-parser/package.json index 93d6566d..3f3070d5 100644 --- a/forms-parser/package.json +++ b/forms-parser/package.json @@ -2,17 +2,14 @@ "name": "forms-parser", "version": "1.0.0", "description": "", - "main": "bin/index.js", + "main": "form-parser.js", "type": "module", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "form-parser": " node form-parser.js -f forms-2023-10-11.xlsx -s 1 -o output" }, "keywords": [], "author": "Ion Dormenco", "license": "MIT", - "bin": { - "hello": "./bin/index.js" - }, "dependencies": { "lodash-es": "^4.17.21", "nanoid": "^4.0.2",