Skip to content

Commit

Permalink
feat: add @InputError tag and change how other edge tags work
Browse files Browse the repository at this point in the history
The @error tag is used to read generic error message
The @InputError tag should be used to read validation error messages
  • Loading branch information
thetutlage committed Dec 26, 2023
1 parent 9a98c1f commit 8d895c1
Show file tree
Hide file tree
Showing 4 changed files with 379 additions and 36 deletions.
68 changes: 63 additions & 5 deletions src/plugins/edge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const edgePluginSession: PluginFn<undefined> = (edge) => {
* Define a local variable
*/
buffer.writeExpression(
`let message = state.flashMessages.get(${key})`,
`let $message = state.flashMessages.get(${key})`,
token.filename,
token.loc.start.line
)
Expand All @@ -53,7 +53,65 @@ export const edgePluginSession: PluginFn<undefined> = (edge) => {
* the existence of the "message" variable
*/
parser.stack.defineScope()
parser.stack.defineVariable('message')
parser.stack.defineVariable('$message')

/**
* Process component children using the parser
*/
token.children.forEach((child) => {
parser.processToken(child, buffer)
})

/**
* Clear the scope of the local variables before we
* close the if statement
*/
parser.stack.clearScope()

/**
* Close if statement
*/
buffer.writeStatement(`}`, token.filename, token.loc.start.line)
},
})

