Skip to content

Commit

Permalink
feat: default value functions (#1139)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dimava authored Sep 19, 2024
1 parent 24dd695 commit 5f860bb
Show file tree
Hide file tree
Showing 9 changed files with 457 additions and 36 deletions.
16 changes: 13 additions & 3 deletions ark/schema/structure/optional.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { printable, throwParseError, unset } from "@ark/util"
import { hasDomain, printable, throwParseError, unset } from "@ark/util"
import type { BaseRoot } from "../roots/root.ts"
import type { declareNode } from "../shared/declare.ts"
import { ArkErrors } from "../shared/errors.ts"
Expand Down Expand Up @@ -100,18 +100,28 @@ export const assertDefaultValueAssignability = (
value: unknown,
key = ""
): unknown => {
const out = node.in(value)
if (hasDomain(value, "object") && typeof value !== "function")
throwParseError(writeNonPrimitiveNonFunctionDefaultValueMessage(key))

const out = node.in(typeof value === "function" ? value() : value)
if (out instanceof ArkErrors)
throwParseError(writeUnassignableDefaultValueMessage(out.message, key))

return value
}

export const writeUnassignableDefaultValueMessage = (
message: string,
key = ""
): string => `Default value${key && ` for key ${key}`} ${message}`
): string =>
`Default value${key && ` for key ${key}`} is not assignable: ${message}`

export type writeUnassignableDefaultValueMessage<
baseDef extends string,
defaultValue extends string
> = `Default value ${defaultValue} is not assignable to ${baseDef}`

export const writeNonPrimitiveNonFunctionDefaultValueMessage = (
key: string
): string =>
`Default value${key && ` for key ${key}`} is not primitive so it should be specified as a function like () => ({my: 'object'})`
21 changes: 14 additions & 7 deletions ark/schema/structure/prop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,11 @@ export abstract class BaseProp<
return result
}

private premorphedDefaultValue: unknown =
this.hasDefault() ?
this.value.includesMorph ?
this.value.assert(this.default)
: this.default
: undefined
private morphedDefaultFactory: () => unknown = this.getMorphedFactory()

private defaultValueMorphs: Morph[] = [
data => {
data[this.key] = this.premorphedDefaultValue
data[this.key] = this.morphedDefaultFactory()
return data
}
]
Expand All @@ -143,6 +138,18 @@ export abstract class BaseProp<
hasDefault(): this is Optional.Node & { default: unknown } {
return "default" in this
}
getDefaultFactory(): () => unknown {
if (!this.hasDefault()) return () => undefined
if (typeof this.default === "function") return this.default as () => unknown
return () => this.default
}
getMorphedFactory(): () => unknown {
if (!this.hasDefault()) return () => undefined
const factory = this.getDefaultFactory()
return this.value.includesMorph ?
() => this.value.assert(factory())
: factory
}

traverseAllows: TraverseAllows<object> = (data, ctx) => {
if (this.key in data) {
Expand Down
Loading

0 comments on commit 5f860bb

Please sign in to comment.