├── .eslintrc.js ├── .github └── workflows │ └── app.yaml ├── .gitignore ├── .prettierrc ├── README.md ├── SECURITY.md ├── documentation ├── classes │ └── ParserCommandDTO.html ├── coverage.html ├── dependencies.html ├── fonts │ ├── ionicons.eot │ ├── ionicons.svg │ ├── ionicons.ttf │ ├── ionicons.woff │ ├── ionicons.woff2 │ ├── roboto-v15-latin-300.eot │ ├── roboto-v15-latin-300.svg │ ├── roboto-v15-latin-300.ttf │ ├── roboto-v15-latin-300.woff │ ├── roboto-v15-latin-300.woff2 │ ├── roboto-v15-latin-700.eot │ ├── roboto-v15-latin-700.svg │ ├── roboto-v15-latin-700.ttf │ ├── roboto-v15-latin-700.woff │ ├── roboto-v15-latin-700.woff2 │ ├── roboto-v15-latin-italic.eot │ ├── roboto-v15-latin-italic.svg │ ├── roboto-v15-latin-italic.ttf │ ├── roboto-v15-latin-italic.woff │ ├── roboto-v15-latin-italic.woff2 │ ├── roboto-v15-latin-regular.eot │ ├── roboto-v15-latin-regular.svg │ ├── roboto-v15-latin-regular.ttf │ ├── roboto-v15-latin-regular.woff │ └── roboto-v15-latin-regular.woff2 ├── graph │ └── dependencies.svg ├── images │ ├── compodoc-vectorise-inverted.png │ ├── compodoc-vectorise-inverted.svg │ ├── compodoc-vectorise.png │ ├── compodoc-vectorise.svg │ ├── coverage-badge-documentation.svg │ └── favicon.ico ├── index.html ├── injectables │ ├── FileHelper.html │ ├── ParserCommand.html │ └── ParserService.html ├── interfaces │ └── LogModel.html ├── js │ ├── compodoc.js │ ├── lazy-load-graphs.js │ ├── libs │ │ ├── EventDispatcher.js │ │ ├── bootstrap-native.js │ │ ├── clipboard.min.js │ │ ├── custom-elements-es5-adapter.js │ │ ├── custom-elements.min.js │ │ ├── d3.v3.min.js │ │ ├── deep-iterator.js │ │ ├── es6-shim.min.js │ │ ├── htmlparser.js │ │ ├── innersvg.js │ │ ├── lit-html.js │ │ ├── prism.js │ │ ├── promise.min.js │ │ ├── svg-pan-zoom.min.js │ │ ├── tablesort.min.js │ │ ├── tablesort.number.min.js │ │ ├── vis.min.js │ │ └── zepto.min.js │ ├── menu-wc.js │ ├── menu-wc_es5.js │ ├── menu.js │ ├── routes.js │ ├── search │ │ ├── lunr.min.js │ │ ├── search-lunr.js │ │ ├── search.js │ │ └── search_index.js │ ├── sourceCode.js │ ├── svg-pan-zoom.controls.js │ ├── tabs.js │ └── tree.js ├── miscellaneous │ ├── enumerations.html │ ├── functions.html │ └── variables.html ├── modules.html ├── modules │ ├── AppModule.html │ ├── AppModule │ │ └── dependencies.svg │ ├── ParserModule.html │ └── ParserModule │ │ └── dependencies.svg ├── overview.html ├── properties.html └── styles │ ├── bootstrap-card.css │ ├── bootstrap.min.css │ ├── compodoc.css │ ├── dark.css │ ├── ionicons.min.css │ ├── laravel.css │ ├── material.css │ ├── original.css │ ├── postmark.css │ ├── prism.css │ ├── readthedocs.css │ ├── reset.css │ ├── stripe.css │ ├── style.css │ ├── tablesort.css │ └── vagrant.css ├── full-documentation.md ├── input.example.log ├── jest.config.js ├── nest-cli.json ├── package-lock.json ├── package.json ├── scripts └── runner.sh ├── src ├── app │ └── app.module.ts ├── cli.ts └── parser │ ├── command │ └── parser.command.ts │ ├── common │ ├── index.ts │ └── utils.ts │ ├── dtos │ └── parser-command-dto.ts │ ├── enum │ ├── index.ts │ └── log-level.enum.ts │ ├── helper │ ├── file-helper.ts │ └── index.ts │ ├── model │ ├── index.ts │ └── log.model.ts │ ├── parser.module.ts │ └── service │ ├── parser.service.ts │ └── test.log ├── test ├── integration-tests │ ├── factories │ │ ├── index.ts │ │ └── parser-command.factory.ts │ ├── fixtures │ │ └── fixture-input.log │ └── parser-command.spec.ts └── unit-tests │ ├── factories │ ├── helper.factory.ts │ ├── index.ts │ ├── parser.factory.ts │ └── utils.factory.ts │ ├── filehelper.spec.ts │ ├── fixtures │ └── fixture-input.log │ ├── parser.service.spec.ts │ └── utils.spec.ts ├── tsconfig.build.json ├── tsconfig.compodoc.json └── tsconfig.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | tsconfigRootDir : __dirname, 6 | sourceType: 'module', 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin'], 9 | extends: [ 10 | 'plugin:@typescript-eslint/recommended', 11 | 'plugin:prettier/recommended', 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true, 17 | }, 18 | ignorePatterns: ['.eslintrc.js'], 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /.github/workflows/app.yaml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | node-version: [12.x, 14.x, 15.x] 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v3 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - run: npm ci 25 | - run: npm run build --if-present 26 | - run: npm test 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | npm-debug.log* 7 | pnpm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | 12 | # OS 13 | .DS_Store 14 | 15 | # Tests 16 | /coverage 17 | /.nyc_output 18 | 19 | # IDEs and editors 20 | /.idea 21 | .project 22 | .classpath 23 | .c9/ 24 | *.launch 25 | .settings/ 26 | *.sublime-workspace 27 | 28 | # IDE - VSCode 29 | .vscode/* 30 | !.vscode/settings.json 31 | !.vscode/tasks.json 32 | !.vscode/launch.json 33 | !.vscode/extensions.json -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![main branch parameter](https://github.com/MoeidHeidari/log-parser/actions/workflows/app.yaml/badge.svg?branch=main) 2 | # Log parser 3 | 4 | # Table of Contents 5 | 6 | - [Table of Contents](#table-of-contents) 7 | 8 | - [Overview](#overview) 9 | 10 | - [Provided Commands](#provided-commands) 11 | 12 | - [Code architecture](#code-architecture) 13 | 14 | - [source code](#source-code) 15 | 16 | - [Service build information](#service-build-information) 17 | 18 | - [Regular user](#regular-user) 19 | 20 | - [Documentation](#documentation) 21 | 22 | - [Example](#example) 23 | 24 | - [ToDo list](#todo-list) 25 | 26 | ## Overview 27 | 28 | Log parser takes a log input file and tries to parse it to extract useful information. It also respects [General Data Protection Regulation (GDPR)](https://gdpr-info.eu/) 29 | 30 | You can see take a look at the Full documentation [here](https://github.com/MoeidHeidari/log-parser/blob/main/full-documentation.md) 31 | 32 | 33 | --- 34 | 35 | #### Provided Commands 36 | 37 | ```bash 38 | cli 39 | 40 | parses a log file 41 | 42 | Options: 43 | -h, --help Show help [boolean] 44 | -l, --log-level log-level (ex: "error,[error,debug,warn,info]") 45 | [string] [default: "error"] 46 | -o, --output output log file (ex: "output.log") 47 | [string] [required] [default: "output.log"] 48 | -i, --input input log file (ex: "input.log") [string] [required] 49 | -v, --version Show version number [boolean] 50 | ``` 51 | 52 | --- 53 | 54 | ## Code architecture 55 | 56 | 57 | ```bash 58 | src 59 | ├── app 60 | └── parser 61 | ├── command 62 | ├── common 63 | ├── dtos 64 | ├── enum 65 | ├── helper 66 | ├── model 67 | └── service 68 | ``` 69 | 70 | --- 71 | 72 | ## source code 73 | 74 | ```bash 75 | git clone https://github.com/MoeidHeidari/log-parser.git 76 | cd log-parser 77 | ``` 78 | 79 | ## Service build information 80 | 81 | ### Regular user 82 | 83 | ```bash 84 | npm install 85 | npm run build 86 | npm run test 87 | npm run lint 88 | npm start:{dev || debug || prod} 89 | ``` 90 | 91 | ### using runner.sh 92 | 93 | ```bash 94 | bash scripts/runner.sh 95 | ... 96 | Done! 😍 97 | now you can use the application by following commmand 98 | node dist/cli.js -h 99 | ``` 100 | 101 | test result 102 | 103 | ```bash 104 | PASS test/unit-tests/utils.spec.ts 105 | PASS test/unit-tests/filehelper.spec.ts 106 | PASS test/unit-tests/parser.service.spec.ts (5.093 s) 107 | PASS test/integration-tests/parser-command.spec.ts (5.418 s) 108 | Test Suites: 4 passed, 4 total 109 | Tests: 33 passed, 33 total 110 | Snapshots: 0 total 111 | Time: 5.732 s, estimated 6 s 112 | Ran all test suites. 113 | ``` 114 | 115 | ## Documentation 116 | 117 | By running following comman you can generate the full code documentation (Compodoc) and get access to it through port `7000` 118 | 119 | ```bash 120 | npm run doc 121 | ``` 122 | 123 | http://localhost:7000 124 | 125 | ## Example 126 | 127 | input.log 128 | 129 | ```textile 130 | 2044-08-09T02:12:51.253Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service is started"} 131 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request the user information","userId": 10} 132 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request user orders list","userId": 10} 133 | 2021-08-09T02:12:51.255Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"Service is started"} 134 | 2021-08-09T02:12:51.257Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"About to request the user information","userId": 16} 135 | 2021-08-09T02:12:51.257Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"User information is gathered","user":{"id":10,"name":"Alice"}} 136 | 2021-08-09T02:12:51.258Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"About to request user orders list","userId":16} 137 | 2021-08-09T02:12:51.259Z - error - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Cannot find user orders list","code": 404,"err":"Not found"} 138 | 2021-08-09T02:12:51.259Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user": {"id": 16, "name": "Michael"}} 139 | 2021-08-09T02:12:51.262Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user":{"id":16,"orders":[{"id":472,"items":{"id":7,"price":7.12}}]}} 140 | 2021-08-09T02:12:51.264Z - warn - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service finished with error","code":404,"err":"Cannot find user orders list"} 141 | 2021-08-09T02:12:51.265Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"Service is successfully finished"} 142 | ``` 143 | 144 | Run Log parser 145 | 146 | ```bash 147 | npm run build 148 | ode dist/cli.js --input input.log --output log.json --log-level error,debug 149 | ``` 150 | 151 | output.json 152 | 153 | ```json 154 | [ 155 | { 156 | "timestamp": 1628475171254, 157 | "logLevel": "debug", 158 | "transactionId": "9abc55b2-807b-4361-9dbe-aa88b1b2e978", 159 | "err": "About to request the user information" 160 | }, 161 | { 162 | "timestamp": 1628475171254, 163 | "logLevel": "debug", 164 | "transactionId": "9abc55b2-807b-4361-9dbe-aa88b1b2e978", 165 | "err": "About to request user orders list" 166 | }, 167 | { 168 | "timestamp": 1628475171257, 169 | "logLevel": "debug", 170 | "transactionId": "9abc55b2-807b-4361-9dbe-aa88b1b2e821", 171 | "err": "About to request the user information" 172 | }, 173 | { 174 | "timestamp": 1628475171257, 175 | "logLevel": "debug", 176 | "transactionId": "9abc55b2-807b-4361-9dbe-aa88b1b2e978", 177 | "err": "User information is gathered" 178 | }, 179 | { 180 | "timestamp": 1628475171258, 181 | "logLevel": "debug", 182 | "transactionId": "9abc55b2-807b-4361-9dbe-aa88b1b2e821", 183 | "err": "About to request user orders list" 184 | }, 185 | { 186 | "timestamp": 1628475171259, 187 | "logLevel": "error", 188 | "transactionId": "9abc55b2-807b-4361-9dbe-aa88b1b2e978", 189 | "err": "Cannot find user orders list" 190 | }, 191 | { 192 | "timestamp": 1628475171259, 193 | "logLevel": "debug", 194 | "transactionId": "9abc55b2-807b-4361-9dbe-aa88b1b2e821", 195 | "err": "User information is retrieved" 196 | }, 197 | { 198 | "timestamp": 1628475171262, 199 | "logLevel": "debug", 200 | "transactionId": "9abc55b2-807b-4361-9dbe-aa88b1b2e821", 201 | "err": "User information is retrieved" 202 | } 203 | ] 204 | ``` 205 | 206 | ## ToDo list 207 | 208 | - [ ] connect it to logstash 209 | - [ ] implement elastic search 210 | 211 | ## 212 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /documentation/coverage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | parser documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 25 | 26 |
27 |
28 | 31 | 32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 56 | 57 |
58 | 59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 76 | 77 | 78 | 82 | 83 | 84 | 88 | 89 | 90 | 94 | 95 | 96 | 100 | 101 | 102 | 106 | 107 | 108 | 112 | 113 | 114 | 118 | 119 | 120 | 124 | 125 | 126 | 130 | 131 | 132 | 136 | 137 | 138 | 142 | 143 | 144 | 148 | 149 | 150 | 154 | 155 | 156 | 160 | 161 | 162 | 166 | 167 | 168 |
FileTypeIdentifierStatements
73 | 74 | src/cli.ts 75 | functionbootstrap 79 | 100 % 80 | (1/1) 81 |
85 | 86 | src/parser/command/parser.command.ts 87 | injectableParserCommand 91 | 100 % 92 | (3/3) 93 |
97 | 98 | src/parser/common/utils.ts 99 | functionvalidateDTO 103 | 100 % 104 | (1/1) 105 |
109 | 110 | src/parser/dtos/parser-command-dto.ts 111 | classParserCommandDTO 115 | 100 % 116 | (5/5) 117 |
121 | 122 | src/parser/dtos/parser-command-dto.ts 123 | variableallowedProperties 127 | 100 % 128 | (1/1) 129 |
133 | 134 | src/parser/helper/file-helper.ts 135 | injectableFileHelper 139 | 100 % 140 | (4/4) 141 |
145 | 146 | src/parser/model/log.model.ts 147 | interfaceLogModel 151 | 100 % 152 | (5/5) 153 |
157 | 158 | src/parser/service/parser.service.ts 159 | injectableParserService 163 | 100 % 164 | (3/3) 165 |
169 | 170 | 171 | 172 | 175 | 176 |
177 |
178 |

results matching ""

