Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,13 @@ jobs:

- name: Type check files
run: yarn tsc

- name: Run Trivy vulnerability scanner in fs mode
uses: aquasecurity/trivy-action@0.33.1
with:
scan-type: 'fs'
scan-ref: '.'
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'

4 changes: 2 additions & 2 deletions lib/exceptions/validation.exception.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ export class ValidationException extends Error {
const failedConstraints = validationErrors
.map(error => {
const [constraint] = Object.values(error.constraints ?? {})
const message = constraint || `${error.property} failed for unknown reason or constraint`
const message = constraint !== '' ? constraint : `${error.property} failed for unknown reason or constraint`

return gray(`- ${message} ${blue(`(was: ${error.value || 'undefined'})`)}`)
return gray(`- ${message} ${blue(`(was: ${error.value ?? 'undefined'})`)}`)
})
.join('\r\n')

Expand Down
2 changes: 1 addition & 1 deletion lib/getters/get-config-value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Class, getConfigInstance } from 'lib/module'
export const getConfigValue = <T extends Class<any>, U>(constructor: T, getter: (config: InstanceType<T>) => U) => {
const instance = getConfigInstance(constructor)

if (!instance) {
if (instance === null || instance === undefined) {
throw new Error('Failed to find instance')
}

Expand Down
76 changes: 38 additions & 38 deletions lib/module/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { registry } from './constants'

export const registerConfigDefaults = (base: Class) => {
if (!registry.has(base)) {
const dependencies: Array<Class> = Reflect.getMetadata('design:paramtypes', base) || []
const dependencies: Array<Class> = Reflect.getMetadata('design:paramtypes', base) ?? []

// eslint-disable-next-line functional/immutable-data
registry.set(base, {
base,
dependencies,
Expand All @@ -28,6 +29,7 @@ export const registerConfigTransformOptions = (base: Class, transformOptions?: C
throw new Error(`Failed to find registered config. Make sure to decorate a class with @Config()!`)
}

// eslint-disable-next-line functional/immutable-data
registry.set(base, {
...current,
transformOptions
Expand All @@ -41,10 +43,11 @@ export const registerConfigTransformTranslations = (base: Class, propertyName: s
throw new Error(`Failed to find registered config. Make sure to decorate a class with @Config()!`)
}

// eslint-disable-next-line functional/immutable-data
registry.set(base, {
...current,
propertyNameTranslations: {
...current?.propertyNameTranslations,
...current.propertyNameTranslations,
[propertyName]: environmentPropertyName
}
})
Expand All @@ -57,7 +60,7 @@ export const getConfigInstance = <T extends Class>(base: T, transformOptions?: T
throw new Error(`Failed to find registered config. Make sure to decorate a class with @Config()!`)
}

if (registeredDependency.instance) {
if (isNotNil(registeredDependency.instance)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return registeredDependency.instance
}
Expand All @@ -80,27 +83,26 @@ export const getConfigInstance = <T extends Class>(base: T, transformOptions?: T

const storage = getMetadataStorage()
const metadatas = storage.getTargetValidationMetadatas(base, base.name, false, false)
const transformedProperties = metadatas.reduce(
(acc, { propertyName, target }) => {
if (acc[propertyName]) {
return acc
}

const prototype: object = typeof target === 'function' ? target.prototype : {}
const environmentPropertyName = registeredDependency.propertyNameTranslations[propertyName]

const key = environmentPropertyName || propertyName
const value = environmentVariables[key] || process.env[key]
const type = Reflect.getMetadata('design:type', prototype, propertyName)

return {
...acc,
[propertyName]: isNotNil(value) ? toValueByType(type, value) : value
}
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
{} as Record<string, any>
)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const transformedProperties = metadatas.reduce<Record<string, any>>((acc, { propertyName, target }) => {
if (isNotNil(acc[propertyName])) {
return acc
}

const prototype: object = typeof target === 'function' ? target.prototype : {}
const environmentPropertyName = registeredDependency.propertyNameTranslations[propertyName]

// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
const key = environmentPropertyName || propertyName
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
const value = environmentVariables[key] || process.env[key]
const type = Reflect.getMetadata('design:type', prototype, propertyName)

return {
...acc,
[propertyName]: isNotNil(value) ? toValueByType(type, value) : value
}
}, {})

/**
* Make the instance methods, auto-bindable to "this" reference so we can destruct the
Expand All @@ -114,18 +116,15 @@ export const getConfigInstance = <T extends Class>(base: T, transformOptions?: T

const descriptors = Object.getOwnPropertyDescriptors(base.prototype)
const descriptorNames = Object.keys(descriptors).filter(name => name !== 'constructor')
const unreferencedMethods = descriptorNames.reduce(
(result, name) => {
const descriptor = descriptors[name]

return {
...result,
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, functional/functional-parameters
[name]: (...args: Array<any>) => descriptor.value.apply(instance, args)
}
},
{} as Record<string, () => void>
)
const unreferencedMethods = descriptorNames.reduce<Record<string, () => void>>((result, name) => {
const descriptor = descriptors[name]

return {
...result,
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, functional/functional-parameters
[name]: (...args: Array<any>) => descriptor.value.apply(instance, args)
}
}, {})

/**
* Due to missing option for passing constructor arguments, we are creating
Expand All @@ -137,7 +136,7 @@ export const getConfigInstance = <T extends Class>(base: T, transformOptions?: T
static readonly name = base.name

// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, functional/functional-parameters
constructor(...unusedArgs: Array<any>) {
constructor(...args: Array<any>) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
super(...resolvedDependencies)
}
Expand All @@ -161,7 +160,7 @@ export const getConfigInstance = <T extends Class>(base: T, transformOptions?: T
}
})

if (validationErrors.length) {
if (validationErrors.length > 0) {
throw new ValidationException(base.name, validationErrors)
}

Expand All @@ -171,6 +170,7 @@ export const getConfigInstance = <T extends Class>(base: T, transformOptions?: T
instance
}

// eslint-disable-next-line functional/immutable-data
registry.set(base, config)

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
Expand Down
42 changes: 21 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,33 +64,33 @@
},
"dependencies": {
"chalk": "4.1.2",
"dotenv": "16.4.7",
"ramda": "0.30.1"
"dotenv": "17.2.3",
"ramda": "0.32.0"
},
"devDependencies": {
"@commitlint/config-conventional": "19.6.0",
"@nestjs/cli": "11.0.2",
"@nestjs/common": "11.0.5",
"@nestjs/core": "11.0.7",
"@nestjs/platform-express": "11.0.7",
"@commitlint/config-conventional": "20.0.0",
"@nestjs/cli": "11.0.10",
"@nestjs/common": "11.1.9",
"@nestjs/core": "11.1.9",
"@nestjs/platform-express": "11.1.9",
"@nestjs/typeorm": "11.0.0",
"@types/jest": "29.5.14",
"@types/node": "22.10.10",
"@types/pg": "8.11.10",
"@types/ramda": "0.30.2",
"@types/jest": "30.0.0",
"@types/node": "24.10.1",
"@types/pg": "8.15.6",
"@types/ramda": "0.31.1",
"class-transformer": "0.5.1",
"class-validator": "0.14.1",
"eslint": "9.19.0",
"eslint-config-codemask": "2.0.0-beta.15",
"jest": "29.7.0",
"pg": "8.13.1",
"prettier": "3.4.2",
"class-validator": "0.14.2",
"eslint": "9.39.1",
"eslint-config-codemask": "2.2.1",
"jest": "30.2.0",
"pg": "8.16.3",
"prettier": "3.6.2",
"reflect-metadata": "0.2.2",
"rimraf": "6.0.1",
"ts-jest": "29.2.5",
"rimraf": "6.1.0",
"ts-jest": "29.4.5",
"tscpaths": "0.0.9",
"typeorm": "0.3.20",
"typescript": "5.7.3"
"typeorm": "0.3.27",
"typescript": "5.9.3"
},
"files": [
"dist",
Expand Down
Loading