You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

129 line
3.3 KiB

  1. const fs = require('fs-extra');
  2. const { toSystemPath } = require('../core/path');
  3. const { keysToLowerCase } = require('../core/util');
  4. // simple inital implementation
  5. // better implementation at:
  6. // https://github.com/adaltas/node-csv-parse
  7. // https://github.com/mafintosh/csv-parser
  8. function parseCSV(csv, options) {
  9. if (!csv) return [];
  10. if (csv.charCodeAt(0) === 0xFEFF) {
  11. csv = csv.slice(1);
  12. }
  13. let delimiter = options.delimiter.replace('\\t', '\t');
  14. let keys = options.fields;
  15. let line = 1;
  16. let data = [];
  17. if (options.header) {
  18. keys = getcsv();
  19. options.fields.forEach(field => {
  20. if (keys.indexOf(field) == -1) {
  21. throw new Error('parseCSV: ' + field + ' is missing in ' + options.path);
  22. }
  23. });
  24. line++;
  25. }
  26. let size = keys.length;
  27. while (csv.length) {
  28. let values = getcsv();
  29. let o = {};
  30. if (values.length != size) {
  31. throw new Error('parseCSV: colomns do not match. keys: ' + size + ', values: ' + values.length + ' at line ' + line);
  32. }
  33. for (let i = 0; i < size; i++) {
  34. o[keys[i]] = values[i];
  35. }
  36. data.push(o);
  37. line++;
  38. }
  39. return data;
  40. function getcsv() {
  41. let data = [''], l = csv.length,
  42. esc = false, escesc = false,
  43. n = 0, i = 0;
  44. while (i < l) {
  45. let s = csv.charAt(i);
  46. if (s == '\n') {
  47. if (esc) {
  48. data[n] += s;
  49. } else {
  50. i++;
  51. break;
  52. }
  53. } else if (s == '\r') {
  54. if (esc) {
  55. data[n] += s;
  56. }
  57. } else if (s == delimiter) {
  58. if (esc) {
  59. data[n] += s;
  60. } else {
  61. data[++n] = '';
  62. esc = false;
  63. escesc = false;
  64. }
  65. } else if (s == '"') {
  66. if (escesc) {
  67. data[n] += s;
  68. escesc = false;
  69. }
  70. if (esc) {
  71. esc = false;
  72. escesc = true;
  73. } else {
  74. esc = true;
  75. escesc = false;
  76. }
  77. } else {
  78. if (escesc) {
  79. data[n] += '"';
  80. escesc = false;
  81. }
  82. data[n] += s;
  83. }
  84. i++;
  85. }
  86. csv = csv.substr(i);
  87. return data;
  88. }
  89. }
  90. module.exports = {
  91. csv: async function(options) {
  92. let path = this.parseRequired(options.path, 'string', 'export.csv: path is required.');
  93. let fields = this.parseOptional(options.fields, 'object', []);
  94. let header = this.parseOptional(options.header, 'boolean', false);
  95. let delimiter = this.parseOptional(options.delimiter, 'string', ',');
  96. let csv = await fs.readFile(toSystemPath(path), 'utf8');
  97. return parseCSV(csv, { fields, header, delimiter });
  98. },
  99. xml: async function(options) {
  100. // TODO: import.xml
  101. throw new Error('import.xml: not implemented.');
  102. },
  103. };