-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(validation-presenter-table): package release
- Loading branch information
Showing
16 changed files
with
380 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# Table validation presenter for [Unifig](https://github.com/Matii96/unifig) | ||
|
||
Transforms configuration validation errors into clear table. | ||
|
||
## Table of contents | ||
|
||
- [Installation](#installation) | ||
- [Quick Start](#quick_start) | ||
- [Example output](#example_output) | ||
- [License](#license) | ||
|
||
## Installation | ||
|
||
<a name="installation"></a> | ||
|
||
```bash | ||
npm i @unifig/validation-presenter-table | ||
# or | ||
yarn add @unifig/validation-presenter-table | ||
``` | ||
|
||
## Quick Start | ||
|
||
<a name="quick_start"></a> | ||
|
||
```ts | ||
// main.ts | ||
import { Config, PlainConfigAdapter } from '@unifig/core'; | ||
import { Config, PlainConfigAdapter } from '@unifig/validation-presenter-table@unifig/validation-presenter-table'; | ||
|
||
async function bootstrap() { | ||
const validationResult = await Config.register({ | ||
template: Settings, | ||
adapter: new PlainConfigAdapter({}), | ||
}); | ||
if (validationResult) { | ||
console.error(toTable(validationResult)); | ||
process.exit(1); | ||
} | ||
} | ||
|
||
bootstrap(); | ||
``` | ||
|
||
## Example output | ||
|
||
<a name="example_output"></a> | ||
|
||
``` | ||
┌──────────────────┬─────────────┬─────────────┬───────────────┬────────────────────┐ | ||
│ Template │ Property │ Source │ Current Value │ Failed constraints │ | ||
├──────────────────┼─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ │ port │ PORT │ not-a-port │ isInt │ | ||
│ ├─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ StorageOptions │ db.url │ DB_URL │ undefined │ isString │ | ||
│ ├─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ │ db.password │ DB_PASSWORD │ undefined │ isString │ | ||
├──────────────────┼─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ NetworkOptions │ ipRange │ IP_RANGE │ undefined │ isDefined │ | ||
└──────────────────┴─────────────┴─────────────┴───────────────┴────────────────────┘ | ||
``` | ||
|
||
`Source` column presents where property value was taken from. | ||
|
||
Example: from env variables in case of [Env Adapter](https://github.com/Matii96/unifig/tree/main/packages/adapter-env). | ||
|
||
## License | ||
|
||
<a name="license"></a> | ||
|
||
This project is licensed under the MIT License - see the [LICENSE file](https://github.com/Matii96/unifig/tree/main/LICENSE) for details. |
16 changes: 16 additions & 0 deletions
16
packages/validation-presenter-table/lib/__snapshots__/to-table.spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`toTable should format table from 2d errors 1`] = ` | ||
"┌──────────────────┬─────────────┬─────────────┬───────────────┬────────────────────┐ | ||
│ Template │ Property │ Source │ Current Value │ Failed constraints │ | ||
├──────────────────┼─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ │ port │ PORT │ not-a-port │ isInt │ | ||
│ ├─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ StorageOptions │ db.url │ DB_URL │ undefined │ isString │ | ||
│ ├─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ │ db.password │ DB_PASSWORD │ undefined │ isString │ | ||
├──────────────────┼─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ NetworkOptions │ ipRange │ │ undefined │ isDefined │ | ||
└──────────────────┴─────────────┴─────────────┴───────────────┴────────────────────┘ | ||
" | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './to-table'; |
21 changes: 21 additions & 0 deletions
21
packages/validation-presenter-table/lib/template-row/__snapshots__/template-row.spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`TemplateRow should format row from 1d error 1`] = ` | ||
[ | ||
"", | ||
"port", | ||
"PORT", | ||
"not-a-port", | ||
"isInt", | ||
] | ||
`; | ||
|
||
exports[`TemplateRow should format table from 2d errors 1`] = ` | ||
[ | ||
"", | ||
"db", | ||
"", | ||
"undefined", | ||
"", | ||
] | ||
`; |
12 changes: 12 additions & 0 deletions
12
packages/validation-presenter-table/lib/template-row/template-row.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { mockFailed1dValidation, mockFailed2dValidation } from '../validator.mocks'; | ||
import { TemplateRow } from './template-row'; | ||
|
||
describe('TemplateRow', () => { | ||
it('should format row from 1d error', () => { | ||
expect(TemplateRow.fromValidationError(mockFailed1dValidation().errors[0]).toArray()).toMatchSnapshot(); | ||
}); | ||
|
||
it('should format table from 2d errors', () => { | ||
expect(TemplateRow.fromValidationError(mockFailed2dValidation()[0].errors[1]).toArray()).toMatchSnapshot(); | ||
}); | ||
}); |
42 changes: 42 additions & 0 deletions
42
packages/validation-presenter-table/lib/template-row/template-row.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { ConfigPropertyValidationError, ConfigSubtemplateValidationError, FailedConstraint } from '@unifig/core'; | ||
|
||
export class TemplateRow { | ||
propertyParentPrefix?: string; | ||
property: string; | ||
source?: string; | ||
currentValue?: any; | ||
failedConstraints?: FailedConstraint[]; | ||
|
||
static fromValidationError( | ||
error: ConfigPropertyValidationError | ConfigSubtemplateValidationError, | ||
propertyParentPrefix?: string | ||
) { | ||
const row = new TemplateRow(); | ||
row.propertyParentPrefix = propertyParentPrefix; | ||
row.property = error.property; | ||
row.failedConstraints = error.failedConstraints; | ||
|
||
if (error instanceof ConfigPropertyValidationError) { | ||
row.source = error.source; | ||
row.currentValue = error.currentValue; | ||
} | ||
|
||
return row; | ||
} | ||
|
||
toArray(): [string, string, string, string, string] { | ||
return [ | ||
'', | ||
(this.propertyParentPrefix ?? '') + this.property, | ||
this.source ?? '', | ||
this.currentValue ?? 'undefined', | ||
this.failedConstraintsToNames(), | ||
]; | ||
} | ||
|
||
private failedConstraintsToNames() { | ||
return this.failedConstraints | ||
? this.failedConstraints.map((failedConstraint) => failedConstraint.name).join(', ') | ||
: ''; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export interface ToTableOptions { | ||
/** | ||
* @default norc | ||
*/ | ||
border?: 'honeywell' | 'norc' | 'ramac' | 'void'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { ConfigValidationException } from '@unifig/core'; | ||
import { mockFailed2dValidation } from './validator.mocks'; | ||
import { toTable } from './to-table'; | ||
|
||
describe('toTable', () => { | ||
it('should format table from 2d errors', () => { | ||
expect(toTable(new ConfigValidationException(mockFailed2dValidation()))).toMatchSnapshot(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { | ||
ConfigTemplateValidationError, | ||
ConfigValidationException, | ||
ConfigPropertyValidationError, | ||
ConfigSubtemplateValidationError, | ||
} from '@unifig/core'; | ||
import { getBorderCharacters, SpanningCellConfig, table } from 'table'; | ||
import { TemplateRow } from './template-row/template-row'; | ||
import { ToTableOptions } from './to-table.options'; | ||
|
||
const HEADER = ['Template', 'Property', 'Source', 'Current Value', 'Failed constraints']; | ||
|
||
export const toTable = (validationException: ConfigValidationException, options: ToTableOptions = {}): string => { | ||
const tableRows = formatTableRowsGroup(validationException.errors); | ||
const tableData = [HEADER, ...tableRows.flatMap(({ templateTableData }) => templateTableData)]; | ||
|
||
return table(tableData, { | ||
columns: [{ alignment: 'left', width: 16 }], | ||
spanningCells: tableRows.map(({ spanningCells }) => spanningCells), | ||
border: getBorderCharacters(options.border ?? 'norc'), | ||
}); | ||
}; | ||
|
||
const formatTableRowsGroup = (failedValidations: ConfigTemplateValidationError[]) => { | ||
let spanningCellsRowIdx = 1; | ||
return failedValidations.map((failedValidation) => { | ||
const templateTableData = failedValidation.errors | ||
.flatMap((error) => formatTemplateRows(error)) | ||
.map((row) => row.toArray()); | ||
templateTableData[0][0] = failedValidation.template.name; | ||
|
||
const spanningCells: SpanningCellConfig = { | ||
col: 0, | ||
row: spanningCellsRowIdx, | ||
rowSpan: templateTableData.length, | ||
verticalAlignment: 'middle', | ||
}; | ||
spanningCellsRowIdx += templateTableData.length; | ||
return { templateTableData, spanningCells }; | ||
}); | ||
}; | ||
|
||
const formatTemplateRows = ( | ||
error: ConfigPropertyValidationError | ConfigSubtemplateValidationError, | ||
parentPrefix = '' | ||
): TemplateRow[] => { | ||
if (error instanceof ConfigPropertyValidationError) { | ||
return [TemplateRow.fromValidationError(error, parentPrefix)]; | ||
} | ||
if (error instanceof ConfigSubtemplateValidationError) { | ||
const propertyParentPrefix = parentPrefix + error.property + '.'; | ||
const subtemplateRows = error.children.flatMap((child) => formatTemplateRows(child, propertyParentPrefix)); | ||
return error.failedConstraints ? [TemplateRow.fromValidationError(error), ...subtemplateRows] : subtemplateRows; | ||
} | ||
throw new Error('Passed plain validation object: ' + JSON.stringify(error)); | ||
}; |
58 changes: 58 additions & 0 deletions
58
packages/validation-presenter-table/lib/validator.mocks.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { | ||
ConfigPropertyValidationError, | ||
ConfigSubtemplateValidationError, | ||
ConfigTemplateValidationError, | ||
} from '@unifig/core'; | ||
|
||
export class StorageOptions {} | ||
export class NetworkOptions {} | ||
|
||
export const mockFailed1dValidation = () => | ||
new ConfigTemplateValidationError({ | ||
template: StorageOptions, | ||
errors: [ | ||
new ConfigPropertyValidationError({ | ||
currentValue: 'not-a-port', | ||
failedConstraints: [{ details: 'port must be an integer number', name: 'isInt' }], | ||
property: 'port', | ||
source: 'PORT', | ||
}), | ||
], | ||
}) satisfies ConfigTemplateValidationError; | ||
|
||
export const mockFailed2dValidation = () => | ||
[ | ||
{ | ||
errors: [ | ||
...mockFailed1dValidation().errors, | ||
new ConfigSubtemplateValidationError({ | ||
property: 'db', | ||
children: [ | ||
new ConfigPropertyValidationError({ | ||
currentValue: undefined, | ||
failedConstraints: [{ details: 'url must be a string', name: 'isString' }], | ||
property: 'url', | ||
source: 'DB_URL', | ||
}), | ||
new ConfigPropertyValidationError({ | ||
currentValue: undefined, | ||
failedConstraints: [{ details: 'password must be a string', name: 'isString' }], | ||
property: 'password', | ||
source: 'DB_PASSWORD', | ||
}), | ||
], | ||
}), | ||
], | ||
template: StorageOptions, | ||
}, | ||
{ | ||
errors: [ | ||
new ConfigSubtemplateValidationError({ | ||
property: 'ipRange', | ||
failedConstraints: [{ details: 'ipRange must be defined', name: 'isDefined' }], | ||
children: [], | ||
}), | ||
], | ||
template: NetworkOptions, | ||
}, | ||
] satisfies ConfigTemplateValidationError[]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"name": "@unifig/validation-presenter-table", | ||
"version": "0.0.1", | ||
"description": "Table validation presenter for unifig", | ||
"keywords": [ | ||
"unifig", | ||
"env" | ||
], | ||
"author": "Matii96", | ||
"license": "MIT", | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"files": [ | ||
"dist" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/Matii96/unifig.git" | ||
}, | ||
"scripts": { | ||
"build": "tsc --build tsconfig.build.json", | ||
"test": "jest --config ../../jest-units.config.json packages/validation-presenter-table", | ||
"test:e2e": "jest --config ../../jest-e2e.config.json packages/validation-presenter-table" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/Matii96/unifig/issues" | ||
}, | ||
"homepage": "https://github.com/Matii96/unifig", | ||
"dependencies": { | ||
"table": "^6.8.1" | ||
}, | ||
"devDependencies": { | ||
"@unifig/core": "workspace:^" | ||
}, | ||
"peerDependencies": { | ||
"@unifig/core": ">=0.1.0" | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
...validation-presenter-table/test/__snapshots__/validation-presenter-table.e2e-spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`@unifig/validation-presenter-table (e2e) should format table from 1d error 1`] = ` | ||
"┌──────────────────┬──────────┬────────┬───────────────┬────────────────────┐ | ||
│ Template │ Property │ Source │ Current Value │ Failed constraints │ | ||
├──────────────────┼──────────┼────────┼───────────────┼────────────────────┤ | ||
│ StorageOptions │ port │ PORT │ not-a-port │ isInt │ | ||
└──────────────────┴──────────┴────────┴───────────────┴────────────────────┘ | ||
" | ||
`; | ||
|
||
exports[`@unifig/validation-presenter-table (e2e) should format table from 2d errors 1`] = ` | ||
"┌──────────────────┬─────────────┬─────────────┬───────────────┬────────────────────┐ | ||
│ Template │ Property │ Source │ Current Value │ Failed constraints │ | ||
├──────────────────┼─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ │ port │ PORT │ not-a-port │ isInt │ | ||
│ ├─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ StorageOptions │ db.url │ DB_URL │ undefined │ isString │ | ||
│ ├─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ │ db.password │ DB_PASSWORD │ undefined │ isString │ | ||
├──────────────────┼─────────────┼─────────────┼───────────────┼────────────────────┤ | ||
│ NetworkOptions │ ipRange │ │ undefined │ isDefined │ | ||
└──────────────────┴─────────────┴─────────────┴───────────────┴────────────────────┘ | ||
" | ||
`; |
13 changes: 13 additions & 0 deletions
13
packages/validation-presenter-table/test/validation-presenter-table.e2e-spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { ConfigValidationException } from '@unifig/core'; | ||
import { mockFailed1dValidation, mockFailed2dValidation } from '../lib/validator.mocks'; | ||
import { toTable } from '../lib'; | ||
|
||
describe('@unifig/validation-presenter-table (e2e)', () => { | ||
it('should format table from 1d error', () => { | ||
expect(toTable(new ConfigValidationException([mockFailed1dValidation()]))).toMatchSnapshot(); | ||
}); | ||
|
||
it('should format table from 2d errors', () => { | ||
expect(toTable(new ConfigValidationException(mockFailed2dValidation()))).toMatchSnapshot(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"extends": "./tsconfig.json", | ||
"include": ["./lib"], | ||
"exclude": ["**/*.mock.ts", "**/*.mocks.ts", "**/*.spec.ts"] | ||
} |
Oops, something went wrong.