@adonisjs/core 6.1.5-2 → 6.1.5-4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/commands/build.d.ts +3 -0
- package/build/commands/build.d.ts.map +1 -0
- package/build/commands/build.js +22 -2
- package/build/commands/commands.json +1 -1
- package/build/commands/configure.d.ts +1 -0
- package/build/commands/configure.d.ts.map +1 -0
- package/build/commands/configure.js +2 -1
- package/build/commands/eject.d.ts +1 -0
- package/build/commands/eject.d.ts.map +1 -0
- package/build/commands/eject.js +2 -1
- package/build/commands/generate_key.d.ts +1 -0
- package/build/commands/generate_key.d.ts.map +1 -0
- package/build/commands/generate_key.js +2 -1
- package/build/commands/inspect_rcfile.d.ts +7 -0
- package/build/commands/inspect_rcfile.d.ts.map +1 -0
- package/build/commands/inspect_rcfile.js +10 -0
- package/build/commands/list/routes.d.ts +1 -0
- package/build/commands/list/routes.d.ts.map +1 -0
- package/build/commands/list/routes.js +2 -1
- package/build/commands/make/_base.d.ts +23 -1
- package/build/commands/make/_base.d.ts.map +1 -0
- package/build/commands/make/_base.js +11 -2
- package/build/commands/make/command.d.ts +1 -0
- package/build/commands/make/command.d.ts.map +1 -0
- package/build/commands/make/command.js +2 -1
- package/build/commands/make/controller.d.ts +1 -0
- package/build/commands/make/controller.d.ts.map +1 -0
- package/build/commands/make/controller.js +2 -1
- package/build/commands/make/event.d.ts +1 -0
- package/build/commands/make/event.d.ts.map +1 -0
- package/build/commands/make/event.js +2 -1
- package/build/commands/make/listener.d.ts +1 -0
- package/build/commands/make/listener.d.ts.map +1 -0
- package/build/commands/make/listener.js +2 -1
- package/build/commands/make/middleware.d.ts +1 -0
- package/build/commands/make/middleware.d.ts.map +1 -0
- package/build/commands/make/middleware.js +2 -1
- package/build/commands/make/prldfile.d.ts +9 -0
- package/build/commands/make/prldfile.d.ts.map +1 -0
- package/build/commands/make/prldfile.js +28 -0
- package/build/commands/make/provider.d.ts +1 -0
- package/build/commands/make/provider.d.ts.map +1 -0
- package/build/commands/make/provider.js +5 -2
- package/build/commands/make/service.d.ts +9 -0
- package/build/commands/make/service.d.ts.map +1 -0
- package/build/commands/make/service.js +26 -0
- package/build/commands/make/test.d.ts +1 -0
- package/build/commands/make/test.d.ts.map +1 -0
- package/build/commands/make/test.js +2 -1
- package/build/commands/serve.d.ts +3 -0
- package/build/commands/serve.d.ts.map +1 -0
- package/build/commands/serve.js +21 -1
- package/build/commands/test.d.ts +21 -0
- package/build/commands/test.d.ts.map +1 -0
- package/build/commands/test.js +155 -0
- package/build/factories/app.d.ts +1 -0
- package/build/factories/app.d.ts.map +1 -0
- package/build/factories/bodyparser.d.ts +1 -0
- package/build/factories/bodyparser.d.ts.map +1 -0
- package/build/factories/core/ace.d.ts +1 -0
- package/build/factories/core/ace.d.ts.map +1 -0
- package/build/factories/core/ignitor.d.ts +1 -0
- package/build/factories/core/ignitor.d.ts.map +1 -0
- package/build/factories/core/main.d.ts +1 -0
- package/build/factories/core/main.d.ts.map +1 -0
- package/build/factories/core/test_utils.d.ts +1 -0
- package/build/factories/core/test_utils.d.ts.map +1 -0
- package/build/factories/encryption.d.ts +1 -0
- package/build/factories/encryption.d.ts.map +1 -0
- package/build/factories/events.d.ts +1 -0
- package/build/factories/events.d.ts.map +1 -0
- package/build/factories/hash.d.ts +1 -0
- package/build/factories/hash.d.ts.map +1 -0
- package/build/factories/http.d.ts +1 -0
- package/build/factories/http.d.ts.map +1 -0
- package/build/factories/logger.d.ts +1 -0
- package/build/factories/logger.d.ts.map +1 -0
- package/build/factories/stubs.d.ts +1 -0
- package/build/factories/stubs.d.ts.map +1 -0
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -0
- package/build/legacy/validator.d.ts +1 -0
- package/build/legacy/validator.d.ts.map +1 -0
- package/build/modules/ace/commands.d.ts +1 -0
- package/build/modules/ace/commands.d.ts.map +1 -0
- package/build/modules/ace/commands.js +4 -2
- package/build/modules/ace/create_kernel.d.ts +1 -0
- package/build/modules/ace/create_kernel.d.ts.map +1 -0
- package/build/modules/ace/create_kernel.js +1 -0
- package/build/modules/ace/kernel.d.ts +1 -0
- package/build/modules/ace/kernel.d.ts.map +1 -0
- package/build/modules/ace/main.d.ts +1 -0
- package/build/modules/ace/main.d.ts.map +1 -0
- package/build/modules/ace/shell.d.ts +1 -0
- package/build/modules/ace/shell.d.ts.map +1 -0
- package/build/modules/app.d.ts +1 -0
- package/build/modules/app.d.ts.map +1 -0
- package/build/modules/bodyparser/bodyparser_middleware.d.ts +1 -0
- package/build/modules/bodyparser/bodyparser_middleware.d.ts.map +1 -0
- package/build/modules/bodyparser/main.d.ts +1 -0
- package/build/modules/bodyparser/main.d.ts.map +1 -0
- package/build/modules/config.d.ts +1 -0
- package/build/modules/config.d.ts.map +1 -0
- package/build/modules/container.d.ts +1 -0
- package/build/modules/container.d.ts.map +1 -0
- package/build/modules/encryption.d.ts +1 -0
- package/build/modules/encryption.d.ts.map +1 -0
- package/build/modules/env.d.ts +1 -0
- package/build/modules/env.d.ts.map +1 -0
- package/build/modules/events.d.ts +1 -0
- package/build/modules/events.d.ts.map +1 -0
- package/build/modules/hash/define_config.d.ts +1 -0
- package/build/modules/hash/define_config.d.ts.map +1 -0
- package/build/modules/hash/drivers_collection.d.ts +4 -4
- package/build/modules/hash/drivers_collection.d.ts.map +1 -0
- package/build/modules/hash/drivers_collection.js +2 -8
- package/build/modules/hash/main.d.ts +2 -0
- package/build/modules/hash/main.d.ts.map +1 -0
- package/build/modules/hash/main.js +1 -0
- package/build/modules/http.d.ts +1 -0
- package/build/modules/http.d.ts.map +1 -0
- package/build/modules/logger.d.ts +1 -0
- package/build/modules/logger.d.ts.map +1 -0
- package/build/providers/app_provider.d.ts +1 -0
- package/build/providers/app_provider.d.ts.map +1 -0
- package/build/providers/app_provider.js +5 -7
- package/build/providers/hash_provider.d.ts +1 -0
- package/build/providers/hash_provider.d.ts.map +1 -0
- package/build/providers/hash_provider.js +7 -6
- package/build/providers/http_provider.d.ts +1 -0
- package/build/providers/http_provider.d.ts.map +1 -0
- package/build/services/ace.d.ts +1 -0
- package/build/services/ace.d.ts.map +1 -0
- package/build/services/app.d.ts +1 -0
- package/build/services/app.d.ts.map +1 -0
- package/build/services/config.d.ts +1 -0
- package/build/services/config.d.ts.map +1 -0
- package/build/services/emitter.d.ts +1 -0
- package/build/services/emitter.d.ts.map +1 -0
- package/build/services/emitter.js +1 -2
- package/build/services/encryption.d.ts +1 -0
- package/build/services/encryption.d.ts.map +1 -0
- package/build/services/encryption.js +1 -2
- package/build/services/hash.d.ts +1 -0
- package/build/services/hash.d.ts.map +1 -0
- package/build/services/hash.js +1 -2
- package/build/services/logger.d.ts +1 -0
- package/build/services/logger.d.ts.map +1 -0
- package/build/services/logger.js +1 -2
- package/build/services/router.d.ts +1 -0
- package/build/services/router.d.ts.map +1 -0
- package/build/services/router.js +1 -2
- package/build/services/server.d.ts +1 -0
- package/build/services/server.d.ts.map +1 -0
- package/build/services/server.js +1 -2
- package/build/services/test_utils.d.ts +1 -0
- package/build/services/test_utils.d.ts.map +1 -0
- package/build/src/cli_formatters/routes_list.d.ts +1 -0
- package/build/src/cli_formatters/routes_list.d.ts.map +1 -0
- package/build/src/debug.d.ts +1 -0
- package/build/src/debug.d.ts.map +1 -0
- package/build/src/helpers/is.d.ts +1 -0
- package/build/src/helpers/is.d.ts.map +1 -0
- package/build/src/helpers/main.d.ts +1 -0
- package/build/src/helpers/main.d.ts.map +1 -0
- package/build/src/helpers/parse_binding_reference.d.ts +1 -0
- package/build/src/helpers/parse_binding_reference.d.ts.map +1 -0
- package/build/src/helpers/string.d.ts +3 -0
- package/build/src/helpers/string.d.ts.map +1 -0
- package/build/src/helpers/string.js +4 -0
- package/build/src/helpers/types.d.ts +1 -0
- package/build/src/helpers/types.d.ts.map +1 -0
- package/build/src/ignitor/ace.d.ts +1 -0
- package/build/src/ignitor/ace.d.ts.map +1 -0
- package/build/src/ignitor/http.d.ts +1 -0
- package/build/src/ignitor/http.d.ts.map +1 -0
- package/build/src/ignitor/main.d.ts +1 -0
- package/build/src/ignitor/main.d.ts.map +1 -0
- package/build/src/ignitor/test.d.ts +1 -0
- package/build/src/ignitor/test.d.ts.map +1 -0
- package/build/src/internal_helpers.d.ts +1 -0
- package/build/src/internal_helpers.d.ts.map +1 -0
- package/build/src/test_utils/http.d.ts +1 -0
- package/build/src/test_utils/http.d.ts.map +1 -0
- package/build/src/test_utils/main.d.ts +2 -1
- package/build/src/test_utils/main.d.ts.map +1 -0
- package/build/src/types.d.ts +3 -2
- package/build/src/types.d.ts.map +1 -0
- package/build/stubs/index.d.ts +1 -0
- package/build/stubs/index.d.ts.map +1 -0
- package/build/stubs/make/preload_file/main.stub +4 -0
- package/build/stubs/make/service/main.stub +4 -0
- package/build/toolkit/commands/index_commands.d.ts +1 -0
- package/build/toolkit/commands/index_commands.d.ts.map +1 -0
- package/build/toolkit/commands/index_commands.js +2 -1
- package/build/toolkit/main.d.ts +1 -0
- package/build/toolkit/main.d.ts.map +1 -0
- package/build/types/ace.d.ts +1 -0
- package/build/types/ace.d.ts.map +1 -0
- package/build/types/app.d.ts +1 -0
- package/build/types/app.d.ts.map +1 -0
- package/build/types/bodyparser.d.ts +1 -0
- package/build/types/bodyparser.d.ts.map +1 -0
- package/build/types/container.d.ts +1 -0
- package/build/types/container.d.ts.map +1 -0
- package/build/types/encryption.d.ts +1 -0
- package/build/types/encryption.d.ts.map +1 -0
- package/build/types/events.d.ts +1 -0
- package/build/types/events.d.ts.map +1 -0
- package/build/types/hash.d.ts +1 -0
- package/build/types/hash.d.ts.map +1 -0
- package/build/types/http.d.ts +1 -0
- package/build/types/http.d.ts.map +1 -0
- package/build/types/logger.d.ts +1 -0
- package/build/types/logger.d.ts.map +1 -0
- package/commands/build.ts +122 -0
- package/commands/configure.ts +179 -0
- package/commands/eject.ts +39 -0
- package/commands/generate_key.ts +53 -0
- package/commands/inspect_rcfile.ts +23 -0
- package/commands/list/routes.ts +121 -0
- package/commands/make/_base.ts +55 -0
- package/commands/make/command.ts +33 -0
- package/commands/make/controller.ts +77 -0
- package/commands/make/event.ts +33 -0
- package/commands/make/listener.ts +63 -0
- package/commands/make/middleware.ts +34 -0
- package/commands/make/prldfile.ts +40 -0
- package/commands/make/provider.ts +40 -0
- package/commands/make/service.ts +33 -0
- package/commands/make/test.ts +115 -0
- package/commands/serve.ts +146 -0
- package/commands/test.ts +188 -0
- package/factories/app.ts +10 -0
- package/factories/bodyparser.ts +10 -0
- package/factories/core/ace.ts +38 -0
- package/factories/core/ignitor.ts +132 -0
- package/factories/core/main.ts +13 -0
- package/factories/core/test_utils.ts +34 -0
- package/factories/encryption.ts +10 -0
- package/factories/events.ts +10 -0
- package/factories/hash.ts +10 -0
- package/factories/http.ts +10 -0
- package/factories/logger.ts +10 -0
- package/factories/stubs.ts +53 -0
- package/index.ts +39 -0
- package/legacy/validator.ts +10 -0
- package/modules/ace/commands.ts +152 -0
- package/modules/ace/create_kernel.ts +74 -0
- package/modules/ace/kernel.ts +28 -0
- package/modules/ace/main.ts +22 -0
- package/modules/ace/shell.ts +49 -0
- package/modules/app.ts +10 -0
- package/modules/bodyparser/bodyparser_middleware.ts +16 -0
- package/modules/bodyparser/main.ts +10 -0
- package/modules/config.ts +10 -0
- package/modules/container.ts +10 -0
- package/modules/encryption.ts +10 -0
- package/modules/env.ts +10 -0
- package/modules/events.ts +10 -0
- package/modules/hash/define_config.ts +64 -0
- package/modules/hash/drivers_collection.ts +61 -0
- package/modules/hash/main.ts +12 -0
- package/modules/http.ts +10 -0
- package/modules/logger.ts +10 -0
- package/package.json +39 -30
- package/providers/app_provider.ts +125 -0
- package/providers/hash_provider.ts +58 -0
- package/providers/http_provider.ts +66 -0
- package/services/ace.ts +26 -0
- package/services/app.ts +26 -0
- package/services/config.ts +22 -0
- package/services/emitter.ts +23 -0
- package/services/encryption.ts +23 -0
- package/services/hash.ts +23 -0
- package/services/logger.ts +23 -0
- package/services/router.ts +23 -0
- package/services/server.ts +23 -0
- package/services/test_utils.ts +26 -0
- package/src/cli_formatters/routes_list.ts +480 -0
- package/src/debug.ts +12 -0
- package/src/helpers/is.ts +11 -0
- package/src/helpers/main.ts +13 -0
- package/src/helpers/parse_binding_reference.ts +93 -0
- package/src/helpers/string.ts +89 -0
- package/src/helpers/types.ts +46 -0
- package/src/ignitor/ace.ts +90 -0
- package/src/ignitor/http.ts +167 -0
- package/src/ignitor/main.ts +118 -0
- package/src/ignitor/test.ts +51 -0
- package/src/internal_helpers.ts +59 -0
- package/src/test_utils/http.ts +79 -0
- package/src/test_utils/main.ts +69 -0
- package/src/types.ts +136 -0
- package/types/ace.ts +15 -0
- package/types/app.ts +10 -0
- package/types/bodyparser.ts +10 -0
- package/types/container.ts +10 -0
- package/types/encryption.ts +10 -0
- package/types/events.ts +10 -0
- package/types/hash.ts +10 -0
- package/types/http.ts +10 -0
- package/types/logger.ts +10 -0
- package/build/src/helpers/string_builder.d.ts +0 -23
- package/build/src/helpers/string_builder.js +0 -86
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/core
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import stringWidth from 'string-width'
|
|
11
|
+
import { type Router } from '../../modules/http.js'
|
|
12
|
+
import type { RouteJSON } from '../../types/http.js'
|
|
13
|
+
import type { UIPrimitives } from '../../types/ace.js'
|
|
14
|
+
import { cliHelpers } from '../../modules/ace/main.js'
|
|
15
|
+
import { parseBindingReference } from '../../src/helpers/main.js'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Shape of the serialized route specific to the formatter
|
|
19
|
+
*/
|
|
20
|
+
type SerializedRoute = {
|
|
21
|
+
name: string
|
|
22
|
+
pattern: string
|
|
23
|
+
methods: string[]
|
|
24
|
+
middleware: string[]
|
|
25
|
+
handler:
|
|
26
|
+
| { type: 'closure'; name: string }
|
|
27
|
+
| { type: 'controller'; moduleNameOrPath: string; method: string }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Routes list formatter is used to format the routes to JSON or an ANSI string
|
|
32
|
+
* with pretty output.
|
|
33
|
+
*
|
|
34
|
+
* The decisions of colors, padding, alignment are all handled by the lists formatter
|
|
35
|
+
*/
|
|
36
|
+
export class RoutesListFormatter {
|
|
37
|
+
#router: Router
|
|
38
|
+
#colors: UIPrimitives['colors']
|
|
39
|
+
#table: UIPrimitives['table']
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Options for printing routes
|
|
43
|
+
*/
|
|
44
|
+
#options: {
|
|
45
|
+
displayHeadRoutes?: boolean
|
|
46
|
+
maxPrettyPrintWidth?: number
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Filters to apply when finding routes
|
|
51
|
+
*/
|
|
52
|
+
#filters: {
|
|
53
|
+
match?: string
|
|
54
|
+
middleware?: string[]
|
|
55
|
+
ignoreMiddleware?: string[]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
constructor(
|
|
59
|
+
router: Router,
|
|
60
|
+
ui: UIPrimitives,
|
|
61
|
+
options: {
|
|
62
|
+
displayHeadRoutes?: boolean
|
|
63
|
+
maxPrettyPrintWidth?: number
|
|
64
|
+
},
|
|
65
|
+
filters: {
|
|
66
|
+
match?: string
|
|
67
|
+
middleware?: string[]
|
|
68
|
+
ignoreMiddleware?: string[]
|
|
69
|
+
}
|
|
70
|
+
) {
|
|
71
|
+
this.#router = router
|
|
72
|
+
this.#colors = ui.colors
|
|
73
|
+
this.#table = ui.table
|
|
74
|
+
this.#filters = filters
|
|
75
|
+
this.#options = options
|
|
76
|
+
this.#router.commit()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Test if a route clears the applied filters
|
|
81
|
+
*/
|
|
82
|
+
#isAllowedByFilters(route: SerializedRoute) {
|
|
83
|
+
let allowRoute = true
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Check if the route is allowed by applying the middleware
|
|
87
|
+
* filter
|
|
88
|
+
*/
|
|
89
|
+
if (this.#filters.middleware) {
|
|
90
|
+
allowRoute = this.#filters.middleware.every((name) => {
|
|
91
|
+
if (name === '*') {
|
|
92
|
+
return route.middleware.length > 0
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return route.middleware.includes(name)
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Check if the route has any or the ignored middleware. If yes, do not
|
|
101
|
+
* display the route
|
|
102
|
+
*/
|
|
103
|
+
if (allowRoute && this.#filters.ignoreMiddleware) {
|
|
104
|
+
allowRoute = this.#filters.ignoreMiddleware.every((name) => {
|
|
105
|
+
if (name === '*') {
|
|
106
|
+
return route.middleware.length === 0
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return !route.middleware.includes(name)
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* No more filters to be applied
|
|
115
|
+
*/
|
|
116
|
+
if (!this.#filters.match) {
|
|
117
|
+
return allowRoute
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check if the route name has the match keyword
|
|
122
|
+
*/
|
|
123
|
+
if (route.name.includes(this.#filters.match)) {
|
|
124
|
+
return true
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check if the route pattern has the match keyword
|
|
129
|
+
*/
|
|
130
|
+
if (route.pattern.includes(this.#filters.match)) {
|
|
131
|
+
return true
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Check if the route handler has the match keyword
|
|
136
|
+
*/
|
|
137
|
+
if (
|
|
138
|
+
route.handler.type === 'controller'
|
|
139
|
+
? route.handler.moduleNameOrPath.includes(this.#filters.match)
|
|
140
|
+
: route.handler.name.includes(this.#filters.match)
|
|
141
|
+
) {
|
|
142
|
+
return true
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Disallow route
|
|
147
|
+
*/
|
|
148
|
+
return false
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Serialize route middleware to an array of names
|
|
153
|
+
*/
|
|
154
|
+
#serializeMiddleware(middleware: RouteJSON['middleware']): string[] {
|
|
155
|
+
return [...middleware.all()].reduce<string[]>((result, one) => {
|
|
156
|
+
if (typeof one === 'function') {
|
|
157
|
+
result.push(one.name || 'closure')
|
|
158
|
+
return result
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if ('name' in one && one.name) {
|
|
162
|
+
result.push(one.name)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return result
|
|
166
|
+
}, [])
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Serialize route handler reference to display object
|
|
171
|
+
*/
|
|
172
|
+
async #serializeHandler(handler: RouteJSON['handler']): Promise<SerializedRoute['handler']> {
|
|
173
|
+
/**
|
|
174
|
+
* Value is a controller reference
|
|
175
|
+
*/
|
|
176
|
+
if ('reference' in handler) {
|
|
177
|
+
return {
|
|
178
|
+
type: 'controller' as const,
|
|
179
|
+
...(await parseBindingReference(handler.reference)),
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Value is an inline closure
|
|
185
|
+
*/
|
|
186
|
+
return {
|
|
187
|
+
type: 'closure' as const,
|
|
188
|
+
name: handler.name || 'closure',
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Serializes routes JSON to an object that can be used for pretty printing
|
|
194
|
+
*/
|
|
195
|
+
async #serializeRoute(route: RouteJSON): Promise<SerializedRoute> {
|
|
196
|
+
let methods = route.methods
|
|
197
|
+
if (!this.#options.displayHeadRoutes) {
|
|
198
|
+
methods = methods.filter((method) => method !== 'HEAD')
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
name: route.name || '',
|
|
203
|
+
pattern: route.pattern,
|
|
204
|
+
methods: methods,
|
|
205
|
+
handler: await this.#serializeHandler(route.handler),
|
|
206
|
+
middleware: this.#serializeMiddleware(route.middleware),
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Formats the route method for the ansi list and table
|
|
212
|
+
*/
|
|
213
|
+
#formatRouteMethod(method: string) {
|
|
214
|
+
return this.#colors.dim(method)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Formats route pattern for the ansi list and table
|
|
219
|
+
*/
|
|
220
|
+
#formatRoutePattern(route: SerializedRoute) {
|
|
221
|
+
const pattern = this.#router
|
|
222
|
+
.parsePattern(route.pattern)
|
|
223
|
+
.map((token) => {
|
|
224
|
+
if (token.type === 1) {
|
|
225
|
+
return this.#colors.yellow(`:${token.val}`)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (token.type === 3) {
|
|
229
|
+
return this.#colors.yellow(`:${token.val}?`)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (token.type === 2) {
|
|
233
|
+
return this.#colors.red(token.val)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return token.val
|
|
237
|
+
})
|
|
238
|
+
.join('/')
|
|
239
|
+
|
|
240
|
+
return `${pattern === '/' ? pattern : `/${pattern}`}${
|
|
241
|
+
route.name ? ` ${this.#colors.dim(`(${route.name})`)}` : ''
|
|
242
|
+
} `
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Formats controller name for the ansi list and table
|
|
247
|
+
*/
|
|
248
|
+
#formatControllerName(route: SerializedRoute) {
|
|
249
|
+
return route.handler.type === 'controller' ? ` ${route.handler.moduleNameOrPath}.` : ''
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Formats action name for the ansi list and table
|
|
254
|
+
*/
|
|
255
|
+
#formatAction(route: SerializedRoute) {
|
|
256
|
+
return route.handler.type === 'controller'
|
|
257
|
+
? `${this.#colors.cyan(route.handler.method)}`
|
|
258
|
+
: ` ${this.#colors.cyan(route.handler.name)}`
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Formats route middleware for the ansi list and table
|
|
263
|
+
*/
|
|
264
|
+
#formatMiddleware(route: SerializedRoute, mode: 'normal' | 'compact' = 'normal') {
|
|
265
|
+
if (mode === 'compact' && route.middleware.length > 3) {
|
|
266
|
+
const firstMiddleware = route.middleware[0]
|
|
267
|
+
const secondMiddleware = route.middleware[1]
|
|
268
|
+
const diff = route.middleware.length - 2
|
|
269
|
+
return this.#colors.dim(`${firstMiddleware}, ${secondMiddleware}, and ${diff} more`)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return this.#colors.dim(`${route.middleware.filter((one) => one).join(', ')}`)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Formatting the domain headling to be in green color with
|
|
277
|
+
* dots around it
|
|
278
|
+
*/
|
|
279
|
+
#formatDomainHeadline(domain: string) {
|
|
280
|
+
if (domain !== 'root') {
|
|
281
|
+
return cliHelpers.justify([`${this.#colors.dim('..')} ${this.#colors.green(domain)} `], {
|
|
282
|
+
maxWidth: this.#options.maxPrettyPrintWidth || cliHelpers.TERMINAL_SIZE,
|
|
283
|
+
paddingChar: this.#colors.dim('.'),
|
|
284
|
+
})[0]
|
|
285
|
+
}
|
|
286
|
+
return ''
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Justify the ansi list
|
|
291
|
+
*/
|
|
292
|
+
#justifyListTables(tables: { heading: string; rows: [string, string, string, string][] }[]) {
|
|
293
|
+
return tables.map((table) => {
|
|
294
|
+
/**
|
|
295
|
+
* Formatting methods
|
|
296
|
+
*/
|
|
297
|
+
const methods = table.rows.map((columns) => columns[0])
|
|
298
|
+
const largestMethodsLength = Math.max(...methods.map((method) => stringWidth(method)))
|
|
299
|
+
const formattedMethods = cliHelpers.justify(methods, {
|
|
300
|
+
maxWidth: largestMethodsLength,
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Formatting patterns
|
|
305
|
+
*/
|
|
306
|
+
const patterns = table.rows.map((columns) => columns[1])
|
|
307
|
+
const largestPatternLength = Math.max(...patterns.map((pattern) => stringWidth(pattern)))
|
|
308
|
+
const formattedPatterns = cliHelpers.justify(patterns, {
|
|
309
|
+
maxWidth: largestPatternLength,
|
|
310
|
+
paddingChar: this.#colors.dim('.'),
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Formatting middleware to be right aligned
|
|
315
|
+
*/
|
|
316
|
+
const middleware = table.rows.map((columns) => columns[3])
|
|
317
|
+
const largestMiddlewareLength = Math.max(...middleware.map((one) => stringWidth(one)))
|
|
318
|
+
const formattedMiddleware = cliHelpers.justify(middleware, {
|
|
319
|
+
maxWidth: largestMiddlewareLength,
|
|
320
|
+
align: 'right',
|
|
321
|
+
paddingChar: ' ',
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Formatting controllers to be right aligned and take all the remaining
|
|
326
|
+
* space after printing route method, pattern and middleware.
|
|
327
|
+
*/
|
|
328
|
+
const controllers = table.rows.map((columns) => columns[2])
|
|
329
|
+
const largestControllerLength =
|
|
330
|
+
(this.#options.maxPrettyPrintWidth || cliHelpers.TERMINAL_SIZE) -
|
|
331
|
+
(largestPatternLength + largestMethodsLength + largestMiddlewareLength)
|
|
332
|
+
|
|
333
|
+
const formattedControllers = cliHelpers.truncate(
|
|
334
|
+
cliHelpers.justify(controllers, {
|
|
335
|
+
maxWidth: largestControllerLength,
|
|
336
|
+
align: 'right',
|
|
337
|
+
paddingChar: this.#colors.dim('.'),
|
|
338
|
+
}),
|
|
339
|
+
{
|
|
340
|
+
maxWidth: largestControllerLength,
|
|
341
|
+
}
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
heading: table.heading,
|
|
346
|
+
rows: formattedMethods.reduce<string[]>((result, method, index) => {
|
|
347
|
+
result.push(
|
|
348
|
+
`${method}${formattedPatterns[index]}${formattedControllers[index]}${formattedMiddleware[index]}`
|
|
349
|
+
)
|
|
350
|
+
return result
|
|
351
|
+
}, []),
|
|
352
|
+
}
|
|
353
|
+
})
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Formats routes as an array of objects. Routes are grouped by
|
|
358
|
+
* domain.
|
|
359
|
+
*/
|
|
360
|
+
async formatAsJSON() {
|
|
361
|
+
const routes = this.#router.toJSON()
|
|
362
|
+
const domains = Object.keys(routes)
|
|
363
|
+
let routesJSON: { domain: string; routes: SerializedRoute[] }[] = []
|
|
364
|
+
|
|
365
|
+
for (let domain of domains) {
|
|
366
|
+
const domainRoutes = await Promise.all(
|
|
367
|
+
routes[domain].map((route) => this.#serializeRoute(route))
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
routesJSON.push({
|
|
371
|
+
domain,
|
|
372
|
+
routes: domainRoutes.filter((route) => this.#isAllowedByFilters(route)),
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return routesJSON
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Format routes to ansi list of tables. Each domain has its own table
|
|
381
|
+
* with heading and rows. Each row has colums with colors and spacing
|
|
382
|
+
* around them.
|
|
383
|
+
*/
|
|
384
|
+
async formatAsAnsiList() {
|
|
385
|
+
const routes = this.#router.toJSON()
|
|
386
|
+
const domains = Object.keys(routes)
|
|
387
|
+
const tables: { heading: string; rows: [string, string, string, string][] }[] = []
|
|
388
|
+
|
|
389
|
+
for (let domain of domains) {
|
|
390
|
+
const list: (typeof tables)[number] = {
|
|
391
|
+
heading: this.#formatDomainHeadline(domain),
|
|
392
|
+
rows: [
|
|
393
|
+
[
|
|
394
|
+
this.#colors.dim('METHOD'),
|
|
395
|
+
` ${this.#colors.dim('ROUTE')} `,
|
|
396
|
+
` ${this.#colors.dim('HANDLER')}`,
|
|
397
|
+
` ${this.#colors.dim('MIDDLEWARE')}`,
|
|
398
|
+
],
|
|
399
|
+
],
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Computing table rows. Each route+method will have its
|
|
404
|
+
* own row
|
|
405
|
+
*/
|
|
406
|
+
for (let route of routes[domain]) {
|
|
407
|
+
const serializedRoute = await this.#serializeRoute(route)
|
|
408
|
+
if (this.#isAllowedByFilters(serializedRoute)) {
|
|
409
|
+
serializedRoute.methods.forEach((method) => {
|
|
410
|
+
list.rows.push([
|
|
411
|
+
this.#formatRouteMethod(method),
|
|
412
|
+
` ${this.#formatRoutePattern(serializedRoute)}`,
|
|
413
|
+
`${this.#formatControllerName(serializedRoute)}${this.#formatAction(
|
|
414
|
+
serializedRoute
|
|
415
|
+
)}`,
|
|
416
|
+
` ${this.#formatMiddleware(serializedRoute, 'compact')}`,
|
|
417
|
+
])
|
|
418
|
+
})
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
tables.push(list)
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return this.#justifyListTables(tables)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Format routes to ansi tables. Each domain has its own table
|
|
430
|
+
* with heading and rows. Each row has colums with colors and spacing
|
|
431
|
+
* around them.
|
|
432
|
+
*/
|
|
433
|
+
async formatAsAnsiTable() {
|
|
434
|
+
const routes = this.#router.toJSON()
|
|
435
|
+
const domains = Object.keys(routes)
|
|
436
|
+
const tables: { heading: string; table: ReturnType<UIPrimitives['table']> }[] = []
|
|
437
|
+
|
|
438
|
+
for (let domain of domains) {
|
|
439
|
+
const list: (typeof tables)[number] = {
|
|
440
|
+
heading: this.#formatDomainHeadline(domain),
|
|
441
|
+
table: this.#table()
|
|
442
|
+
.fullWidth()
|
|
443
|
+
.fluidColumnIndex(2)
|
|
444
|
+
.head([
|
|
445
|
+
this.#colors.dim('METHOD'),
|
|
446
|
+
this.#colors.dim('ROUTE'),
|
|
447
|
+
{ hAlign: 'right', content: this.#colors.dim('HANDLER') },
|
|
448
|
+
{ content: this.#colors.dim('MIDDLEWARE'), hAlign: 'right' },
|
|
449
|
+
]),
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Computing table rows. Each route+method will have its
|
|
454
|
+
* own row
|
|
455
|
+
*/
|
|
456
|
+
for (let route of routes[domain]) {
|
|
457
|
+
const serializedRoute = await this.#serializeRoute(route)
|
|
458
|
+
if (this.#isAllowedByFilters(serializedRoute)) {
|
|
459
|
+
serializedRoute.methods.forEach((method) => {
|
|
460
|
+
list.table.row([
|
|
461
|
+
this.#formatRouteMethod(method),
|
|
462
|
+
this.#formatRoutePattern(serializedRoute),
|
|
463
|
+
{
|
|
464
|
+
content: `${this.#formatControllerName(serializedRoute)}${this.#formatAction(
|
|
465
|
+
serializedRoute
|
|
466
|
+
)}`,
|
|
467
|
+
hAlign: 'right',
|
|
468
|
+
},
|
|
469
|
+
{ content: this.#formatMiddleware(serializedRoute), hAlign: 'right' },
|
|
470
|
+
])
|
|
471
|
+
})
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
tables.push(list)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return tables
|
|
479
|
+
}
|
|
480
|
+
}
|
package/src/debug.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/core
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { debuglog } from 'node:util'
|
|
11
|
+
|
|
12
|
+
export default debuglog('adonisjs:core')
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/core
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { default as parseImports } from 'parse-imports'
|
|
11
|
+
export { createId as cuid } from '@paralleldrive/cuid2'
|
|
12
|
+
export { safeEqual, compose, base64, fsImportAll, fsReadAll, slash } from '@poppinss/utils'
|
|
13
|
+
export { parseBindingReference } from './parse_binding_reference.js'
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/core
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import parseImports from 'parse-imports'
|
|
11
|
+
import { LazyImport, Constructor } from '../../types/http.js'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The "parseBindingReference" method can be used to parse a binding references
|
|
15
|
+
* similar to route controller binding value or event listener binding value.
|
|
16
|
+
*
|
|
17
|
+
* See the following examples to understand how this function works.
|
|
18
|
+
*
|
|
19
|
+
* ### Magic strings
|
|
20
|
+
* ```ts
|
|
21
|
+
* parseBindingReference('#controllers/home_controller')
|
|
22
|
+
* // returns { moduleNameOrPath: '#controllers/home_controller', method: 'handle' }
|
|
23
|
+
|
|
24
|
+
* parseBindingReference('#controllers/home_controller.index')
|
|
25
|
+
* // returns { moduleNameOrPath: '#controllers/home_controller', method: 'index' }
|
|
26
|
+
|
|
27
|
+
* parseBindingReference('#controllers/home.controller.index')
|
|
28
|
+
* // returns { moduleNameOrPath: '#controllers/home.controller', method: 'index' }
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* ### Class reference
|
|
32
|
+
* ```ts
|
|
33
|
+
* class HomeController {}
|
|
34
|
+
*
|
|
35
|
+
* parseBindingReference([HomeController])
|
|
36
|
+
* // returns { moduleNameOrPath: 'HomeController', method: 'handle' }
|
|
37
|
+
|
|
38
|
+
* parseBindingReference([HomeController, 'index'])
|
|
39
|
+
* // returns { moduleNameOrPath: 'HomeController', method: 'index' }
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* ### Lazy import reference
|
|
43
|
+
* ```ts
|
|
44
|
+
* const HomeController = () => import('#controllers/home_controller')
|
|
45
|
+
*
|
|
46
|
+
* parseBindingReference([HomeController])
|
|
47
|
+
* // returns { moduleNameOrPath: '#controllers/home_controller', method: 'handle' }
|
|
48
|
+
|
|
49
|
+
* parseBindingReference([HomeController, 'index'])
|
|
50
|
+
* // returns { moduleNameOrPath: 'controllers/home_controller', method: 'index' }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export async function parseBindingReference(
|
|
54
|
+
binding: string | [LazyImport<Constructor<any>> | Constructor<any>, any?]
|
|
55
|
+
): Promise<{ moduleNameOrPath: string; method: string }> {
|
|
56
|
+
/**
|
|
57
|
+
* The binding reference is a magic string. It might not have method
|
|
58
|
+
* name attached to it. Therefore we split the string and attempt
|
|
59
|
+
* to find the method or use the default method name "handle".
|
|
60
|
+
*/
|
|
61
|
+
if (typeof binding === 'string') {
|
|
62
|
+
const tokens = binding.split('.')
|
|
63
|
+
if (tokens.length === 1) {
|
|
64
|
+
return { moduleNameOrPath: binding, method: 'handle' }
|
|
65
|
+
}
|
|
66
|
+
return { method: tokens.pop()!, moduleNameOrPath: tokens.join('.') }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const [bindingReference, method] = binding
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Parsing the binding reference for dynamic imports and using its
|
|
73
|
+
* import value.
|
|
74
|
+
*/
|
|
75
|
+
const imports = [...(await parseImports(bindingReference.toString()))]
|
|
76
|
+
const importedModule = imports.find(
|
|
77
|
+
($import) => $import.isDynamicImport && $import.moduleSpecifier.value
|
|
78
|
+
)
|
|
79
|
+
if (importedModule) {
|
|
80
|
+
return {
|
|
81
|
+
moduleNameOrPath: importedModule.moduleSpecifier.value!,
|
|
82
|
+
method: method || 'handle',
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Otherwise using the name of the binding reference.
|
|
88
|
+
*/
|
|
89
|
+
return {
|
|
90
|
+
moduleNameOrPath: bindingReference.name,
|
|
91
|
+
method: method || 'handle',
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/core
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import he, { EncodeOptions } from 'he'
|
|
11
|
+
import prettyHrTime from 'pretty-hrtime'
|
|
12
|
+
import string from '@poppinss/utils/string'
|
|
13
|
+
import StringBuilder from '@poppinss/utils/string_builder'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Collection of string helpers to transform a string value.
|
|
17
|
+
*/
|
|
18
|
+
const stringHelpers: typeof string & {
|
|
19
|
+
/**
|
|
20
|
+
* Creates an instance of the string builder
|
|
21
|
+
*/
|
|
22
|
+
create(value: string | StringBuilder): StringBuilder
|
|
23
|
+
|
|
24
|
+
ordinalize: (typeof string)['ordinal']
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Convert a string to a sentence
|
|
28
|
+
*/
|
|
29
|
+
toSentence: (typeof string)['sentence']
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generate a random string value of a given length
|
|
33
|
+
*/
|
|
34
|
+
generateRandom: (typeof string)['random']
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Pretty print hrtime diff
|
|
38
|
+
*/
|
|
39
|
+
prettyHrTime(
|
|
40
|
+
time: [number, number],
|
|
41
|
+
options?: { verbose?: boolean | undefined; precise?: boolean | undefined }
|
|
42
|
+
): string
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check if a string is empty.
|
|
46
|
+
*/
|
|
47
|
+
isEmpty(value: string): boolean
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Escape HTML entities
|
|
51
|
+
*/
|
|
52
|
+
escapeHTML(value: string, options?: { encodeSymbols?: boolean }): string
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Encode symbols to html entities
|
|
56
|
+
*/
|
|
57
|
+
encodeSymbols(value: string, options?: EncodeOptions): string
|
|
58
|
+
} = {
|
|
59
|
+
...string,
|
|
60
|
+
toSentence: string.sentence,
|
|
61
|
+
ordinalize: string.ordinal,
|
|
62
|
+
generateRandom: string.random,
|
|
63
|
+
|
|
64
|
+
create(value: string | StringBuilder): StringBuilder {
|
|
65
|
+
return new StringBuilder(value)
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
prettyHrTime(time, options) {
|
|
69
|
+
return prettyHrTime(time, options)
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
isEmpty(value: string): boolean {
|
|
73
|
+
return value.trim().length === 0
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
escapeHTML(value: string, options?: { encodeSymbols?: boolean }): string {
|
|
77
|
+
value = he.escape(value)
|
|
78
|
+
if (options && options.encodeSymbols) {
|
|
79
|
+
value = this.encodeSymbols(value, { allowUnsafeSymbols: true })
|
|
80
|
+
}
|
|
81
|
+
return value
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
encodeSymbols(value: string, options?: EncodeOptions): string {
|
|
85
|
+
return he.encode(value, options)
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export default stringHelpers
|