@ellipticltd/aml-utils 0.16.26 → 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 -161
- 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 -669
- 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
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
version: 2.1
|
|
2
|
+
|
|
3
|
+
executors:
|
|
4
|
+
node-18:
|
|
5
|
+
docker:
|
|
6
|
+
- image: cimg/node:18.19.0
|
|
7
|
+
working_directory: /tmp/workspace
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
install:
|
|
11
|
+
executor: node-18
|
|
12
|
+
steps:
|
|
13
|
+
- checkout
|
|
14
|
+
- restore_cache:
|
|
15
|
+
keys:
|
|
16
|
+
- npm-cache-{{ checksum "package-lock.json" }}
|
|
17
|
+
- run:
|
|
18
|
+
name: install node modules
|
|
19
|
+
command: |
|
|
20
|
+
npm i
|
|
21
|
+
- save_cache:
|
|
22
|
+
key: npm-cache-{{ checksum "package-lock.json" }}
|
|
23
|
+
paths:
|
|
24
|
+
- node_modules
|
|
25
|
+
- persist_to_workspace:
|
|
26
|
+
root: /tmp
|
|
27
|
+
paths:
|
|
28
|
+
- workspace
|
|
29
|
+
|
|
30
|
+
unit_test:
|
|
31
|
+
executor: node-18
|
|
32
|
+
steps:
|
|
33
|
+
- attach_workspace:
|
|
34
|
+
at: /tmp
|
|
35
|
+
- run:
|
|
36
|
+
name: unit_test
|
|
37
|
+
command: npm run coverage
|
|
38
|
+
- store_artifacts:
|
|
39
|
+
path: coverage
|
|
40
|
+
|
|
41
|
+
lint:
|
|
42
|
+
executor: node-18
|
|
43
|
+
steps:
|
|
44
|
+
- attach_workspace:
|
|
45
|
+
at: /tmp
|
|
46
|
+
- run:
|
|
47
|
+
name: lint
|
|
48
|
+
command: npm run lint
|
|
49
|
+
|
|
50
|
+
semantic_release:
|
|
51
|
+
executor: node-18
|
|
52
|
+
steps:
|
|
53
|
+
- checkout
|
|
54
|
+
- attach_workspace:
|
|
55
|
+
at: /tmp
|
|
56
|
+
- add_ssh_keys:
|
|
57
|
+
fingerprints:
|
|
58
|
+
- "14:c6:29:a4:9e:45:36:d2:0e:e9:be:41:35:d7:06:23"
|
|
59
|
+
- run:
|
|
60
|
+
command: npx semantic-release
|
|
61
|
+
|
|
62
|
+
workflows:
|
|
63
|
+
version: 2.1
|
|
64
|
+
build-test-deploy:
|
|
65
|
+
jobs:
|
|
66
|
+
- install:
|
|
67
|
+
context: npm
|
|
68
|
+
|
|
69
|
+
- unit_test:
|
|
70
|
+
context: npm
|
|
71
|
+
requires:
|
|
72
|
+
- install
|
|
73
|
+
|
|
74
|
+
- lint:
|
|
75
|
+
context: npm
|
|
76
|
+
requires:
|
|
77
|
+
- install
|
|
78
|
+
|
|
79
|
+
- semantic_release:
|
|
80
|
+
context: npm
|
|
81
|
+
requires:
|
|
82
|
+
- lint
|
|
83
|
+
- unit_test
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# VS Code Extension Version: 1.5.1
|
package/.eslintrc
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["airbnb-base"],
|
|
3
|
+
"overrides": [
|
|
4
|
+
{
|
|
5
|
+
"files": [
|
|
6
|
+
"*.ts"
|
|
7
|
+
],
|
|
8
|
+
"parser": "@typescript-eslint/parser",
|
|
9
|
+
"parserOptions": {
|
|
10
|
+
"project": "tsconfig.json"
|
|
11
|
+
},
|
|
12
|
+
"rules": {
|
|
13
|
+
"no-unused-vars": 0
|
|
14
|
+
// annoyingly this must be switched off
|
|
15
|
+
// https://github.com/typescript-eslint/typescript-eslint/issues/46
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"files": [
|
|
20
|
+
"*.spec.js"
|
|
21
|
+
],
|
|
22
|
+
"env": {
|
|
23
|
+
"mocha": true
|
|
24
|
+
},
|
|
25
|
+
"rules": {
|
|
26
|
+
"no-unused-expressions": 0,
|
|
27
|
+
"chai-friendly/no-unused-expressions": 2
|
|
28
|
+
},
|
|
29
|
+
"plugins": [
|
|
30
|
+
"chai-friendly"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"rules": {
|
|
35
|
+
"no-underscore-dangle": 0,
|
|
36
|
+
"prefer-object-spread": 0,
|
|
37
|
+
"new-parens": 0,
|
|
38
|
+
"import/extensions": 0
|
|
39
|
+
},
|
|
40
|
+
"settings": {
|
|
41
|
+
"import/resolver": {
|
|
42
|
+
"typescript": {}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
package/.huskyrc
ADDED
package/.mocharc.json
ADDED
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
18.19.0
|
package/.nycrc.json
ADDED
package/.releaserc.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"branches": [
|
|
3
|
+
"master",
|
|
4
|
+
{
|
|
5
|
+
"name": "*",
|
|
6
|
+
"prerelease": true
|
|
7
|
+
}
|
|
8
|
+
],
|
|
9
|
+
"plugins": [
|
|
10
|
+
"@semantic-release/commit-analyzer",
|
|
11
|
+
"@semantic-release/npm",
|
|
12
|
+
[ "@semantic-release/git", {
|
|
13
|
+
"assets": ["package.json"],
|
|
14
|
+
"message": "chore(release): ${nextRelease.version} [skip ci]"
|
|
15
|
+
}]
|
|
16
|
+
],
|
|
17
|
+
"repositoryUrl": "git@bitbucket.org:elliptic/aml-utils.git"
|
|
18
|
+
}
|
package/.snyk
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
|
|
2
|
+
version: v1.25.0
|
|
3
|
+
ignore: {}
|
|
4
|
+
# patches apply the minimum changes required to fix a vulnerability
|
|
5
|
+
patch:
|
|
6
|
+
SNYK-JS-LODASH-567746:
|
|
7
|
+
- stellar-sdk > lodash:
|
|
8
|
+
patched: '2022-11-24T10:44:51.115Z'
|
|
9
|
+
- stellar-sdk > stellar-base > lodash:
|
|
10
|
+
patched: '2022-11-24T10:44:51.115Z'
|
|
11
|
+
- stellar-sdk > stellar-base > js-xdr > lodash:
|
|
12
|
+
patched: '2022-11-24T10:44:51.115Z'
|
package/README.md
CHANGED
|
@@ -1,19 +1,51 @@
|
|
|
1
|
-
# aml-utils
|
|
1
|
+
# Elliptic aml-utils
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
This is a library that contains a set of utilities used by aml-api. In particular:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- Custom errors used when returning a response from aml-api, e.g. BadRequest, Forbidden etc.
|
|
6
|
+
- Formatting functions (sql escaping)
|
|
7
|
+
- Validator functions, also used by swagger node middleware. E.g. Bitcoin and Ethereum addresses validators
|
|
8
|
+
- Express middlewares to validate params types
|
|
9
|
+
- An async CSV file parser
|
|
6
10
|
|
|
7
|
-
Run `npx nx test aml-utils` to execute the unit tests via [Jest](https://jestjs.io).
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
Prereqs
|
|
13
|
+
-------
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
1. Correct version of node (use [nvm](https://github.com/creationix/nvm)).
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
Development
|
|
18
|
+
-----------
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
`nvm use` ensures you are running the correct version of node.js.
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
`npm i` installs your dependencies.
|
|
23
|
+
|
|
24
|
+
`npm run build:dev`:
|
|
25
|
+
- starts webpack on watch mode, recompiling any changes made to the code
|
|
26
|
+
|
|
27
|
+
To test your changes locally go to the repo you are working on's package.json and replace:
|
|
28
|
+
```
|
|
29
|
+
@ellipticltd/aml-utils: "*.*.*"
|
|
30
|
+
```
|
|
31
|
+
with
|
|
32
|
+
```
|
|
33
|
+
@ellipticltd/aml-utils: "file:../aml-utils"
|
|
34
|
+
```
|
|
35
|
+
(if you repositories are in the same directory).
|
|
36
|
+
|
|
37
|
+
Commiting
|
|
38
|
+
-----------
|
|
39
|
+
|
|
40
|
+
**N.B. The semantic release process described below currently does not work, meaning this package has to be deployed manually using npm publish.**
|
|
41
|
+
|
|
42
|
+
**If a permissions error is encountered when authenticating with an npm token, remove .npmrc and authenticate using npm login.**
|
|
43
|
+
|
|
44
|
+
This repository uses [Semantic release](https://semantic-release.gitbook.io/) for version publishing. To create a new version of the package simply push to bitbucket and CircleCI will create a new version. No change to this repo's package.json is required.
|
|
45
|
+
|
|
46
|
+
To work out what the next version of package should be a git commit linter is used. This is enforced by Husky and only commits with the following syntax can be [used](https://github.com/conventional-changelog/commitlint/tree/master/@commitlint/config-angular).
|
|
47
|
+
|
|
48
|
+
Setting up Semantic release
|
|
49
|
+
-----------
|
|
50
|
+
|
|
51
|
+
This [article](https://circleci.com/docs/2.0/gh-bb-integration/#creating-a-bitbucket-user-key) explains the integration between Bitbucket and CirlceCI. An NPM token also needs to be provided for the write access to the npm package
|
package/codecov.yml
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
codecov:
|
|
2
|
+
require_ci_to_pass: yes
|
|
3
|
+
|
|
4
|
+
coverage:
|
|
5
|
+
precision: 2
|
|
6
|
+
round: down
|
|
7
|
+
range: "70...100"
|
|
8
|
+
|
|
9
|
+
status:
|
|
10
|
+
project:
|
|
11
|
+
default:
|
|
12
|
+
target: 85%
|
|
13
|
+
patch:
|
|
14
|
+
default:
|
|
15
|
+
target: 85%
|
|
16
|
+
changes: no
|
|
17
|
+
|
|
18
|
+
parsers:
|
|
19
|
+
gcov:
|
|
20
|
+
branch_detection:
|
|
21
|
+
conditional: yes
|
|
22
|
+
loop: yes
|
|
23
|
+
method: no
|
|
24
|
+
macro: no
|
|
25
|
+
|
|
26
|
+
comment:
|
|
27
|
+
layout: "reach,diff,flags,tree"
|
|
28
|
+
behavior: default
|
|
29
|
+
require_changes: no
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = { extends: ['@commitlint/config-angular'] };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const create = require('create-error');
|
|
3
|
+
const AppError = create('AppError');
|
|
4
|
+
const RequestError = create(AppError, 'RequestError');
|
|
5
|
+
RequestError.toJSON = () => ({
|
|
6
|
+
message: this.message,
|
|
7
|
+
});
|
|
8
|
+
const Forbidden = create(RequestError, 'ForbiddenError', {
|
|
9
|
+
status: 403,
|
|
10
|
+
});
|
|
11
|
+
const Unauthorized = create(RequestError, 'UnauthorizedError', {
|
|
12
|
+
status: 401,
|
|
13
|
+
});
|
|
14
|
+
const BadRequest = create(RequestError, 'BadRequestError', {
|
|
15
|
+
status: 400,
|
|
16
|
+
});
|
|
17
|
+
const NotFound = create(RequestError, 'NotFoundError', {
|
|
18
|
+
status: 404,
|
|
19
|
+
});
|
|
20
|
+
const ConflictError = create(RequestError, 'ConflictError', {
|
|
21
|
+
status: 409,
|
|
22
|
+
});
|
|
23
|
+
const ServerError = create(RequestError, 'ServerError', {
|
|
24
|
+
status: 500,
|
|
25
|
+
});
|
|
26
|
+
const InvalidArguments = create(RequestError, 'InvalidArgumentsError', {
|
|
27
|
+
status: 500,
|
|
28
|
+
});
|
|
29
|
+
const ServerTimeout = create(RequestError, 'ServerTimeoutError', {
|
|
30
|
+
status: 503,
|
|
31
|
+
});
|
|
32
|
+
module.exports = {
|
|
33
|
+
RequestError,
|
|
34
|
+
ServerError,
|
|
35
|
+
Forbidden,
|
|
36
|
+
Unauthorized,
|
|
37
|
+
BadRequest,
|
|
38
|
+
NotFound,
|
|
39
|
+
ConflictError,
|
|
40
|
+
InvalidArguments,
|
|
41
|
+
ServerTimeout,
|
|
42
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const { RequestError, Forbidden, Unauthorized, BadRequest, NotFound, } = require('./errors');
|
|
3
|
+
describe('lib/error', () => {
|
|
4
|
+
describe('RequestError', () => {
|
|
5
|
+
it('should inherit from Error', () => (new RequestError instanceof Error).should.be.true);
|
|
6
|
+
describe('Forbidden Error', () => {
|
|
7
|
+
it('should inherit from Error', () => new Forbidden instanceof Error);
|
|
8
|
+
return it('should inherit from RequestError', () => new Forbidden instanceof RequestError);
|
|
9
|
+
});
|
|
10
|
+
describe('Unauthorized Error', () => {
|
|
11
|
+
it('should inherit from Error', () => new Unauthorized instanceof Error);
|
|
12
|
+
return it('should inherit from RequestError', () => new Unauthorized instanceof RequestError);
|
|
13
|
+
});
|
|
14
|
+
describe('BadRequest Error', () => {
|
|
15
|
+
it('should inherit from Error', () => new BadRequest instanceof Error);
|
|
16
|
+
return it('should inherit from RequestError', () => new BadRequest instanceof RequestError);
|
|
17
|
+
});
|
|
18
|
+
return describe('NotFound Error', () => {
|
|
19
|
+
it('should inherit from Error', () => new NotFound instanceof Error);
|
|
20
|
+
return it('should inherit from RequestError', () => new NotFound instanceof RequestError);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
26
|
+
const chai_1 = require("chai");
|
|
27
|
+
const file_parser_1 = __importDefault(require("../file-parser"));
|
|
28
|
+
const sanitizeRows = __importStar(require("../sanitzeRows"));
|
|
29
|
+
const parseRow = __importStar(require("../parse-row"));
|
|
30
|
+
describe('file-parser', () => {
|
|
31
|
+
const dependencies = {
|
|
32
|
+
processRow: sinon_1.default.spy(),
|
|
33
|
+
};
|
|
34
|
+
const parsedRows = [];
|
|
35
|
+
let mockParseRow;
|
|
36
|
+
let mockSanitizeRows;
|
|
37
|
+
let mockSetTimeout;
|
|
38
|
+
before(() => {
|
|
39
|
+
mockParseRow = sinon_1.default.stub(parseRow, 'default').returns(parsedRows);
|
|
40
|
+
mockSanitizeRows = sinon_1.default.stub(sanitizeRows, 'default').returns([{}]);
|
|
41
|
+
mockSetTimeout = sinon_1.default.stub(global, 'setTimeout').callsFake((callback) => callback());
|
|
42
|
+
});
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
sinon_1.default.resetHistory();
|
|
45
|
+
});
|
|
46
|
+
after(() => {
|
|
47
|
+
sinon_1.default.restore();
|
|
48
|
+
});
|
|
49
|
+
it('should call parseRow once per input new line', async () => {
|
|
50
|
+
const input = '\n';
|
|
51
|
+
await file_parser_1.default(input, 50, dependencies);
|
|
52
|
+
chai_1.expect(mockParseRow).to.be.calledTwice;
|
|
53
|
+
});
|
|
54
|
+
it('should call pass parseRow result into sanitizeRows', async () => {
|
|
55
|
+
const input = '\n';
|
|
56
|
+
await file_parser_1.default(input, 50, dependencies);
|
|
57
|
+
chai_1.expect(mockSanitizeRows).to.be.calledOnce;
|
|
58
|
+
chai_1.expect(mockSanitizeRows).to.be.deep.calledWith([[], []], dependencies.processRow);
|
|
59
|
+
});
|
|
60
|
+
it('should throw error when number of rows is more than max rows', async () => {
|
|
61
|
+
const input = '\n';
|
|
62
|
+
mockSanitizeRows.returns(new Array(20));
|
|
63
|
+
try {
|
|
64
|
+
await file_parser_1.default(input, 10, dependencies);
|
|
65
|
+
chai_1.expect(1).to.equal(2);
|
|
66
|
+
}
|
|
67
|
+
catch (ex) {
|
|
68
|
+
chai_1.expect(ex.name).to.equal('TooManyRowsError');
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
it('should throw error when no rows returned from sanitizeRows', async () => {
|
|
72
|
+
const input = '\n';
|
|
73
|
+
mockSanitizeRows.returns([]);
|
|
74
|
+
try {
|
|
75
|
+
await file_parser_1.default(input, 10, dependencies);
|
|
76
|
+
chai_1.expect(1).to.equal(2);
|
|
77
|
+
}
|
|
78
|
+
catch (ex) {
|
|
79
|
+
chai_1.expect(ex.name).to.equal('Error');
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
it('should throw error an error when content is "invalidFileType"', async () => {
|
|
83
|
+
const input = 'invalidFileType';
|
|
84
|
+
mockSanitizeRows.returns([]);
|
|
85
|
+
try {
|
|
86
|
+
await file_parser_1.default(input, 10, dependencies);
|
|
87
|
+
chai_1.expect(1).to.equal(2);
|
|
88
|
+
}
|
|
89
|
+
catch (ex) {
|
|
90
|
+
chai_1.expect(ex.message).to.equal('Invalid file type');
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
it('should call process row once per row in single timeout', async () => {
|
|
94
|
+
const input = '\n';
|
|
95
|
+
const fakeRows = (new Array(30)).fill({});
|
|
96
|
+
mockSanitizeRows.returns(fakeRows);
|
|
97
|
+
await file_parser_1.default(input, 70, dependencies);
|
|
98
|
+
chai_1.expect(dependencies.processRow).to.be.callCount(30);
|
|
99
|
+
chai_1.expect(mockSetTimeout).to.be.calledOnce;
|
|
100
|
+
});
|
|
101
|
+
it('should call process row once per row in two timeouts when more than 30 rows', async () => {
|
|
102
|
+
const input = '\n';
|
|
103
|
+
const fakeRows = (new Array(50)).fill({});
|
|
104
|
+
mockSanitizeRows.returns(fakeRows);
|
|
105
|
+
await file_parser_1.default(input, 70, dependencies);
|
|
106
|
+
chai_1.expect(dependencies.processRow).to.be.callCount(50);
|
|
107
|
+
chai_1.expect(mockSetTimeout).to.be.calledTwice;
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
const chai_1 = require("chai");
|
|
7
|
+
const parse_row_1 = __importDefault(require("../parse-row"));
|
|
8
|
+
describe('parse-row', () => {
|
|
9
|
+
it('should handle tabs', () => {
|
|
10
|
+
const input = 'asdas \t asdar \t aaaaa \t bbb bb';
|
|
11
|
+
const result = parse_row_1.default(input);
|
|
12
|
+
chai_1.expect(result).to.have.length(4);
|
|
13
|
+
});
|
|
14
|
+
it('should handle comas', () => {
|
|
15
|
+
const input = 'asdas, asdar, aaaaa, bbb bb';
|
|
16
|
+
const result = parse_row_1.default(input);
|
|
17
|
+
chai_1.expect(result).to.have.length(4);
|
|
18
|
+
});
|
|
19
|
+
it('should handle spaces', () => {
|
|
20
|
+
const input = 'asdas asdar aaaaa bbb bb';
|
|
21
|
+
const result = parse_row_1.default(input);
|
|
22
|
+
chai_1.expect(result).to.have.length(4);
|
|
23
|
+
});
|
|
24
|
+
it('should handle spaces', () => {
|
|
25
|
+
const input = 'asdas asdar aaaaa bbb bb';
|
|
26
|
+
const result = parse_row_1.default(input);
|
|
27
|
+
chai_1.expect(result).to.have.length(5);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
const chai_1 = require("chai");
|
|
7
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
8
|
+
const sanitzeRows_1 = __importDefault(require("../sanitzeRows"));
|
|
9
|
+
describe('sanitize-rows', () => {
|
|
10
|
+
it('should remove empty rows at the start of the array', () => {
|
|
11
|
+
const input = [
|
|
12
|
+
['', '', ''],
|
|
13
|
+
['this', 'is', 'valid'],
|
|
14
|
+
['this', 'is', 'valid'],
|
|
15
|
+
];
|
|
16
|
+
const result = sanitzeRows_1.default(input, () => ({
|
|
17
|
+
isValid: true,
|
|
18
|
+
}));
|
|
19
|
+
chai_1.expect(result).to.have.length(2);
|
|
20
|
+
});
|
|
21
|
+
it('should remove empty rows at the end of the array', () => {
|
|
22
|
+
const input = [
|
|
23
|
+
['this', 'is', 'valid'],
|
|
24
|
+
['this', 'is', 'valid'],
|
|
25
|
+
['', '', ''],
|
|
26
|
+
];
|
|
27
|
+
const result = sanitzeRows_1.default(input, () => ({
|
|
28
|
+
isValid: true,
|
|
29
|
+
}));
|
|
30
|
+
chai_1.expect(result).to.have.length(2);
|
|
31
|
+
});
|
|
32
|
+
it('should remove empty rows at the start and end of the array', () => {
|
|
33
|
+
const input = [
|
|
34
|
+
['', '', ''],
|
|
35
|
+
['', '', ''],
|
|
36
|
+
['', '', ''],
|
|
37
|
+
['this', 'is', 'valid'],
|
|
38
|
+
['this', 'is', 'valid'],
|
|
39
|
+
['', '', ''],
|
|
40
|
+
['', '', ''],
|
|
41
|
+
['', '', ''],
|
|
42
|
+
];
|
|
43
|
+
const result = sanitzeRows_1.default(input, () => ({
|
|
44
|
+
isValid: true,
|
|
45
|
+
}));
|
|
46
|
+
chai_1.expect(result).to.have.length(2);
|
|
47
|
+
});
|
|
48
|
+
it('should remove the first row if it is not empty and not valid', () => {
|
|
49
|
+
const input = [
|
|
50
|
+
['', '', ''],
|
|
51
|
+
['this', 'is', 'invalid'],
|
|
52
|
+
['this', 'is', 'valid'],
|
|
53
|
+
['this', 'is', 'valid'],
|
|
54
|
+
['', '', ''],
|
|
55
|
+
['', '', ''],
|
|
56
|
+
['', '', ''],
|
|
57
|
+
];
|
|
58
|
+
const returnsFalseOnce = sinon_1.default.stub();
|
|
59
|
+
returnsFalseOnce.returns(true);
|
|
60
|
+
returnsFalseOnce.onFirstCall().returns(false);
|
|
61
|
+
const result = sanitzeRows_1.default(input, returnsFalseOnce);
|
|
62
|
+
chai_1.expect(result).to.have.length(2);
|
|
63
|
+
});
|
|
64
|
+
it('should allow rows with some empty values', () => {
|
|
65
|
+
const input = [
|
|
66
|
+
['this', 'is', 'invalid'],
|
|
67
|
+
['this', 'is', 'valid'],
|
|
68
|
+
['this', 'is', 'valid'],
|
|
69
|
+
['valid', '', ''],
|
|
70
|
+
['', '', ''],
|
|
71
|
+
['', '', ''],
|
|
72
|
+
];
|
|
73
|
+
const result = sanitzeRows_1.default(input, () => ({
|
|
74
|
+
isValid: true,
|
|
75
|
+
}));
|
|
76
|
+
chai_1.expect(result).to.have.length(4);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TooManyRowsError = void 0;
|
|
4
|
+
// eslint-disable-next-line import/prefer-default-export
|
|
4
5
|
class TooManyRowsError extends Error {
|
|
5
6
|
constructor() {
|
|
6
7
|
super('More than configured number of rows imported');
|
|
@@ -8,4 +9,3 @@ class TooManyRowsError extends Error {
|
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
11
|
exports.TooManyRowsError = TooManyRowsError;
|
|
11
|
-
//# sourceMappingURL=errors.js.map
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare type ProcessingEntry = {
|
|
2
|
+
isValid: boolean;
|
|
3
|
+
};
|
|
4
|
+
declare type Dependencies<T extends ProcessingEntry> = {
|
|
3
5
|
processRow: (cells: string[]) => T;
|
|
4
6
|
};
|
|
5
7
|
declare function parseFile<T extends ProcessingEntry>(fileContent: string, maxRows: number, dependencies: Dependencies<T>): Promise<T[]>;
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
const parse_row_1 = __importDefault(require("./parse-row"));
|
|
7
|
+
const errors_1 = require("./errors");
|
|
8
|
+
const sanitzeRows_1 = __importDefault(require("./sanitzeRows"));
|
|
9
|
+
function chunk(array, size) {
|
|
10
|
+
if (!array.length) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
const head = array.slice(0, size);
|
|
14
|
+
const tail = array.slice(size);
|
|
15
|
+
return [head, ...chunk(tail, size)];
|
|
16
|
+
}
|
|
17
|
+
async function processChunk(parsedRows, dependencies) {
|
|
18
|
+
const { processRow } = dependencies;
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
try {
|
|
22
|
+
const processedRows = parsedRows.map(processRow);
|
|
23
|
+
resolve(processedRows);
|
|
24
|
+
}
|
|
25
|
+
catch (ex) {
|
|
26
|
+
reject(ex);
|
|
27
|
+
}
|
|
28
|
+
}, 0);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async function parseFile(fileContent, maxRows, dependencies) {
|
|
32
|
+
const { processRow } = dependencies;
|
|
33
|
+
if (fileContent === 'invalidFileType') {
|
|
34
|
+
throw Error('Invalid file type');
|
|
35
|
+
}
|
|
36
|
+
const rows = fileContent.split('\n');
|
|
37
|
+
const parsedRows = rows.map(parse_row_1.default);
|
|
38
|
+
const sanitizedRows = sanitzeRows_1.default(parsedRows, processRow);
|
|
39
|
+
if (sanitizedRows.length > maxRows) {
|
|
40
|
+
throw new errors_1.TooManyRowsError();
|
|
41
|
+
}
|
|
42
|
+
if (sanitizedRows.length === 0) {
|
|
43
|
+
throw new Error('No rows');
|
|
44
|
+
}
|
|
45
|
+
const parsedRowChunks = chunk(sanitizedRows, 30);
|
|
46
|
+
let results = [];
|
|
47
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
48
|
+
for (const currentRowChunk of parsedRowChunks) {
|
|
49
|
+
// eslint-disable-next-line no-await-in-loop
|
|
50
|
+
const chunkResult = await processChunk(currentRowChunk, dependencies);
|
|
51
|
+
results = results.concat(chunkResult);
|
|
52
|
+
}
|
|
53
|
+
return results;
|
|
54
|
+
}
|
|
55
|
+
exports.default = parseFile;
|