mock-fried 1.0.0
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/README.md +229 -0
- package/dist/module.d.mts +125 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +160 -0
- package/dist/runtime/components/ApiExplorer.d.vue.ts +7 -0
- package/dist/runtime/components/ApiExplorer.vue +168 -0
- package/dist/runtime/components/ApiExplorer.vue.d.ts +7 -0
- package/dist/runtime/components/EndpointCard.d.vue.ts +24 -0
- package/dist/runtime/components/EndpointCard.vue +173 -0
- package/dist/runtime/components/EndpointCard.vue.d.ts +24 -0
- package/dist/runtime/components/ResponseViewer.d.vue.ts +16 -0
- package/dist/runtime/components/ResponseViewer.vue +78 -0
- package/dist/runtime/components/ResponseViewer.vue.d.ts +16 -0
- package/dist/runtime/components/RpcMethodCard.d.vue.ts +20 -0
- package/dist/runtime/components/RpcMethodCard.vue +129 -0
- package/dist/runtime/components/RpcMethodCard.vue.d.ts +20 -0
- package/dist/runtime/composables/index.d.ts +1 -0
- package/dist/runtime/composables/index.js +1 -0
- package/dist/runtime/composables/useApi.d.ts +19 -0
- package/dist/runtime/composables/useApi.js +5 -0
- package/dist/runtime/plugin.d.ts +7 -0
- package/dist/runtime/plugin.js +75 -0
- package/dist/runtime/server/handlers/openapi.d.ts +2 -0
- package/dist/runtime/server/handlers/openapi.js +346 -0
- package/dist/runtime/server/handlers/rpc.d.ts +7 -0
- package/dist/runtime/server/handlers/rpc.js +140 -0
- package/dist/runtime/server/handlers/schema.d.ts +7 -0
- package/dist/runtime/server/handlers/schema.js +190 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/client-parser.d.ts +13 -0
- package/dist/runtime/server/utils/client-parser.js +272 -0
- package/dist/runtime/server/utils/mock/client-generator.d.ts +108 -0
- package/dist/runtime/server/utils/mock/client-generator.js +346 -0
- package/dist/runtime/server/utils/mock/index.d.ts +9 -0
- package/dist/runtime/server/utils/mock/index.js +38 -0
- package/dist/runtime/server/utils/mock/openapi-generator.d.ts +4 -0
- package/dist/runtime/server/utils/mock/openapi-generator.js +118 -0
- package/dist/runtime/server/utils/mock/pagination/cursor-manager.d.ts +38 -0
- package/dist/runtime/server/utils/mock/pagination/cursor-manager.js +129 -0
- package/dist/runtime/server/utils/mock/pagination/index.d.ts +8 -0
- package/dist/runtime/server/utils/mock/pagination/index.js +18 -0
- package/dist/runtime/server/utils/mock/pagination/page-manager.d.ts +41 -0
- package/dist/runtime/server/utils/mock/pagination/page-manager.js +96 -0
- package/dist/runtime/server/utils/mock/pagination/snapshot-store.d.ts +64 -0
- package/dist/runtime/server/utils/mock/pagination/snapshot-store.js +125 -0
- package/dist/runtime/server/utils/mock/pagination/types.d.ts +141 -0
- package/dist/runtime/server/utils/mock/pagination/types.js +14 -0
- package/dist/runtime/server/utils/mock/proto-generator.d.ts +12 -0
- package/dist/runtime/server/utils/mock/proto-generator.js +67 -0
- package/dist/runtime/server/utils/mock/shared.d.ts +69 -0
- package/dist/runtime/server/utils/mock/shared.js +150 -0
- package/dist/runtime/server/utils/mock-generator.d.ts +9 -0
- package/dist/runtime/server/utils/mock-generator.js +30 -0
- package/dist/types.d.mts +9 -0
- package/package.json +73 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ParsedClientPackage, OpenApiClientConfig } from '../../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 클라이언트 패키지 전체 파싱
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseClientPackage(packageRoot: string, config?: Partial<OpenApiClientConfig>): ParsedClientPackage;
|
|
6
|
+
/**
|
|
7
|
+
* 클라이언트 패키지 파싱 (캐시 지원)
|
|
8
|
+
*/
|
|
9
|
+
export declare function getClientPackage(packageRoot: string, config?: Partial<OpenApiClientConfig>): ParsedClientPackage;
|
|
10
|
+
/**
|
|
11
|
+
* 캐시 초기화
|
|
12
|
+
*/
|
|
13
|
+
export declare function clearClientPackageCache(): void;
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, existsSync } from "node:fs";
|
|
2
|
+
import { resolve, join } from "pathe";
|
|
3
|
+
function parseApiFile(filePath, fileName) {
|
|
4
|
+
const content = readFileSync(filePath, "utf-8");
|
|
5
|
+
const endpoints = [];
|
|
6
|
+
const classMatch = content.match(/export class (\w+Api)/);
|
|
7
|
+
const apiClassName = classMatch?.[1] || fileName.replace(".ts", "");
|
|
8
|
+
const rawMethodRegex = /\/\*\*([\s\S]*?)\*\/\s*\n\s*async\s+(\w+)Raw\([^)]*\):\s*Promise<runtime\.ApiResponse<((?:[^<>]|<[^>]*>)+)>>/g;
|
|
9
|
+
const methodBodyRegex = /async\s+(\w+)Raw\([^{]+\{([\s\S]*?)return new runtime\./g;
|
|
10
|
+
let match;
|
|
11
|
+
const methodBodies = /* @__PURE__ */ new Map();
|
|
12
|
+
while ((match = methodBodyRegex.exec(content)) !== null) {
|
|
13
|
+
const methodName = match[1];
|
|
14
|
+
const body = match[2];
|
|
15
|
+
methodBodies.set(methodName, body);
|
|
16
|
+
}
|
|
17
|
+
rawMethodRegex.lastIndex = 0;
|
|
18
|
+
while ((match = rawMethodRegex.exec(content)) !== null) {
|
|
19
|
+
const jsdocContent = match[1];
|
|
20
|
+
const operationId = match[2];
|
|
21
|
+
const responseType = match[3];
|
|
22
|
+
const jsdocLines = jsdocContent.split("\n").map((line) => line.replace(/^\s*\*\s?/, "").trim()).filter((line) => line.length > 0 && !line.startsWith("@"));
|
|
23
|
+
const summary = jsdocLines[jsdocLines.length - 1] || jsdocLines[0] || operationId;
|
|
24
|
+
const body = methodBodies.get(operationId);
|
|
25
|
+
if (!body) continue;
|
|
26
|
+
const pathMatch = body.match(/path:\s*`([^`]+)`/);
|
|
27
|
+
if (!pathMatch) continue;
|
|
28
|
+
let path = pathMatch[1];
|
|
29
|
+
path = path.replace(/\$\{[^}]+\}/g, (match2) => {
|
|
30
|
+
const paramName = match2.match(/\["?(\w+)"?\]/)?.[1] || "param";
|
|
31
|
+
return `{${paramName}}`;
|
|
32
|
+
});
|
|
33
|
+
const methodMatch = body.match(/method:\s*'(\w+)'/);
|
|
34
|
+
const method = methodMatch?.[1] || "GET";
|
|
35
|
+
const pathParams = [];
|
|
36
|
+
const pathParamMatches = path.matchAll(/\{(\w+)\}/g);
|
|
37
|
+
for (const pm of pathParamMatches) {
|
|
38
|
+
pathParams.push({
|
|
39
|
+
name: pm[1],
|
|
40
|
+
type: "string",
|
|
41
|
+
required: true
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const queryParams = [];
|
|
45
|
+
const queryParamRegex = /if\s*\(requestParameters\.(\w+)\s*!==\s*undefined\)\s*\{\s*queryParameters\['(\w+)'\]/g;
|
|
46
|
+
let qpm;
|
|
47
|
+
while ((qpm = queryParamRegex.exec(body)) !== null) {
|
|
48
|
+
queryParams.push({
|
|
49
|
+
name: qpm[2],
|
|
50
|
+
type: "string",
|
|
51
|
+
required: false
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
let requestBodyType;
|
|
55
|
+
const bodyMatch = body.match(/body:\s*(\w+)ToJSON\(requestParameters\.(\w+)\)/);
|
|
56
|
+
if (bodyMatch) {
|
|
57
|
+
requestBodyType = bodyMatch[1];
|
|
58
|
+
}
|
|
59
|
+
endpoints.push({
|
|
60
|
+
path,
|
|
61
|
+
method: method.toUpperCase(),
|
|
62
|
+
operationId,
|
|
63
|
+
summary,
|
|
64
|
+
apiClassName,
|
|
65
|
+
pathParams,
|
|
66
|
+
queryParams,
|
|
67
|
+
requestBodyType,
|
|
68
|
+
responseType
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return endpoints;
|
|
72
|
+
}
|
|
73
|
+
function analyzeType(rawType) {
|
|
74
|
+
const primitives = ["string", "number", "boolean", "Date", "object", "any", "unknown", "void", "null", "undefined"];
|
|
75
|
+
const isArray = rawType.startsWith("Array<") || rawType.endsWith("[]");
|
|
76
|
+
let type = rawType;
|
|
77
|
+
if (isArray) {
|
|
78
|
+
const arrayTypeMatch = rawType.match(/Array<(.+)>/) || rawType.match(/(.+)\[\]/);
|
|
79
|
+
if (arrayTypeMatch) {
|
|
80
|
+
type = arrayTypeMatch[1].trim();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
let refType;
|
|
84
|
+
if (!primitives.includes(type) && !type.includes("|") && !type.includes("&")) {
|
|
85
|
+
refType = type;
|
|
86
|
+
}
|
|
87
|
+
return { type, isArray, refType };
|
|
88
|
+
}
|
|
89
|
+
function parseModelFile(filePath, fileName) {
|
|
90
|
+
const content = readFileSync(filePath, "utf-8");
|
|
91
|
+
const modelName = fileName.replace(".ts", "");
|
|
92
|
+
const hasInterface = content.includes(`export interface ${modelName}`);
|
|
93
|
+
if (!hasInterface) {
|
|
94
|
+
const enumRegex = new RegExp(`export\\s+const\\s+(${modelName})\\s*=\\s*\\{([^}]+)\\}\\s*as\\s*const`);
|
|
95
|
+
const enumMatch = content.match(enumRegex);
|
|
96
|
+
if (enumMatch) {
|
|
97
|
+
const enumValues = [];
|
|
98
|
+
const valueMatches = enumMatch[2].matchAll(/(\w+):\s*['"]([^'"]+)['"]/g);
|
|
99
|
+
for (const vm of valueMatches) {
|
|
100
|
+
enumValues.push(vm[2]);
|
|
101
|
+
}
|
|
102
|
+
if (enumValues.length > 0) {
|
|
103
|
+
return {
|
|
104
|
+
name: modelName,
|
|
105
|
+
fields: [],
|
|
106
|
+
enumValues
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const fields = [];
|
|
112
|
+
const jsonKeyMap = /* @__PURE__ */ new Map();
|
|
113
|
+
const toJsonMatch = content.match(/export\s+function\s+\w+ToJSON[^{]*\{[\s\S]*?return\s*\{([\s\S]*?)\};?\s*\}/);
|
|
114
|
+
if (toJsonMatch) {
|
|
115
|
+
const returnBody = toJsonMatch[1];
|
|
116
|
+
const fieldMatches = returnBody.matchAll(/['"](\w+)['"]\s*:\s*(?:value\.(\w+)|[^,\n]*?value\.(\w+))/g);
|
|
117
|
+
for (const fm of fieldMatches) {
|
|
118
|
+
const jsonKey = fm[1];
|
|
119
|
+
const propertyName = fm[2] || fm[3];
|
|
120
|
+
if (!propertyName) continue;
|
|
121
|
+
jsonKeyMap.set(propertyName, jsonKey);
|
|
122
|
+
if (fields.some((f) => f.name === propertyName)) continue;
|
|
123
|
+
fields.push({
|
|
124
|
+
name: propertyName,
|
|
125
|
+
jsonKey: jsonKey !== propertyName ? jsonKey : void 0,
|
|
126
|
+
type: "unknown",
|
|
127
|
+
// ToJSON에서는 타입을 알 수 없음, 나중에 interface에서 보완
|
|
128
|
+
required: false,
|
|
129
|
+
isArray: false
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const fromJsonMatch = content.match(/export\s+function\s+\w+FromJSONTyped[^{]*\{[\s\S]*?return\s*\{([\s\S]*?)\};?\s*\}/);
|
|
134
|
+
if (fromJsonMatch) {
|
|
135
|
+
const returnBody = fromJsonMatch[1];
|
|
136
|
+
const dateFields = /* @__PURE__ */ new Set();
|
|
137
|
+
const dateMatches = returnBody.matchAll(/['"](\w+)['"]\s*:.*?new\s+Date\(/g);
|
|
138
|
+
for (const dm of dateMatches) {
|
|
139
|
+
dateFields.add(dm[1]);
|
|
140
|
+
}
|
|
141
|
+
const arrayFields = /* @__PURE__ */ new Set();
|
|
142
|
+
const arrayMatches = returnBody.matchAll(/['"](\w+)['"]\s*:.*?\(json\[['"](\w+)['"]\]\s*as\s*Array/g);
|
|
143
|
+
for (const am of arrayMatches) {
|
|
144
|
+
arrayFields.add(am[1]);
|
|
145
|
+
}
|
|
146
|
+
const refTypeMap = /* @__PURE__ */ new Map();
|
|
147
|
+
const refMatches = returnBody.matchAll(/['"](\w+)['"]\s*:.*?(\w+)FromJSON\(json\[/g);
|
|
148
|
+
for (const rm of refMatches) {
|
|
149
|
+
if (!rm[2].includes("Array")) {
|
|
150
|
+
refTypeMap.set(rm[1], rm[2]);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const arrayRefMatches = returnBody.matchAll(/['"](\w+)['"]\s*:.*?\.map\((\w+)FromJSON\)/g);
|
|
154
|
+
for (const arm of arrayRefMatches) {
|
|
155
|
+
refTypeMap.set(arm[1], arm[2]);
|
|
156
|
+
arrayFields.add(arm[1]);
|
|
157
|
+
}
|
|
158
|
+
for (const field of fields) {
|
|
159
|
+
if (dateFields.has(field.name)) {
|
|
160
|
+
field.type = "Date";
|
|
161
|
+
}
|
|
162
|
+
if (arrayFields.has(field.name)) {
|
|
163
|
+
field.isArray = true;
|
|
164
|
+
}
|
|
165
|
+
const refType = refTypeMap.get(field.name);
|
|
166
|
+
if (refType) {
|
|
167
|
+
field.refType = refType;
|
|
168
|
+
field.type = refType;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const interfaceMatch = content.match(/export\s+interface\s+(\w+)(?:\s+extends\s+[\w,\s]+)?\s*\{([\s\S]*?)\n\}/);
|
|
173
|
+
if (interfaceMatch) {
|
|
174
|
+
const interfaceBody = interfaceMatch[2];
|
|
175
|
+
const simpleFieldRegex = /^\s+(\w+)(\?)?:\s*([^;]+);/gm;
|
|
176
|
+
let sfm;
|
|
177
|
+
while ((sfm = simpleFieldRegex.exec(interfaceBody)) !== null) {
|
|
178
|
+
const name = sfm[1];
|
|
179
|
+
const optional = sfm[2] === "?";
|
|
180
|
+
const rawType = sfm[3].trim();
|
|
181
|
+
const { type, isArray, refType } = analyzeType(rawType);
|
|
182
|
+
const existingField = fields.find((f) => f.name === name);
|
|
183
|
+
if (existingField) {
|
|
184
|
+
if (existingField.type === "unknown") {
|
|
185
|
+
existingField.type = type;
|
|
186
|
+
}
|
|
187
|
+
existingField.required = !optional;
|
|
188
|
+
if (!existingField.isArray) {
|
|
189
|
+
existingField.isArray = isArray;
|
|
190
|
+
}
|
|
191
|
+
if (!existingField.refType && refType) {
|
|
192
|
+
existingField.refType = refType;
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
const jsonKey = jsonKeyMap.get(name);
|
|
196
|
+
fields.push({
|
|
197
|
+
name,
|
|
198
|
+
jsonKey: jsonKey && jsonKey !== name ? jsonKey : void 0,
|
|
199
|
+
type,
|
|
200
|
+
required: !optional,
|
|
201
|
+
isArray,
|
|
202
|
+
refType
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (fields.length === 0) {
|
|
208
|
+
return void 0;
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
name: modelName,
|
|
212
|
+
fields
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
export function parseClientPackage(packageRoot, config) {
|
|
216
|
+
const apisDir = config?.apisDir || "src/apis";
|
|
217
|
+
const modelsDir = config?.modelsDir || "src/models";
|
|
218
|
+
const apisPath = resolve(packageRoot, apisDir);
|
|
219
|
+
const modelsPath = resolve(packageRoot, modelsDir);
|
|
220
|
+
const pkgJsonPath = join(packageRoot, "package.json");
|
|
221
|
+
let pkgInfo = { name: "unknown", title: void 0, version: void 0 };
|
|
222
|
+
if (existsSync(pkgJsonPath)) {
|
|
223
|
+
try {
|
|
224
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
225
|
+
pkgInfo = {
|
|
226
|
+
name: pkgJson.name || "unknown",
|
|
227
|
+
title: pkgJson.description,
|
|
228
|
+
version: pkgJson.version
|
|
229
|
+
};
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const endpoints = [];
|
|
234
|
+
if (existsSync(apisPath)) {
|
|
235
|
+
const apiFiles = readdirSync(apisPath).filter((f) => f.endsWith("Api.ts") && f !== "index.ts");
|
|
236
|
+
for (const file of apiFiles) {
|
|
237
|
+
const filePath = join(apisPath, file);
|
|
238
|
+
const parsed = parseApiFile(filePath, file);
|
|
239
|
+
endpoints.push(...parsed);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const models = /* @__PURE__ */ new Map();
|
|
243
|
+
if (existsSync(modelsPath)) {
|
|
244
|
+
const modelFiles = readdirSync(modelsPath).filter((f) => f.endsWith(".ts") && f !== "index.ts");
|
|
245
|
+
for (const file of modelFiles) {
|
|
246
|
+
const filePath = join(modelsPath, file);
|
|
247
|
+
const parsed = parseModelFile(filePath, file);
|
|
248
|
+
if (parsed) {
|
|
249
|
+
models.set(parsed.name, parsed);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
info: pkgInfo,
|
|
255
|
+
endpoints,
|
|
256
|
+
models
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
let cachedPackage = null;
|
|
260
|
+
let cachedPackagePath = null;
|
|
261
|
+
export function getClientPackage(packageRoot, config) {
|
|
262
|
+
if (cachedPackage && cachedPackagePath === packageRoot) {
|
|
263
|
+
return cachedPackage;
|
|
264
|
+
}
|
|
265
|
+
cachedPackage = parseClientPackage(packageRoot, config);
|
|
266
|
+
cachedPackagePath = packageRoot;
|
|
267
|
+
return cachedPackage;
|
|
268
|
+
}
|
|
269
|
+
export function clearClientPackageCache() {
|
|
270
|
+
cachedPackage = null;
|
|
271
|
+
cachedPackagePath = null;
|
|
272
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client Package Mock 데이터 생성기
|
|
3
|
+
* OpenAPI Generator로 생성된 TypeScript 클라이언트 패키지 기반 Mock 생성
|
|
4
|
+
*/
|
|
5
|
+
import type { ParsedModelSchema, MockIdConfig } from '../../../../types.js';
|
|
6
|
+
import { hashString, SeededRandom } from './shared.js';
|
|
7
|
+
/**
|
|
8
|
+
* 필드명 기반 Mock 값 추론
|
|
9
|
+
*/
|
|
10
|
+
export declare function inferValueByFieldName(fieldName: string, rng: SeededRandom, index?: number, idConfig?: MockIdConfig): unknown;
|
|
11
|
+
/**
|
|
12
|
+
* TypeScript 타입에 따른 기본값 생성
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateValueByType(type: string, fieldName: string, rng: SeededRandom, index?: number, idConfig?: MockIdConfig): unknown;
|
|
15
|
+
/**
|
|
16
|
+
* 필드명에서 타입을 추측하여 적절한 값 생성
|
|
17
|
+
*/
|
|
18
|
+
export declare function inferTypeFromFieldName(fieldName: string, rng: SeededRandom, index: number, idConfig?: MockIdConfig): unknown;
|
|
19
|
+
/**
|
|
20
|
+
* 응답 타입 분석 결과
|
|
21
|
+
*/
|
|
22
|
+
export interface ResponseTypeInfo {
|
|
23
|
+
/** 실제 데이터 모델명 */
|
|
24
|
+
modelName: string;
|
|
25
|
+
/** 리스트 응답 여부 */
|
|
26
|
+
isList: boolean;
|
|
27
|
+
/** 배열 필드명 (posts, items, comments 등) - 응답 구조 생성시 사용 */
|
|
28
|
+
listFieldName?: string;
|
|
29
|
+
/** 래퍼 응답 타입인 경우 원본 타입명 */
|
|
30
|
+
wrapperType?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 응답 타입에서 실제 데이터 모델명 추출
|
|
34
|
+
* 다양한 배열 필드명을 지원 (items, data, posts, comments 등)
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractDataModelName(responseType: string, models: Map<string, ParsedModelSchema>): ResponseTypeInfo;
|
|
37
|
+
/**
|
|
38
|
+
* 스키마 기반 Mock 데이터 생성기 클래스
|
|
39
|
+
*/
|
|
40
|
+
export declare class SchemaMockGenerator {
|
|
41
|
+
private models;
|
|
42
|
+
private dataStore;
|
|
43
|
+
private idConfig;
|
|
44
|
+
constructor(models: Map<string, ParsedModelSchema>, idConfig?: MockIdConfig);
|
|
45
|
+
/**
|
|
46
|
+
* 모델 스키마 기반 단일 객체 생성
|
|
47
|
+
*/
|
|
48
|
+
generateOne(modelName: string, seed?: string | number, index?: number): Record<string, unknown>;
|
|
49
|
+
/**
|
|
50
|
+
* ID 부여된 단일 객체 생성 (Pagination용)
|
|
51
|
+
* 주어진 ID를 모델의 ID 필드에 설정하여 cursor와 응답 ID가 일치하도록 함
|
|
52
|
+
*/
|
|
53
|
+
generateOneWithId(modelName: string, itemId: string, seed?: string | number, index?: number): Record<string, unknown>;
|
|
54
|
+
/**
|
|
55
|
+
* 모델의 ID 필드명 찾기 (MockIdConfig 기반)
|
|
56
|
+
*/
|
|
57
|
+
private findIdFieldName;
|
|
58
|
+
/**
|
|
59
|
+
* 필드의 출력 키 가져오기 (jsonKey 또는 name)
|
|
60
|
+
*/
|
|
61
|
+
private getOutputKey;
|
|
62
|
+
/**
|
|
63
|
+
* 필드 값 생성
|
|
64
|
+
*/
|
|
65
|
+
private generateField;
|
|
66
|
+
/**
|
|
67
|
+
* 리스트 데이터 생성 (캐시 지원 - Pagination)
|
|
68
|
+
* @deprecated Use pagination/page-manager.ts instead for enhanced pagination
|
|
69
|
+
*/
|
|
70
|
+
generateList(modelName: string, options?: {
|
|
71
|
+
page?: number;
|
|
72
|
+
limit?: number;
|
|
73
|
+
total?: number;
|
|
74
|
+
seed?: string;
|
|
75
|
+
}): {
|
|
76
|
+
items: Record<string, unknown>[];
|
|
77
|
+
pagination: {
|
|
78
|
+
page: number;
|
|
79
|
+
limit: number;
|
|
80
|
+
total: number;
|
|
81
|
+
totalPages: number;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* 커서 기반 리스트 생성 (무한 스크롤용)
|
|
86
|
+
* @deprecated Use pagination/cursor-manager.ts instead for enhanced pagination
|
|
87
|
+
*/
|
|
88
|
+
generateCursorList(modelName: string, options?: {
|
|
89
|
+
cursor?: string;
|
|
90
|
+
limit?: number;
|
|
91
|
+
total?: number;
|
|
92
|
+
seed?: string;
|
|
93
|
+
}): {
|
|
94
|
+
items: Record<string, unknown>[];
|
|
95
|
+
nextCursor?: string;
|
|
96
|
+
prevCursor?: string;
|
|
97
|
+
hasMore: boolean;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* 모델 가져오기
|
|
101
|
+
*/
|
|
102
|
+
getModels(): Map<string, ParsedModelSchema>;
|
|
103
|
+
/**
|
|
104
|
+
* 캐시 초기화
|
|
105
|
+
*/
|
|
106
|
+
clearCache(): void;
|
|
107
|
+
}
|
|
108
|
+
export { SeededRandom, hashString };
|