Skip to content

Commit cc1bbea

Browse files
committed
Refactor api
1 parent 5a63ba9 commit cc1bbea

File tree

15 files changed

+5638
-83
lines changed

15 files changed

+5638
-83
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"changes":{"packages/webpack-plugin/package.json":"Patch","packages/utils/package.json":"Patch","packages/fetch/package.json":"Patch","packages/rsbuild-plugin/package.json":"Patch","packages/vite-plugin/package.json":"Patch","packages/core/package.json":"Patch","packages/generator/package.json":"Patch","packages/next-plugin/package.json":"Patch"},"note":"Refactor api","date":"2025-12-01T05:46:36.030011100Z"}

bun.lock

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,15 @@
8484
},
8585
"packages/core": {
8686
"name": "@devup-api/core",
87-
"version": "0.1.0",
87+
"version": "0.1.3",
8888
"devDependencies": {
8989
"@types/node": "^24.10",
9090
"typescript": "^5.9",
9191
},
9292
},
9393
"packages/fetch": {
9494
"name": "@devup-api/fetch",
95-
"version": "0.1.0",
95+
"version": "0.1.3",
9696
"dependencies": {
9797
"@devup-api/core": "workspace:*",
9898
},
@@ -103,7 +103,7 @@
103103
},
104104
"packages/generator": {
105105
"name": "@devup-api/generator",
106-
"version": "0.1.0",
106+
"version": "0.1.3",
107107
"dependencies": {
108108
"@devup-api/core": "workspace:*",
109109
"@devup-api/utils": "workspace:*",
@@ -116,7 +116,7 @@
116116
},
117117
"packages/next-plugin": {
118118
"name": "@devup-api/next-plugin",
119-
"version": "0.1.0",
119+
"version": "0.1.3",
120120
"dependencies": {
121121
"@devup-api/core": "workspace:*",
122122
"@devup-api/generator": "workspace:*",
@@ -135,7 +135,7 @@
135135
},
136136
"packages/rsbuild-plugin": {
137137
"name": "@devup-api/rsbuild-plugin",
138-
"version": "0.1.0",
138+
"version": "0.1.3",
139139
"dependencies": {
140140
"@devup-api/core": "workspace:*",
141141
"@devup-api/generator": "workspace:*",
@@ -152,7 +152,7 @@
152152
},
153153
"packages/utils": {
154154
"name": "@devup-api/utils",
155-
"version": "0.1.0",
155+
"version": "0.1.3",
156156
"devDependencies": {
157157
"@types/node": "^24.10",
158158
"openapi-types": "^12.1",
@@ -161,7 +161,7 @@
161161
},
162162
"packages/vite-plugin": {
163163
"name": "@devup-api/vite-plugin",
164-
"version": "0.1.0",
164+
"version": "0.1.3",
165165
"dependencies": {
166166
"@devup-api/core": "workspace:*",
167167
"@devup-api/generator": "workspace:*",
@@ -178,7 +178,7 @@
178178
},
179179
"packages/webpack-plugin": {
180180
"name": "@devup-api/webpack-plugin",
181-
"version": "0.1.0",
181+
"version": "0.1.3",
182182
"dependencies": {
183183
"@devup-api/core": "workspace:*",
184184
"@devup-api/generator": "workspace:*",
@@ -191,7 +191,6 @@
191191
},
192192
"peerDependencies": {
193193
"@devup-api/core": "*",
194-
"webpack": "*",
195194
},
196195
},
197196
},

packages/fetch/src/__tests__/url-map.test.ts

Lines changed: 84 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@ test.each([
1212
['createUser', '/users', JSON.stringify(urlMap)],
1313
['updateUser', '/users/{id}', JSON.stringify(urlMap)],
1414
['deleteUser', '/users/{id}', JSON.stringify(urlMap)],
15-
] as const)('getUrl returns url for existing key: %s -> %s', async (key, expected, envValue) => {
15+
] as const)('getApiEndpointInfo returns url for existing key: %s -> %s', async (key, expected, envValue) => {
1616
process.env.DEVUP_API_URL_MAP = envValue
1717
// Add query parameter to bypass module cache and reload
18-
const { getUrl } = await import(`../url-map?t=${Date.now()}`)
19-
expect(getUrl(key)).toBe(expected)
18+
const { getApiEndpointInfo } = await import(`../url-map?t=${Date.now()}`)
19+
expect(getApiEndpointInfo(key).url).toBe(expected)
2020
})
2121

2222
test.each([
2323
['nonExistentKey', 'nonExistentKey', JSON.stringify(urlMap)],
2424
['unknown', 'unknown', JSON.stringify(urlMap)],
2525
['', '', JSON.stringify(urlMap)],
2626
['/users', '/users', JSON.stringify(urlMap)],
27-
] as const)('getUrl returns key itself when key does not exist: %s -> %s', async (key, expected, envValue) => {
27+
] as const)('getApiEndpointInfo returns key itself when key does not exist: %s -> %s', async (key, expected, envValue) => {
2828
process.env.DEVUP_API_URL_MAP = envValue
29-
const { getUrl } = await import(`../url-map?t=${Date.now()}`)
30-
expect(getUrl(key)).toBe(expected)
29+
const { getApiEndpointInfo } = await import(`../url-map?t=${Date.now()}`)
30+
expect(getApiEndpointInfo(key).url).toBe(expected)
3131
})
3232

3333
test.each([
@@ -39,10 +39,10 @@ test.each([
3939
{ method: 'DELETE', url: '/users/{id}' },
4040
JSON.stringify(urlMap),
4141
],
42-
] as const)('getUrlWithMethod returns UrlMapValue for existing key: %s -> %s', async (key, expected, envValue) => {
42+
] as const)('getApiEndpointInfo returns UrlMapValue for existing key: %s -> %s', async (key, expected, envValue) => {
4343
process.env.DEVUP_API_URL_MAP = envValue
44-
const { getUrlWithMethod } = await import(`../url-map?t=${Date.now()}`)
45-
expect(getUrlWithMethod(key)).toEqual(expected)
44+
const { getApiEndpointInfo } = await import(`../url-map?t=${Date.now()}`)
45+
expect(getApiEndpointInfo(key)).toEqual(expected)
4646
})
4747

4848
test.each([
@@ -54,56 +54,58 @@ test.each([
5454
['unknown', { method: 'GET', url: 'unknown' }, JSON.stringify(urlMap)],
5555
['', { method: 'GET', url: '' }, JSON.stringify(urlMap)],
5656
['/users', { method: 'GET', url: '/users' }, JSON.stringify(urlMap)],
57-
] as const)('getUrlWithMethod returns default for non-existent key: %s -> %s', async (key, expected, envValue) => {
57+
] as const)('getApiEndpointInfo returns default for non-existent key: %s -> %s', async (key, expected, envValue) => {
5858
process.env.DEVUP_API_URL_MAP = envValue
59-
const { getUrlWithMethod } = await import(`../url-map?t=${Date.now()}`)
60-
expect(getUrlWithMethod(key)).toEqual(expected)
59+
const { getApiEndpointInfo } = await import(`../url-map?t=${Date.now()}`)
60+
expect(getApiEndpointInfo(key)).toEqual(expected)
6161
})
6262

6363
test.each([
6464
['anyKey', 'anyKey', '{}'],
6565
['test', 'test', '{}'],
66-
] as const)('getUrl works with empty URL map: %s -> %s', async (key, expected, envValue) => {
66+
] as const)('getApiEndpointInfo works with empty URL map: %s -> %s', async (key, expected, envValue) => {
6767
process.env.DEVUP_API_URL_MAP = envValue
68-
const { getUrl } = await import(`../url-map?t=${Date.now()}`)
69-
expect(getUrl(key)).toBe(expected)
68+
const { getApiEndpointInfo } = await import(`../url-map?t=${Date.now()}`)
69+
expect(getApiEndpointInfo(key).url).toBe(expected)
7070
})
7171

7272
test.each([
7373
['anyKey', { method: 'GET', url: 'anyKey' }, '{}'],
7474
['test', { method: 'GET', url: 'test' }, '{}'],
75-
] as const)('getUrlWithMethod works with empty URL map: %s -> %s', async (key, expected, envValue) => {
75+
] as const)('getApiEndpointInfo works with empty URL map: %s -> %s', async (key, expected, envValue) => {
7676
process.env.DEVUP_API_URL_MAP = envValue
77-
const { getUrlWithMethod } = await import(`../url-map?t=${Date.now()}`)
78-
expect(getUrlWithMethod(key)).toEqual(expected)
77+
const { getApiEndpointInfo } = await import(`../url-map?t=${Date.now()}`)
78+
expect(getApiEndpointInfo(key)).toEqual(expected)
7979
})
8080

8181
test.each([
8282
['anyKey', 'anyKey'],
8383
['test', 'test'],
84-
] as const)('getUrl works when DEVUP_API_URL_MAP is not set: %s -> %s', async (key, expected) => {
84+
] as const)('getApiEndpointInfo works when DEVUP_API_URL_MAP is not set: %s -> %s', async (key, expected) => {
8585
delete process.env.DEVUP_API_URL_MAP
86-
const { getUrl } = await import(`../url-map?t=${Date.now()}`)
87-
expect(getUrl(key)).toBe(expected)
86+
const { getApiEndpointInfo } = await import(`../url-map?t=${Date.now()}`)
87+
expect(getApiEndpointInfo(key).url).toBe(expected)
8888
})
8989

9090
test.each([
9191
['anyKey', { method: 'GET', url: 'anyKey' }],
9292
['test', { method: 'GET', url: 'test' }],
93-
] as const)('getUrlWithMethod works when DEVUP_API_URL_MAP is not set: %s -> %s', async (key, expected) => {
93+
] as const)('getApiEndpointInfo works when DEVUP_API_URL_MAP is not set: %s -> %s', async (key, expected) => {
9494
delete process.env.DEVUP_API_URL_MAP
95-
const { getUrlWithMethod } = await import(`../url-map?t=${Date.now()}`)
96-
expect(getUrlWithMethod(key)).toEqual(expected)
95+
const { getApiEndpointInfo } = await import(`../url-map?t=${Date.now()}`)
96+
expect(getApiEndpointInfo(key)).toEqual(expected)
9797
})
9898

99-
test('getUrl handles key that exists but url property is missing', async () => {
99+
test('getApiEndpointInfo handles key that exists but url property is missing', async () => {
100100
const urlMapWithoutUrl = {
101101
testKey: { method: 'GET' as const },
102102
}
103103
process.env.DEVUP_API_URL_MAP = JSON.stringify(urlMapWithoutUrl)
104-
const { getUrl } = await import(`../url-map?t=${Date.now() + Math.random()}`)
104+
const { getApiEndpointInfo } = await import(
105+
`../url-map?t=${Date.now() + Math.random()}`
106+
)
105107
// When url property is missing, optional chaining returns undefined, so key is returned
106-
expect(getUrl('testKey')).toBe('testKey')
108+
expect(getApiEndpointInfo('testKey').url).toBe('testKey')
107109
})
108110

109111
test('DEVUP_API_URL_MAP constant is exported and accessible', async () => {
@@ -117,8 +119,8 @@ test('DEVUP_API_URL_MAP constant is exported and accessible', async () => {
117119
// Directly access the constant to ensure it's covered
118120
const urlMap = urlMapModule.DEVUP_API_URL_MAP
119121
expect(urlMap).toEqual(testUrlMap)
120-
// Verify it's used by getUrl function
121-
expect(urlMapModule.getUrl('testKey')).toBe('/test')
122+
// Verify it's used by getApiEndpointInfo function
123+
expect(urlMapModule.getApiEndpointInfo('testKey').url).toBe('/test')
122124
})
123125

124126
test('DEVUP_API_URL_MAP uses fallback when env var is undefined', async () => {
@@ -129,11 +131,15 @@ test('DEVUP_API_URL_MAP uses fallback when env var is undefined', async () => {
129131
// Directly access the constant to ensure the fallback path is covered
130132
const urlMap = urlMapModule.DEVUP_API_URL_MAP
131133
expect(urlMap).toEqual({})
132-
expect(urlMapModule.getUrl('anyKey')).toBe('anyKey')
133-
expect(urlMapModule.getUrlWithMethod('anyKey')).toEqual({
134+
expect(urlMapModule.getApiEndpointInfo('anyKey').url).toBe('anyKey')
135+
// Explicitly call getApiEndpointInfo to ensure it's covered
136+
const result = urlMapModule.getApiEndpointInfo('anyKey')
137+
expect(result).toEqual({
134138
method: 'GET',
135139
url: 'anyKey',
136140
})
141+
// Also test that the function exists and is callable
142+
expect(typeof urlMapModule.getApiEndpointInfo).toBe('function')
137143
})
138144

139145
test('DEVUP_API_URL_MAP uses fallback when env var is empty string', async () => {
@@ -144,39 +150,75 @@ test('DEVUP_API_URL_MAP uses fallback when env var is empty string', async () =>
144150
// Directly access the constant to ensure the fallback path is covered
145151
const urlMap = urlMapModule.DEVUP_API_URL_MAP
146152
expect(urlMap).toEqual({})
147-
expect(urlMapModule.getUrl('anyKey')).toBe('anyKey')
148-
expect(urlMapModule.getUrlWithMethod('anyKey')).toEqual({
153+
expect(urlMapModule.getApiEndpointInfo('anyKey').url).toBe('anyKey')
154+
expect(urlMapModule.getApiEndpointInfo('anyKey')).toEqual({
149155
method: 'GET',
150156
url: 'anyKey',
151157
})
152158
})
153159

154-
test('getUrl handles key where DEVUP_API_URL_MAP[key] exists but url is undefined', async () => {
160+
test('getApiEndpointInfo handles key where DEVUP_API_URL_MAP[key] exists but url is undefined', async () => {
155161
const urlMapWithUndefinedUrl = {
156162
testKey: { method: 'GET' as const },
157163
}
158164
process.env.DEVUP_API_URL_MAP = JSON.stringify(urlMapWithUndefinedUrl)
159-
const { getUrl } = await import(`../url-map?t=${Date.now() + Math.random()}`)
165+
const { getApiEndpointInfo } = await import(
166+
`../url-map?t=${Date.now() + Math.random()}`
167+
)
160168
// When url property is missing, optional chaining returns undefined, so key is returned
161-
expect(getUrl('testKey')).toBe('testKey')
169+
expect(getApiEndpointInfo('testKey').url).toBe('testKey')
162170
})
163171

164-
test('getUrl handles key where DEVUP_API_URL_MAP[key] exists but url is null', async () => {
172+
test('getApiEndpointInfo handles key where DEVUP_API_URL_MAP[key] exists but url is null', async () => {
165173
const urlMapWithNullUrl = {
166174
testKey: { method: 'GET' as const, url: null as unknown as string },
167175
}
168176
process.env.DEVUP_API_URL_MAP = JSON.stringify(urlMapWithNullUrl)
169-
const { getUrl } = await import(`../url-map?t=${Date.now() + Math.random()}`)
177+
const { getApiEndpointInfo } = await import(
178+
`../url-map?t=${Date.now() + Math.random()}`
179+
)
170180
// When url is null, optional chaining returns null, so key is returned
171-
expect(getUrl('testKey')).toBe('testKey')
181+
expect(getApiEndpointInfo('testKey').url).toBe('testKey')
172182
})
173183

174-
test('getUrl handles key where DEVUP_API_URL_MAP[key] exists but url is empty string', async () => {
184+
test('getApiEndpointInfo handles key where DEVUP_API_URL_MAP[key] exists but url is empty string', async () => {
175185
const urlMapWithEmptyUrl = {
176186
testKey: { method: 'GET' as const, url: '' },
177187
}
178188
process.env.DEVUP_API_URL_MAP = JSON.stringify(urlMapWithEmptyUrl)
179-
const { getUrl } = await import(`../url-map?t=${Date.now() + Math.random()}`)
189+
const { getApiEndpointInfo } = await import(
190+
`../url-map?t=${Date.now() + Math.random()}`
191+
)
180192
// When url is empty string, it's falsy, so key is returned
181-
expect(getUrl('testKey')).toBe('testKey')
193+
expect(getApiEndpointInfo('testKey').url).toBe('testKey')
194+
})
195+
196+
test('getApiEndpointInfo returns default when key does not exist in map (explicit coverage for line 10)', async () => {
197+
const urlMap = { existingKey: { method: 'POST' as const, url: '/existing' } }
198+
process.env.DEVUP_API_URL_MAP = JSON.stringify(urlMap)
199+
const { getApiEndpointInfo } = await import(
200+
`../url-map?t=${Date.now() + Math.random()}`
201+
)
202+
// Explicitly test the if(!result) branch to ensure line 10 is covered
203+
const result = getApiEndpointInfo('nonExistentKeyInMap')
204+
expect(result).toEqual({ method: 'GET', url: 'nonExistentKeyInMap' })
205+
expect(result.method).toBe('GET')
206+
expect(result.url).toBe('nonExistentKeyInMap')
207+
})
208+
209+
test('getApiEndpointInfo returns result when key exists with url (explicit coverage for lines 12-13)', async () => {
210+
const urlMap = {
211+
testKey: { method: 'PUT' as const, url: '/test/url' },
212+
}
213+
process.env.DEVUP_API_URL_MAP = JSON.stringify(urlMap)
214+
const { getApiEndpointInfo } = await import(
215+
`../url-map?t=${Date.now() + Math.random()}`
216+
)
217+
// Explicitly test the result.url ||= key and return result path (lines 12-13)
218+
const result = getApiEndpointInfo('testKey')
219+
expect(result).toEqual({ method: 'PUT', url: '/test/url' })
220+
expect(result.method).toBe('PUT')
221+
expect(result.url).toBe('/test/url')
222+
// Verify that url was not changed (since it already exists)
223+
expect(result.url).not.toBe('testKey')
182224
})

packages/fetch/src/api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import type {
1717
RequiredOptions,
1818
} from '@devup-api/core'
1919
import { convertResponse } from './response-converter'
20-
import { getUrlWithMethod } from './url-map'
20+
import { getApiEndpointInfo } from './url-map'
2121
import { getApiEndpoint, isPlainObject } from './utils'
2222

2323
// biome-ignore lint/suspicious/noExplicitAny: any is used to allow for flexibility in the type
@@ -220,7 +220,7 @@ export class DevupApi {
220220
): Promise<
221221
DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error'>>
222222
> {
223-
const { method, url } = getUrlWithMethod(path)
223+
const { method, url } = getApiEndpointInfo(path)
224224
const mergedOptions = {
225225
...this.defaultOptions,
226226
...options[0],

packages/fetch/src/url-map.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ export const DEVUP_API_URL_MAP: Record<string, UrlMapValue> = JSON.parse(
44
process.env.DEVUP_API_URL_MAP || '{}',
55
)
66

7-
export function getUrl(key: string): string {
8-
return DEVUP_API_URL_MAP[key]?.url || key
9-
}
10-
11-
export function getUrlWithMethod(key: string): UrlMapValue {
12-
return DEVUP_API_URL_MAP[key] || { method: 'GET', url: key }
7+
export function getApiEndpointInfo(key: string): UrlMapValue {
8+
const result = DEVUP_API_URL_MAP[key] ?? { method: 'GET', url: key }
9+
result.url ||= key
10+
return result
1311
}

0 commit comments

Comments
 (0)