@kubb/core 2.0.0-alpha.3 → 2.0.0-alpha.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.
Files changed (52) hide show
  1. package/dist/index.cjs +62 -74
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +18 -38
  4. package/dist/index.d.ts +18 -38
  5. package/dist/index.js +62 -72
  6. package/dist/index.js.map +1 -1
  7. package/dist/utils.cjs +12 -7
  8. package/dist/utils.cjs.map +1 -1
  9. package/dist/utils.d.cts +2 -1
  10. package/dist/utils.d.ts +2 -1
  11. package/dist/utils.js +12 -7
  12. package/dist/utils.js.map +1 -1
  13. package/package.json +8 -7
  14. package/src/BarrelManager.ts +123 -0
  15. package/src/FileManager.ts +482 -0
  16. package/src/Generator.ts +34 -0
  17. package/src/PackageManager.ts +163 -0
  18. package/src/PluginManager.ts +640 -0
  19. package/src/PromiseManager.ts +48 -0
  20. package/src/SchemaGenerator.ts +8 -0
  21. package/src/build.ts +198 -0
  22. package/src/config.ts +21 -0
  23. package/src/errors.ts +12 -0
  24. package/src/index.ts +28 -0
  25. package/src/plugin.ts +80 -0
  26. package/src/types.ts +370 -0
  27. package/src/utils/EventEmitter.ts +24 -0
  28. package/src/utils/FunctionParams.ts +85 -0
  29. package/src/utils/Queue.ts +110 -0
  30. package/src/utils/TreeNode.ts +122 -0
  31. package/src/utils/URLPath.ts +128 -0
  32. package/src/utils/cache.ts +35 -0
  33. package/src/utils/clean.ts +5 -0
  34. package/src/utils/executeStrategies.ts +71 -0
  35. package/src/utils/index.ts +19 -0
  36. package/src/utils/logger.ts +76 -0
  37. package/src/utils/promise.ts +13 -0
  38. package/src/utils/randomColour.ts +39 -0
  39. package/src/utils/read.ts +68 -0
  40. package/src/utils/renderTemplate.ts +31 -0
  41. package/src/utils/throttle.ts +30 -0
  42. package/src/utils/timeout.ts +7 -0
  43. package/src/utils/transformers/combineCodes.ts +3 -0
  44. package/src/utils/transformers/createJSDocBlockText.ts +15 -0
  45. package/src/utils/transformers/escape.ts +31 -0
  46. package/src/utils/transformers/indent.ts +3 -0
  47. package/src/utils/transformers/index.ts +20 -0
  48. package/src/utils/transformers/nameSorter.ts +9 -0
  49. package/src/utils/transformers/searchAndReplace.ts +25 -0
  50. package/src/utils/transformers/transformReservedWord.ts +97 -0
  51. package/src/utils/uniqueName.ts +20 -0
  52. package/src/utils/write.ts +63 -0