edge.registerTag({
tagName: 'inputError',
seekable: true,
block: true,
compile(parser, buffer, token) {
const expression = parser.utils.transformAst(
parser.utils.generateAST(token.properties.jsArg, token.loc, token.filename),
token.filename,
parser
)

const key = parser.utils.stringify(expression)

/**
* Write an if statement
*/
buffer.writeStatement(
`if (!!state.flashMessages.get('inputErrorsBag', {})[${key}]) {`,
token.filename,
token.loc.start.line
)

/**
* Define a local variable
*/
buffer.writeExpression(
`let $messages = state.flashMessages.get('inputErrorsBag', {})[${key}]`,
token.filename,
token.loc.start.line
)

/**
* Create a local variables scope and tell the parser about
* the existence of the "messages" variable
*/
parser.stack.defineScope()
parser.stack.defineVariable('$messages')

/**
* Process component children using the parser
Expand Down Expand Up @@ -92,7 +150,7 @@ export const edgePluginSession: PluginFn<undefined> = (edge) => {
* Write an if statement
*/
buffer.writeStatement(
`if (!!state.flashMessages.get('errors', {})[${key}]) {`,
`if (state.flashMessages.has(['errorsBag', ${key}])) {`,
token.filename,
token.loc.start.line
)
Expand All @@ -101,7 +159,7 @@ export const edgePluginSession: PluginFn<undefined> = (edge) => {
* Define a local variable
*/
buffer.writeExpression(
`let messages = state.flashMessages.get('errors', {})[${key}]`,
`let $message = state.flashMessages.get(['errorsBag', ${key}])`,
token.filename,
token.loc.start.line
)
Expand All @@ -111,7 +169,7 @@ export const edgePluginSession: PluginFn<undefined> = (edge) => {
* the existence of the "messages" variable
*/
parser.stack.defineScope()
parser.stack.defineVariable('messages')
parser.stack.defineVariable('$message')

/**
* Process component children using the parser
Expand Down
55 changes: 39 additions & 16 deletions src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,36 @@ export class Session {
return this.#getValuesStore('write').clear()
}

/**
* Add a key-value pair to flash messages
*/
flash(key: string, value: AllowedSessionValues): void
flash(keyValue: SessionData): void
flash(key: string | SessionData, value?: AllowedSessionValues): void {
if (typeof key === 'string') {
if (value) {
this.#getFlashStore('write').set(key, value)
}
} else {
this.#getFlashStore('write').merge(key)
}
}

/**
* Flash errors to the errorsBag. You can read these
* errors via the "@error" tag.
*
* Appends new messages to the existing collection.
*/
flashErrors(errorsCollection: Record<string, string | string[]>) {
this.flash({ errorsBag: errorsCollection })
}

/**
* Flash validation error messages. Make sure the error
* is an instance of VineJS ValidationException
* is an instance of VineJS ValidationException.
*
* Overrides existing inputErrors
*/
flashValidationErrors(error: HttpError) {
const errorsBag = error.messages.reduce((result: Record<string, string[]>, message: any) => {
Expand All @@ -308,22 +335,18 @@ export class Session {
}, {})

this.flashExcept(['_csrf', '_method'])
this.flash('errors', errorsBag)
}

/**
* Add a key-value pair to flash messages
*/
flash(key: string, value: AllowedSessionValues): void
flash(keyValue: SessionData): void
flash(key: string | SessionData, value?: AllowedSessionValues): void {
if (typeof key === 'string') {
if (value) {
this.#getFlashStore('write').set(key, value)
}
} else {
this.#getFlashStore('write').merge(key)
}
/**
* Adding to inputErrorsBag for "@inputError" tag
* to read validation errors
*/
this.flash('inputErrorsBag', errorsBag)

/**
* For legacy support and not to break apps using
* the older version of @adonisjs/session package
*/
this.flash('errors', errorsBag)
}

/**
Expand Down
14 changes: 7 additions & 7 deletions src/values_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class ReadOnlyValuesStore {
/**
* Get value for a given key
*/
get(key: string, defaultValue?: any): any {
get(key: string | string[], defaultValue?: any): any {
const value = lodash.get(this.values, key)
if (defaultValue !== undefined && (value === null || value === undefined)) {
return defaultValue
Expand All @@ -47,7 +47,7 @@ export class ReadOnlyValuesStore {
* A boolean to know if value exists. Extra guards to check
* arrays for it's length as well.
*/
has(key: string, checkForArraysLength: boolean = true): boolean {
has(key: string | string[], checkForArraysLength: boolean = true): boolean {
const value = this.get(key)
if (!Array.isArray(value)) {
return !!value
Expand Down Expand Up @@ -110,15 +110,15 @@ export class ValuesStore extends ReadOnlyValuesStore {
/**
* Set key/value pair
*/
set(key: string, value: AllowedSessionValues): void {
set(key: string | string[], value: AllowedSessionValues): void {
this.#modified = true
lodash.set(this.values, key, value)
}

/**
* Remove key
*/
unset(key: string): void {
unset(key: string | string[]): void {
this.#modified = true
lodash.unset(this.values, key)
}
Expand All @@ -127,7 +127,7 @@ export class ValuesStore extends ReadOnlyValuesStore {
* Pull value from the store. It is same as calling
* store.get and then store.unset
*/
pull(key: string, defaultValue?: any): any {
pull(key: string | string[], defaultValue?: any): any {
return ((value): any => {
this.unset(key)
return value
Expand All @@ -138,7 +138,7 @@ export class ValuesStore extends ReadOnlyValuesStore {
* Increment number. The method raises an error when
* nderlying value is not a number
*/
increment(key: string, steps: number = 1): void {
increment(key: string | string[], steps: number = 1): void {
const value = this.get(key, 0)
if (typeof value !== 'number') {
throw new RuntimeException(`Cannot increment "${key}". Existing value is not a number`)
Expand All @@ -151,7 +151,7 @@ export class ValuesStore extends ReadOnlyValuesStore {
* Increment number. The method raises an error when
* nderlying value is not a number
*/
decrement(key: string, steps: number = 1): void {
decrement(key: string | string[], steps: number = 1): void {
const value = this.get(key, 0)
if (typeof value !== 'number') {
throw new RuntimeException(`Cannot decrement "${key}". Existing value is not a number`)
Expand Down
Loading

0 comments on commit 8d895c1

Please sign in to comment.