@ellipticltd/aml-utils 0.16.25 → 0.16.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.circleci/config.yml +87 -0
- package/.claude/settings.local.json +7 -0
- package/.eslintrc +45 -0
- package/.huskyrc +5 -0
- package/.mocharc.json +3 -0
- package/.nvmrc +1 -0
- package/.nycrc.json +11 -0
- package/.releaserc.json +18 -0
- package/.snyk +12 -0
- package/README.md +43 -11
- package/codecov.yml +29 -0
- package/commitlint.config.js +1 -0
- package/dist/errors/errors.js +42 -0
- package/dist/errors/errors.spec.d.ts +1 -0
- package/dist/errors/errors.spec.js +23 -0
- package/dist/file-parser/__tests/file-parser.spec.d.ts +1 -0
- package/dist/file-parser/__tests/file-parser.spec.js +109 -0
- package/dist/file-parser/__tests/parse-row.spec.d.ts +1 -0
- package/dist/file-parser/__tests/parse-row.spec.js +29 -0
- package/dist/file-parser/__tests/sanitize-rows.spec.d.ts +1 -0
- package/dist/file-parser/__tests/sanitize-rows.spec.js +78 -0
- package/{lib → dist}/file-parser/errors.js +1 -1
- package/{lib → dist}/file-parser/file-parser.d.ts +4 -2
- package/dist/file-parser/file-parser.js +55 -0
- package/{lib → dist}/file-parser/parse-row.js +1 -2
- package/{lib/file-parser/sanitizeRows.d.ts → dist/file-parser/sanitzeRows.d.ts} +1 -3
- package/dist/file-parser/sanitzeRows.js +18 -0
- package/dist/formatting/formatting.js +17 -0
- package/dist/formatting/formatting.spec.d.ts +1 -0
- package/dist/formatting/formatting.spec.js +37 -0
- package/{lib → dist}/index.d.ts +1 -1
- package/dist/index.js +22 -0
- package/dist/middleware/middleware.js +22 -0
- package/dist/orm-helpers/ormHelpers.js +17 -0
- package/dist/orm-helpers/ormHelpers.spec.d.ts +1 -0
- package/dist/orm-helpers/ormHelpers.spec.js +38 -0
- package/{lib → dist}/structured-file-parser/errors.js +0 -1
- package/{lib → dist}/structured-file-parser/parse-row.js +1 -2
- package/{lib → dist}/structured-file-parser/sanitize-rows.js +4 -3
- package/{lib → dist}/structured-file-parser/structured-file-parser.d.ts +2 -2
- package/dist/structured-file-parser/structured-file-parser.js +98 -0
- package/{lib → dist}/types/types.d.ts +6 -0
- package/dist/types/types.js +203 -0
- package/{lib → dist}/validations/validations.d.ts +110 -157
- package/dist/validations/validations.js +470 -0
- package/dist/validations/validations.spec.d.ts +1 -0
- package/dist/validations/validations.spec.js +463 -0
- package/lib/errors/errors.js +30 -19
- package/lib/errors/errors.spec.js +37 -0
- package/lib/file-parser/__tests/file-parser.spec.js +107 -0
- package/lib/file-parser/__tests/parse-row.spec.js +35 -0
- package/lib/file-parser/__tests/sanitize-rows.spec.js +88 -0
- package/lib/file-parser/errors.ts +7 -0
- package/lib/file-parser/file-parser.ts +84 -0
- package/lib/file-parser/parse-row.ts +52 -0
- package/lib/file-parser/sanitzeRows.ts +32 -0
- package/lib/formatting/formatting.js +12 -11
- package/lib/formatting/formatting.spec.js +45 -0
- package/lib/index.ts +19 -0
- package/lib/middleware/middleware.js +17 -14
- package/lib/orm-helpers/ormHelpers.js +13 -12
- package/lib/orm-helpers/ormHelpers.spec.js +41 -0
- package/lib/structured-file-parser/errors.ts +25 -0
- package/lib/structured-file-parser/parse-row.ts +52 -0
- package/lib/structured-file-parser/sanitize-rows.ts +24 -0
- package/lib/structured-file-parser/structured-file-parser.ts +155 -0
- package/lib/types/types.js +203 -191
- package/lib/validations/validations.js +461 -661
- package/lib/validations/validations.spec.js +603 -0
- package/package.json +61 -8
- package/tsconfig.json +26 -0
- package/lib/errors/errors.js.map +0 -1
- package/lib/file-parser/errors.js.map +0 -1
- package/lib/file-parser/file-parser.js +0 -59
- package/lib/file-parser/file-parser.js.map +0 -1
- package/lib/file-parser/parse-row.js.map +0 -1
- package/lib/file-parser/sanitizeRows.js +0 -15
- package/lib/file-parser/sanitizeRows.js.map +0 -1
- package/lib/formatting/formatting.js.map +0 -1
- package/lib/index.js +0 -21
- package/lib/index.js.map +0 -1
- package/lib/middleware/middleware.js.map +0 -1
- package/lib/orm-helpers/ormHelpers.js.map +0 -1
- package/lib/structured-file-parser/errors.js.map +0 -1
- package/lib/structured-file-parser/parse-row.js.map +0 -1
- package/lib/structured-file-parser/sanitize-rows.js.map +0 -1
- package/lib/structured-file-parser/structured-file-parser.js +0 -95
- package/lib/structured-file-parser/structured-file-parser.js.map +0 -1
- package/lib/types/types.js.map +0 -1
- package/lib/validations/validations.js.map +0 -1
- /package/{lib → dist}/errors/errors.d.ts +0 -0
- /package/{lib → dist}/file-parser/errors.d.ts +0 -0
- /package/{lib → dist}/file-parser/parse-row.d.ts +0 -0
- /package/{lib → dist}/formatting/formatting.d.ts +0 -0
- /package/{lib → dist}/middleware/middleware.d.ts +0 -0
- /package/{lib → dist}/orm-helpers/ormHelpers.d.ts +0 -0
- /package/{lib → dist}/structured-file-parser/errors.d.ts +0 -0
- /package/{lib → dist}/structured-file-parser/parse-row.d.ts +0 -0
- /package/{lib → dist}/structured-file-parser/sanitize-rows.d.ts +0 -0
|
@@ -32,9 +32,8 @@ const parseRow = (row) => {
|
|
|
32
32
|
}
|
|
33
33
|
return line;
|
|
34
34
|
};
|
|
35
|
-
const splitRow =
|
|
35
|
+
const splitRow = fp_1.pipe(trySplitByTab, trySplitByComa, trySplitByMultipleSpaces, trySplitBySpace, trySplitByNothing);
|
|
36
36
|
const cells = splitRow(row);
|
|
37
37
|
return cells.map((c) => c.trim());
|
|
38
38
|
};
|
|
39
39
|
exports.default = parseRow;
|
|
40
|
-
//# sourceMappingURL=parse-row.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const sensicalRowCheck = (cells) => (cells.some((cell) => !!cell));
|
|
4
|
+
function sanitizeRows(parsedRows, processRow) {
|
|
5
|
+
const firstSensicalRowIndex = parsedRows
|
|
6
|
+
.findIndex(sensicalRowCheck);
|
|
7
|
+
const lastSensicalRowIndex = [...parsedRows]
|
|
8
|
+
.reverse()
|
|
9
|
+
.findIndex(sensicalRowCheck);
|
|
10
|
+
const sanitizedRows = parsedRows
|
|
11
|
+
.splice(firstSensicalRowIndex, parsedRows.length - firstSensicalRowIndex - lastSensicalRowIndex);
|
|
12
|
+
const firstRow = processRow(sanitizedRows[0]);
|
|
13
|
+
if (firstRow.isValid) {
|
|
14
|
+
return sanitizedRows;
|
|
15
|
+
}
|
|
16
|
+
return sanitizedRows.splice(1);
|
|
17
|
+
}
|
|
18
|
+
exports.default = sanitizeRows;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const _ = require('lodash');
|
|
3
|
+
const rethrowError = (fnName, e) => {
|
|
4
|
+
let formattedError;
|
|
5
|
+
if (_.isPlainObject(e.error) || _.isArray(e.error)) {
|
|
6
|
+
formattedError = `\n${JSON.stringify(e.error, null, 2)}`;
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
formattedError = e.error;
|
|
10
|
+
}
|
|
11
|
+
return `${fnName} - ${e.name}: ${e.statusCode} - ${formattedError}`;
|
|
12
|
+
};
|
|
13
|
+
const sqlEscapeWildcard = (str) => str.replace(/_|%|\\/g, (x) => `\\${x}`);
|
|
14
|
+
module.exports = {
|
|
15
|
+
rethrowError,
|
|
16
|
+
sqlEscapeWildcard,
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const chai = require('chai');
|
|
3
|
+
const { sqlEscapeWildcard, rethrowError } = require('./formatting');
|
|
4
|
+
const { expect } = chai;
|
|
5
|
+
describe('formatting.sqlEscapeWildcard', () => {
|
|
6
|
+
describe('when passed an empty string', () => {
|
|
7
|
+
it('returns an empty string', () => sqlEscapeWildcard('').should.equal(''));
|
|
8
|
+
});
|
|
9
|
+
describe('when passed a string with no sql wildcards', () => {
|
|
10
|
+
it('returns the same string', () => {
|
|
11
|
+
const str = 'foo bar';
|
|
12
|
+
return sqlEscapeWildcard(str).should.equal(str);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
return describe('when passed a string with sql wildcards', () => {
|
|
16
|
+
it('returns the string with \\ % _ escaped', () => {
|
|
17
|
+
const str = 'foo\\dfs_erwr%rewr';
|
|
18
|
+
return sqlEscapeWildcard(str).should.equal('foo\\\\dfs\\_erwr\\%rewr');
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('rethrowError', () => {
|
|
23
|
+
it('returns an error when given a string', () => rethrowError('myFunc', { error: 'Oh dear, myFunc is broken' })
|
|
24
|
+
.should.equal('myFunc - undefined: undefined - Oh dear, myFunc is broken'));
|
|
25
|
+
it('returns an error when passed an error object', () => rethrowError('myFunc', {
|
|
26
|
+
name: "I'm a teapot",
|
|
27
|
+
statusCode: 418,
|
|
28
|
+
error: "I'm a little teapot, short and stout",
|
|
29
|
+
}).should.equal("myFunc - I'm a teapot: 418 - I'm a little teapot, short and stout"));
|
|
30
|
+
it('accepts an array containing an error', () => {
|
|
31
|
+
const thrownError = rethrowError('myFunc', {
|
|
32
|
+
error: ["I'm a teapot", 418, "I'm a little teapot, short and stout"],
|
|
33
|
+
});
|
|
34
|
+
const expected = JSON.stringify('myFunc - undefined: undefined - \n[\n "I\'m a teapot",\n 418,\n "I\'m a little teapot, short and stout"\n]');
|
|
35
|
+
expect(JSON.stringify(thrownError)).to.equal(expected);
|
|
36
|
+
});
|
|
37
|
+
});
|
package/{lib → dist}/index.d.ts
RENAMED
|
@@ -6,4 +6,4 @@ import middleware from './middleware/middleware';
|
|
|
6
6
|
import ormHelpers from './orm-helpers/ormHelpers';
|
|
7
7
|
import fileParser from './file-parser/file-parser';
|
|
8
8
|
import structuredFileParser from './structured-file-parser/structured-file-parser';
|
|
9
|
-
export { types, validations, errors, formatting, fileParser, structuredFileParser, middleware, ormHelpers };
|
|
9
|
+
export { types, validations, errors, formatting, fileParser, structuredFileParser, middleware, ormHelpers, };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ormHelpers = exports.middleware = exports.structuredFileParser = exports.fileParser = exports.formatting = exports.errors = exports.validations = exports.types = void 0;
|
|
7
|
+
const types_1 = __importDefault(require("./types/types"));
|
|
8
|
+
exports.types = types_1.default;
|
|
9
|
+
const validations_1 = __importDefault(require("./validations/validations"));
|
|
10
|
+
exports.validations = validations_1.default;
|
|
11
|
+
const errors_1 = __importDefault(require("./errors/errors"));
|
|
12
|
+
exports.errors = errors_1.default;
|
|
13
|
+
const formatting_1 = __importDefault(require("./formatting/formatting"));
|
|
14
|
+
exports.formatting = formatting_1.default;
|
|
15
|
+
const middleware_1 = __importDefault(require("./middleware/middleware"));
|
|
16
|
+
exports.middleware = middleware_1.default;
|
|
17
|
+
const ormHelpers_1 = __importDefault(require("./orm-helpers/ormHelpers"));
|
|
18
|
+
exports.ormHelpers = ormHelpers_1.default;
|
|
19
|
+
const file_parser_1 = __importDefault(require("./file-parser/file-parser"));
|
|
20
|
+
exports.fileParser = file_parser_1.default;
|
|
21
|
+
const structured_file_parser_1 = __importDefault(require("./structured-file-parser/structured-file-parser"));
|
|
22
|
+
exports.structuredFileParser = structured_file_parser_1.default;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const T = require('../types/types');
|
|
3
|
+
const ensureType = (type) => (req, res, next, id, name) => {
|
|
4
|
+
let error;
|
|
5
|
+
try {
|
|
6
|
+
T.ensureType(type, id, `Invalid ${name}`);
|
|
7
|
+
return next();
|
|
8
|
+
}
|
|
9
|
+
catch (error1) {
|
|
10
|
+
error = error1;
|
|
11
|
+
return next(error);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const ensureUUID = ensureType('UUID');
|
|
15
|
+
const ensureHex32 = ensureType('Hex32');
|
|
16
|
+
const ensureInteger = ensureType('IntString');
|
|
17
|
+
module.exports = {
|
|
18
|
+
ensureType,
|
|
19
|
+
ensureUUID,
|
|
20
|
+
ensureHex32,
|
|
21
|
+
ensureInteger,
|
|
22
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const _ = require('lodash');
|
|
3
|
+
const includeNested = (orm, models) => _.map(_.toPairs(models), (arg) => {
|
|
4
|
+
const [modelName, inclusion] = arg;
|
|
5
|
+
const include = includeNested(orm, inclusion);
|
|
6
|
+
const model = orm[modelName];
|
|
7
|
+
if (_.isEmpty(include)) {
|
|
8
|
+
return model;
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
model,
|
|
12
|
+
include,
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
module.exports = {
|
|
16
|
+
includeNested,
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const { includeNested } = require('./ormHelpers');
|
|
3
|
+
describe('ormIncludeNested', () => {
|
|
4
|
+
const orm = {
|
|
5
|
+
a: 'a',
|
|
6
|
+
b: 'b',
|
|
7
|
+
c: 'c',
|
|
8
|
+
d: 'd',
|
|
9
|
+
};
|
|
10
|
+
describe('when passed an empty object', () => {
|
|
11
|
+
it('returns an empty array', () => includeNested(orm, {}).should.deep.equal([]));
|
|
12
|
+
});
|
|
13
|
+
describe('when passed an object with no inclusions', () => {
|
|
14
|
+
it('returns an array of just the key', () => includeNested(orm, {
|
|
15
|
+
a: {},
|
|
16
|
+
}).should.deep.equal(['a']));
|
|
17
|
+
});
|
|
18
|
+
describe('when passed a hierarchy of inclusions', () => {
|
|
19
|
+
it('should nest them in sequelize style', () => includeNested(orm, {
|
|
20
|
+
a: {
|
|
21
|
+
b: {
|
|
22
|
+
c: {},
|
|
23
|
+
d: {},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
}).should.deep.equal([
|
|
27
|
+
{
|
|
28
|
+
model: 'a',
|
|
29
|
+
include: [
|
|
30
|
+
{
|
|
31
|
+
model: 'b',
|
|
32
|
+
include: ['c', 'd'],
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
]));
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -32,9 +32,8 @@ const parseRow = (row) => {
|
|
|
32
32
|
}
|
|
33
33
|
return line;
|
|
34
34
|
};
|
|
35
|
-
const splitRow =
|
|
35
|
+
const splitRow = fp_1.pipe(trySplitByTab, trySplitByComa, trySplitByMultipleSpaces, trySplitBySpace, trySplitByNothing);
|
|
36
36
|
const cells = splitRow(row);
|
|
37
37
|
return cells.map((c) => c.trim());
|
|
38
38
|
};
|
|
39
39
|
exports.default = parseRow;
|
|
40
|
-
//# sourceMappingURL=parse-row.js.map
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const sensicalRowCheck = (cells) => cells.some((cell) => !!cell);
|
|
3
|
+
const sensicalRowCheck = (cells) => (cells.some((cell) => !!cell));
|
|
4
4
|
function sanitizeRows(parsedRows) {
|
|
5
5
|
const firstSensicalRowIndex = parsedRows.findIndex(sensicalRowCheck);
|
|
6
|
-
const lastSensicalRowIndex = [...parsedRows]
|
|
6
|
+
const lastSensicalRowIndex = [...parsedRows]
|
|
7
|
+
.reverse()
|
|
8
|
+
.findIndex(sensicalRowCheck);
|
|
7
9
|
if (firstSensicalRowIndex < 0) {
|
|
8
10
|
return [];
|
|
9
11
|
}
|
|
@@ -11,4 +13,3 @@ function sanitizeRows(parsedRows) {
|
|
|
11
13
|
return sanitizedRows;
|
|
12
14
|
}
|
|
13
15
|
exports.default = sanitizeRows;
|
|
14
|
-
//# sourceMappingURL=sanitize-rows.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export type ProcessingEntry = {
|
|
1
|
+
export declare type ProcessingEntry = {
|
|
2
2
|
isValid: boolean;
|
|
3
3
|
};
|
|
4
|
-
type Dependencies<T extends ProcessingEntry> = {
|
|
4
|
+
declare type Dependencies<T extends ProcessingEntry> = {
|
|
5
5
|
processRow: (cells: string[], headers: string[]) => T;
|
|
6
6
|
};
|
|
7
7
|
export declare const hasHeaderRow: (rows: string[][], requiredHeaderNames: string[]) => boolean;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isHeaderRowValid = exports.hasHeaderRow = void 0;
|
|
7
|
+
/* eslint-disable no-await-in-loop */
|
|
8
|
+
/* eslint-disable no-restricted-syntax */
|
|
9
|
+
const parse_row_1 = __importDefault(require("./parse-row"));
|
|
10
|
+
const errors_1 = require("./errors");
|
|
11
|
+
const sanitize_rows_1 = __importDefault(require("./sanitize-rows"));
|
|
12
|
+
function chunk(array, size) {
|
|
13
|
+
if (!array.length) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
const head = array.slice(0, size);
|
|
17
|
+
const tail = array.slice(size);
|
|
18
|
+
return [head, ...chunk(tail, size)];
|
|
19
|
+
}
|
|
20
|
+
async function processChunk(parsedRows, dependencies) {
|
|
21
|
+
const { processRow, headers } = dependencies;
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
setTimeout(() => {
|
|
25
|
+
try {
|
|
26
|
+
const processedRows = parsedRows.map((row) => processRow(row, headers));
|
|
27
|
+
resolve(processedRows);
|
|
28
|
+
}
|
|
29
|
+
catch (ex) {
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
reject(ex);
|
|
32
|
+
}
|
|
33
|
+
}, 0);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
// a row is said to contain headers if two valid header names are present
|
|
37
|
+
exports.hasHeaderRow = (rows, requiredHeaderNames) => {
|
|
38
|
+
const firstRow = rows[0];
|
|
39
|
+
if (!firstRow) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const foundIndex = firstRow.findIndex((value) => requiredHeaderNames.includes(value.toLowerCase()));
|
|
43
|
+
if (foundIndex < 0) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const containsSecondHeader = firstRow
|
|
47
|
+
.filter((_val, i) => i !== foundIndex)
|
|
48
|
+
.some((value) => requiredHeaderNames.includes(value.toLowerCase()));
|
|
49
|
+
return containsSecondHeader;
|
|
50
|
+
};
|
|
51
|
+
exports.isHeaderRowValid = (rows, requiredHeaderNames) => {
|
|
52
|
+
const firstRow = rows[0];
|
|
53
|
+
if (!firstRow) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return (requiredHeaderNames.every((header) => firstRow.map((value) => value.toLowerCase()).includes(header)) && requiredHeaderNames.length === firstRow.length);
|
|
57
|
+
};
|
|
58
|
+
async function parseFile(fileContent, maxRows, requiredHeaderNames, dependencies) {
|
|
59
|
+
if (fileContent === 'invalidFileType') {
|
|
60
|
+
throw new errors_1.InvalidFileError();
|
|
61
|
+
}
|
|
62
|
+
const rows = fileContent.split('\n');
|
|
63
|
+
const parsedRows = rows.map(parse_row_1.default);
|
|
64
|
+
const sanitizedRows = sanitize_rows_1.default(parsedRows);
|
|
65
|
+
if (sanitizedRows.length > maxRows) {
|
|
66
|
+
throw new errors_1.TooManyRowsError();
|
|
67
|
+
}
|
|
68
|
+
if (sanitizedRows.length === 0) {
|
|
69
|
+
throw new errors_1.NoRowsError();
|
|
70
|
+
}
|
|
71
|
+
const containsHeaders = exports.hasHeaderRow(sanitizedRows, requiredHeaderNames);
|
|
72
|
+
if (containsHeaders
|
|
73
|
+
&& !exports.isHeaderRowValid(sanitizedRows, requiredHeaderNames)) {
|
|
74
|
+
throw new errors_1.InvalidHeadersError();
|
|
75
|
+
}
|
|
76
|
+
const firstSanitizedRow = sanitizedRows[0];
|
|
77
|
+
if (!firstSanitizedRow) {
|
|
78
|
+
throw new errors_1.NoRowsError();
|
|
79
|
+
}
|
|
80
|
+
const headers = containsHeaders
|
|
81
|
+
? firstSanitizedRow.map((value) => value.toLowerCase())
|
|
82
|
+
: requiredHeaderNames;
|
|
83
|
+
const dataRows = containsHeaders ? sanitizedRows.splice(1) : sanitizedRows;
|
|
84
|
+
if (dataRows.length === 0) {
|
|
85
|
+
throw new errors_1.NoRowsError();
|
|
86
|
+
}
|
|
87
|
+
const parsedRowChunks = chunk(dataRows, 30);
|
|
88
|
+
let results = [];
|
|
89
|
+
for (const currentRowChunk of parsedRowChunks) {
|
|
90
|
+
const chunkResult = await processChunk(currentRowChunk, {
|
|
91
|
+
...dependencies,
|
|
92
|
+
headers,
|
|
93
|
+
});
|
|
94
|
+
results = results.concat(chunkResult);
|
|
95
|
+
}
|
|
96
|
+
return results;
|
|
97
|
+
}
|
|
98
|
+
exports.default = parseFile;
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
declare const withNullable: {};
|
|
2
2
|
export function parseType(str: any): any;
|
|
3
|
+
export function parseType(str: any): any;
|
|
4
|
+
export function parsedTypeCheck(type: any, obj: any): any;
|
|
3
5
|
export function parsedTypeCheck(type: any, obj: any): any;
|
|
4
6
|
export function typeCheck(type: any, obj: any): any;
|
|
7
|
+
export function typeCheck(type: any, obj: any): any;
|
|
5
8
|
export namespace opts {
|
|
6
9
|
export { withNullable as customTypes };
|
|
7
10
|
}
|
|
8
11
|
export function ensureType(type: any, obj: any, msg: any): boolean;
|
|
12
|
+
export function ensureType(type: any, obj: any, msg: any): boolean;
|
|
13
|
+
export function checkArg(obj: any, prop: any, type: any, msg: any): any;
|
|
9
14
|
export function checkArg(obj: any, prop: any, type: any, msg: any): any;
|
|
10
15
|
export function checkArgs(input: any, types: any): void;
|
|
16
|
+
export function checkArgs(input: any, types: any): void;
|
|
11
17
|
export {};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const TC = require('type-check');
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const E = require('../errors/errors');
|
|
5
|
+
const V = require('../validations/validations');
|
|
6
|
+
const customTypes = {
|
|
7
|
+
Integer: {
|
|
8
|
+
typeOf: 'Number',
|
|
9
|
+
validate(x) {
|
|
10
|
+
return x % 1 === 0;
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
IntString: {
|
|
14
|
+
typeOf: 'String',
|
|
15
|
+
validate: V.isInt,
|
|
16
|
+
},
|
|
17
|
+
BoolString: {
|
|
18
|
+
typeOf: 'String',
|
|
19
|
+
validate: V.isBoolean,
|
|
20
|
+
},
|
|
21
|
+
Hex32: {
|
|
22
|
+
typeOf: 'String',
|
|
23
|
+
validate(x) {
|
|
24
|
+
return V.isHexadecimal(x) && x.length === 32;
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
Email: {
|
|
28
|
+
typeOf: 'String',
|
|
29
|
+
validate: V.isEmail,
|
|
30
|
+
},
|
|
31
|
+
UUID: {
|
|
32
|
+
typeOf: 'String',
|
|
33
|
+
validate: V.isUUID,
|
|
34
|
+
},
|
|
35
|
+
UUIDv4: {
|
|
36
|
+
typeOf: 'String',
|
|
37
|
+
validate(x) {
|
|
38
|
+
return V.isUUID(x, 4);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
JSON: {
|
|
42
|
+
typeOf: 'String',
|
|
43
|
+
validate: V.isJSON,
|
|
44
|
+
},
|
|
45
|
+
Url: {
|
|
46
|
+
typeOf: 'String',
|
|
47
|
+
validate: V.isURL,
|
|
48
|
+
},
|
|
49
|
+
DateString: {
|
|
50
|
+
typeOf: 'String',
|
|
51
|
+
validate: V.isDate,
|
|
52
|
+
},
|
|
53
|
+
NonEmptyArray: {
|
|
54
|
+
typeOf: 'Array',
|
|
55
|
+
validate: V.nonEmpty,
|
|
56
|
+
},
|
|
57
|
+
NonNullString: {
|
|
58
|
+
typeOf: 'String',
|
|
59
|
+
validate: V.nonEmpty,
|
|
60
|
+
},
|
|
61
|
+
CustomerReference: {
|
|
62
|
+
typeOf: 'String',
|
|
63
|
+
validate: V.isCustomerReference,
|
|
64
|
+
},
|
|
65
|
+
CustomerLabelName: {
|
|
66
|
+
typeOf: 'String',
|
|
67
|
+
validate: V.isCustomerLabelName,
|
|
68
|
+
},
|
|
69
|
+
BitcoinAddress: {
|
|
70
|
+
typeOf: 'String',
|
|
71
|
+
validate: V.bitcoin.isAddress,
|
|
72
|
+
},
|
|
73
|
+
EthereumAddress: {
|
|
74
|
+
typeOf: 'String',
|
|
75
|
+
validate: V.ethereum.isAddress,
|
|
76
|
+
},
|
|
77
|
+
EthereumTx: {
|
|
78
|
+
typeOf: 'String',
|
|
79
|
+
validate: V.ethereum.isTxHash,
|
|
80
|
+
},
|
|
81
|
+
EthereumBlockHash: {
|
|
82
|
+
typeOf: 'String',
|
|
83
|
+
validate: V.ethereum.isBlockHash,
|
|
84
|
+
},
|
|
85
|
+
EthereumWeiAmount: {
|
|
86
|
+
typeOf: 'String',
|
|
87
|
+
validate: V.ethereum.isValidWeiAmount,
|
|
88
|
+
},
|
|
89
|
+
EthereumAddressCode: {
|
|
90
|
+
typeOf: 'String',
|
|
91
|
+
validate: V.ethereum.isAddressCode,
|
|
92
|
+
},
|
|
93
|
+
MineId: {
|
|
94
|
+
typeOf: 'String',
|
|
95
|
+
validate(x) {
|
|
96
|
+
return x === 'mine';
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
BitcoinTxHash: {
|
|
100
|
+
typeOf: 'String',
|
|
101
|
+
validate: V.bitcoin.isTxHash,
|
|
102
|
+
},
|
|
103
|
+
BitcoinAddressArray: {
|
|
104
|
+
typeOf: 'Array',
|
|
105
|
+
validate(as) {
|
|
106
|
+
return _.every(as, V.bitcoin.isAddress);
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
BitcoinTxHashArray: {
|
|
110
|
+
typeOf: 'Array',
|
|
111
|
+
validate(as) {
|
|
112
|
+
return _.every(as, V.bitcoin.isTxHash);
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
BitcoinTxHex: {
|
|
116
|
+
typeOf: 'String',
|
|
117
|
+
validate: V.bitcoin.isTxHex,
|
|
118
|
+
},
|
|
119
|
+
BitcoinScriptHex: {
|
|
120
|
+
typeOf: 'String',
|
|
121
|
+
validate: V.bitcoin.isScriptHex,
|
|
122
|
+
},
|
|
123
|
+
BitcoinHDPath: {
|
|
124
|
+
typeOf: 'String',
|
|
125
|
+
validate: V.bitcoin.isHDPath,
|
|
126
|
+
},
|
|
127
|
+
BitcoinPublicKey: {
|
|
128
|
+
typeOf: 'String',
|
|
129
|
+
validate: V.bitcoin.isPublicKey,
|
|
130
|
+
},
|
|
131
|
+
BitcoinXpub: {
|
|
132
|
+
typeOf: 'String',
|
|
133
|
+
validate: V.bitcoin.isHDPublicKey,
|
|
134
|
+
},
|
|
135
|
+
BitcoinTxSignature: {
|
|
136
|
+
typeOf: 'String',
|
|
137
|
+
validate: V.bitcoin.isTxSignature,
|
|
138
|
+
},
|
|
139
|
+
BitcoinBlockHeight: {
|
|
140
|
+
typeOf: 'Number',
|
|
141
|
+
validate: V.bitcoin.isBlockHeight,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
// add support for nullable properties
|
|
145
|
+
const withNullable = Object.keys(customTypes).reduce((acc, _type) => {
|
|
146
|
+
acc[_type] = customTypes[_type];
|
|
147
|
+
const { typeOf, validate } = customTypes[_type];
|
|
148
|
+
// for every type, add Nullable+type. A nullable string can also be empty
|
|
149
|
+
acc[`Nullable${_type}`] = Object.assign({}, customTypes[_type], {
|
|
150
|
+
validate: (x) => x == null || (typeOf === 'String' && x === '') || validate(x),
|
|
151
|
+
});
|
|
152
|
+
return acc;
|
|
153
|
+
}, {});
|
|
154
|
+
module.exports = {
|
|
155
|
+
parseType(str) {
|
|
156
|
+
return TC.parseType(str);
|
|
157
|
+
},
|
|
158
|
+
parsedTypeCheck(type, obj) {
|
|
159
|
+
return TC.parsedTypeCheck(type, obj, this.opts);
|
|
160
|
+
},
|
|
161
|
+
typeCheck(type, obj) {
|
|
162
|
+
return TC.typeCheck(type, obj, this.opts);
|
|
163
|
+
},
|
|
164
|
+
opts: {
|
|
165
|
+
customTypes: withNullable,
|
|
166
|
+
},
|
|
167
|
+
ensureType(type, obj, msg) {
|
|
168
|
+
return V.ensure(this.typeCheck(type, obj), msg);
|
|
169
|
+
},
|
|
170
|
+
checkArg(obj, prop, type, msg) {
|
|
171
|
+
let message;
|
|
172
|
+
if (msg == null) {
|
|
173
|
+
message = `Invalid ${prop}`;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
message = msg;
|
|
177
|
+
}
|
|
178
|
+
this.ensureType(type, obj[prop], message);
|
|
179
|
+
return obj[prop];
|
|
180
|
+
},
|
|
181
|
+
checkArgs(input, types) {
|
|
182
|
+
const inputKeys = {};
|
|
183
|
+
const [typ] = types;
|
|
184
|
+
const fields = typ.of;
|
|
185
|
+
let numInputKeys = 0;
|
|
186
|
+
let numKeys;
|
|
187
|
+
Object.keys(input).forEach((k) => {
|
|
188
|
+
inputKeys[k] = true;
|
|
189
|
+
numInputKeys += 1;
|
|
190
|
+
});
|
|
191
|
+
numKeys = 0;
|
|
192
|
+
Object.keys(fields).forEach((key) => {
|
|
193
|
+
const objTypes = fields[key];
|
|
194
|
+
V.ensure(this.parsedTypeCheck(objTypes, input[key]), `Invalid ${key}`);
|
|
195
|
+
if (inputKeys[key]) {
|
|
196
|
+
numKeys += 1;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
if (!(typ.subset || numInputKeys === numKeys)) {
|
|
200
|
+
throw new E.BadRequest('invalid extra arguments are present');
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
};
|