179 |
    180 |
    181 |
    182 |

    No results matching ""

    183 |
    184 |
    185 |
    186 | 187 |
    188 |
    189 | 190 | 198 | 199 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | -------------------------------------------------------------------------------- /documentation/dependencies.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | parser documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 25 | 26 |
    27 |
    28 | 31 | 32 |
    33 |
    34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 52 |
      53 |
    • 54 | @compodoc/compodoc : ^1.1.19
    • 55 |
    • 56 | @nestjs/common : ^8.0.0
    • 57 |
    • 58 | @nestjs/core : ^8.0.0
    • 59 |
    • 60 | @nestjs/platform-express : ^8.0.0
    • 61 |
    • 62 | class-transformer : ^0.5.1
    • 63 |
    • 64 | class-validator : ^0.13.2
    • 65 |
    • 66 | @types/faker : ^5.1.4
    • 67 |
    • 68 | nest-winston : ^1.6.2
    • 69 |
    • 70 | nestjs-command : ^3.1.1
    • 71 |
    • 72 | reflect-metadata : ^0.1.13
    • 73 |
    • 74 | rimraf : ^3.0.2
    • 75 |
    • 76 | rxjs : ^7.2.0
    • 77 |
    • 78 | faker : ^5.1.0
    • 79 |
    • 80 | winston : ^3.7.2
    • 81 |
    • 82 | yargs : ^17.5.1
    • 83 |
    84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
    92 |
    93 |

    results matching ""

    94 |
      95 |
      96 |
      97 |

      No results matching ""

      98 |
      99 |
      100 |
      101 | 102 |
      103 |
      104 | 105 | 113 | 114 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /documentation/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/ionicons.eot -------------------------------------------------------------------------------- /documentation/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/ionicons.ttf -------------------------------------------------------------------------------- /documentation/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/ionicons.woff -------------------------------------------------------------------------------- /documentation/fonts/ionicons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/ionicons.woff2 -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-300.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-300.eot -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-300.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-300.ttf -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-300.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-300.woff -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-300.woff2 -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-700.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-700.eot -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-700.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-700.ttf -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-700.woff -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-700.woff2 -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-italic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-italic.eot -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-italic.ttf -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-italic.woff -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-italic.woff2 -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-regular.eot -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-regular.ttf -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-regular.woff -------------------------------------------------------------------------------- /documentation/fonts/roboto-v15-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/fonts/roboto-v15-latin-regular.woff2 -------------------------------------------------------------------------------- /documentation/graph/dependencies.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | dependencies 11 | 12 | dependencies 13 | 14 | cluster_AppModule 15 | 16 | 17 | 18 | cluster_AppModule_imports 19 | 20 | 21 | 22 | cluster_ParserModule 23 | 24 | 25 | 26 | cluster_ParserModule_providers 27 | 28 | 29 | 30 | 31 | ParserModule 32 | 33 | ParserModule 34 | 35 | 36 | 37 | AppModule 38 | 39 | AppModule 40 | 41 | 42 | 43 | ParserModule->AppModule 44 | 45 | 46 | 47 | 48 | 49 | ParserCommand 50 | 51 | ParserCommand 52 | 53 | 54 | 55 | ParserCommand->ParserModule 56 | 57 | 58 | 59 | 60 | 61 | ParserService 62 | 63 | ParserService 64 | 65 | 66 | 67 | ParserService->ParserModule 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /documentation/images/compodoc-vectorise-inverted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/images/compodoc-vectorise-inverted.png -------------------------------------------------------------------------------- /documentation/images/compodoc-vectorise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/images/compodoc-vectorise.png -------------------------------------------------------------------------------- /documentation/images/coverage-badge-documentation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | documentation 7 | 100% 8 | 9 | 10 | -------------------------------------------------------------------------------- /documentation/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoeidHeidari/log-parser/3c08b96617974640690a12001437aa475b9a4e02/documentation/images/favicon.ico -------------------------------------------------------------------------------- /documentation/js/compodoc.js: -------------------------------------------------------------------------------- 1 | var compodoc = { 2 | EVENTS: { 3 | READY: 'compodoc.ready', 4 | SEARCH_READY: 'compodoc.search.ready' 5 | } 6 | }; 7 | 8 | Object.assign( compodoc, EventDispatcher.prototype ); 9 | 10 | document.addEventListener('DOMContentLoaded', function() { 11 | compodoc.dispatchEvent({ 12 | type: compodoc.EVENTS.READY 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /documentation/js/lazy-load-graphs.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | var lazyGraphs = [].slice.call(document.querySelectorAll('[lazy]')); 3 | var active = false; 4 | 5 | var lazyLoad = function() { 6 | if (active === false) { 7 | active = true; 8 | 9 | setTimeout(function() { 10 | lazyGraphs.forEach(function(lazyGraph) { 11 | if ( 12 | lazyGraph.getBoundingClientRect().top <= window.innerHeight && 13 | lazyGraph.getBoundingClientRect().bottom >= 0 && 14 | getComputedStyle(lazyGraph).display !== 'none' 15 | ) { 16 | lazyGraph.data = lazyGraph.getAttribute('lazy'); 17 | lazyGraph.removeAttribute('lazy'); 18 | 19 | lazyGraphs = lazyGraphs.filter(function(image) { return image !== lazyGraph}); 20 | 21 | if (lazyGraphs.length === 0) { 22 | document.removeEventListener('scroll', lazyLoad); 23 | window.removeEventListener('resize', lazyLoad); 24 | window.removeEventListener('orientationchange', lazyLoad); 25 | } 26 | } 27 | }); 28 | 29 | active = false; 30 | }, 200); 31 | } 32 | }; 33 | 34 | // initial load 35 | lazyLoad(); 36 | 37 | var container = document.querySelector('.container-fluid.modules'); 38 | if (container) { 39 | container.addEventListener('scroll', lazyLoad); 40 | window.addEventListener('resize', lazyLoad); 41 | window.addEventListener('orientationchange', lazyLoad); 42 | } 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /documentation/js/libs/EventDispatcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | var EventDispatcher=function(){};Object.assign(EventDispatcher.prototype,{addEventListener:function(i,t){void 0===this._listeners&&(this._listeners={});var e=this._listeners;void 0===e[i]&&(e[i]=[]),-1===e[i].indexOf(t)&&e[i].push(t)},hasEventListener:function(i,t){if(void 0===this._listeners)return!1;var e=this._listeners;return void 0!==e[i]&&-1!==e[i].indexOf(t)},removeEventListener:function(i,t){if(void 0!==this._listeners){var e=this._listeners[i];if(void 0!==e){var s=e.indexOf(t);-1!==s&&e.splice(s,1)}}},dispatchEvent:function(i){if(void 0!==this._listeners){var t=this._listeners[i.type];if(void 0!==t){i.target=this;var e=[],s=0,n=t.length;for(s=0;s1?t[t.length-1]:void 0:t[0]},this.getActiveContent=function(){var t=this.getActiveTab().getElementsByTagName("A")[0].getAttribute("href").replace("#","");return t&&document.getElementById("c-"+t)},this.tab.addEventListener("click",this.handle,!1)},d=document.querySelectorAll("[data-toggle='tab'], [data-toggle='pill']"),u=0,h=d.length;u",">"));else if(1==i){if(r.push("<",e.tagName),e.hasAttributes())for(var n=e.attributes,s=0,o=n.length;s");for(var h=e.childNodes,s=0,o=h.length;s")}else r.push("/>")}else{if(8!=i)throw"Error serializing XML. Unhandled node of type: "+i;r.push("\x3c!--",e.nodeValue,"--\x3e")}};Object.defineProperty(e.prototype,"innerHTML",{get:function(){for(var e=[],r=this.firstChild;r;)t(r,e),r=r.nextSibling;return e.join("")},set:function(e){for(;this.firstChild;)this.removeChild(this.firstChild);try{var t=new DOMParser;t.async=!1,sXML=""+e+"";for(var r=t.parseFromString(sXML,"text/xml").documentElement.firstChild;r;)this.appendChild(this.ownerDocument.importNode(r,!0)),r=r.nextSibling}catch(e){throw new Error("Error parsing XML string")}}})}}((0,eval)("this").SVGElement); -------------------------------------------------------------------------------- /documentation/js/libs/promise.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 (c) Pierre Duquesne 3 | * Licensed under the New BSD License. 4 | * https://github.com/stackp/promisejs 5 | */ 6 | (function(a){function b(){this._callbacks=[];}b.prototype.then=function(a,c){var d;if(this._isdone)d=a.apply(c,this.result);else{d=new b();this._callbacks.push(function(){var b=a.apply(c,arguments);if(b&&typeof b.then==='function')b.then(d.done,d);});}return d;};b.prototype.done=function(){this.result=arguments;this._isdone=true;for(var a=0;a=300)&&j.status!==304);h.done(a,j.responseText,j);}};j.send(k);return h;}function h(a){return function(b,c,d){return g(a,b,c,d);};}var i={Promise:b,join:c,chain:d,ajax:g,get:h('GET'),post:h('POST'),put:h('PUT'),del:h('DELETE'),ENOXHR:1,ETIMEOUT:2,ajaxTimeout:0};if(typeof define==='function'&&define.amd)define(function(){return i;});else a.promise=i;})(this); -------------------------------------------------------------------------------- /documentation/js/libs/tablesort.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * tablesort v5.1.0 (2018-09-14) 3 | * http://tristen.ca/tablesort/demo/ 4 | * Copyright (c) 2018 ; Licensed MIT 5 | */ 6 | !function(){function a(b,c){if(!(this instanceof a))return new a(b,c);if(!b||"TABLE"!==b.tagName)throw new Error("Element must be a table");this.init(b,c||{})}var b=[],c=function(a){var b;return window.CustomEvent&&"function"==typeof window.CustomEvent?b=new CustomEvent(a):(b=document.createEvent("CustomEvent"),b.initCustomEvent(a,!1,!1,void 0)),b},d=function(a){return a.getAttribute("data-sort")||a.textContent||a.innerText||""},e=function(a,b){return a=a.trim().toLowerCase(),b=b.trim().toLowerCase(),a===b?0:a0)if(a.tHead&&a.tHead.rows.length>0){for(e=0;e0&&l.push(k),m++;if(!l)return}for(m=0;m 16 | 151 | 152 | `); 153 | this.innerHTML = tp.strings; 154 | } 155 | }); -------------------------------------------------------------------------------- /documentation/js/search/search-lunr.js: -------------------------------------------------------------------------------- 1 | (function(compodoc) { 2 | 3 | function LunrSearchEngine() { 4 | this.index = undefined; 5 | this.store = {}; 6 | this.name = 'LunrSearchEngine'; 7 | } 8 | 9 | LunrSearchEngine.prototype.init = function() { 10 | var that = this, 11 | d = new promise.Promise(); 12 | 13 | that.index = lunr.Index.load(COMPODOC_SEARCH_INDEX.index); 14 | that.store = COMPODOC_SEARCH_INDEX.store; 15 | d.done(); 16 | 17 | return d; 18 | }; 19 | 20 | LunrSearchEngine.prototype.search = function(q, offset, length) { 21 | var that = this, 22 | results = [], 23 | d = new promise.Promise(); 24 | 25 | if (this.index) { 26 | results = $.map(this.index.search('*' + q + '*'), function(result) { 27 | var doc = that.store[result.ref]; 28 | 29 | return { 30 | title: doc.title, 31 | url: doc.url, 32 | body: doc.summary || doc.body 33 | }; 34 | }); 35 | } 36 | 37 | d.done({ 38 | query: q, 39 | results: length === 0 ? results : results.slice(0, length), 40 | count: results.length 41 | }); 42 | 43 | return d; 44 | }; 45 | 46 | compodoc.addEventListener(compodoc.EVENTS.READY, function(event) { 47 | var engine = new LunrSearchEngine(), 48 | initialized = false; 49 | 50 | function query(q, offset, length) { 51 | if (!initialized) throw new Error('Search has not been initialized'); 52 | return engine.search(q, offset, length); 53 | } 54 | 55 | compodoc.search = { 56 | query: query 57 | }; 58 | 59 | engine.init() 60 | .then(function() { 61 | initialized = true; 62 | compodoc.dispatchEvent({ 63 | type: compodoc.EVENTS.SEARCH_READY 64 | }); 65 | }); 66 | }); 67 | })(compodoc); 68 | -------------------------------------------------------------------------------- /documentation/js/sourceCode.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | var $tabSource = document.querySelector('#source-tab'), 3 | $tabInfo = document.querySelector('#info-tab'), 4 | $tabReadme = document.querySelector('#readme-tab'), 5 | $tabTemplate = document.querySelector('#templateData-tab'), 6 | $tabTree = document.querySelector('#tree-tab'), 7 | $tabExample = document.querySelector('#example-tab'), 8 | $prismPre = document.querySelector('pre.compodoc-sourcecode'); 9 | if ($tabSource && $prismPre) { 10 | $prismCode = $prismPre.querySelector('code'), 11 | $content = document.querySelector('.content'), 12 | prismLinks = document.querySelectorAll('.link-to-prism') 13 | 14 | for (var i = 0; i < prismLinks.length; i++) { 15 | prismLinks[i].addEventListener('click', linkToPrism, false); 16 | } 17 | 18 | function linkToPrism(event) { 19 | var targetLine = event.target.getAttribute('data-line'); 20 | event.preventDefault(); 21 | 22 | $prismPre.setAttribute('data-line', targetLine); 23 | Prism.highlightElement($prismCode, function() {}); 24 | 25 | $tabSource.click(); 26 | 27 | setTimeout(function() { 28 | var $prismHighlightLine = document.querySelector('.line-highlight'), 29 | top = parseInt(getComputedStyle($prismHighlightLine)['top']); 30 | $content.scrollTop = top; 31 | }, 500); 32 | }; 33 | 34 | window.onhashchange = function(event) { 35 | switch (window.location.hash) { 36 | case '': 37 | case '#info': 38 | $tabInfo.click(); 39 | break; 40 | case '#readme': 41 | $tabReadme.click(); 42 | break; 43 | case '#source': 44 | $tabSource.click(); 45 | break; 46 | case '#template': 47 | $tabTemplate.click(); 48 | break; 49 | case '#dom-tree': 50 | $tabTree.click(); 51 | break; 52 | case '#example': 53 | $tabExample.click(); 54 | break; 55 | } 56 | } 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /documentation/js/svg-pan-zoom.controls.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | if (document.getElementById('module-graph-svg')) { 3 | panZoom = svgPanZoom(document.getElementById('module-graph-svg').querySelector('svg'), { 4 | zoomEnabled: true, 5 | minZoom: 1, 6 | maxZoom: 5 7 | }); 8 | 9 | document.getElementById('zoom-in').addEventListener('click', function(ev) { 10 | ev.preventDefault(); 11 | panZoom.zoomIn(); 12 | }); 13 | 14 | document.getElementById('zoom-out').addEventListener('click', function(ev) { 15 | ev.preventDefault(); 16 | panZoom.zoomOut(); 17 | }); 18 | 19 | document.getElementById('reset').addEventListener('click', function(ev) { 20 | ev.preventDefault(); 21 | panZoom.resetZoom(); 22 | panZoom.resetPan(); 23 | }); 24 | 25 | var overviewFullscreen = false, 26 | originalOverviewHeight; 27 | 28 | document.getElementById('fullscreen').addEventListener('click', function(ev) { 29 | if (overviewFullscreen) { 30 | document.getElementById('module-graph-svg').style.height = originalOverviewHeight; 31 | overviewFullscreen = false; 32 | if (ev.target) { 33 | ev.target.classList.remove('ion-md-close'); 34 | ev.target.classList.add('ion-ios-resize'); 35 | } 36 | } else { 37 | originalOverviewHeight = document.getElementById('module-graph-svg').style.height; 38 | document.getElementById('module-graph-svg').style.height = '85vh'; 39 | overviewFullscreen = true; 40 | if (ev.target) { 41 | ev.target.classList.remove('ion-ios-resize'); 42 | ev.target.classList.add('ion-md-close'); 43 | } 44 | } 45 | document.getElementById('module-graph-svg').querySelector('svg').style.height = document.getElementById('module-graph-svg').clientHeight; 46 | setTimeout(function() { 47 | panZoom.resize(); 48 | panZoom.fit(); 49 | panZoom.center(); 50 | }, 0) 51 | }); 52 | } 53 | }); 54 | -------------------------------------------------------------------------------- /documentation/js/tabs.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | var tabs = document.getElementsByClassName('nav-tabs'), 3 | updateAddress = function(e) { 4 | if(history.pushState && e.target.dataset.link) { 5 | history.pushState(null, null, '#' + e.target.dataset.link); 6 | } 7 | }; 8 | if (tabs.length > 0) { 9 | tabs = tabs[0].querySelectorAll('li'); 10 | for (var i = 0; i < tabs.length; i++) { 11 | tabs[i].addEventListener('click', updateAddress); 12 | var linkTag = tabs[i].querySelector('a'); 13 | if (location.hash !== '') { 14 | var currentHash = location.hash.substr(1); 15 | if (currentHash === linkTag.dataset.link) { 16 | linkTag.click(); 17 | } 18 | } 19 | } 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /documentation/js/tree.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | var tabs = document.getElementsByClassName('nav-tabs')[0], 3 | tabsCollection = tabs.getElementsByTagName('A'), 4 | treeTab; 5 | var len = tabsCollection.length; 6 | for(var i = 0; i < len; i++) { 7 | if (tabsCollection[i].getAttribute('id') === 'tree-tab') { 8 | treeTab = tabsCollection[i]; 9 | } 10 | } 11 | 12 | // short-circuit if no tree tab 13 | if (!treeTab) return; 14 | 15 | var handler = new Tautologistics.NodeHtmlParser.HtmlBuilder(function(error, dom) { 16 | if (error) { 17 | console.log('handler ko'); 18 | } 19 | }), 20 | parser = new Tautologistics.NodeHtmlParser.Parser(handler), 21 | currentLocation = window.location; 22 | parser.parseComplete(COMPONENT_TEMPLATE); 23 | 24 | var newNodes = [], 25 | newEdges = [], 26 | parsedHtml = handler.dom[0], 27 | nodeCount = 0, 28 | nodeLevel = 0; 29 | 30 | newNodes.push({ 31 | _id: 0, 32 | label: parsedHtml.name, 33 | type: parsedHtml.type 34 | }) 35 | //Add id for nodes 36 | var traverseIds = function(o) { 37 | for (i in o) { 38 | if (!!o[i] && typeof(o[i]) == "object") { 39 | if (!o[i].length && o[i].type === 'tag') { 40 | nodeCount += 1; 41 | o[i]._id = nodeCount; 42 | } 43 | traverseIds(o[i]); 44 | } 45 | } 46 | } 47 | parsedHtml._id = 0; 48 | traverseIds(parsedHtml); 49 | 50 | 51 | var DeepIterator = deepIterator.default, 52 | it = DeepIterator(parsedHtml); 53 | for (let { 54 | value, 55 | parent, 56 | parentNode, 57 | key, 58 | type 59 | } of it) { 60 | if (type === 'NonIterableObject' && typeof key !== 'undefined' && value.type === 'tag') { 61 | var newNode = { 62 | id: value._id, 63 | label: value.name, 64 | type: value.type 65 | }; 66 | for(var i = 0; i < COMPONENTS.length; i++) { 67 | if (COMPONENTS[i].selector === value.name) { 68 | newNode.font = { 69 | multi: 'html' 70 | }; 71 | newNode.label = '' + newNode.label + ''; 72 | newNode.color = '#FB7E81'; 73 | newNode.name = COMPONENTS[i].name; 74 | } 75 | } 76 | for(var i = 0; i < DIRECTIVES.length; i++) { 77 | if (value.attributes) { 78 | for(attr in value.attributes) { 79 | if (DIRECTIVES[i].selector.indexOf(attr) !== -1) { 80 | newNode.font = { 81 | multi: 'html' 82 | }; 83 | newNode.label = '' + newNode.label + ''; 84 | newNode.color = '#FF9800'; 85 | newNode.name = DIRECTIVES[i].name; 86 | } 87 | } 88 | } 89 | } 90 | newNodes.push(newNode); 91 | newEdges.push({ 92 | from: parentNode._parent._id, 93 | to: value._id, 94 | arrows: 'to' 95 | }); 96 | } 97 | } 98 | 99 | newNodes.shift(); 100 | 101 | var container = document.getElementById('tree-container'), 102 | data = { 103 | nodes: newNodes, 104 | edges: newEdges 105 | }, 106 | options = { 107 | layout: { 108 | hierarchical: { 109 | sortMethod: 'directed', 110 | enabled: true 111 | } 112 | }, 113 | nodes: { 114 | shape: 'ellipse', 115 | fixed: true 116 | } 117 | }, 118 | 119 | handleClickNode = function(params) { 120 | var clickeNodeId; 121 | if (params.nodes.length > 0) { 122 | clickeNodeId = params.nodes[0]; 123 | for(var i = 0; i < newNodes.length; i++) { 124 | if (newNodes[i].id === clickeNodeId) { 125 | for(var j = 0; j < COMPONENTS.length; j++) { 126 | if (COMPONENTS[j].name === newNodes[i].name) { 127 | document.location.href = currentLocation.origin + currentLocation.pathname.replace(ACTUAL_COMPONENT.name, newNodes[i].name); 128 | } 129 | } 130 | } 131 | } 132 | } 133 | }, 134 | 135 | loadTree = function () { 136 | setTimeout(function() { 137 | container.style.height = document.getElementsByClassName('content')[0].offsetHeight - 140 + 'px'; 138 | var network = new vis.Network(container, data, options); 139 | network.on('click', handleClickNode); 140 | }, 200); // Fade is 0.150 141 | }; 142 | 143 | loadTree(); 144 | treeTab.addEventListener('click', function() { 145 | loadTree(); 146 | }); 147 | }); 148 | -------------------------------------------------------------------------------- /documentation/miscellaneous/enumerations.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | parser documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 25 | 26 |
      27 |
      28 | 31 | 32 |
      33 |
      34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 56 | 57 |
      58 |

      Index

      59 | 60 | 61 | 62 | 69 | 70 | 71 |
      63 | 68 |
      72 |
      73 | 74 |

      src/parser/enum/log-level.enum.ts

      75 |
      76 | 77 | 78 | 79 | 83 | 84 | 85 | 89 | 90 | 91 | 94 | 95 | 96 | 99 | 100 | 101 | 104 | 105 | 106 | 109 | 110 | 111 | 114 | 115 | 116 | 119 | 120 | 121 | 124 | 125 | 126 | 129 | 130 | 131 |
      80 | 81 | LogLevel 82 |
      86 |

      An enum that represents the log levels the parser understands

      87 |
      88 |
      92 |  ERROR 93 |
      97 | Value : error 98 |
      102 |  INFO 103 |
      107 | Value : info 108 |
      112 |  WARN 113 |
      117 | Value : warn 118 |
      122 |  DEBUG 123 |
      127 | Value : debug 128 |
      132 |
      133 | 134 | 135 | 136 |
      137 |
      138 |

      results matching ""

      139 |
        140 |
        141 |
        142 |

        No results matching ""

        143 |
        144 |
        145 |
        146 | 147 |
        148 |
        149 | 150 | 158 | 159 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /documentation/miscellaneous/functions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | parser documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 25 | 26 |
        27 |
        28 | 31 | 32 |
        33 |
        34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 56 | 57 |
        58 |

        Index

        59 | 60 | 61 | 62 | 72 | 73 | 74 |
        63 | 71 |
        75 |
        76 | 77 |

        src/cli.ts

        78 |
        79 |

        80 | 81 | 82 | 89 | 90 | 91 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 105 | 106 | 107 |
        83 | 84 | 85 | bootstrap 86 | 87 | 88 |
        92 | bootstrap() 93 |
        101 |

        Main application entry point

        102 |
        103 | 104 |
        108 |

        src/parser/common/utils.ts

        109 |
        110 |

        111 | 112 | 113 | 120 | 121 | 122 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 177 | 178 | 179 |
        114 | 115 | 116 | validateDTO 117 | 118 | 119 |
        123 | validateDTO(dto: any) 124 |
        132 |

        validates dto and returns bad request if it is wrong

        133 |
        134 | 135 |
        136 | Parameters : 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 153 | 154 | 157 | 158 | 159 | 163 | 164 | 165 |
        NameTypeOptionalDescription
        dto 151 | any 152 | 155 | No 156 | 160 |

        dto

        161 | 162 |
        166 |
        167 |
        168 |
        169 |
        170 | Returns : Promise<any> 171 | 172 |
        173 |
        174 | 175 |
        176 |
        180 |
        181 | 182 | 183 |
        184 |
        185 |

        results matching ""

        186 |
          187 |
          188 |
          189 |

          No results matching ""

          190 |
          191 |
          192 |
          193 | 194 |
          195 |
          196 | 197 | 205 | 206 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /documentation/miscellaneous/variables.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | parser documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 25 | 26 |
          27 |
          28 | 31 | 32 |
          33 |
          34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 56 | 57 |
          58 |

          Index

          59 | 60 | 61 | 62 | 69 | 70 | 71 |
          63 | 68 |
          72 |
          73 | 74 |

          src/parser/dtos/parser-command-dto.ts

          75 |
          76 |

          77 | 78 | 79 | 86 | 87 | 88 | 92 | 93 | 94 | 97 | 98 | 99 | 100 | 104 | 105 | 106 | 107 |
          80 | 81 | 82 | allowedProperties 83 | 84 | 85 |
          89 | Type : [] 90 | 91 |
          95 | Default value : ['input', 'output', 'logLevel'] 96 |
          101 |

          list of allowed properties

          102 |
          103 |
          108 |
          109 | 110 | 111 | 112 |
          113 |
          114 |

          results matching ""

          115 |
            116 |
            117 |
            118 |

            No results matching ""

            119 |
            120 |
            121 |
            122 | 123 |
            124 |
            125 | 126 | 134 | 135 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /documentation/modules.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | parser documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 25 | 26 |
            27 |
            28 | 31 | 32 |
            33 |
            34 | 35 | 36 | 37 | 40 |
            41 |
            42 |
            43 |
            44 |
            45 |

            AppModule

            46 |
            47 |
            48 |

            49 | 50 | Your browser does not support SVG 51 | 52 |

            53 | 56 |
            57 |
            58 |
            59 |
            60 |
            61 |
            62 |

            ParserModule

            63 |
            64 |
            65 |

            66 | 67 | Your browser does not support SVG 68 | 69 |

            70 | 73 |
            74 |
            75 |
            76 |
            77 |
            78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 |
            97 |
            98 |

            results matching ""

            99 |
              100 |
              101 |
              102 |

              No results matching ""

              103 |
              104 |
              105 |
              106 | 107 |
              108 |
              109 | 110 | 118 | 119 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /documentation/modules/AppModule.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | parser documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 25 | 26 |
              27 |
              28 | 31 | 32 |
              33 |
              34 | 35 | 36 | 37 | 41 | 42 |
              43 |
              44 | 45 | 47 | 49 | 50 | 52 | 53 | dependencies 54 | 55 | dependencies 56 | 57 | cluster_AppModule 58 | 59 | 60 | 61 | cluster_AppModule_imports 62 | 63 | 64 | 65 | 66 | ParserModule 67 | 68 | ParserModule 69 | 70 | 71 | 72 | AppModule 73 | 74 | AppModule 75 | 76 | 77 | 78 | ParserModule->AppModule 79 | 80 | 81 | 82 | 83 | 84 | 85 |
              86 | 87 |
              88 | 89 | 90 | 91 |
              92 |
              93 | 94 | 95 | 96 | 104 | 105 |
              106 |
              107 | 108 |

              109 |

              File

              110 |

              111 |

              112 | src/app/app.module.ts 113 |

              114 | 115 | 116 | 117 | 118 | 119 |
              120 |
              121 |
              122 |

              Imports

              124 | 129 |
              130 |
              131 |
              132 | 133 | 134 |
              135 | 136 | 137 |
              138 |
              import { Module } from '@nestjs/common';
              139 | import { CommandModule } from 'nestjs-command';
              140 | import { ParserModule } from '../parser/parser.module';
              141 | 
              142 | 
              143 | 
              144 | @Module({
              145 |   imports: [CommandModule,ParserModule,],
              146 |   providers: []
              147 | })
              148 | export class AppModule {}
              149 |
              150 |
              151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 |
              169 |
              170 |

              results matching ""

              171 |
                172 |
                173 |
                174 |

                No results matching ""

                175 |
                176 |
                177 |
                178 | 179 |
                180 |
                181 | 182 | 190 | 191 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | -------------------------------------------------------------------------------- /documentation/modules/AppModule/dependencies.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | dependencies 11 | 12 | dependencies 13 | 14 | cluster_AppModule 15 | 16 | 17 | 18 | cluster_AppModule_imports 19 | 20 | 21 | 22 | 23 | ParserModule 24 | 25 | ParserModule 26 | 27 | 28 | 29 | AppModule 30 | 31 | AppModule 32 | 33 | 34 | 35 | ParserModule->AppModule 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /documentation/modules/ParserModule/dependencies.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | dependencies 11 | 12 | dependencies 13 | 14 | cluster_ParserModule 15 | 16 | 17 | 18 | cluster_ParserModule_providers 19 | 20 | 21 | 22 | 23 | ParserCommand 24 | 25 | ParserCommand 26 | 27 | 28 | 29 | ParserModule 30 | 31 | ParserModule 32 | 33 | 34 | 35 | ParserCommand->ParserModule 36 | 37 | 38 | 39 | 40 | 41 | ParserService 42 | 43 | ParserService 44 | 45 | 46 | 47 | ParserService->ParserModule 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /documentation/properties.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | parser documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 25 | 26 |
                27 |
                28 | 31 | 32 |
                33 |
                34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 53 |
                  54 |
                • 55 | Version : 0.0.1
                • 56 |
                • 57 | Description :
                • 58 |
                • 59 | License : UNLICENSED
                • 60 |
                • 61 | Author :
                • 62 |
                63 | 64 | 65 | 66 | 67 | 68 |
                69 |
                70 |

                results matching ""

                71 |
                  72 |
                  73 |
                  74 |

                  No results matching ""

                  75 |
                  76 |
                  77 |
                  78 | 79 |
                  80 |
                  81 | 82 | 90 | 91 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /documentation/styles/bootstrap-card.css: -------------------------------------------------------------------------------- 1 | .card { 2 | position: relative; 3 | display: block; 4 | margin-bottom: 20px; 5 | background-color: #fff; 6 | border: 1px solid #ddd; 7 | border-radius: 4px; 8 | } 9 | 10 | .card-block { 11 | padding: 15px; 12 | } 13 | .card-block:before, .card-block:after { 14 | content: " "; 15 | display: table; 16 | } 17 | .card-block:after { 18 | clear: both; 19 | } 20 | 21 | .card-title { 22 | margin: 5px; 23 | margin-bottom: 2px; 24 | text-align: center; 25 | } 26 | 27 | .card-subtitle { 28 | margin-top: -10px; 29 | margin-bottom: 0; 30 | } 31 | 32 | .card-text:last-child { 33 | margin-bottom: 0; 34 | margin-top: 10px; 35 | } 36 | 37 | .card-link:hover { 38 | text-decoration: none; 39 | } 40 | .card-link + .card-link { 41 | margin-left: 15px; 42 | } 43 | 44 | .card > .list-group:first-child .list-group-item:first-child { 45 | border-top-right-radius: 4px; 46 | border-top-left-radius: 4px; 47 | } 48 | .card > .list-group:last-child .list-group-item:last-child { 49 | border-bottom-right-radius: 4px; 50 | border-bottom-left-radius: 4px; 51 | } 52 | 53 | .card-header { 54 | padding: 10px 15px; 55 | background-color: #f5f5f5; 56 | border-bottom: 1px solid #ddd; 57 | } 58 | .card-header:before, .card-header:after { 59 | content: " "; 60 | display: table; 61 | } 62 | .card-header:after { 63 | clear: both; 64 | } 65 | .card-header:first-child { 66 | border-radius: 4px 4px 0 0; 67 | } 68 | 69 | .card-footer { 70 | padding: 10px 15px; 71 | background-color: #f5f5f5; 72 | border-top: 1px solid #ddd; 73 | } 74 | .card-footer:before, .card-footer:after { 75 | content: " "; 76 | display: table; 77 | } 78 | .card-footer:after { 79 | clear: both; 80 | } 81 | .card-footer:last-child { 82 | border-radius: 0 0 4px 4px; 83 | } 84 | 85 | .card-header-tabs { 86 | margin-right: -5px; 87 | margin-bottom: -10px; 88 | margin-left: -5px; 89 | border-bottom: 0; 90 | } 91 | 92 | .card-header-pills { 93 | margin-right: -5px; 94 | margin-left: -5px; 95 | } 96 | 97 | .card-primary { 98 | background-color: #337ab7; 99 | border-color: #337ab7; 100 | } 101 | .card-primary .card-header, 102 | .card-primary .card-footer { 103 | background-color: transparent; 104 | } 105 | 106 | .card-success { 107 | background-color: #5cb85c; 108 | border-color: #5cb85c; 109 | } 110 | .card-success .card-header, 111 | .card-success .card-footer { 112 | background-color: transparent; 113 | } 114 | 115 | .card-info { 116 | background-color: #5bc0de; 117 | border-color: #5bc0de; 118 | } 119 | .card-info .card-header, 120 | .card-info .card-footer { 121 | background-color: transparent; 122 | } 123 | 124 | .card-warning { 125 | background-color: #f0ad4e; 126 | border-color: #f0ad4e; 127 | } 128 | .card-warning .card-header, 129 | .card-warning .card-footer { 130 | background-color: transparent; 131 | } 132 | 133 | .card-danger { 134 | background-color: #d9534f; 135 | border-color: #d9534f; 136 | } 137 | .card-danger .card-header, 138 | .card-danger .card-footer { 139 | background-color: transparent; 140 | } 141 | 142 | .card-outline-primary { 143 | background-color: transparent; 144 | border-color: #337ab7; 145 | } 146 | 147 | .card-outline-secondary { 148 | background-color: transparent; 149 | border-color: #ccc; 150 | } 151 | 152 | .card-outline-info { 153 | background-color: transparent; 154 | border-color: #5bc0de; 155 | } 156 | 157 | .card-outline-success { 158 | background-color: transparent; 159 | border-color: #5cb85c; 160 | } 161 | 162 | .card-outline-warning { 163 | background-color: transparent; 164 | border-color: #f0ad4e; 165 | } 166 | 167 | .card-outline-danger { 168 | background-color: transparent; 169 | border-color: #d9534f; 170 | } 171 | 172 | .card-inverse .card-header, 173 | .card-inverse .card-footer { 174 | border-color: rgba(255, 255, 255, 0.2); 175 | } 176 | .card-inverse .card-header, 177 | .card-inverse .card-footer, 178 | .card-inverse .card-title, 179 | .card-inverse .card-blockquote { 180 | color: #fff; 181 | } 182 | .card-inverse .card-link, 183 | .card-inverse .card-text, 184 | .card-inverse .card-subtitle, 185 | .card-inverse .card-blockquote .blockquote-footer { 186 | color: rgba(255, 255, 255, 0.65); 187 | } 188 | .card-inverse .card-link:hover, .card-inverse .card-link:focus { 189 | color: #fff; 190 | } 191 | 192 | .card-blockquote { 193 | padding: 0; 194 | margin-bottom: 0; 195 | border-left: 0; 196 | } 197 | 198 | .card-img { 199 | border-radius: .25em; 200 | } 201 | 202 | .card-img-overlay { 203 | position: absolute; 204 | top: 0; 205 | right: 0; 206 | bottom: 0; 207 | left: 0; 208 | padding: 15px; 209 | } 210 | 211 | .card-img-top { 212 | border-top-right-radius: 4px; 213 | border-top-left-radius: 4px; 214 | } 215 | 216 | .card-img-bottom { 217 | border-bottom-right-radius: 4px; 218 | border-bottom-left-radius: 4px; 219 | } 220 | -------------------------------------------------------------------------------- /documentation/styles/dark.css: -------------------------------------------------------------------------------- 1 | body.dark { 2 | background: #212121; 3 | color: #fafafa; 4 | } 5 | 6 | .dark code { 7 | color: #e09393; 8 | } 9 | 10 | .dark a, 11 | .dark .menu ul.list li a.active { 12 | color: #7fc9ff; 13 | } 14 | 15 | .dark .menu { 16 | background: #212121; 17 | border-right: 1px solid #444; 18 | } 19 | 20 | .dark .menu ul.list li a { 21 | color: #fafafa; 22 | } 23 | 24 | .dark .menu ul.list li.divider { 25 | background: #444; 26 | } 27 | 28 | .dark .xs-menu ul.list li:nth-child(2) { 29 | margin: 0; 30 | background: none; 31 | } 32 | 33 | .dark .menu ul.list li:nth-child(2) { 34 | margin: 0; 35 | background: none; 36 | } 37 | 38 | .dark #book-search-input { 39 | background: #212121; 40 | border-top: 1px solid #444; 41 | border-bottom: 1px solid #444; 42 | color: #fafafa; 43 | } 44 | 45 | .dark .table.metadata > tbody > tr:hover { 46 | color: #555; 47 | } 48 | 49 | .dark .table-bordered { 50 | border: 1px solid #444; 51 | } 52 | 53 | .dark .table-bordered > tbody > tr > td, 54 | .dark .table-bordered > tbody > tr > th, 55 | .dark .table-bordered > tfoot > tr > td, 56 | .dark .table-bordered > tfoot > tr > th, 57 | .dark .table-bordered > thead > tr > td, 58 | .dark .table-bordered > thead > tr > th { 59 | border: 1px solid #444; 60 | } 61 | 62 | .dark .coverage a, 63 | .dark .coverage-count { 64 | color: #fafafa; 65 | } 66 | 67 | .dark .coverage-header { 68 | color: black; 69 | } 70 | 71 | .dark .routes svg text, 72 | .dark .routes svg a { 73 | fill: white; 74 | } 75 | .dark .routes svg rect { 76 | fill: #212121 !important; 77 | } 78 | 79 | .dark .navbar-default, 80 | .dark .btn-default { 81 | background-color: black; 82 | border-color: #444; 83 | color: #fafafa; 84 | } 85 | 86 | .dark .navbar-default .navbar-brand { 87 | color: #fafafa; 88 | } 89 | 90 | .dark .overview .card, 91 | .dark .modules .card { 92 | background: #171717; 93 | color: #fafafa; 94 | border: 1px solid #444; 95 | } 96 | .dark .overview .card a { 97 | color: #fafafa; 98 | } 99 | 100 | .dark .modules .card-header { 101 | background: none; 102 | border-bottom: 1px solid #444; 103 | } 104 | 105 | .dark .module .list-group-item { 106 | background: none; 107 | border: 1px solid #444; 108 | } 109 | 110 | .dark .container-fluid.module h3 a { 111 | color: #337ab7; 112 | } 113 | 114 | .dark table.params thead { 115 | background: #484848; 116 | color: #fafafa; 117 | } 118 | -------------------------------------------------------------------------------- /documentation/styles/laravel.css: -------------------------------------------------------------------------------- 1 | .nav-tabs > li > a { 2 | text-decoration: none; 3 | } 4 | 5 | .navbar-default .navbar-brand { 6 | color: #f4645f; 7 | text-decoration: none; 8 | font-size: 16px; 9 | } 10 | 11 | .menu ul.list li a[data-type='chapter-link'], 12 | .menu ul.list li.chapter .simple { 13 | color: #525252; 14 | border-bottom: 1px dashed rgba(0, 0, 0, 0.1); 15 | } 16 | 17 | .content h1, 18 | .content h2, 19 | .content h3, 20 | .content h4, 21 | .content h5 { 22 | color: #292e31; 23 | font-weight: normal; 24 | } 25 | 26 | .content { 27 | color: #4c555a; 28 | } 29 | 30 | a { 31 | color: #f4645f; 32 | text-decoration: underline; 33 | } 34 | a:hover { 35 | color: #f1362f; 36 | } 37 | 38 | .menu ul.list li:nth-child(2) { 39 | margin-top: 0; 40 | } 41 | 42 | .menu ul.list li.title a { 43 | color: #f4645f; 44 | text-decoration: none; 45 | font-size: 16px; 46 | } 47 | 48 | .menu ul.list li a { 49 | color: #f4645f; 50 | text-decoration: none; 51 | } 52 | .menu ul.list li a.active { 53 | color: #f4645f; 54 | font-weight: bold; 55 | } 56 | 57 | code { 58 | box-sizing: border-box; 59 | display: inline-block; 60 | padding: 0 5px; 61 | background: #f0f2f1; 62 | border-radius: 3px; 63 | color: #b93d6a; 64 | font-size: 13px; 65 | line-height: 20px; 66 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.125); 67 | } 68 | 69 | pre { 70 | margin: 0; 71 | padding: 12px 12px; 72 | background: rgba(238, 238, 238, 0.35); 73 | border-radius: 3px; 74 | font-size: 13px; 75 | line-height: 1.5em; 76 | font-weight: 500; 77 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.125); 78 | } 79 | 80 | .dark body { 81 | color: #fafafa; 82 | } 83 | .dark .content h1, 84 | .dark .content h2, 85 | .dark .content h3, 86 | .dark .content h4, 87 | .dark .content h5 { 88 | color: #fafafa; 89 | } 90 | 91 | .dark code { 92 | background: none; 93 | } 94 | 95 | .dark .content { 96 | color: #fafafa; 97 | } 98 | 99 | .dark .menu ul.list li a[data-type='chapter-link'], 100 | .dark .menu ul.list li.chapter .simple { 101 | color: #fafafa; 102 | } 103 | 104 | .dark .menu ul.list li.title a { 105 | color: #fafafa; 106 | } 107 | 108 | .dark .menu ul.list li a { 109 | color: #fafafa; 110 | } 111 | .dark .menu ul.list li a.active { 112 | color: #7fc9ff; 113 | } 114 | -------------------------------------------------------------------------------- /documentation/styles/material.css: -------------------------------------------------------------------------------- 1 | .menu { 2 | background: none; 3 | } 4 | 5 | a:hover { 6 | text-decoration: none; 7 | } 8 | 9 | /** LINK **/ 10 | 11 | .menu ul.list li a { 12 | text-decoration: none; 13 | } 14 | 15 | .menu ul.list li a:hover, 16 | .menu ul.list li.chapter .simple:hover { 17 | background-color: #f8f9fa; 18 | text-decoration: none; 19 | } 20 | 21 | #book-search-input { 22 | margin-bottom: 0; 23 | } 24 | 25 | .menu ul.list li.divider { 26 | margin-top: 0; 27 | background: #e9ecef; 28 | } 29 | 30 | .menu .title:hover { 31 | background-color: #f8f9fa; 32 | } 33 | 34 | /** CARD **/ 35 | 36 | .card { 37 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 38 | 0 1px 5px 0 rgba(0, 0, 0, 0.12); 39 | border-radius: 0.125rem; 40 | border: 0; 41 | margin-top: 1px; 42 | } 43 | 44 | .card-header { 45 | background: none; 46 | } 47 | 48 | /** BUTTON **/ 49 | 50 | .btn { 51 | border-radius: 0.125rem; 52 | } 53 | 54 | /** NAV BAR **/ 55 | 56 | .nav { 57 | border: 0; 58 | } 59 | .nav-tabs > li > a { 60 | border: 0; 61 | border-bottom: 0.214rem solid transparent; 62 | color: rgba(0, 0, 0, 0.54); 63 | margin-right: 0; 64 | } 65 | .nav-tabs > li.active > a, 66 | .nav-tabs > li.active > a:focus, 67 | .nav-tabs > li.active > a:hover { 68 | color: rgba(0, 0, 0, 0.87); 69 | border-top: 0; 70 | border-left: 0; 71 | border-right: 0; 72 | border-bottom: 0.214rem solid transparent; 73 | border-color: #008cff; 74 | font-weight: bold; 75 | } 76 | .nav > li > a:focus, 77 | .nav > li > a:hover { 78 | background: none; 79 | } 80 | 81 | /** LIST **/ 82 | 83 | .list-group-item:first-child { 84 | border-top-left-radius: 0.125rem; 85 | border-top-right-radius: 0.125rem; 86 | } 87 | .list-group-item:last-child { 88 | border-bottom-left-radius: 0.125rem; 89 | border-bottom-right-radius: 0.125rem; 90 | } 91 | 92 | /** MISC **/ 93 | 94 | .modifier { 95 | border-radius: 0.125rem; 96 | } 97 | 98 | pre[class*='language-'] { 99 | border-radius: 0.125rem; 100 | } 101 | 102 | /** TABLE **/ 103 | 104 | .table-hover > tbody > tr:hover { 105 | background: rgba(0, 0, 0, 0.075); 106 | } 107 | 108 | table.params thead { 109 | background: none; 110 | } 111 | table.params thead td { 112 | color: rgba(0, 0, 0, 0.54); 113 | font-weight: bold; 114 | } 115 | 116 | .dark .menu .title:hover { 117 | background-color: #2d2d2d; 118 | } 119 | .dark .menu ul.list li a:hover, 120 | .dark .menu ul.list li.chapter .simple:hover { 121 | background-color: #2d2d2d; 122 | } 123 | .dark .nav-tabs > li:not(.active) > a { 124 | color: #fafafa; 125 | } 126 | .dark table.params thead { 127 | background: #484848; 128 | } 129 | .dark table.params thead td { 130 | color: #fafafa; 131 | } 132 | -------------------------------------------------------------------------------- /documentation/styles/original.css: -------------------------------------------------------------------------------- 1 | .navbar-default .navbar-brand, 2 | .menu ul.list li.title { 3 | font-weight: bold; 4 | color: #3c3c3c; 5 | padding-bottom: 5px; 6 | } 7 | 8 | .menu ul.list li a[data-type='chapter-link'], 9 | .menu ul.list li.chapter .simple { 10 | font-weight: bold; 11 | font-size: 14px; 12 | } 13 | 14 | .menu ul.list li a[href='./routes.html'] { 15 | border-bottom: none; 16 | } 17 | 18 | .menu ul.list > li:nth-child(2) { 19 | display: none; 20 | } 21 | 22 | .menu ul.list li.chapter ul.links { 23 | background: #fff; 24 | padding-left: 0; 25 | } 26 | 27 | .menu ul.list li.chapter ul.links li { 28 | border-bottom: 1px solid #ddd; 29 | padding-left: 20px; 30 | } 31 | 32 | .menu ul.list li.chapter ul.links li:last-child { 33 | border-bottom: none; 34 | } 35 | 36 | .menu ul.list li a.active { 37 | color: #337ab7; 38 | font-weight: bold; 39 | } 40 | 41 | #book-search-input { 42 | margin-bottom: 0; 43 | border-bottom: none; 44 | } 45 | .menu ul.list li.divider { 46 | margin: 0; 47 | } 48 | 49 | .dark .menu ul.list li.chapter ul.links { 50 | background: none; 51 | } 52 | -------------------------------------------------------------------------------- /documentation/styles/postmark.css: -------------------------------------------------------------------------------- 1 | .navbar-default { 2 | background: #ffde00; 3 | border: none; 4 | } 5 | 6 | .navbar-default .navbar-brand { 7 | color: #333; 8 | font-weight: bold; 9 | } 10 | 11 | .menu { 12 | background: #333; 13 | color: #fcfcfc; 14 | } 15 | 16 | .menu ul.list li a { 17 | color: #333; 18 | } 19 | 20 | .menu ul.list li.title { 21 | background: #ffde00; 22 | color: #333; 23 | padding-bottom: 5px; 24 | } 25 | 26 | .menu ul.list li:nth-child(2) { 27 | margin-top: 0; 28 | } 29 | 30 | .menu ul.list li.chapter a, 31 | .menu ul.list li.chapter .simple { 32 | color: white; 33 | text-decoration: none; 34 | } 35 | 36 | .menu ul.list li.chapter ul.links a { 37 | color: #949494; 38 | text-transform: none; 39 | padding-left: 35px; 40 | } 41 | 42 | .menu ul.list li.chapter ul.links a:hover, 43 | .menu ul.list li.chapter ul.links a.active { 44 | color: #ffde00; 45 | } 46 | 47 | .menu ul.list li.chapter ul.links { 48 | padding-left: 0; 49 | } 50 | 51 | .menu ul.list li.divider { 52 | background: rgba(255, 255, 255, 0.07); 53 | } 54 | 55 | #book-search-input input, 56 | #book-search-input input:focus, 57 | #book-search-input input:hover { 58 | color: #949494; 59 | } 60 | 61 | .copyright { 62 | color: #b3b3b3; 63 | background: #272525; 64 | } 65 | 66 | .content { 67 | background: #fcfcfc; 68 | } 69 | 70 | .content a { 71 | color: #007dcc; 72 | } 73 | 74 | .content a:visited { 75 | color: #0165a5; 76 | } 77 | 78 | .menu ul.list li:nth-last-child(2) { 79 | background: none; 80 | } 81 | 82 | .list-group-item:first-child, 83 | .list-group-item:last-child { 84 | border-radius: 0; 85 | } 86 | 87 | .menu ul.list li.title a { 88 | text-decoration: none; 89 | font-weight: bold; 90 | } 91 | 92 | .menu ul.list li.title a:hover { 93 | background: rgba(255, 255, 255, 0.1); 94 | } 95 | 96 | .breadcrumb > li + li:before { 97 | content: '»\00a0'; 98 | } 99 | 100 | .breadcrumb { 101 | padding-bottom: 15px; 102 | border-bottom: 1px solid #e1e4e5; 103 | } 104 | 105 | code { 106 | white-space: nowrap; 107 | max-width: 100%; 108 | background: #f5f5f5; 109 | padding: 2px 5px; 110 | color: #666666; 111 | overflow-x: auto; 112 | border-radius: 0; 113 | } 114 | 115 | pre { 116 | white-space: pre; 117 | margin: 0; 118 | padding: 12px 12px; 119 | font-size: 12px; 120 | line-height: 1.5; 121 | display: block; 122 | overflow: auto; 123 | color: #404040; 124 | background: #f3f3f3; 125 | } 126 | 127 | pre code.hljs { 128 | border: none; 129 | background: inherit; 130 | } 131 | 132 | /* 133 | Atom One Light by Daniel Gamage 134 | Original One Light Syntax theme from https://github.com/atom/one-light-syntax 135 | base: #fafafa 136 | mono-1: #383a42 137 | mono-2: #686b77 138 | mono-3: #a0a1a7 139 | hue-1: #0184bb 140 | hue-2: #4078f2 141 | hue-3: #a626a4 142 | hue-4: #50a14f 143 | hue-5: #e45649 144 | hue-5-2: #c91243 145 | hue-6: #986801 146 | hue-6-2: #c18401 147 | */ 148 | 149 | .hljs { 150 | display: block; 151 | overflow-x: auto; 152 | padding: 0.5em; 153 | color: #383a42; 154 | background: #fafafa; 155 | } 156 | 157 | .hljs-comment, 158 | .hljs-quote { 159 | color: #a0a1a7; 160 | font-style: italic; 161 | } 162 | 163 | .hljs-doctag, 164 | .hljs-keyword, 165 | .hljs-formula { 166 | color: #a626a4; 167 | } 168 | 169 | .hljs-section, 170 | .hljs-name, 171 | .hljs-selector-tag, 172 | .hljs-deletion, 173 | .hljs-subst { 174 | color: #e45649; 175 | } 176 | 177 | .hljs-literal { 178 | color: #0184bb; 179 | } 180 | 181 | .hljs-string, 182 | .hljs-regexp, 183 | .hljs-addition, 184 | .hljs-attribute, 185 | .hljs-meta-string { 186 | color: #50a14f; 187 | } 188 | 189 | .hljs-built_in, 190 | .hljs-class .hljs-title { 191 | color: #c18401; 192 | } 193 | 194 | .hljs-attr, 195 | .hljs-variable, 196 | .hljs-template-variable, 197 | .hljs-type, 198 | .hljs-selector-class, 199 | .hljs-selector-attr, 200 | .hljs-selector-pseudo, 201 | .hljs-number { 202 | color: #986801; 203 | } 204 | 205 | .hljs-symbol, 206 | .hljs-bullet, 207 | .hljs-link, 208 | .hljs-meta, 209 | .hljs-selector-id, 210 | .hljs-title { 211 | color: #4078f2; 212 | } 213 | 214 | .hljs-emphasis { 215 | font-style: italic; 216 | } 217 | 218 | .hljs-strong { 219 | font-weight: bold; 220 | } 221 | 222 | .hljs-link { 223 | text-decoration: underline; 224 | } 225 | 226 | .dark .content { 227 | background: none; 228 | } 229 | .dark code { 230 | background: none; 231 | color: #e09393; 232 | } 233 | .dark .menu ul.list li.chapter a.active { 234 | color: #ffde00; 235 | } 236 | .dark .menu { 237 | background: #272525; 238 | } 239 | -------------------------------------------------------------------------------- /documentation/styles/prism.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.24.0 2 | https://prismjs.com/download.html?#themes=prism-okaidia&languages=markup+css+clike+javascript+apacheconf+aspnet+bash+c+csharp+cpp+coffeescript+dart+docker+elm+git+go+graphql+handlebars+haskell+http+ignore+java+json+kotlin+less+markdown+markup-templating+nginx+php+powershell+ruby+rust+sass+scss+sql+swift+typescript+wasm+yaml&plugins=line-highlight+line-numbers+toolbar+copy-to-clipboard */ 3 | /** 4 | * okaidia theme for JavaScript, CSS and HTML 5 | * Loosely based on Monokai textmate theme by http://www.monokai.nl/ 6 | * @author ocodia 7 | */ 8 | 9 | code[class*='language-'], 10 | pre[class*='language-'] { 11 | color: #f8f8f2; 12 | background: none; 13 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 14 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 15 | font-size: 1em; 16 | text-align: left; 17 | white-space: pre; 18 | word-spacing: normal; 19 | word-break: normal; 20 | word-wrap: normal; 21 | line-height: 1.5; 22 | 23 | -moz-tab-size: 4; 24 | -o-tab-size: 4; 25 | tab-size: 4; 26 | 27 | -webkit-hyphens: none; 28 | -moz-hyphens: none; 29 | -ms-hyphens: none; 30 | hyphens: none; 31 | } 32 | 33 | /* Code blocks */ 34 | pre[class*='language-'] { 35 | padding: 1em; 36 | margin: 0.5em 0; 37 | overflow: auto; 38 | border-radius: 0.3em; 39 | } 40 | 41 | :not(pre) > code[class*='language-'], 42 | pre[class*='language-'] { 43 | background: #272822; 44 | } 45 | 46 | /* Inline code */ 47 | :not(pre) > code[class*='language-'] { 48 | padding: 0.1em; 49 | border-radius: 0.3em; 50 | white-space: normal; 51 | } 52 | 53 | .token.comment, 54 | .token.prolog, 55 | .token.doctype, 56 | .token.cdata { 57 | color: #8292a2; 58 | } 59 | 60 | .token.punctuation { 61 | color: #f8f8f2; 62 | } 63 | 64 | .token.namespace { 65 | opacity: 0.7; 66 | } 67 | 68 | .token.property, 69 | .token.tag, 70 | .token.constant, 71 | .token.symbol, 72 | .token.deleted { 73 | color: #f92672; 74 | } 75 | 76 | .token.boolean, 77 | .token.number { 78 | color: #ae81ff; 79 | } 80 | 81 | .token.selector, 82 | .token.attr-name, 83 | .token.string, 84 | .token.char, 85 | .token.builtin, 86 | .token.inserted { 87 | color: #a6e22e; 88 | } 89 | 90 | .token.operator, 91 | .token.entity, 92 | .token.url, 93 | .language-css .token.string, 94 | .style .token.string, 95 | .token.variable { 96 | color: #f8f8f2; 97 | } 98 | 99 | .token.atrule, 100 | .token.attr-value, 101 | .token.function, 102 | .token.class-name { 103 | color: #e6db74; 104 | } 105 | 106 | .token.keyword { 107 | color: #66d9ef; 108 | } 109 | 110 | .token.regex, 111 | .token.important { 112 | color: #fd971f; 113 | } 114 | 115 | .token.important, 116 | .token.bold { 117 | font-weight: bold; 118 | } 119 | .token.italic { 120 | font-style: italic; 121 | } 122 | 123 | .token.entity { 124 | cursor: help; 125 | } 126 | 127 | pre[data-line] { 128 | position: relative; 129 | padding: 1em 0 1em 3em; 130 | } 131 | 132 | .line-highlight { 133 | position: absolute; 134 | left: 0; 135 | right: 0; 136 | padding: inherit 0; 137 | margin-top: 1em; /* Same as .prism’s padding-top */ 138 | 139 | background: hsla(24, 20%, 50%, 0.08); 140 | background: linear-gradient(to right, hsla(24, 20%, 50%, 0.1) 70%, hsla(24, 20%, 50%, 0)); 141 | 142 | pointer-events: none; 143 | 144 | line-height: inherit; 145 | white-space: pre; 146 | } 147 | 148 | @media print { 149 | .line-highlight { 150 | /* 151 | * This will prevent browsers from replacing the background color with white. 152 | * It's necessary because the element is layered on top of the displayed code. 153 | */ 154 | -webkit-print-color-adjust: exact; 155 | color-adjust: exact; 156 | } 157 | } 158 | 159 | .line-highlight:before, 160 | .line-highlight[data-end]:after { 161 | content: attr(data-start); 162 | position: absolute; 163 | top: 0.4em; 164 | left: 0.6em; 165 | min-width: 1em; 166 | padding: 0 0.5em; 167 | background-color: hsla(24, 20%, 50%, 0.4); 168 | color: hsl(24, 20%, 95%); 169 | font: bold 65%/1.5 sans-serif; 170 | text-align: center; 171 | vertical-align: 0.3em; 172 | border-radius: 999px; 173 | text-shadow: none; 174 | box-shadow: 0 1px white; 175 | } 176 | 177 | .line-highlight[data-end]:after { 178 | content: attr(data-end); 179 | top: auto; 180 | bottom: 0.4em; 181 | } 182 | 183 | .line-numbers .line-highlight:before, 184 | .line-numbers .line-highlight:after { 185 | content: none; 186 | } 187 | 188 | pre[id].linkable-line-numbers span.line-numbers-rows { 189 | pointer-events: all; 190 | } 191 | pre[id].linkable-line-numbers span.line-numbers-rows > span:before { 192 | cursor: pointer; 193 | } 194 | pre[id].linkable-line-numbers span.line-numbers-rows > span:hover:before { 195 | background-color: rgba(128, 128, 128, 0.2); 196 | } 197 | 198 | pre[class*='language-'].line-numbers { 199 | position: relative; 200 | padding-left: 3.8em; 201 | counter-reset: linenumber; 202 | } 203 | 204 | pre[class*='language-'].line-numbers > code { 205 | position: relative; 206 | white-space: inherit; 207 | } 208 | 209 | .line-numbers .line-numbers-rows { 210 | position: absolute; 211 | pointer-events: none; 212 | top: 0; 213 | font-size: 100%; 214 | left: -3.8em; 215 | width: 3em; /* works for line-numbers below 1000 lines */ 216 | letter-spacing: -1px; 217 | border-right: 1px solid #999; 218 | 219 | -webkit-user-select: none; 220 | -moz-user-select: none; 221 | -ms-user-select: none; 222 | user-select: none; 223 | } 224 | 225 | .line-numbers-rows > span { 226 | display: block; 227 | counter-increment: linenumber; 228 | } 229 | 230 | .line-numbers-rows > span:before { 231 | content: counter(linenumber); 232 | color: #999; 233 | display: block; 234 | padding-right: 0.8em; 235 | text-align: right; 236 | } 237 | 238 | div.code-toolbar { 239 | position: relative; 240 | } 241 | 242 | div.code-toolbar > .toolbar { 243 | position: absolute; 244 | top: 0.3em; 245 | right: 0.2em; 246 | transition: opacity 0.3s ease-in-out; 247 | opacity: 0; 248 | } 249 | 250 | div.code-toolbar:hover > .toolbar { 251 | opacity: 1; 252 | } 253 | 254 | /* Separate line b/c rules are thrown out if selector is invalid. 255 | IE11 and old Edge versions don't support :focus-within. */ 256 | div.code-toolbar:focus-within > .toolbar { 257 | opacity: 1; 258 | } 259 | 260 | div.code-toolbar > .toolbar .toolbar-item { 261 | display: inline-block; 262 | } 263 | 264 | div.code-toolbar > .toolbar a { 265 | cursor: pointer; 266 | } 267 | 268 | div.code-toolbar > .toolbar button { 269 | background: none; 270 | border: 0; 271 | color: inherit; 272 | font: inherit; 273 | line-height: normal; 274 | overflow: visible; 275 | padding: 0; 276 | -webkit-user-select: none; /* for button */ 277 | -moz-user-select: none; 278 | -ms-user-select: none; 279 | } 280 | 281 | div.code-toolbar > .toolbar a, 282 | div.code-toolbar > .toolbar button, 283 | div.code-toolbar > .toolbar span { 284 | color: #bbb; 285 | font-size: 0.8em; 286 | padding: 0 0.5em; 287 | background: #f5f2f0; 288 | background: rgba(224, 224, 224, 0.2); 289 | box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.2); 290 | border-radius: 0.5em; 291 | } 292 | 293 | div.code-toolbar > .toolbar a:hover, 294 | div.code-toolbar > .toolbar a:focus, 295 | div.code-toolbar > .toolbar button:hover, 296 | div.code-toolbar > .toolbar button:focus, 297 | div.code-toolbar > .toolbar span:hover, 298 | div.code-toolbar > .toolbar span:focus { 299 | color: inherit; 300 | text-decoration: none; 301 | } 302 | -------------------------------------------------------------------------------- /documentation/styles/readthedocs.css: -------------------------------------------------------------------------------- 1 | .navbar-default { 2 | background: #2980b9; 3 | border: none; 4 | } 5 | 6 | .navbar-default .navbar-brand { 7 | color: #fcfcfc; 8 | } 9 | 10 | .menu { 11 | background: #343131; 12 | color: #fcfcfc; 13 | } 14 | 15 | .menu ul.list li a { 16 | color: #fcfcfc; 17 | } 18 | 19 | .menu ul.list li.title { 20 | background: #2980b9; 21 | padding-bottom: 5px; 22 | } 23 | 24 | .menu ul.list li:nth-child(2) { 25 | margin-top: 0; 26 | } 27 | 28 | .menu ul.list li.chapter a, 29 | .menu ul.list li.chapter .simple { 30 | color: #555; 31 | text-transform: uppercase; 32 | text-decoration: none; 33 | } 34 | 35 | .menu ul.list li.chapter ul.links a { 36 | color: #b3b3b3; 37 | text-transform: none; 38 | padding-left: 35px; 39 | } 40 | 41 | .menu ul.list li.chapter ul.links a:hover { 42 | background: #4e4a4a; 43 | } 44 | 45 | .menu ul.list li.chapter a.active, 46 | .menu ul.list li.chapter ul.links a.active { 47 | color: #0099e5; 48 | } 49 | 50 | .menu ul.list li.chapter ul.links { 51 | padding-left: 0; 52 | } 53 | 54 | .menu ul.list li.divider { 55 | background: rgba(255, 255, 255, 0.07); 56 | } 57 | 58 | #book-search-input input, 59 | #book-search-input input:focus, 60 | #book-search-input input:hover { 61 | color: #949494; 62 | } 63 | 64 | .copyright { 65 | color: #b3b3b3; 66 | background: #272525; 67 | } 68 | 69 | .content { 70 | background: #fcfcfc; 71 | } 72 | 73 | .content a { 74 | color: #2980b9; 75 | } 76 | 77 | .content a:hover { 78 | color: #3091d1; 79 | } 80 | 81 | .content a:visited { 82 | color: #9b59b6; 83 | } 84 | 85 | .menu ul.list li:nth-last-child(2) { 86 | background: none; 87 | } 88 | 89 | code { 90 | white-space: nowrap; 91 | max-width: 100%; 92 | background: #fff; 93 | padding: 2px 5px; 94 | color: #e74c3c; 95 | overflow-x: auto; 96 | border-radius: 0; 97 | } 98 | 99 | pre { 100 | white-space: pre; 101 | margin: 0; 102 | padding: 12px 12px; 103 | font-size: 12px; 104 | line-height: 1.5; 105 | display: block; 106 | overflow: auto; 107 | color: #404040; 108 | background: rgba(238, 238, 238, 0.35); 109 | } 110 | 111 | .dark .content { 112 | background: none; 113 | } 114 | .dark code { 115 | background: none; 116 | color: #e09393; 117 | } 118 | -------------------------------------------------------------------------------- /documentation/styles/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, 7 | body, 8 | div, 9 | span, 10 | applet, 11 | object, 12 | iframe, 13 | h1, 14 | h2, 15 | h3, 16 | h4, 17 | h5, 18 | h6, 19 | p, 20 | blockquote, 21 | pre, 22 | a, 23 | abbr, 24 | acronym, 25 | address, 26 | big, 27 | cite, 28 | code, 29 | del, 30 | dfn, 31 | em, 32 | img, 33 | ins, 34 | kbd, 35 | q, 36 | s, 37 | samp, 38 | small, 39 | strike, 40 | strong, 41 | sub, 42 | sup, 43 | tt, 44 | var, 45 | b, 46 | u, 47 | i, 48 | center, 49 | dl, 50 | dt, 51 | dd, 52 | ol, 53 | ul, 54 | li, 55 | fieldset, 56 | form, 57 | label, 58 | legend, 59 | table, 60 | caption, 61 | tbody, 62 | tfoot, 63 | thead, 64 | tr, 65 | th, 66 | td, 67 | article, 68 | aside, 69 | canvas, 70 | details, 71 | embed, 72 | figure, 73 | figcaption, 74 | footer, 75 | header, 76 | hgroup, 77 | menu, 78 | nav, 79 | output, 80 | ruby, 81 | section, 82 | summary, 83 | time, 84 | mark, 85 | audio, 86 | video { 87 | margin: 0; 88 | padding: 0; 89 | border: 0; 90 | font: inherit; 91 | font-size: 100%; 92 | vertical-align: baseline; 93 | } 94 | /* HTML5 display-role reset for older browsers */ 95 | article, 96 | aside, 97 | details, 98 | figcaption, 99 | figure, 100 | footer, 101 | header, 102 | hgroup, 103 | menu, 104 | nav, 105 | section { 106 | display: block; 107 | } 108 | body { 109 | line-height: 1; 110 | } 111 | ol, 112 | ul { 113 | list-style: none; 114 | } 115 | blockquote, 116 | q { 117 | quotes: none; 118 | } 119 | blockquote:before, 120 | blockquote:after, 121 | q:before, 122 | q:after { 123 | content: ''; 124 | content: none; 125 | } 126 | table { 127 | border-collapse: collapse; 128 | border-spacing: 0; 129 | } 130 | -------------------------------------------------------------------------------- /documentation/styles/stripe.css: -------------------------------------------------------------------------------- 1 | .navbar-default .navbar-brand { 2 | color: #0099e5; 3 | } 4 | 5 | .menu ul.list li a[data-type='chapter-link'], 6 | .menu ul.list li.chapter .simple { 7 | color: #939da3; 8 | text-transform: uppercase; 9 | } 10 | 11 | .content h1, 12 | .content h2, 13 | .content h3, 14 | .content h4, 15 | .content h5 { 16 | color: #292e31; 17 | font-weight: normal; 18 | } 19 | 20 | .content { 21 | color: #4c555a; 22 | } 23 | 24 | .menu ul.list li.title { 25 | padding: 5px 0; 26 | } 27 | 28 | a { 29 | color: #0099e5; 30 | text-decoration: none; 31 | } 32 | a:hover { 33 | color: #292e31; 34 | text-decoration: none; 35 | } 36 | 37 | .menu ul.list li:nth-child(2) { 38 | margin-top: 0; 39 | } 40 | 41 | .menu ul.list li.title a, 42 | .navbar a { 43 | color: #0099e5; 44 | text-decoration: none; 45 | font-size: 16px; 46 | } 47 | 48 | .menu ul.list li a.active { 49 | color: #0099e5; 50 | } 51 | 52 | code { 53 | box-sizing: border-box; 54 | display: inline-block; 55 | padding: 0 5px; 56 | background: #fafcfc; 57 | border-radius: 4px; 58 | color: #b93d6a; 59 | font-size: 13px; 60 | line-height: 20px; 61 | } 62 | 63 | pre { 64 | margin: 0; 65 | padding: 12px 12px; 66 | background: #272b2d; 67 | border-radius: 5px; 68 | font-size: 13px; 69 | line-height: 1.5em; 70 | font-weight: 500; 71 | } 72 | 73 | .dark body { 74 | color: #fafafa; 75 | } 76 | .dark .content h1, 77 | .dark .content h2, 78 | .dark .content h3, 79 | .dark .content h4, 80 | .dark .content h5 { 81 | color: #fafafa; 82 | } 83 | 84 | .dark code { 85 | background: none; 86 | } 87 | 88 | .dark .content { 89 | color: #fafafa; 90 | } 91 | 92 | .dark .menu ul.list li a[data-type='chapter-link'], 93 | .dark .menu ul.list li.chapter .simple { 94 | color: #fafafa; 95 | } 96 | 97 | .dark .menu ul.list li.title a { 98 | color: #fafafa; 99 | } 100 | 101 | .dark .menu ul.list li a { 102 | color: #fafafa; 103 | } 104 | .dark .menu ul.list li a.active { 105 | color: #7fc9ff; 106 | } 107 | -------------------------------------------------------------------------------- /documentation/styles/style.css: -------------------------------------------------------------------------------- 1 | @import "./reset.css"; 2 | @import "./bootstrap.min.css"; 3 | @import "./bootstrap-card.css"; 4 | @import "./prism.css"; 5 | @import "./ionicons.min.css"; 6 | @import "./compodoc.css"; 7 | @import "./tablesort.css"; 8 | -------------------------------------------------------------------------------- /documentation/styles/tablesort.css: -------------------------------------------------------------------------------- 1 | th[role=columnheader]:not(.no-sort) { 2 | cursor: pointer; 3 | } 4 | 5 | th[role=columnheader]:not(.no-sort):after { 6 | content: ''; 7 | float: right; 8 | margin-top: 7px; 9 | border-width: 0 4px 4px; 10 | border-style: solid; 11 | border-color: #404040 transparent; 12 | visibility: visible; 13 | opacity: 1; 14 | -ms-user-select: none; 15 | -webkit-user-select: none; 16 | -moz-user-select: none; 17 | user-select: none; 18 | } 19 | 20 | th[aria-sort=ascending]:not(.no-sort):after { 21 | border-bottom: none; 22 | border-width: 4px 4px 0; 23 | } 24 | 25 | th[aria-sort]:not(.no-sort):after { 26 | visibility: visible; 27 | opacity: 0.4; 28 | } 29 | 30 | th[role=columnheader]:not(.no-sort):hover:after { 31 | visibility: visible; 32 | opacity: 1; 33 | } 34 | -------------------------------------------------------------------------------- /documentation/styles/vagrant.css: -------------------------------------------------------------------------------- 1 | .navbar-default .navbar-brand { 2 | background: white; 3 | color: #8d9ba8; 4 | } 5 | 6 | .menu .list { 7 | background: #0c5593; 8 | } 9 | 10 | .menu .chapter { 11 | padding: 0 20px; 12 | } 13 | 14 | .menu ul.list li a[data-type='chapter-link'], 15 | .menu ul.list li.chapter .simple { 16 | color: white; 17 | text-transform: uppercase; 18 | border-bottom: 1px solid rgba(255, 255, 255, 0.4); 19 | } 20 | 21 | .content h1, 22 | .content h2, 23 | .content h3, 24 | .content h4, 25 | .content h5 { 26 | color: #292e31; 27 | font-weight: normal; 28 | } 29 | 30 | .content { 31 | color: #4c555a; 32 | } 33 | 34 | a { 35 | color: #0094bf; 36 | text-decoration: underline; 37 | } 38 | a:hover { 39 | color: #f1362f; 40 | } 41 | 42 | .menu ul.list li.title { 43 | background: white; 44 | padding-bottom: 5px; 45 | } 46 | 47 | .menu ul.list li:nth-child(2) { 48 | margin-top: 0; 49 | } 50 | 51 | .menu ul.list li:nth-last-child(2) { 52 | background: none; 53 | } 54 | 55 | .menu ul.list li.title a { 56 | padding: 10px 15px; 57 | } 58 | 59 | .menu ul.list li.title a, 60 | .navbar a { 61 | color: #8d9ba8; 62 | text-decoration: none; 63 | font-size: 16px; 64 | font-weight: 300; 65 | } 66 | 67 | .menu ul.list li a { 68 | color: white; 69 | padding: 10px; 70 | font-weight: 300; 71 | text-decoration: none; 72 | } 73 | .menu ul.list li a.active { 74 | color: white; 75 | font-weight: bold; 76 | } 77 | 78 | .copyright { 79 | color: white; 80 | background: #000; 81 | } 82 | 83 | code { 84 | box-sizing: border-box; 85 | display: inline-block; 86 | padding: 0 5px; 87 | background: rgba(0, 148, 191, 0.1); 88 | border-radius: 3px; 89 | color: #0094bf; 90 | font-size: 13px; 91 | line-height: 20px; 92 | } 93 | 94 | pre { 95 | margin: 0; 96 | padding: 12px 12px; 97 | background: rgba(238, 238, 238, 0.35); 98 | border-radius: 3px; 99 | font-size: 13px; 100 | line-height: 1.5em; 101 | font-weight: 500; 102 | } 103 | 104 | .dark body { 105 | color: #fafafa; 106 | } 107 | .dark .content h1, 108 | .dark .content h2, 109 | .dark .content h3, 110 | .dark .content h4, 111 | .dark .content h5 { 112 | color: #fafafa; 113 | } 114 | 115 | .dark code { 116 | background: none; 117 | } 118 | 119 | .dark .content { 120 | color: #fafafa; 121 | } 122 | 123 | .dark .menu ul.list li.title a, 124 | .dark .navbar a { 125 | color: #8d9ba8; 126 | } 127 | 128 | .dark .menu ul.list li a { 129 | color: #fafafa; 130 | } 131 | -------------------------------------------------------------------------------- /input.example.log: -------------------------------------------------------------------------------- 1 | 2044-08-09T02:12:51.253Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service is started"} 2 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request the user information","userId": 10} 3 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request user orders list","userId": 10} 4 | 2021-08-09T02:12:51.255Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"Service is started"} 5 | 2021-08-09T02:12:51.257Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"About to request the user information","userId": 16} 6 | 2021-08-09T02:12:51.257Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"User information is gathered","user":{"id":10,"name":"Alice"}} 7 | 2021-08-09T02:12:51.258Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"About to request user orders list","userId":16} 8 | 2021-08-09T02:12:51.259Z - error - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Cannot find user orders list","code": 404,"err":"Not found"} 9 | 2021-08-09T02:12:51.259Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user": {"id": 16, "name": "Michael"}} 10 | 2021-08-09T02:12:51.262Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user":{"id":16,"orders":[{"id":472,"items":{"id":7,"price":7.12}}]}} 11 | 2021-08-09T02:12:51.264Z - warn - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service finished with error","code":404,"err":"Cannot find user orders list"} 12 | 2021-08-09T02:12:51.265Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"Service is successfully finished"} 13 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | roots: ['./'], 5 | transform: { '\\.ts$': ['ts-jest'] }, 6 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec|e2e-spec))\\.tsx?$', 7 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 8 | globals: { 9 | 'ts-jest': { 10 | tsconfig: { 11 | // allow js in typescript 12 | allowJs: true, 13 | }, 14 | }, 15 | }, 16 | coverageProvider: 'v8', 17 | collectCoverageFrom: [ 18 | 'src/**/*.ts', 19 | '!src/main.ts', 20 | '!src/**/*.config.ts', 21 | '!src/application/controllers/*', 22 | '!src/application/interceptors/*', 23 | '!src/domain/entities/**', 24 | '!src/domain/interfaces/*', 25 | '!src/domain/modules/*', 26 | '!src/infrastructure/**', 27 | ], 28 | coverageThreshold: { 29 | global: { 30 | lines: 70, 31 | statements: 70, 32 | }, 33 | }, 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src" 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parser", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "", 6 | "private": true, 7 | "license": "UNLICENSED", 8 | "scripts": { 9 | "prebuild": "rimraf dist", 10 | "build": "nest build", 11 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 12 | "start": "nest start", 13 | "start:dev": "nest start --watch", 14 | "start:debug": "nest start --debug --watch", 15 | "start:prod": "node dist/main", 16 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 17 | "test": "jest", 18 | "test:watch": "jest --watch", 19 | "test:cov": "jest --coverage", 20 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 21 | "test:e2e": "jest --config ./test/jest-e2e.json", 22 | "doc": "./node_modules/.bin/compodoc -p tsconfig.compodoc.json -w -s -r 7000 --theme 'Stripe'" 23 | }, 24 | "dependencies": { 25 | "@compodoc/compodoc": "^1.1.19", 26 | "@nestjs/common": "^8.0.0", 27 | "@nestjs/core": "^8.0.0", 28 | "@nestjs/platform-express": "^8.0.0", 29 | "class-transformer": "^0.5.1", 30 | "class-validator": "^0.13.2", 31 | "@types/faker": "^5.1.4", 32 | "nest-winston": "^1.6.2", 33 | "nestjs-command": "^3.1.1", 34 | "reflect-metadata": "^0.1.13", 35 | "rimraf": "^3.0.2", 36 | "rxjs": "^7.2.0", 37 | "faker": "^5.1.0", 38 | "winston": "^3.7.2", 39 | "yargs": "^17.5.1" 40 | }, 41 | "devDependencies": { 42 | "@nestjs/cli": "^8.0.0", 43 | "@nestjs/schematics": "^8.0.0", 44 | "@nestjs/testing": "^8.0.0", 45 | "@types/express": "^4.17.13", 46 | "@types/jest": "27.5.0", 47 | "@types/node": "^16.0.0", 48 | "@types/supertest": "^2.0.11", 49 | "@types/yargs": "^17.0.10", 50 | "@typescript-eslint/eslint-plugin": "^5.0.0", 51 | "@typescript-eslint/parser": "^5.0.0", 52 | "eslint": "^8.0.1", 53 | "eslint-config-prettier": "^8.3.0", 54 | "eslint-plugin-prettier": "^4.0.0", 55 | "jest": "28.0.3", 56 | "prettier": "^2.3.2", 57 | "source-map-support": "^0.5.20", 58 | "supertest": "^6.1.3", 59 | "ts-jest": "28.0.1", 60 | "ts-loader": "^9.2.3", 61 | "ts-node": "^10.0.0", 62 | "tsconfig-paths": "4.0.0", 63 | "typescript": "^4.3.5" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /scripts/runner.sh: -------------------------------------------------------------------------------- 1 | npm install 2 | npm run build 3 | npm test 4 | npm run lint 5 | echo 'Done! 😍' 6 | echo 'now you can use the application by following commmand' 7 | echo 'node dist/cli.js -h' -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { CommandModule } from 'nestjs-command'; 3 | import { ParserModule } from '../parser/parser.module'; 4 | 5 | @Module({ 6 | imports: [CommandModule, ParserModule], 7 | providers: [], 8 | }) 9 | export class AppModule {} 10 | -------------------------------------------------------------------------------- /src/cli.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { CommandModule, CommandService } from 'nestjs-command'; 3 | import { AppModule } from './app/app.module'; 4 | 5 | /** 6 | * Main application entry point 7 | */ 8 | async function bootstrap() { 9 | const app = await NestFactory.createApplicationContext(AppModule, { 10 | logger: ['error'], 11 | }); 12 | 13 | try { 14 | await app.select(CommandModule).get(CommandService).exec(); 15 | await app.close(); 16 | } catch (error) { 17 | console.error(error); 18 | await app.close(); 19 | process.exit(1); 20 | } 21 | } 22 | /** 23 | * Bootstraps the application 24 | */ 25 | bootstrap(); 26 | -------------------------------------------------------------------------------- /src/parser/command/parser.command.ts: -------------------------------------------------------------------------------- 1 | import { Command, Option } from 'nestjs-command'; 2 | import { Injectable } from '@nestjs/common'; 3 | import { ParserService } from '../service/parser.service'; 4 | import { ParserCommandDTO } from '../dtos/parser-command-dto'; 5 | import { validateDTO } from '../common'; 6 | 7 | /** 8 | * Log parser command 9 | */ 10 | @Injectable() 11 | export class ParserCommand { 12 | /** 13 | * Constructs the Log parser command class 14 | * @param parserService Injection of parser service 15 | */ 16 | constructor(private readonly parserService: ParserService) {} 17 | 18 | /** 19 | * Parser command that takes the input log file, parses and writes the result to the output file as ajson content. 20 | * @param input address of the input file 21 | * @param output address of the output file 22 | * @param log_level log level to be filtered 23 | * @returns LogModel[] 24 | */ 25 | @Command({ 26 | command: '*', 27 | describe: 'parses a log file', 28 | }) 29 | async parse( 30 | @Option({ 31 | name: 'input', 32 | describe: 'input log file (ex: "input.log")', 33 | type: 'string', 34 | alias: 'i', 35 | required: true, 36 | }) 37 | input: string, 38 | @Option({ 39 | name: 'output', 40 | describe: 'output log file (ex: "output.log")', 41 | type: 'string', 42 | alias: 'o', 43 | default: 'output.log', 44 | required: true, 45 | }) 46 | output: string, 47 | @Option({ 48 | name: 'log-level', 49 | describe: 'log-level (ex: "error,[error,debug,warn,info]")', 50 | type: 'string', 51 | alias: 'l', 52 | default: 'error', 53 | required: false, 54 | }) 55 | log_level: string, 56 | ) { 57 | try { 58 | const logFilter = log_level.split(','); 59 | const command = new ParserCommandDTO({ 60 | input: input, 61 | output: output, 62 | logLevel: logFilter, 63 | }); 64 | await validateDTO(command); 65 | return this.parserService 66 | .parse(command) 67 | .then(() => { 68 | console.log(`Success 😀. output is written in ${output}`); 69 | }) 70 | .catch((error) => { 71 | console.error(error); 72 | }); 73 | } catch (error) { 74 | console.log(error); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/parser/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './utils'; 2 | -------------------------------------------------------------------------------- /src/parser/common/utils.ts: -------------------------------------------------------------------------------- 1 | import { validate } from 'class-validator'; 2 | 3 | /** 4 | * validates dto and returns bad request if it is wrong 5 | * @param dto dto 6 | * @param httpResponseGenerator http response service 7 | */ 8 | export async function validateDTO(dto: any): Promise { 9 | const errors = await validate(dto); 10 | 11 | if (errors.length) throw new Error(`InvalidArgumentExcpetion ${errors}`); 12 | 13 | return dto; 14 | } 15 | -------------------------------------------------------------------------------- /src/parser/dtos/parser-command-dto.ts: -------------------------------------------------------------------------------- 1 | import { 2 | IsDefined, 3 | IsEnum, 4 | IsNotEmpty, 5 | IsOptional, 6 | IsString, 7 | } from 'class-validator'; 8 | import { LogLevel } from '../enum'; 9 | 10 | /** 11 | * list of allowed properties 12 | */ 13 | const allowedProperties = ['input', 'output', 'logLevel']; 14 | /** 15 | * Log parser command DTO 16 | */ 17 | export class ParserCommandDTO { 18 | /** 19 | * addres of the log file input 20 | */ 21 | @IsNotEmpty() 22 | @IsDefined() 23 | @IsString() 24 | input: string; 25 | //........................................................................................................... 26 | /** 27 | * address of the output log file 28 | */ 29 | @IsNotEmpty() 30 | @IsDefined() 31 | @IsString() 32 | output: string; 33 | //........................................................................................................... 34 | /** 35 | * list of log levels to be filtered by the parser 36 | */ 37 | @IsOptional() 38 | @IsEnum(LogLevel, { each: true }) 39 | logLevel: LogLevel[]; 40 | //........................................................................................................... 41 | /** 42 | * Constructs the DTO based on given properties 43 | * @param properties list of passed properties to the DTO 44 | */ 45 | constructor(properties: any = {}) { 46 | Object.keys(properties).forEach((key: string) => { 47 | if (allowedProperties.includes(key)) 48 | this[key as keyof this] = properties[key]; 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/parser/enum/index.ts: -------------------------------------------------------------------------------- 1 | export * from './log-level.enum'; 2 | -------------------------------------------------------------------------------- /src/parser/enum/log-level.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An enum that represents the log levels the parser understands 3 | */ 4 | export enum LogLevel { 5 | /** 6 | * Error log level 7 | */ 8 | ERROR = 'error', 9 | /** 10 | * Info log level 11 | */ 12 | INFO = 'info', 13 | /** 14 | * Warning log level 15 | */ 16 | WARN = 'warn', 17 | /** 18 | * Debug log level 19 | */ 20 | DEBUG = 'debug', 21 | } 22 | -------------------------------------------------------------------------------- /src/parser/helper/file-helper.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, NotAcceptableException, Logger } from '@nestjs/common'; 2 | import * as fs from 'fs'; 3 | import * as rd from 'readline'; 4 | import { Observable, of } from 'rxjs'; 5 | /** 6 | * File helper class 7 | */ 8 | @Injectable() 9 | export class FileHelper { 10 | //======================================================================================================================================================================= 11 | /** 12 | * Reads the input log file 13 | * @param path Address of the file to be red 14 | * @param filter Log level filter (An array of log levels) 15 | * @returns Promise>> 16 | */ 17 | async readLogFile( 18 | path: string, 19 | filter: string[], 20 | ): Promise>> { 21 | return new Promise((resolve, reject) => { 22 | try { 23 | const reader = rd.createInterface(fs.createReadStream(path)); 24 | const data: Array = []; 25 | reader.on('line', async (line: string) => { 26 | try { 27 | const log = await this.parsLog(line, filter); 28 | if (log) data.push(log); 29 | } catch (error) { 30 | Logger.warn(`Illigal format on line ${line}`); 31 | } 32 | }); 33 | reader.on('close', () => { 34 | resolve(of(data)); 35 | }); 36 | } catch (error) { 37 | Logger.error(`file not readable or it does not exists`); 38 | reject(error); 39 | } 40 | }); 41 | } 42 | //======================================================================================================================================================================= 43 | /** 44 | * Writes the given data (Parsed log json array) to the output log file 45 | * @param path address of the out put parsed log file 46 | * @param data data to be written inside the output log file 47 | * @returns Promise 48 | */ 49 | async writeLogFile(path, data: T[]): Promise { 50 | return new Promise(function (resolve, reject) { 51 | fs.writeFile(path, JSON.stringify(data, null, 2), function (err) { 52 | if (err) reject(err); 53 | else resolve(data); 54 | }); 55 | }); 56 | } 57 | //======================================================================================================================================================================= 58 | /** 59 | * parses a given log information according to the log level (it uses different regex patterns to find desired parts of the log info) 60 | * @param log log to be parsed 61 | * @param filter Log level filter (An array of log levels) 62 | * @returns Promise 63 | */ 64 | async parsLog(log: string, filter: string[]): Promise { 65 | try { 66 | const log_level: string = log 67 | .match('\\s-\\s\\w+\\s-\\s')[0] 68 | .replace(/\s-\s/g, ''); 69 | if (!filter.includes(log_level) && filter.length > 0) return; 70 | const time_stamp = new Date( 71 | log.match( 72 | '[0-9]{1,4}-[0-9]{1,2}-[0-9]{1,2}[A-Z][0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}.[0-9]{1,3}[A-Z]', 73 | )?.[0], 74 | ).getTime(); 75 | const log_info = JSON.parse(log.match('{(?:)(.*)}')[0]); 76 | const transaction_id = log_info.transactionId; 77 | const err = log_info.details; 78 | return { 79 | timestamp: time_stamp, 80 | logLevel: log_level, 81 | transactionId: transaction_id, 82 | err: err, 83 | }; 84 | } catch (error) { 85 | throw new NotAcceptableException(error); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/parser/helper/index.ts: -------------------------------------------------------------------------------- 1 | export * from './file-helper'; 2 | -------------------------------------------------------------------------------- /src/parser/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './log.model'; 2 | -------------------------------------------------------------------------------- /src/parser/model/log.model.ts: -------------------------------------------------------------------------------- 1 | import { LogLevel } from '../enum'; 2 | /** 3 | * Log model (We generate the parsed log json objects based on this model) 4 | */ 5 | export interface LogModel { 6 | /** 7 | * Timestamp of the log generated 8 | */ 9 | timeStamp: Date; 10 | /** 11 | * level of the log (error,debug,warn,info) 12 | */ 13 | logLevel: LogLevel; 14 | /** 15 | * transaction id of the log 16 | */ 17 | transactionId: string; 18 | /** 19 | * error message of the log 20 | */ 21 | err: string; 22 | } 23 | -------------------------------------------------------------------------------- /src/parser/parser.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ParserCommand } from './command/parser.command'; 3 | import { FileHelper } from './helper'; 4 | import { ParserService } from './service/parser.service'; 5 | 6 | /** 7 | * Parser module 8 | */ 9 | @Module({ 10 | imports: [], 11 | providers: [ 12 | ParserCommand, 13 | ParserService, 14 | { 15 | provide: 'FILE_HELPER', 16 | useClass: FileHelper, 17 | }, 18 | ], 19 | }) 20 | export class ParserModule {} 21 | -------------------------------------------------------------------------------- /src/parser/service/parser.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable, NotAcceptableException } from '@nestjs/common'; 2 | import { FileHelper } from '../helper'; 3 | import { take } from 'rxjs'; 4 | import { LogModel } from '../model'; 5 | import { ParserCommandDTO } from '../dtos/parser-command-dto'; 6 | 7 | /** 8 | * Log parser service 9 | */ 10 | @Injectable() 11 | export class ParserService { 12 | /** 13 | *Constructs the log parser service 14 | * @param file_helper file helper injection (useful to work with the log files) represented as a single tone class 15 | */ 16 | constructor( 17 | @Inject('FILE_HELPER') private readonly file_helper: FileHelper, 18 | ) {} 19 | //============================================================================================================== 20 | /** 21 | * Parses the input log file based on the provided commands 22 | * @param command Command entered by the user (Comming from Command class) 23 | * @returns Promise 24 | */ 25 | async parse(command: ParserCommandDTO): Promise { 26 | return new Promise(async (resolve, reject) => { 27 | try { 28 | ( 29 | await this.file_helper.readLogFile( 30 | command.input, 31 | command.logLevel, 32 | ) 33 | ) 34 | .pipe(take(1)) 35 | .subscribe(async (data: any) => { 36 | await this.file_helper.writeLogFile(command.output, data); 37 | resolve(data); 38 | }); 39 | } catch (error) { 40 | reject(error); 41 | } 42 | }).catch((error) => { 43 | throw new NotAcceptableException(error); 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/parser/service/test.log: -------------------------------------------------------------------------------- 1 | 2044-08-09T02:12:51.253Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service is started"} 2 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request the user information","userId": 10} 3 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request user orders list","userId": 10} 4 | 2021-08-09T02:12:51.255Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"Service is started"} 5 | 2021-08-09T02:12:51.257Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"About to request the user information","userId": 16} 6 | 2021-08-09T02:12:51.257Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"User information is gathered","user":{"id":10,"name":"Alice"}} 7 | 2021-08-09T02:12:51.258Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"About to request user orders list","userId":16} 8 | 2021-08-09T02:12:51.259Z - error - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Cannot find user orders list","code": 404,"err":"Not found"} 9 | 2021-08-09T02:12:51.259Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user": {"id": 16, "name": "Michael"}} 10 | 2021-08-09T02:12:51.262Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user":{"id":16,"orders":[{"id":472,"items":{"id":7,"price":7.12}}]}} 11 | 2021-08-09T02:12:51.264Z - warn - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service finished with error","code":404,"err":"Cannot find user orders list"} 12 | 2021-08-09T02:12:51.265Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"Service is successfully finished"} 13 | -------------------------------------------------------------------------------- /test/integration-tests/factories/index.ts: -------------------------------------------------------------------------------- 1 | export * from './parser-command.factory'; 2 | -------------------------------------------------------------------------------- /test/integration-tests/factories/parser-command.factory.ts: -------------------------------------------------------------------------------- 1 | import { datatype } from 'faker'; 2 | import * as path from 'path'; 3 | export const FIXTURE_BASE_PATH = path.resolve(__dirname, '../fixtures'); 4 | //===================================================================================== 5 | export const PARSE_COMMAND_INTEGRATION_TEST_CASE_1 = { 6 | data: { 7 | comman: '*', 8 | args: { 9 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 10 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 11 | 'log-level': 'debug', 12 | }, 13 | }, 14 | expectation: { 15 | should: 'should write parssed logs to the file', 16 | }, 17 | }; 18 | //===================================================================================== 19 | export const PARSE_COMMAND_INTEGRATION_TEST_CASE_2 = { 20 | data: { 21 | comman: '*', 22 | args: { 23 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 24 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 25 | 'log-level': 'error', 26 | }, 27 | }, 28 | expectation: { 29 | should: 'should write parssed logs to the file', 30 | }, 31 | }; 32 | //===================================================================================== 33 | export const PARSE_COMMAND_INTEGRATION_TEST_CASE_3 = { 34 | data: { 35 | comman: '*', 36 | args: { 37 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 38 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 39 | 'log-level': datatype.string(10), 40 | }, 41 | }, 42 | expectation: { 43 | should: 'should write parssed logs to the file', 44 | }, 45 | }; 46 | -------------------------------------------------------------------------------- /test/integration-tests/fixtures/fixture-input.log: -------------------------------------------------------------------------------- 1 | 2044-08-09T02:12:51.253Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service is started"} 2 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request the user information","userId": 10} 3 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request user orders list","userId": 10} 4 | 2021-08-09T02:12:51.255Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"Service is started"} 5 | 2021-08-09T02:12:51.257Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"About to request the user information","userId": 16} 6 | 2021-08-09T02:12:51.257Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"User information is gathered","user":{"id":10,"name":"Alice"}} 7 | 2021-08-09T02:12:51.258Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"About to request user orders list","userId":16} 8 | 2021-08-09T02:12:51.259Z - error - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Cannot find user orders list","code": 404,"err":"Not found"} 9 | 2021-08-09T02:12:51.259Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user": {"id": 16, "name": "Michael"}} 10 | 2021-08-09T02:12:51.262Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user":{"id":16,"orders":[{"id":472,"items":{"id":7,"price":7.12}}]}} 11 | 2021-08-09T02:12:51.264Z - warn - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service finished with error","code":404,"err":"Cannot find user orders list"} 12 | 2021-08-09T02:12:51.265Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"Service is successfully finished"} 13 | -------------------------------------------------------------------------------- /test/integration-tests/parser-command.spec.ts: -------------------------------------------------------------------------------- 1 | import { CommandModule, CommandModuleTest } from 'nestjs-command'; 2 | import { AppModule } from '../../src/app/app.module'; 3 | import { Test } from '@nestjs/testing'; 4 | import { 5 | FIXTURE_BASE_PATH, 6 | PARSE_COMMAND_INTEGRATION_TEST_CASE_1, 7 | PARSE_COMMAND_INTEGRATION_TEST_CASE_2, 8 | PARSE_COMMAND_INTEGRATION_TEST_CASE_3, 9 | } from './factories'; 10 | import * as fs from 'fs'; 11 | describe('AppModule', () => { 12 | let commandModule: CommandModuleTest; 13 | let app; 14 | async function readFile(path: string): Promise { 15 | return new Promise(function (resolve, reject) { 16 | fs.readFile(path, 'utf-8', (err, data) => { 17 | if (err) { 18 | reject(err); 19 | } else { 20 | resolve(data); 21 | } 22 | }); 23 | }); 24 | } 25 | 26 | beforeEach(async () => { 27 | const moduleFixture = await Test.createTestingModule({ 28 | imports: [AppModule], 29 | }).compile(); 30 | 31 | app = moduleFixture.createNestApplication(); 32 | await app.init(); 33 | commandModule = new CommandModuleTest(app.select(CommandModule)); 34 | }); 35 | //=========================================================================================================== 36 | it(PARSE_COMMAND_INTEGRATION_TEST_CASE_1.expectation.should, async () => { 37 | await commandModule.execute( 38 | PARSE_COMMAND_INTEGRATION_TEST_CASE_1.data.comman, 39 | PARSE_COMMAND_INTEGRATION_TEST_CASE_1.data.args, 40 | ); 41 | const result = await readFile(FIXTURE_BASE_PATH + '/fixture-output.log'); 42 | expect(JSON.parse(result).length).toBeGreaterThan(0); 43 | }); 44 | //.......................................................................................................... 45 | it(PARSE_COMMAND_INTEGRATION_TEST_CASE_2.expectation.should, async () => { 46 | await commandModule.execute( 47 | PARSE_COMMAND_INTEGRATION_TEST_CASE_2.data.comman, 48 | PARSE_COMMAND_INTEGRATION_TEST_CASE_2.data.args, 49 | ); 50 | const result = await readFile(FIXTURE_BASE_PATH + '/fixture-output.log'); 51 | expect( 52 | JSON.parse(result).filter( 53 | (log: { logLevel: string }) => 54 | log.logLevel == 55 | PARSE_COMMAND_INTEGRATION_TEST_CASE_2.data.args['log-level'], 56 | ).length, 57 | ).toBeGreaterThan(0); 58 | }); 59 | //.......................................................................................................... 60 | it(PARSE_COMMAND_INTEGRATION_TEST_CASE_3.expectation.should, async () => { 61 | try { 62 | await commandModule.execute( 63 | PARSE_COMMAND_INTEGRATION_TEST_CASE_3.data.comman, 64 | PARSE_COMMAND_INTEGRATION_TEST_CASE_3.data.args, 65 | ); 66 | } catch (error) { 67 | expect(error).toBeDefined(); 68 | } 69 | }); 70 | afterAll(() => { 71 | fs.unlinkSync(FIXTURE_BASE_PATH + '/fixture-output.log'); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /test/unit-tests/factories/helper.factory.ts: -------------------------------------------------------------------------------- 1 | import { datatype } from 'faker'; 2 | 3 | export const LOG_PARSER_TEST_CASE_1 = { 4 | data: `2044-08-09T02:12:51.253Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service is started"}`, 5 | logLevel: ['info'], 6 | expectation: { 7 | should: 8 | 'should return log object that matches the object in this test case ', 9 | value: { 10 | timestamp: 2354321571253, 11 | logLevel: 'info', 12 | transactionId: '9abc55b2-807b-4361-9dbe-aa88b1b2e978', 13 | err: 'Service is started', 14 | }, 15 | }, 16 | }; 17 | 18 | export const LOG_PARSER_TEST_CASE_2 = { 19 | data: datatype.string(500), 20 | logLevel: ['info', 'error', 'debug', 'warn'], 21 | expectation: { 22 | should: 'should throw not acceptable exception ', 23 | }, 24 | }; 25 | 26 | export const LOG_PARSER_TEST_CASE_3 = { 27 | data: `2021-08-09T02:12:51.254Z - debug -`, 28 | logLevel: ['info', 'error', 'debug', 'warn'], 29 | expectation: { 30 | should: 'should throw not acceptable exception', 31 | }, 32 | }; 33 | 34 | export const LOG_PARSER_TEST_CASE_4 = { 35 | data: `2021-08-09T02:12:51. - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request the user information","userId": 10} 36 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request user orders list","userId": 10}`, 37 | logLevel: ['info', 'error', 'debug', 'warn'], 38 | expectation: { 39 | should: 'should throw not acceptable exception', 40 | }, 41 | }; 42 | 43 | export const LOG_PARSER_TEST_CASE_5 = { 44 | data: `2044-08-09T02:12:51.253Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service is started"}`, 45 | logLevel: [datatype.string(5)], 46 | expectation: { 47 | should: 48 | 'should return log object that matches the object in this test case ', 49 | value: undefined, 50 | }, 51 | }; 52 | 53 | export const LOG_PARSER_TEST_CASE_6 = { 54 | data: `2021-08-09T02:12:51.262Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user":{"id":16,"orders":[{"id":472,"items":{"id":7,"price":7.12}}]}}`, 55 | logLevel: ['debug'], 56 | expectation: { 57 | should: 'should contain a correct log level ', 58 | value: { 59 | logLevel: 'debug', 60 | }, 61 | }, 62 | }; 63 | 64 | export const LOG_PARSER_TEST_CASE_7 = { 65 | data: `2021-08-09T02:12:51.259Z - error - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Cannot find user orders list","code": 404,"err":"Not found"}`, 66 | logLevel: ['error'], 67 | expectation: { 68 | should: 'should contain a correct log level ', 69 | value: { 70 | logLevel: 'error', 71 | transactionId: '9abc55b2-807b-4361-9dbe-aa88b1b2e978', 72 | }, 73 | }, 74 | }; 75 | 76 | export const LOG_PARSER_TEST_CASE_8 = { 77 | data: `2021-08-09T02:12:51.264Z - warn - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service finished with error","code":404,"err":"Cannot find user orders list"}`, 78 | logLevel: ['error', 'warn'], 79 | expectation: { 80 | should: 'should contain a correct log level ', 81 | value: { 82 | logLevel: 'warn', 83 | transactionId: '9abc55b2-807b-4361-9dbe-aa88b1b2e978', 84 | err: 'Service finished with error', 85 | }, 86 | }, 87 | }; 88 | -------------------------------------------------------------------------------- /test/unit-tests/factories/index.ts: -------------------------------------------------------------------------------- 1 | export * from './parser.factory'; 2 | export * from './helper.factory'; 3 | export * from './utils.factory'; 4 | -------------------------------------------------------------------------------- /test/unit-tests/factories/parser.factory.ts: -------------------------------------------------------------------------------- 1 | import { datatype } from 'faker'; 2 | import * as path from 'path'; 3 | 4 | export const FIXTURE_BASE_PATH = path.resolve(__dirname, '../fixtures'); 5 | //===================================================================================== 6 | export const PARSER_INPUT_TEST_CASE_1 = { 7 | data: { 8 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 9 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 10 | logLevel: ['error'], 11 | }, 12 | expectation: { 13 | should: 'should return at least one log ', 14 | }, 15 | }; 16 | //===================================================================================== 17 | export const PARSER_INPUT_TEST_CASE_2 = { 18 | data: { 19 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 20 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 21 | logLevel: ['error', 'debug'], 22 | }, 23 | expectation: { 24 | should: 'should return a list of logs and has debug and error inside ', 25 | }, 26 | }; 27 | //===================================================================================== 28 | export const PARSER_INPUT_TEST_CASE_3 = { 29 | data: { 30 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 31 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 32 | logLevel: ['unknown'], 33 | }, 34 | expectation: { 35 | should: 'should return a list with 0 elements inside ', 36 | }, 37 | }; 38 | //===================================================================================== 39 | export const PARSER_INPUT_TEST_CASE_4 = { 40 | data: { 41 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 42 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 43 | logLevel: ['error', 'warn', 'debug'], 44 | }, 45 | expectation: { 46 | should: 47 | 'should return a list of logs and has debug, warn and error inside ', 48 | }, 49 | }; 50 | //===================================================================================== 51 | export const PARSER_INPUT_TEST_CASE_5 = { 52 | data: { 53 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 54 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 55 | logLevel: ['error', 'warn', 'info', 'debug'], 56 | }, 57 | expectation: { 58 | should: 59 | 'should return a list of logs and has debug, wanr, info and error inside ', 60 | }, 61 | }; 62 | //===================================================================================== 63 | export const PARSER_INPUT_TEST_CASE_6 = { 64 | data: { 65 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 66 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 67 | logLevel: [datatype.string(20)], 68 | }, 69 | expectation: { 70 | should: 'should return a list with 0 elements inside ', 71 | }, 72 | }; 73 | //===================================================================================== 74 | export const PARSER_INPUT_TEST_CASE_7 = { 75 | data: { 76 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 77 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 78 | logLevel: [datatype.number(345464)], 79 | }, 80 | expectation: { 81 | should: 'should throw error ', 82 | }, 83 | }; 84 | //===================================================================================== 85 | export const PARSER_INPUT_TEST_CASE_8 = { 86 | data: { 87 | input: FIXTURE_BASE_PATH + '/fixture-input.log', 88 | output: FIXTURE_BASE_PATH + '/fixture-output.log', 89 | logLevel: [datatype.string(20), datatype.string(20), datatype.string(20)], 90 | }, 91 | expectation: { 92 | should: 'should return a list with 0 elements inside', 93 | }, 94 | }; 95 | -------------------------------------------------------------------------------- /test/unit-tests/factories/utils.factory.ts: -------------------------------------------------------------------------------- 1 | import { datatype } from 'faker'; 2 | 3 | export const DTO_VALIDATION_TEST_CASE_1 = { 4 | data: { 5 | input: 'input.log', 6 | output: 'output.log', 7 | logLevel: ['error', 'warn', 'info', 'debug'], 8 | }, 9 | expectation: { 10 | should: 'should return ok', 11 | }, 12 | }; 13 | //=========================================================================================== 14 | export const DTO_VALIDATION_TEST_CASE_2 = { 15 | data: { 16 | input: 'input.log', 17 | output: 'output.log', 18 | logLevel: [], 19 | }, 20 | expectation: { 21 | should: 'should return ok', 22 | }, 23 | }; 24 | //=========================================================================================== 25 | export const DTO_VALIDATION_TEST_CASE_3 = { 26 | data: { 27 | input: datatype.string(5), 28 | output: 'output.log', 29 | logLevel: ['error'], 30 | }, 31 | expectation: { 32 | should: 'should return ok', 33 | }, 34 | }; 35 | //=========================================================================================== 36 | export const DTO_VALIDATION_TEST_CASE_4 = { 37 | data: { 38 | input: datatype.string(5), 39 | output: datatype.string(5), 40 | logLevel: [], 41 | }, 42 | expectation: { 43 | should: 'should return ok', 44 | }, 45 | }; 46 | //=========================================================================================== 47 | export const DTO_VALIDATION_TEST_CASE_5 = { 48 | data: { 49 | input: datatype.number(5), 50 | output: datatype.number(5), 51 | logLevel: [], 52 | }, 53 | expectation: { 54 | should: 'should return error', 55 | }, 56 | }; 57 | //=========================================================================================== 58 | export const DTO_VALIDATION_TEST_CASE_6 = { 59 | data: { 60 | input: 'input.log', 61 | output: 'output.log', 62 | logLevel: [datatype.string(10)], 63 | }, 64 | expectation: { 65 | should: 'should return error', 66 | }, 67 | }; 68 | //=========================================================================================== 69 | export const DTO_VALIDATION_TEST_CASE_7 = { 70 | data: { 71 | input: 'input.log', 72 | output: 'output.log', 73 | logLevel: [datatype.number(200)], 74 | }, 75 | expectation: { 76 | should: 'should return error', 77 | }, 78 | }; 79 | //=========================================================================================== 80 | export const DTO_VALIDATION_TEST_CASE_8 = { 81 | data: { 82 | input: 'input.log', 83 | output: 'output.log', 84 | logLevel: datatype.number(200), 85 | }, 86 | expectation: { 87 | should: 'should return error', 88 | }, 89 | }; 90 | //=========================================================================================== 91 | export const DTO_VALIDATION_TEST_CASE_9 = { 92 | data: { 93 | input: 'input.log', 94 | logLevel: datatype.number(200), 95 | }, 96 | expectation: { 97 | should: 'should return error', 98 | }, 99 | }; 100 | //=========================================================================================== 101 | export const DTO_VALIDATION_TEST_CASE_10 = { 102 | data: { 103 | output: 'output.log', 104 | logLevel: datatype.number(200), 105 | }, 106 | expectation: { 107 | should: 'should return error', 108 | }, 109 | }; 110 | //=========================================================================================== 111 | export const DTO_VALIDATION_TEST_CASE_11 = { 112 | data: { 113 | logLevel: datatype.number(200), 114 | }, 115 | expectation: { 116 | should: 'should return error', 117 | }, 118 | }; 119 | //=========================================================================================== 120 | export const DTO_VALIDATION_TEST_CASE_12 = { 121 | data: { 122 | input: 'input.log', 123 | output: 'output.log', 124 | }, 125 | expectation: { 126 | should: 'should return ok', 127 | }, 128 | }; 129 | //=========================================================================================== 130 | export const DTO_VALIDATION_TEST_CASE_13 = { 131 | data: { 132 | input: true, 133 | output: 'output.log', 134 | }, 135 | expectation: { 136 | should: 'should return error', 137 | }, 138 | }; 139 | //=========================================================================================== 140 | export const DTO_VALIDATION_TEST_CASE_14 = { 141 | data: { 142 | input: 'input.log', 143 | output: false, 144 | }, 145 | expectation: { 146 | should: 'should return error', 147 | }, 148 | }; 149 | -------------------------------------------------------------------------------- /test/unit-tests/filehelper.spec.ts: -------------------------------------------------------------------------------- 1 | import { FileHelper } from '../../src/parser/helper'; 2 | import { 3 | LOG_PARSER_TEST_CASE_1, 4 | LOG_PARSER_TEST_CASE_2, 5 | LOG_PARSER_TEST_CASE_3, 6 | LOG_PARSER_TEST_CASE_4, 7 | LOG_PARSER_TEST_CASE_5, 8 | LOG_PARSER_TEST_CASE_6, 9 | LOG_PARSER_TEST_CASE_7, 10 | LOG_PARSER_TEST_CASE_8, 11 | } from './factories'; 12 | 13 | describe('tests the behavior of file helper class', () => { 14 | const fileHelper = new FileHelper(); 15 | //================================================================================================================== 16 | it(LOG_PARSER_TEST_CASE_1.expectation.should, async () => { 17 | const result = await fileHelper.parsLog( 18 | LOG_PARSER_TEST_CASE_1.data, 19 | LOG_PARSER_TEST_CASE_1.logLevel, 20 | ); 21 | expect(result.timestamp).toEqual( 22 | LOG_PARSER_TEST_CASE_1.expectation.value.timestamp, 23 | ); 24 | expect(result.logLevel).toEqual( 25 | LOG_PARSER_TEST_CASE_1.expectation.value.logLevel, 26 | ); 27 | expect(result.transactionId).toEqual( 28 | LOG_PARSER_TEST_CASE_1.expectation.value.transactionId, 29 | ); 30 | expect(result.err).toEqual(LOG_PARSER_TEST_CASE_1.expectation.value.err); 31 | }); 32 | //.................................................................................................................. 33 | it(LOG_PARSER_TEST_CASE_2.expectation.should, async () => { 34 | try { 35 | await fileHelper.parsLog( 36 | LOG_PARSER_TEST_CASE_2.data, 37 | LOG_PARSER_TEST_CASE_2.logLevel, 38 | ); 39 | } catch (error) { 40 | expect(error).toBeDefined(); 41 | } 42 | }); 43 | //.................................................................................................................. 44 | it(LOG_PARSER_TEST_CASE_3.expectation.should, async () => { 45 | try { 46 | await fileHelper.parsLog( 47 | LOG_PARSER_TEST_CASE_3.data, 48 | LOG_PARSER_TEST_CASE_3.logLevel, 49 | ); 50 | } catch (error) { 51 | expect(error).toBeDefined(); 52 | } 53 | }); 54 | //.................................................................................................................. 55 | it(LOG_PARSER_TEST_CASE_4.expectation.should, async () => { 56 | try { 57 | await fileHelper.parsLog( 58 | LOG_PARSER_TEST_CASE_4.data, 59 | LOG_PARSER_TEST_CASE_4.logLevel, 60 | ); 61 | } catch (error) { 62 | expect(error).toBeDefined(); 63 | } 64 | }); 65 | //.................................................................................................................. 66 | it(LOG_PARSER_TEST_CASE_5.expectation.should, async () => { 67 | const result = await fileHelper.parsLog( 68 | LOG_PARSER_TEST_CASE_5.data, 69 | LOG_PARSER_TEST_CASE_5.logLevel, 70 | ); 71 | expect(result).toBeUndefined(); 72 | }); 73 | //.................................................................................................................. 74 | it(LOG_PARSER_TEST_CASE_6.expectation.should, async () => { 75 | const result = await fileHelper.parsLog( 76 | LOG_PARSER_TEST_CASE_6.data, 77 | LOG_PARSER_TEST_CASE_6.logLevel, 78 | ); 79 | expect(result.logLevel).toEqual( 80 | LOG_PARSER_TEST_CASE_6.expectation.value.logLevel, 81 | ); 82 | }); 83 | //.................................................................................................................. 84 | it(LOG_PARSER_TEST_CASE_7.expectation.should, async () => { 85 | const result = await fileHelper.parsLog( 86 | LOG_PARSER_TEST_CASE_7.data, 87 | LOG_PARSER_TEST_CASE_7.logLevel, 88 | ); 89 | expect(result.logLevel).toEqual( 90 | LOG_PARSER_TEST_CASE_7.expectation.value.logLevel, 91 | ); 92 | expect(result.transactionId).toEqual( 93 | LOG_PARSER_TEST_CASE_7.expectation.value.transactionId, 94 | ); 95 | }); 96 | //.................................................................................................................. 97 | it(LOG_PARSER_TEST_CASE_8.expectation.should, async () => { 98 | const result = await fileHelper.parsLog( 99 | LOG_PARSER_TEST_CASE_8.data, 100 | LOG_PARSER_TEST_CASE_8.logLevel, 101 | ); 102 | expect(result.logLevel).toEqual( 103 | LOG_PARSER_TEST_CASE_8.expectation.value.logLevel, 104 | ); 105 | expect(result.transactionId).toEqual( 106 | LOG_PARSER_TEST_CASE_8.expectation.value.transactionId, 107 | ); 108 | expect(result.err).toEqual(LOG_PARSER_TEST_CASE_8.expectation.value.err); 109 | }); 110 | //.................................................................................................................. 111 | //.................................................................................................................. 112 | //.................................................................................................................. 113 | //.................................................................................................................. 114 | }); 115 | -------------------------------------------------------------------------------- /test/unit-tests/fixtures/fixture-input.log: -------------------------------------------------------------------------------- 1 | 2044-08-09T02:12:51.253Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service is started"} 2 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request the user information","userId": 10} 3 | 2021-08-09T02:12:51.254Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"About to request user orders list","userId": 10} 4 | 2021-08-09T02:12:51.255Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"Service is started"} 5 | 2021-08-09T02:12:51.257Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"About to request the user information","userId": 16} 6 | 2021-08-09T02:12:51.257Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"User information is gathered","user":{"id":10,"name":"Alice"}} 7 | 2021-08-09T02:12:51.258Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"About to request user orders list","userId":16} 8 | 2021-08-09T02:12:51.259Z - error - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Cannot find user orders list","code": 404,"err":"Not found"} 9 | 2021-08-09T02:12:51.259Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user": {"id": 16, "name": "Michael"}} 10 | 2021-08-09T02:12:51.262Z - debug - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"User information is retrieved","user":{"id":16,"orders":[{"id":472,"items":{"id":7,"price":7.12}}]}} 11 | 2021-08-09T02:12:51.264Z - warn - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e978","details":"Service finished with error","code":404,"err":"Cannot find user orders list"} 12 | 2021-08-09T02:12:51.265Z - info - {"transactionId":"9abc55b2-807b-4361-9dbe-aa88b1b2e821","details":"Service is successfully finished"} 13 | -------------------------------------------------------------------------------- /test/unit-tests/parser.service.spec.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import { ParserCommandDTO } from '../../src/parser/dtos/parser-command-dto'; 3 | import { FileHelper } from '../../src/parser/helper'; 4 | import { ParserService } from '../../src/parser/service/parser.service'; 5 | import { 6 | FIXTURE_BASE_PATH, 7 | PARSER_INPUT_TEST_CASE_1, 8 | PARSER_INPUT_TEST_CASE_2, 9 | PARSER_INPUT_TEST_CASE_3, 10 | PARSER_INPUT_TEST_CASE_4, 11 | PARSER_INPUT_TEST_CASE_5, 12 | PARSER_INPUT_TEST_CASE_6, 13 | PARSER_INPUT_TEST_CASE_7, 14 | PARSER_INPUT_TEST_CASE_8, 15 | } from './factories'; 16 | 17 | describe('tests the behavior of parser service class', () => { 18 | const fileHelper = new FileHelper(); 19 | const service = new ParserService(fileHelper); 20 | //================================================================================================================== 21 | it(PARSER_INPUT_TEST_CASE_1.expectation.should, async () => { 22 | const result = await service.parse( 23 | new ParserCommandDTO(PARSER_INPUT_TEST_CASE_1.data), 24 | ); 25 | expect(result.length).toBeGreaterThan(0); 26 | }); 27 | //.................................................................................................................. 28 | it(PARSER_INPUT_TEST_CASE_2.expectation.should, async () => { 29 | const result = await service.parse( 30 | new ParserCommandDTO(PARSER_INPUT_TEST_CASE_2.data), 31 | ); 32 | expect( 33 | ( 34 | await result.filter( 35 | (log: { logLevel: string }) => log.logLevel === 'debug', 36 | ) 37 | ).length, 38 | ).toBeGreaterThan(0); 39 | expect( 40 | ( 41 | await result.filter( 42 | (log: { logLevel: string }) => log.logLevel === 'error', 43 | ) 44 | ).length, 45 | ).toBeGreaterThan(0); 46 | }); 47 | //.................................................................................................................. 48 | it(PARSER_INPUT_TEST_CASE_3.expectation.should, async () => { 49 | const result = await service.parse( 50 | new ParserCommandDTO(PARSER_INPUT_TEST_CASE_3.data), 51 | ); 52 | expect(await result.length).toEqual(0); 53 | }); 54 | //.................................................................................................................. 55 | it(PARSER_INPUT_TEST_CASE_4.expectation.should, async () => { 56 | const result = await service.parse( 57 | new ParserCommandDTO(PARSER_INPUT_TEST_CASE_4.data), 58 | ); 59 | expect( 60 | ( 61 | await result.filter( 62 | (log: { logLevel: string }) => log.logLevel === 'warn', 63 | ) 64 | ).length, 65 | ).toBeGreaterThan(0); 66 | expect( 67 | ( 68 | await result.filter( 69 | (log: { logLevel: string }) => log.logLevel === 'error', 70 | ) 71 | ).length, 72 | ).toBeGreaterThan(0); 73 | expect( 74 | ( 75 | await result.filter( 76 | (log: { logLevel: string }) => log.logLevel === 'debug', 77 | ) 78 | ).length, 79 | ).toBeGreaterThan(0); 80 | }); 81 | //.................................................................................................................. 82 | it(PARSER_INPUT_TEST_CASE_5.expectation.should, async () => { 83 | const result = await service.parse( 84 | new ParserCommandDTO(PARSER_INPUT_TEST_CASE_5.data), 85 | ); 86 | expect( 87 | ( 88 | await result.filter( 89 | (log: { logLevel: string }) => log.logLevel === 'warn', 90 | ) 91 | ).length, 92 | ).toBeGreaterThan(0); 93 | expect( 94 | ( 95 | await result.filter( 96 | (log: { logLevel: string }) => log.logLevel === 'error', 97 | ) 98 | ).length, 99 | ).toBeGreaterThan(0); 100 | expect( 101 | ( 102 | await result.filter( 103 | (log: { logLevel: string }) => log.logLevel === 'debug', 104 | ) 105 | ).length, 106 | ).toBeGreaterThan(0); 107 | expect( 108 | ( 109 | await result.filter( 110 | (log: { logLevel: string }) => log.logLevel === 'info', 111 | ) 112 | ).length, 113 | ).toBeGreaterThan(0); 114 | }); 115 | //.................................................................................................................. 116 | it(PARSER_INPUT_TEST_CASE_6.expectation.should, async () => { 117 | const result = await service.parse( 118 | new ParserCommandDTO(PARSER_INPUT_TEST_CASE_6.data), 119 | ); 120 | expect( 121 | ( 122 | await result.filter( 123 | (log: { logLevel: string }) => log.logLevel === 'warn', 124 | ) 125 | ).length, 126 | ).toEqual(0); 127 | expect( 128 | ( 129 | await result.filter( 130 | (log: { logLevel: string }) => log.logLevel === 'error', 131 | ) 132 | ).length, 133 | ).toEqual(0); 134 | expect( 135 | ( 136 | await result.filter( 137 | (log: { logLevel: string }) => log.logLevel === 'debug', 138 | ) 139 | ).length, 140 | ).toEqual(0); 141 | expect( 142 | ( 143 | await result.filter( 144 | (log: { logLevel: string }) => log.logLevel === 'info', 145 | ) 146 | ).length, 147 | ).toEqual(0); 148 | }); 149 | //.................................................................................................................. 150 | it(PARSER_INPUT_TEST_CASE_7.expectation.should, async () => { 151 | try { 152 | await service.parse(new ParserCommandDTO(PARSER_INPUT_TEST_CASE_7.data)); 153 | } catch (error) { 154 | expect(error).toBeDefined(); 155 | } 156 | }); 157 | //.................................................................................................................. 158 | it(PARSER_INPUT_TEST_CASE_8.expectation.should, async () => { 159 | const result = await service.parse( 160 | new ParserCommandDTO(PARSER_INPUT_TEST_CASE_8.data), 161 | ); 162 | expect( 163 | ( 164 | await result.filter( 165 | (log: { logLevel: string }) => log.logLevel === 'warn', 166 | ) 167 | ).length, 168 | ).toEqual(0); 169 | expect( 170 | ( 171 | await result.filter( 172 | (log: { logLevel: string }) => log.logLevel === 'error', 173 | ) 174 | ).length, 175 | ).toEqual(0); 176 | expect( 177 | ( 178 | await result.filter( 179 | (log: { logLevel: string }) => log.logLevel === 'debug', 180 | ) 181 | ).length, 182 | ).toEqual(0); 183 | expect( 184 | ( 185 | await result.filter( 186 | (log: { logLevel: string }) => log.logLevel === 'info', 187 | ) 188 | ).length, 189 | ).toEqual(0); 190 | }); 191 | //.................................................................................................................. 192 | //================================================================================================================== 193 | afterAll(() => { 194 | fs.unlinkSync(FIXTURE_BASE_PATH + '/fixture-output.log'); 195 | }); 196 | }); 197 | -------------------------------------------------------------------------------- /test/unit-tests/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { validateDTO } from '../../src/parser/common'; 2 | import { ParserCommandDTO } from '../../src/parser/dtos/parser-command-dto'; 3 | import { 4 | DTO_VALIDATION_TEST_CASE_1, 5 | DTO_VALIDATION_TEST_CASE_10, 6 | DTO_VALIDATION_TEST_CASE_11, 7 | DTO_VALIDATION_TEST_CASE_12, 8 | DTO_VALIDATION_TEST_CASE_13, 9 | DTO_VALIDATION_TEST_CASE_14, 10 | DTO_VALIDATION_TEST_CASE_2, 11 | DTO_VALIDATION_TEST_CASE_3, 12 | DTO_VALIDATION_TEST_CASE_4, 13 | DTO_VALIDATION_TEST_CASE_5, 14 | DTO_VALIDATION_TEST_CASE_6, 15 | DTO_VALIDATION_TEST_CASE_7, 16 | DTO_VALIDATION_TEST_CASE_8, 17 | DTO_VALIDATION_TEST_CASE_9, 18 | } from './factories'; 19 | 20 | describe('tests the functions inside utils file', () => { 21 | //================================================================================================================== 22 | it(DTO_VALIDATION_TEST_CASE_1.expectation.should, async () => { 23 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_1.data); 24 | await validateDTO(dto); 25 | expect(dto.input).toBeDefined(); 26 | }); 27 | //.................................................................................................................. 28 | it(DTO_VALIDATION_TEST_CASE_2.expectation.should, async () => { 29 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_2.data); 30 | await validateDTO(dto); 31 | expect(dto.input).toBeDefined(); 32 | }); 33 | //.................................................................................................................. 34 | it(DTO_VALIDATION_TEST_CASE_3.expectation.should, async () => { 35 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_3.data); 36 | await validateDTO(dto); 37 | expect(dto.input).toBeDefined(); 38 | }); 39 | //.................................................................................................................. 40 | it(DTO_VALIDATION_TEST_CASE_4.expectation.should, async () => { 41 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_4.data); 42 | await validateDTO(dto); 43 | expect(dto.input).toBeDefined(); 44 | }); 45 | //.................................................................................................................. 46 | it(DTO_VALIDATION_TEST_CASE_5.expectation.should, async () => { 47 | try { 48 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_5.data); 49 | await validateDTO(dto); 50 | } catch (error) { 51 | expect(error).toBeDefined(); 52 | } 53 | }); 54 | //.................................................................................................................. 55 | it(DTO_VALIDATION_TEST_CASE_6.expectation.should, async () => { 56 | try { 57 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_6.data); 58 | await validateDTO(dto); 59 | } catch (error) { 60 | expect(error).toBeDefined(); 61 | } 62 | }); 63 | //.................................................................................................................. 64 | it(DTO_VALIDATION_TEST_CASE_7.expectation.should, async () => { 65 | try { 66 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_7.data); 67 | await validateDTO(dto); 68 | } catch (error) { 69 | expect(error).toBeDefined(); 70 | } 71 | }); 72 | //.................................................................................................................. 73 | it(DTO_VALIDATION_TEST_CASE_8.expectation.should, async () => { 74 | try { 75 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_8.data); 76 | await validateDTO(dto); 77 | } catch (error) { 78 | expect(error).toBeDefined(); 79 | } 80 | }); 81 | //.................................................................................................................. 82 | it(DTO_VALIDATION_TEST_CASE_9.expectation.should, async () => { 83 | try { 84 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_9.data); 85 | await validateDTO(dto); 86 | } catch (error) { 87 | expect(error).toBeDefined(); 88 | } 89 | }); 90 | //.................................................................................................................. 91 | it(DTO_VALIDATION_TEST_CASE_10.expectation.should, async () => { 92 | try { 93 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_10.data); 94 | await validateDTO(dto); 95 | } catch (error) { 96 | expect(error).toBeDefined(); 97 | } 98 | }); 99 | //.................................................................................................................. 100 | it(DTO_VALIDATION_TEST_CASE_11.expectation.should, async () => { 101 | try { 102 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_11.data); 103 | await validateDTO(dto); 104 | } catch (error) { 105 | expect(error).toBeDefined(); 106 | } 107 | }); 108 | //.................................................................................................................. 109 | it(DTO_VALIDATION_TEST_CASE_12.expectation.should, async () => { 110 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_12.data); 111 | await validateDTO(dto); 112 | expect(dto.input).toBeDefined(); 113 | }); 114 | //.................................................................................................................. 115 | it(DTO_VALIDATION_TEST_CASE_13.expectation.should, async () => { 116 | try { 117 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_13.data); 118 | await validateDTO(dto); 119 | } catch (error) { 120 | expect(error).toBeDefined(); 121 | } 122 | }); 123 | //.................................................................................................................. 124 | it(DTO_VALIDATION_TEST_CASE_14.expectation.should, async () => { 125 | try { 126 | const dto = new ParserCommandDTO(DTO_VALIDATION_TEST_CASE_14.data); 127 | await validateDTO(dto); 128 | } catch (error) { 129 | expect(error).toBeDefined(); 130 | } 131 | }); 132 | //.................................................................................................................. 133 | }); 134 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.compodoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "src/**/*" 4 | ], 5 | "exclude": [ 6 | "node_modules/", 7 | "projects/" 8 | ] 9 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": false, 16 | "noImplicitAny": false, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": false, 19 | "noFallthroughCasesInSwitch": false 20 | } 21 | } 22 | --------------------------------------------------------------------------------