@@ -0,0 +1,128 @@
1
+ import { camelCase, camelCaseTransformMerge } from 'change-case'
2
+
3
+ export type URLObject = {
4
+ url: string
5
+ params?: Record<string, string>
6
+ }
7
+
8
+ type ObjectOptions = {
9
+ type?: 'path' | 'template'
10
+ replacer?: (pathParam: string) => string
11
+ stringify?: boolean
12
+ }
13
+
14
+ export class URLPath {
15
+ path: string
16
+
17
+ constructor(path: string) {
18
+ this.path = path
19
+
20
+ return this
21
+ }
22
+
23
+ /**
24
+ * Convert Swagger path to URLPath(syntax of Express)
25
+ * @example /pet/{petId} => /pet/:petId
26
+ */
27
+ get URL(): string {
28
+ return this.toURLPath()
29
+ }
30
+ get isURL(): boolean {
31
+ try {
32
+ const url = new URL(this.path)
33
+ if (url?.href) {
34
+ return true
35
+ }
36
+ } catch (error) {
37
+ return false
38
+ }
39
+ return false
40
+ }
41
+
42
+ /**
43
+ * Convert Swagger path to template literals/ template strings(camelcase)
44
+ * @example /pet/{petId} => `/pet/${petId}`
45
+ * @example /account/monetary-accountID => `/account/${monetaryAccountId}`
46
+ * @example /account/userID => `/account/${userId}`
47
+ */
48
+ get template(): string {
49
+ return this.toTemplateString()
50
+ }
51
+ get object(): URLObject | string {
52
+ return this.toObject()
53
+ }
54
+ get params(): Record<string, string> | undefined {
55
+ return this.getParams()
56
+ }
57
+
58
+ toObject({ type = 'path', replacer, stringify }: ObjectOptions = {}): URLObject | string {
59
+ const object = {
60
+ url: type === 'path' ? this.toURLPath() : this.toTemplateString(replacer),
61
+ params: this.getParams(),
62
+ }
63
+
64
+ if (stringify) {
65
+ if (type !== 'template') {
66
+ throw new Error('Type should be `template` when using stringiyf')
67
+ }
68
+ return JSON.stringify(object).replaceAll("'", '').replaceAll(`"`, '')
69
+ }
70
+
71
+ return object
72
+ }
73
+
74
+ /**
75
+ * Convert Swagger path to template literals/ template strings(camelcase)
76
+ * @example /pet/{petId} => `/pet/${petId}`
77
+ * @example /account/monetary-accountID => `/account/${monetaryAccountId}`
78
+ * @example /account/userID => `/account/${userId}`
79
+ */
80
+ toTemplateString(replacer?: (pathParam: string) => string): string {
81
+ const regex = /{(\w|-)*}/g
82
+ const found = this.path.match(regex)
83
+ let newPath = this.path.replaceAll('{', '${')
84
+
85
+ if (found) {
86
+ newPath = found.reduce((prev, curr) => {
87
+ const pathParam = replacer
88
+ ? replacer(camelCase(curr, { delimiter: '', transform: camelCaseTransformMerge }))
89
+ : camelCase(curr, { delimiter: '', transform: camelCaseTransformMerge })
90
+ const replacement = `\${${pathParam}}`
91
+
92
+ return prev.replace(curr, replacement)
93
+ }, this.path)
94
+ }
95
+
96
+ return `\`${newPath}\``
97
+ }
98
+
99
+ getParams(replacer?: (pathParam: string) => string): Record<string, string> | undefined {
100
+ const regex = /{(\w|-)*}/g
101
+ const found = this.path.match(regex)
102
+
103
+ if (!found) {
104
+ return undefined
105
+ }
106
+
107
+ const params: Record<string, string> = {}
108
+ found.forEach((item) => {
109
+ item = item.replaceAll('{', '').replaceAll('}', '')
110
+
111
+ const pathParam = replacer
112
+ ? replacer(camelCase(item, { delimiter: '', transform: camelCaseTransformMerge }))
113
+ : camelCase(item, { delimiter: '', transform: camelCaseTransformMerge })
114
+
115
+ params[pathParam] = pathParam
116
+ }, this.path)
117
+
118
+ return params
119
+ }
120
+
121
+ /**
122
+ * Convert Swagger path to URLPath(syntax of Express)
123
+ * @example /pet/{petId} => /pet/:petId
124
+ */
125
+ toURLPath(): string {
126
+ return this.path.replaceAll('{', ':').replaceAll('}', '')
127
+ }
128
+ }
@@ -0,0 +1,35 @@
1
+ import type { PluginCache } from '../types.ts'
2
+
3
+ export interface Cache<TStore extends object = object> {
4
+ delete(id: keyof TStore): boolean
5
+ get(id: keyof TStore): TStore[keyof TStore] | null
6
+ has(id: keyof TStore): boolean
7
+ set(id: keyof TStore, value: unknown): void
8
+ }
9
+
10
+ export function createPluginCache<TStore extends PluginCache>(Store: TStore = Object.create(null) as TStore): Cache<TStore> {
11
+ return {
12
+ set(id, value): void {
13
+ Store[id] = [0, value] as TStore[keyof TStore]
14
+ },
15
+ get(id): TStore[keyof TStore] | null {
16
+ const item = Store[id]
17
+ if (!item) {
18
+ return null
19
+ }
20
+ item[0] = 0
21
+ return item[1] as TStore[keyof TStore]
22
+ },
23
+ has(id): boolean {
24
+ const item = Store[id]
25
+ if (!item) {
26
+ return false
27
+ }
28
+ item[0] = 0
29
+ return true
30
+ },
31
+ delete(id: keyof TStore): boolean {
32
+ return delete Store[id]
33
+ },
34
+ }
35
+ }
@@ -0,0 +1,5 @@
1
+ import { remove } from 'fs-extra'
2
+
3
+ export async function clean(path: string): Promise<void> {
4
+ return remove(path)
5
+ }
@@ -0,0 +1,71 @@
1
+ /* eslint-disable unused-imports/no-unused-vars */
2
+ /* eslint-disable @typescript-eslint/no-unused-vars */
3
+ type PromiseFunc<T = unknown, T2 = never> = (state: T) => T2 extends never ? Promise<T> : Promise<T> | T2
4
+
5
+ export type ValueOfPromiseFuncArray<TInput extends Array<unknown>> = TInput extends Array<PromiseFunc<infer X, infer Y>> ? X | Y : never
6
+
7
+ export function noReturn(): void {}
8
+
9
+ type SeqOutput<TInput extends Array<PromiseFunc<TValue, null>>, TValue> = Array<Awaited<ValueOfPromiseFuncArray<TInput>>>
10
+
11
+ /**
12
+ * Chains promises
13
+ */
14
+ export function hookSeq<TInput extends Array<PromiseFunc<TValue, null>>, TValue, TOutput = SeqOutput<TInput, TValue>>(
15
+ promises: TInput,
16
+ ): TOutput {
17
+ return promises.filter(Boolean).reduce(
18
+ (promise, func) => {
19
+ if (typeof func !== 'function') {
20
+ throw new Error('HookSeq needs a function that returns a promise `() => Promise<unknown>`')
21
+ }
22
+
23
+ return promise.then((state) => {
24
+ const calledFunc = func(state as TValue)
25
+
26
+ if (calledFunc) {
27
+ return calledFunc.then(Array.prototype.concat.bind(state))
28
+ }
29
+ })
30
+ },
31
+ Promise.resolve([] as unknown),
32
+ ) as TOutput
33
+ }
34
+
35
+ type HookFirstOutput<TInput extends Array<PromiseFunc<TValue, null>>, TValue = unknown> = ValueOfPromiseFuncArray<TInput>
36
+
37
+ /**
38
+ * Chains promises, first non-null result stops and returns
39
+ */
40
+ export function hookFirst<TInput extends Array<PromiseFunc<TValue, null>>, TValue = unknown, TOutput = HookFirstOutput<TInput, TValue>>(
41
+ promises: TInput,
42
+ nullCheck = (state: any) => state !== null,
43
+ ): TOutput {
44
+ let promise: Promise<unknown> = Promise.resolve(null) as Promise<unknown>
45
+
46
+ for (const func of promises.filter(Boolean)) {
47
+ promise = promise.then((state) => {
48
+ if (nullCheck(state)) {
49
+ return state
50
+ }
51
+
52
+ const calledFunc = func(state as TValue)
53
+
54
+ return calledFunc
55
+ })
56
+ }
57
+
58
+ return promise as TOutput
59
+ }
60
+
61
+ export type Strategy = 'seq' | 'first'
62
+
63
+ export type StrategySwitch<TStrategy extends Strategy, TInput extends Array<PromiseFunc<TValue, null>>, TValue> = TStrategy extends 'first'
64
+ ? HookFirstOutput<TInput, TValue>
65
+ : TStrategy extends 'seq' ? SeqOutput<TInput, TValue>
66
+ : never
67
+
68
+ // tests
69
+
70
+ type test = ValueOfPromiseFuncArray<Array<PromiseFunc<number, null>>>
71
+ // ^?
@@ -0,0 +1,19 @@
1
+ export * from './cache.ts'
2
+ export * from './cache.ts'
3
+ export * from './clean.ts'
4
+ export * from './FunctionParams.ts'
5
+ export * from './FunctionParams.ts'
6
+ export * from './logger.ts'
7
+ export * from './promise.ts'
8
+ export * from './Queue.ts'
9
+ export * from './Queue.ts'
10
+ export * from './randomColour.ts'
11
+ export * from './read.ts'
12
+ export * from './renderTemplate.ts'
13
+ export * from './throttle.ts'
14
+ export * from './timeout.ts'
15
+ export * from './transformers/index.ts'
16
+ export * from './TreeNode.ts'
17
+ export * from './uniqueName.ts'
18
+ export * from './URLPath.ts'
19
+ export * from './write.ts'
@@ -0,0 +1,76 @@
1
+ import pc from 'picocolors'
2
+
3
+ import type { Ora } from 'ora'
4
+
5
+ export const LogLevel = {
6
+ silent: 'silent',
7
+ info: 'info',
8
+ debug: 'debug',
9
+ } as const
10
+
11
+ export type LogLevel = keyof typeof LogLevel
12
+
13
+ export type Logger = {
14
+ /**
15
+ * Optional config name to show in CLI output
16
+ */
17
+ name?: string
18
+ logLevel: LogLevel
19
+ log: (message: string | null) => void
20
+ error: (message: string | null) => void
21
+ info: (message: string | null) => void
22
+ warn: (message: string | null) => void
23
+ spinner?: Ora
24
+ logs: string[]
25
+ }
26
+
27
+ type Props = {
28
+ name?: string
29
+ logLevel: LogLevel
30
+ spinner?: Ora
31
+ }
32
+
33
+ export function createLogger({ logLevel, name, spinner }: Props): Logger {
34
+ const logs: string[] = []
35
+ const log: Logger['log'] = (message) => {
36
+ if (message && spinner) {
37
+ spinner.text = message
38
+ logs.push(message)
39
+ }
40
+ }
41
+
42
+ const error: Logger['error'] = (message) => {
43
+ if (message) {
44
+ throw new Error(message || 'Something went wrong')
45
+ }
46
+ }
47
+
48
+ const warn: Logger['warn'] = (message) => {
49
+ if (message && spinner) {
50
+ spinner.warn(pc.yellow(message))
51
+ logs.push(message)
52
+ }
53
+ }
54
+
55
+ const info: Logger['warn'] = (message) => {
56
+ if (message && spinner) {
57
+ spinner.info(message)
58
+ logs.push(message)
59
+ }
60
+ }
61
+
62
+ const logger: Logger = {
63
+ name,
64
+ logLevel,
65
+ log,
66
+ error,
67
+ warn,
68
+ info,
69
+ spinner,
70
+ logs,
71
+ }
72
+
73
+ return logger
74
+ }
75
+
76
+ export { default as pc } from 'picocolors'
@@ -0,0 +1,13 @@
1
+ type PossiblePromise<T> = Promise<T> | T
2
+
3
+ export function isPromise<T>(result: PossiblePromise<T>): result is Promise<T> {
4
+ return !!result && typeof (result as Promise<unknown>)?.then === 'function'
5
+ }
6
+
7
+ export function isPromiseFulfilledResult<T = unknown>(result: PromiseSettledResult<unknown>): result is PromiseFulfilledResult<T> {
8
+ return result.status === 'fulfilled'
9
+ }
10
+
11
+ export function isPromiseRejectedResult<T>(result: PromiseSettledResult<unknown>): result is Omit<PromiseRejectedResult, 'reason'> & { reason: T } {
12
+ return result.status === 'rejected'
13
+ }
@@ -0,0 +1,39 @@
1
+ import pc from 'picocolors'
2
+ import seedrandom from 'seedrandom'
3
+
4
+ import type { Formatter } from 'picocolors/types.ts'
5
+
6
+ const defaultColours = ['black', 'blue', 'darkBlue', 'cyan', 'gray', 'green', 'darkGreen', 'magenta', 'red', 'darkRed', 'yellow', 'darkYellow'] as const
7
+
8
+ export function randomColour(text?: string, colours = defaultColours): string {
9
+ if (!text) {
10
+ return 'white'
11
+ }
12
+
13
+ const random = seedrandom(text)
14
+ const colour = colours.at(Math.floor(random() * colours.length)) || 'white'
15
+
16
+ return colour
17
+ }
18
+
19
+ export function randomPicoColour(text?: string, colors = defaultColours): string {
20
+ const colours = pc.createColors(true)
21
+
22
+ if (!text) {
23
+ return colours.white(text)
24
+ }
25
+
26
+ const colour = randomColour(text, colors)
27
+ const isDark = colour.includes('dark')
28
+ const key = colour.replace('dark', '').toLowerCase() as keyof typeof colours
29
+ const formatter: Formatter = colours[key] as Formatter
30
+
31
+ if (isDark) {
32
+ return pc.bold(formatter(text))
33
+ }
34
+
35
+ if (typeof formatter !== 'function') {
36
+ throw new Error('Formatter for picoColor is not of type function/Formatter')
37
+ }
38
+ return formatter(text)
39
+ }
@@ -0,0 +1,68 @@
1
+ import { basename, extname, relative } from 'node:path'
2
+
3
+ import fs from 'fs-extra'
4
+ import { switcher } from 'js-runtime'
5
+
6
+ function slash(path: string, platform: 'windows' | 'mac' | 'linux' = 'linux') {
7
+ const isWindowsPath = /^\\\\\?\\/.test(path)
8
+
9
+ if (['linux', 'mac'].includes(platform) && !isWindowsPath) {
10
+ // linux and mac
11
+ return path.replaceAll(/\\/g, '/').replace('../', '').trimEnd()
12
+ }
13
+
14
+ // windows
15
+ return path.replaceAll(/\\/g, '/').replace('../', '').trimEnd()
16
+ }
17
+
18
+ export function getRelativePath(rootDir?: string | null, filePath?: string | null, platform: 'windows' | 'mac' | 'linux' = 'linux'): string {
19
+ if (!rootDir || !filePath) {
20
+ throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ''} ${filePath || ''}`)
21
+ }
22
+
23
+ const relativePath = relative(rootDir, filePath)
24
+
25
+ // On Windows, paths are separated with a "\"
26
+ // However, web browsers use "/" no matter the platform
27
+ const slashedPath = slash(relativePath, platform)
28
+
29
+ if (slashedPath.startsWith('../')) {
30
+ return slashedPath.replace(basename(slashedPath), basename(slashedPath, extname(filePath)))
31
+ }
32
+
33
+ return `./${slashedPath.replace(basename(slashedPath), basename(slashedPath, extname(filePath)))}`
34
+ }
35
+
36
+ const reader = switcher(
37
+ {
38
+ node: async (path: string) => {
39
+ return fs.readFile(path, { encoding: 'utf8' })
40
+ },
41
+ bun: async (path: string) => {
42
+ const file = Bun.file(path)
43
+
44
+ return file.text()
45
+ },
46
+ },
47
+ 'node',
48
+ )
49
+
50
+ const syncReader = switcher(
51
+ {
52
+ node: (path: string) => {
53
+ return fs.readFileSync(path, { encoding: 'utf8' })
54
+ },
55
+ bun: () => {
56
+ throw new Error('Bun cannot read sync')
57
+ },
58
+ },
59
+ 'node',
60
+ )
61
+
62
+ export async function read(path: string): Promise<string> {
63
+ return reader(path)
64
+ }
65
+
66
+ export function readSync(path: string): string {
67
+ return syncReader(path)
68
+ }
@@ -0,0 +1,31 @@
1
+ export function renderTemplate<TData extends Record<string, unknown> = Record<string, unknown>>(template: string, data: TData | undefined = undefined): string {
2
+ if (!data || !Object.keys(data).length) {
3
+ return template.replace(/{{(.*?)}}/g, '')
4
+ }
5
+
6
+ const matches = template.match(/{{(.*?)}}/g)
7
+
8
+ return (
9
+ matches?.reduce((prev, curr) => {
10
+ const index = curr.split(/{{|}}/).filter(Boolean)[0]?.trim()
11
+ if (index === undefined) {
12
+ return prev
13
+ }
14
+ const value = data[index]
15
+
16
+ if (value === undefined) {
17
+ return prev
18
+ }
19
+
20
+ return prev
21
+ .replace(curr, () => {
22
+ if (typeof value === 'boolean') {
23
+ return `${value.toString()}` || 'false'
24
+ }
25
+
26
+ return (value as string) || ''
27
+ })
28
+ .trim()
29
+ }, template) || ''
30
+ )
31
+ }
@@ -0,0 +1,30 @@
1
+ export const throttle = <R, A extends any[]>(fn: (...args: A) => R, delay: number): [(...args: A) => R | undefined, () => void] => {
2
+ let wait = false
3
+ let timeout: NodeJS.Timeout
4
+ let cancelled = false
5
+
6
+ return [
7
+ (...args: A) => {
8
+ if (cancelled) {
9
+ return undefined
10
+ }
11
+ if (wait) {
12
+ return undefined
13
+ }
14
+
15
+ const val = fn(...args)
16
+
17
+ wait = true
18
+
19
+ timeout = setTimeout(() => {
20
+ wait = false
21
+ }, delay)
22
+
23
+ return val
24
+ },
25
+ () => {
26
+ cancelled = true
27
+ clearTimeout(timeout)
28
+ },
29
+ ]
30
+ }
@@ -0,0 +1,7 @@
1
+ export async function timeout(ms: number): Promise<unknown> {
2
+ return new Promise((resolve) => {
3
+ setTimeout(() => {
4
+ resolve(true)
5
+ }, ms)
6
+ })
7
+ }
@@ -0,0 +1,3 @@
1
+ export function combineCodes(codes: string[]): string {
2
+ return codes.join('\n')
3
+ }
@@ -0,0 +1,15 @@
1
+ export function createJSDocBlockText({ comments, newLine }: { comments: Array<string>; newLine?: boolean }): string {
2
+ const filteredComments = comments.filter(Boolean)
3
+
4
+ if (!filteredComments.length) {
5
+ return ''
6
+ }
7
+
8
+ const source = `/**\n * ${filteredComments.join('\n * ')}\n */`
9
+
10
+ if (newLine) {
11
+ return `${source}\n`
12
+ }
13
+
14
+ return source
15
+ }
@@ -0,0 +1,31 @@
1
+ export function escape(text?: string): string {
2
+ return text ? text.replaceAll('`', '\\`') : ''
3
+ }
4
+
5
+ /**
6
+ * Escape all characters not included in SingleStringCharacters and DoubleStringCharacters on
7
+ * @link http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
8
+ * @link https://github.com/joliss/js-string-escape/blob/master/index.js
9
+ */
10
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
11
+ export function jsStringEscape(input: any): string {
12
+ return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => {
13
+ switch (character) {
14
+ case '"':
15
+ case "'":
16
+ case '\\':
17
+ return '\\' + character
18
+ // Four possible LineTerminator characters need to be escaped:
19
+ case '\n':
20
+ return '\\n'
21
+ case '\r':
22
+ return '\\r'
23
+ case '\u2028':
24
+ return '\\u2028'
25
+ case '\u2029':
26
+ return '\\u2029'
27
+ default:
28
+ return ''
29
+ }
30
+ })
31
+ }
@@ -0,0 +1,3 @@
1
+ export function createIndent(size: number): string {
2
+ return Array.from({ length: size + 1 }).join(' ')
3
+ }
@@ -0,0 +1,20 @@
1
+ import { combineCodes } from './combineCodes.ts'
2
+ import { createJSDocBlockText } from './createJSDocBlockText.ts'
3
+ import { escape, jsStringEscape } from './escape.ts'
4
+ import { createIndent } from './indent.ts'
5
+ import { nameSorter } from './nameSorter.ts'
6
+ import { searchAndReplace } from './searchAndReplace.ts'
7
+ import { transformReservedWord } from './transformReservedWord.ts'
8
+
9
+ export const transformers = {
10
+ combineCodes,
11
+ escape,
12
+ jsStringEscape,
13
+ createIndent,
14
+ transformReservedWord,
15
+ nameSorter,
16
+ searchAndReplace,
17
+ JSDoc: {
18
+ createJSDocBlockText,
19
+ },
20
+ } as const
@@ -0,0 +1,9 @@
1
+ export function nameSorter<T extends { name: string }>(a: T, b: T): 0 | 1 | -1 {
2
+ if (a.name < b.name) {
3
+ return -1
4
+ }
5
+ if (a.name > b.name) {
6
+ return 1
7
+ }
8
+ return 0
9
+ }
@@ -0,0 +1,25 @@
1
+ type Options = {
2
+ text: string
3
+ replaceBy: string
4
+ prefix?: string
5
+ key: string
6
+ searchValues?: (prefix: string, key: string) => Array<RegExp | string>
7
+ }
8
+
9
+ export function searchAndReplace(options: Options): string {
10
+ const { text, replaceBy, prefix = '', key } = options
11
+
12
+ const searchValues = options.searchValues?.(prefix, key) || [
13
+ `${prefix}["${key}"]`,
14
+ `${prefix}['${key}']`,
15
+ `${prefix}[\`${key}\`]`,
16
+ `${prefix}"${key}"`,
17
+ `${prefix}'${key}'`,
18
+ `${prefix}\`${key}\``,
19
+ new RegExp(`${prefix}${key}`, 'g'),
20
+ ]
21
+
22
+ return searchValues.reduce((prev, searchValue) => {
23
+ return prev.toString().replaceAll(searchValue, replaceBy)
24
+ }, text) as string
25
+ }