speccore 8.3.55 → 8.3.57

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.
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ /**
3
+ * page-scanner — 页面目录结构扫描
4
+ *
5
+ * 扫描 src/views/、src/pages/、src/screens/ 等目录
6
+ * 按目录层级推断模块划分,生成页面清单
7
+ *
8
+ * v8.3.57+ 新增
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.scanPages = scanPages;
12
+ const fs_extra_1 = require("fs-extra");
13
+ const path_1 = require("path");
14
+ // 常见的前端页面目录名
15
+ const PAGE_DIR_CANDIDATES = [
16
+ 'src/views',
17
+ 'src/pages',
18
+ 'src/screens',
19
+ 'src/routes',
20
+ 'views',
21
+ 'pages',
22
+ 'screens',
23
+ ];
24
+ // 页面文件扩展名
25
+ const PAGE_EXTENSIONS = ['.vue', '.tsx', '.jsx', '.ts', '.js'];
26
+ // ── 扫描页面目录 ──
27
+ async function scanPages(projectRoot) {
28
+ const rootDir = await findPageDir(projectRoot);
29
+ if (!rootDir)
30
+ return null;
31
+ const pages = [];
32
+ await scanDirRecursive(rootDir, rootDir, '', pages);
33
+ const modules = [...new Set(pages.map(p => p.module))].sort();
34
+ return { rootDir, pages, modules };
35
+ }
36
+ // 查找页面目录
37
+ async function findPageDir(projectRoot) {
38
+ for (const dir of PAGE_DIR_CANDIDATES) {
39
+ const full = (0, path_1.join)(projectRoot, dir);
40
+ if (await (0, fs_extra_1.pathExists)(full))
41
+ return full;
42
+ }
43
+ return null;
44
+ }
45
+ // 递归扫描目录
46
+ async function scanDirRecursive(rootDir, currentDir, relativePath, pages) {
47
+ const entries = await (0, fs_extra_1.readdir)(currentDir, { withFileTypes: true });
48
+ for (const entry of entries) {
49
+ const entryRelPath = relativePath ? (0, path_1.join)(relativePath, entry.name) : entry.name;
50
+ const entryFullPath = (0, path_1.join)(currentDir, entry.name);
51
+ if (entry.isDirectory()) {
52
+ // 跳过常见非页面目录
53
+ if (shouldSkipDir(entry.name))
54
+ continue;
55
+ await scanDirRecursive(rootDir, entryFullPath, entryRelPath, pages);
56
+ }
57
+ else if (entry.isFile()) {
58
+ const ext = PAGE_EXTENSIONS.find(e => entry.name.endsWith(e));
59
+ if (ext) {
60
+ const name = entry.name.slice(0, -ext.length);
61
+ // 模块名 = 相对路径的第一层目录(如果没有子目录,则用文件名作为模块)
62
+ const module = relativePath
63
+ ? relativePath.split('/')[0]
64
+ : name;
65
+ const routePath = inferRoutePath(entryRelPath, name, ext);
66
+ pages.push({
67
+ name,
68
+ filePath: entryRelPath,
69
+ fullPath: entryFullPath,
70
+ module,
71
+ routePath,
72
+ });
73
+ }
74
+ }
75
+ }
76
+ }
77
+ // 跳过不需要扫描的目录
78
+ function shouldSkipDir(name) {
79
+ const skipList = new Set([
80
+ 'components', 'composables', 'hooks', 'utils', 'helpers',
81
+ 'assets', 'styles', 'css', 'scss', 'less',
82
+ '__tests__', '__mocks__', 'test', 'tests', 'spec',
83
+ 'node_modules', '.git', 'dist', 'build', 'public',
84
+ ]);
85
+ return skipList.has(name.toLowerCase());
86
+ }
87
+ // 从文件路径推断路由路径
88
+ function inferRoutePath(relativePath, fileName, ext) {
89
+ const parts = relativePath.split('/');
90
+ // 如果文件叫 Index.vue / index.vue / Home.vue,使用目录名作为路径
91
+ if (/^(index|home)$/i.test(fileName) && parts.length > 1) {
92
+ return '/' + parts.slice(0, -1).join('/');
93
+ }
94
+ // 常规情况:目录 + 文件名(去掉扩展名)
95
+ const routeParts = [...parts];
96
+ routeParts[routeParts.length - 1] = fileName;
97
+ // 处理动态路由 [id].vue → :id
98
+ const normalized = routeParts.map(p => p.replace(/^\[(\.\.\.)?(.+?)\]$/, (match, rest, name) => rest ? `:${name}+` : `:${name}`));
99
+ return '/' + normalized.join('/');
100
+ }
101
+ //# sourceMappingURL=page-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-scanner.js","sourceRoot":"","sources":["../../../src/core/ui-verify/page-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * route-scanner — 前端路由自动发现
3
+ *
4
+ * 支持 Vue Router / React Router 配置扫描
5
+ * 从源码中提取路由清单,自动生成测试规格
6
+ *
7
+ * v8.3.57+ 新增
8
+ */
9
+ export interface DiscoveredRoute {
10
+ path: string;
11
+ name?: string;
12
+ component?: string;
13
+ module?: string;
14
+ isLayout?: boolean;
15
+ children?: DiscoveredRoute[];
16
+ }
17
+ export interface RouteScanResult {
18
+ framework: 'vue' | 'react' | 'unknown';
19
+ routerFile: string;
20
+ routes: DiscoveredRoute[];
21
+ modules: string[];
22
+ }
23
+ export declare function detectFramework(projectRoot: string): Promise<'vue' | 'react' | 'unknown'>;
24
+ export declare function scanRoutes(projectRoot: string): Promise<RouteScanResult>;
25
+ export declare function flattenRoutes(routes: DiscoveredRoute[]): DiscoveredRoute[];
26
+ //# sourceMappingURL=route-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-scanner.d.ts","sourceRoot":"","sources":["../../../src/core/ui-verify/route-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,KAAK,GAAG,OAAO,GAAG,SAAS,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAwBD,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,OAAO,GAAG,SAAS,CAAC,CAoB/F;AAGD,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAoB9E;AAoPD,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAU1E"}
@@ -0,0 +1,310 @@
1
+ "use strict";
2
+ /**
3
+ * route-scanner — 前端路由自动发现
4
+ *
5
+ * 支持 Vue Router / React Router 配置扫描
6
+ * 从源码中提取路由清单,自动生成测试规格
7
+ *
8
+ * v8.3.57+ 新增
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.detectFramework = detectFramework;
12
+ exports.scanRoutes = scanRoutes;
13
+ exports.flattenRoutes = flattenRoutes;
14
+ const fs_extra_1 = require("fs-extra");
15
+ const path_1 = require("path");
16
+ // ── 路由器配置文件候选路径 ──
17
+ const VUE_ROUTER_CANDIDATES = [
18
+ 'src/router/index.ts',
19
+ 'src/router/index.js',
20
+ 'src/router/routes.ts',
21
+ 'src/router/routes.js',
22
+ 'src/router.ts',
23
+ 'src/router.js',
24
+ ];
25
+ const REACT_ROUTER_CANDIDATES = [
26
+ 'src/App.tsx',
27
+ 'src/App.jsx',
28
+ 'src/routes.tsx',
29
+ 'src/routes.jsx',
30
+ 'src/router.tsx',
31
+ 'src/router.jsx',
32
+ 'src/App.ts',
33
+ 'src/App.js',
34
+ ];
35
+ // ── 检测前端框架类型 ──
36
+ async function detectFramework(projectRoot) {
37
+ const pkgPath = (0, path_1.join)(projectRoot, 'package.json');
38
+ if (await (0, fs_extra_1.pathExists)(pkgPath)) {
39
+ try {
40
+ const pkg = JSON.parse(await (0, fs_extra_1.readFile)(pkgPath, 'utf-8'));
41
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
42
+ if (deps['vue-router'] || deps['vue'])
43
+ return 'vue';
44
+ if (deps['react-router-dom'] || deps['react-router'] || deps['react'])
45
+ return 'react';
46
+ }
47
+ catch { /* ignore */ }
48
+ }
49
+ // 根据文件存在性推断
50
+ for (const p of VUE_ROUTER_CANDIDATES) {
51
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(projectRoot, p)))
52
+ return 'vue';
53
+ }
54
+ for (const p of REACT_ROUTER_CANDIDATES) {
55
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(projectRoot, p)))
56
+ return 'react';
57
+ }
58
+ return 'unknown';
59
+ }
60
+ // ── 扫描路由(入口)──
61
+ async function scanRoutes(projectRoot) {
62
+ const framework = await detectFramework(projectRoot);
63
+ if (framework === 'vue') {
64
+ const routerFile = await findRouterFile(projectRoot, VUE_ROUTER_CANDIDATES);
65
+ if (routerFile) {
66
+ const routes = await parseVueRoutes(routerFile, projectRoot);
67
+ return { framework, routerFile, routes, modules: extractModules(routes) };
68
+ }
69
+ }
70
+ if (framework === 'react') {
71
+ const routerFile = await findRouterFile(projectRoot, REACT_ROUTER_CANDIDATES);
72
+ if (routerFile) {
73
+ const routes = await parseReactRoutes(routerFile, projectRoot);
74
+ return { framework, routerFile, routes, modules: extractModules(routes) };
75
+ }
76
+ }
77
+ return { framework: 'unknown', routerFile: '', routes: [], modules: [] };
78
+ }
79
+ // ── 查找路由配置文件 ──
80
+ async function findRouterFile(projectRoot, candidates) {
81
+ for (const p of candidates) {
82
+ const full = (0, path_1.join)(projectRoot, p);
83
+ if (await (0, fs_extra_1.pathExists)(full))
84
+ return full;
85
+ }
86
+ return null;
87
+ }
88
+ // ═══════════════════════════════════════════════════════════
89
+ // Vue Router 解析
90
+ // ═══════════════════════════════════════════════════════════
91
+ async function parseVueRoutes(routerFile, projectRoot) {
92
+ const content = await (0, fs_extra_1.readFile)(routerFile, 'utf-8');
93
+ const routes = [];
94
+ // 策略1:直接提取路由数组字面量(最常用)
95
+ // const routes = [ { path: '...', component: ... }, ... ]
96
+ const arrayMatch = content.match(/(?:const|let|var)\s+routes\s*=\s*(\[[\s\S]*?\]);?\s*(?:export|const|function|new|createRouter|$)/);
97
+ if (arrayMatch) {
98
+ const routeArray = extractRouteObjects(arrayMatch[1], projectRoot);
99
+ routes.push(...routeArray);
100
+ }
101
+ // 策略2:提取从其他文件导入的路由
102
+ // import routes from './routes'
103
+ const importMatch = content.match(/import\s+routes\s+from\s+['"]([^'"]+)['"]/);
104
+ if (importMatch && routes.length === 0) {
105
+ const importedPath = resolveImportPath(importMatch[1], (0, path_1.dirname)(routerFile));
106
+ if (importedPath && await (0, fs_extra_1.pathExists)(importedPath)) {
107
+ const importedRoutes = await parseVueRoutes(importedPath, projectRoot);
108
+ routes.push(...importedRoutes);
109
+ }
110
+ }
111
+ // 策略3:提取 createRouter({ routes: [...] }) 中的 routes
112
+ const createRouterMatch = content.match(/routes\s*:\s*(\[[\s\S]*?\])\s*[,}]/);
113
+ if (createRouterMatch && routes.length === 0) {
114
+ const routeArray = extractRouteObjects(createRouterMatch[1], projectRoot);
115
+ routes.push(...routeArray);
116
+ }
117
+ return routes;
118
+ }
119
+ // 从数组文本中提取路由对象
120
+ function extractRouteObjects(arrayText, projectRoot) {
121
+ const routes = [];
122
+ // 匹配单个路由对象:{ path: '...', ... }
123
+ const routeRegex = /\{\s*path\s*:\s*['"]([^'"]*?)['"]\s*,?/g;
124
+ let match;
125
+ while ((match = routeRegex.exec(arrayText)) !== null) {
126
+ const startIdx = match.index;
127
+ const path = match[1];
128
+ // 找到这个对象的结束位置(匹配花括号)
129
+ const endIdx = findObjectEnd(arrayText, startIdx);
130
+ const objText = arrayText.slice(startIdx, endIdx);
131
+ const route = parseRouteObject(objText, projectRoot);
132
+ if (route)
133
+ routes.push(route);
134
+ }
135
+ return routes;
136
+ }
137
+ // 解析单个路由对象文本
138
+ function parseRouteObject(objText, projectRoot) {
139
+ const pathMatch = objText.match(/path\s*:\s*['"]([^'"]*?)['"]/);
140
+ if (!pathMatch)
141
+ return null;
142
+ const path = pathMatch[1];
143
+ if (path === '*' || path === '' || path === '/') {
144
+ // 跳过通配符和根路由(通常重定向)
145
+ return null;
146
+ }
147
+ const nameMatch = objText.match(/name\s*:\s*['"]([^'"]*?)['"]/);
148
+ const name = nameMatch ? nameMatch[1] : undefined;
149
+ // 提取 component(直接引用或动态导入)
150
+ let component;
151
+ const compMatch = objText.match(/component\s*:\s*([A-Za-z0-9_]+)/);
152
+ if (compMatch) {
153
+ component = compMatch[1];
154
+ }
155
+ else {
156
+ const lazyMatch = objText.match(/component\s*:\s*\(\)\s*=>\s*import\(['"]([^'"]+)['"]\)/);
157
+ if (lazyMatch) {
158
+ component = lazyMatch[1];
159
+ }
160
+ }
161
+ // 从 component 路径推断模块
162
+ let module;
163
+ if (component) {
164
+ module = inferModuleFromPath(component);
165
+ }
166
+ if (!module) {
167
+ module = inferModuleFromRoutePath(path);
168
+ }
169
+ const route = { path, name, component, module };
170
+ // 处理 children
171
+ const childrenMatch = objText.match(/children\s*:\s*(\[[\s\S]*?\])\s*[,}]/);
172
+ if (childrenMatch) {
173
+ route.children = extractRouteObjects(childrenMatch[1], projectRoot);
174
+ route.children.forEach(c => {
175
+ if (!c.module && module)
176
+ c.module = module;
177
+ // 子路由路径拼接
178
+ if (!c.path.startsWith('/')) {
179
+ c.path = path.replace(/\/$/, '') + '/' + c.path;
180
+ }
181
+ });
182
+ }
183
+ return route;
184
+ }
185
+ // ═══════════════════════════════════════════════════════════
186
+ // React Router 解析
187
+ // ═══════════════════════════════════════════════════════════
188
+ async function parseReactRoutes(routesFile, projectRoot) {
189
+ const content = await (0, fs_extra_1.readFile)(routesFile, 'utf-8');
190
+ const routes = [];
191
+ // 策略1:createBrowserRouter/createHashRouter 数组参数
192
+ const routerMatch = content.match(/create(?:Browser|Hash|Memory)Router\s*\((\[[\s\S]*?\])\s*\)/);
193
+ if (routerMatch) {
194
+ const routeArray = extractRouteObjects(routerMatch[1], projectRoot);
195
+ routes.push(...routeArray);
196
+ }
197
+ // 策略2:JSX Route 组件
198
+ // <Route path="..." element={<Xxx />} />
199
+ const jsxRouteRegex = /<Route\s+[^>]*path\s*=\s*['"]([^'"]*?)['"][^>]*>/g;
200
+ let jsxMatch;
201
+ while ((jsxMatch = jsxRouteRegex.exec(content)) !== null) {
202
+ const path = jsxMatch[1];
203
+ const fullTag = jsxMatch[0];
204
+ if (path === '*' || path === '')
205
+ continue;
206
+ const elementMatch = fullTag.match(/element\s*=\s*\{<([A-Za-z0-9_]+)/);
207
+ const lazyMatch = fullTag.match(/element\s*=\s*\{<(?:React\.)?Suspense[^>]*>[^<]*<([A-Za-z0-9_]+)/);
208
+ let component;
209
+ if (elementMatch)
210
+ component = elementMatch[1];
211
+ else if (lazyMatch)
212
+ component = lazyMatch[1];
213
+ const module = inferModuleFromRoutePath(path) || (component ? inferModuleFromPath(component) : undefined);
214
+ routes.push({ path, component, module });
215
+ }
216
+ return routes;
217
+ }
218
+ // ═══════════════════════════════════════════════════════════
219
+ // 辅助函数
220
+ // ═══════════════════════════════════════════════════════════
221
+ // 找到对象字面量的结束位置(匹配花括号)
222
+ function findObjectEnd(text, startIdx) {
223
+ let depth = 0;
224
+ let inString = null;
225
+ for (let i = startIdx; i < text.length; i++) {
226
+ const ch = text[i];
227
+ const prev = text[i - 1];
228
+ if (inString) {
229
+ if (ch === inString && prev !== '\\')
230
+ inString = null;
231
+ continue;
232
+ }
233
+ if (ch === '"' || ch === "'" || ch === '`') {
234
+ inString = ch;
235
+ continue;
236
+ }
237
+ if (ch === '{')
238
+ depth++;
239
+ if (ch === '}') {
240
+ depth--;
241
+ if (depth === 0)
242
+ return i + 1;
243
+ }
244
+ }
245
+ return text.length;
246
+ }
247
+ // 从 component 路径推断模块名
248
+ function inferModuleFromPath(componentPath) {
249
+ // 例如:@/views/booking/List.vue → booking
250
+ // 例如:../views/user/Profile.tsx → user
251
+ const parts = componentPath.split('/');
252
+ const viewsIdx = parts.findIndex(p => p === 'views' || p === 'pages' || p === 'screens');
253
+ if (viewsIdx >= 0 && viewsIdx + 1 < parts.length) {
254
+ return parts[viewsIdx + 1];
255
+ }
256
+ // 从父目录推断
257
+ if (parts.length >= 2) {
258
+ const dir = parts[parts.length - 2];
259
+ if (dir && dir !== '.' && dir !== '..')
260
+ return dir;
261
+ }
262
+ return undefined;
263
+ }
264
+ // 从路由路径推断模块名
265
+ function inferModuleFromRoutePath(routePath) {
266
+ const segments = routePath.split('/').filter(Boolean);
267
+ if (segments.length > 0) {
268
+ return segments[0];
269
+ }
270
+ return undefined;
271
+ }
272
+ // 提取所有模块名(去重)
273
+ function extractModules(routes) {
274
+ const modules = new Set();
275
+ function collect(r) {
276
+ for (const route of r) {
277
+ if (route.module)
278
+ modules.add(route.module);
279
+ if (route.children)
280
+ collect(route.children);
281
+ }
282
+ }
283
+ collect(routes);
284
+ return Array.from(modules).sort();
285
+ }
286
+ // 解析 import 路径为绝对路径
287
+ function resolveImportPath(importPath, baseDir) {
288
+ if (importPath.startsWith('.')) {
289
+ return (0, path_1.join)(baseDir, importPath);
290
+ }
291
+ if (importPath.startsWith('@/')) {
292
+ // 简化为从 baseDir 的父目录查找 src/
293
+ return (0, path_1.join)(baseDir, '..', importPath.replace('@/', ''));
294
+ }
295
+ return null;
296
+ }
297
+ // ── 扁平化路由(把嵌套路由展开为列表)──
298
+ function flattenRoutes(routes) {
299
+ const flat = [];
300
+ function walk(r) {
301
+ for (const route of r) {
302
+ flat.push(route);
303
+ if (route.children)
304
+ walk(route.children);
305
+ }
306
+ }
307
+ walk(routes);
308
+ return flat;
309
+ }
310
+ //# sourceMappingURL=route-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-scanner.js","sourceRoot":"","sources":["../../../src/core/ui-verify/route-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * spec-generator — 从扫描结果生成 VERIFY_SPEC.yaml
3
+ *
4
+ * v8.3.57+ 新增
5
+ */
6
+ import type { DiscoveredRoute } from './route-scanner';
7
+ import type { PageEntry } from './page-scanner';
8
+ import type { VerifySpec } from './types';
9
+ export interface SpecGenerationOptions {
10
+ baseUrl: string;
11
+ platform: string;
12
+ name?: string;
13
+ }
14
+ export declare function generateSpecFromRoutes(routes: DiscoveredRoute[], options: SpecGenerationOptions): VerifySpec;
15
+ export declare function generateSpecFromPages(pages: PageEntry[], options: SpecGenerationOptions): VerifySpec;
16
+ export declare function writeVerifySpec(spec: VerifySpec, outputPath: string): Promise<string>;
17
+ //# sourceMappingURL=spec-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-generator.d.ts","sourceRoot":"","sources":["../../../src/core/ui-verify/spec-generator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAA+B,MAAM,SAAS,CAAC;AAEvE,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAGD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,EAAE,EACzB,OAAO,EAAE,qBAAqB,GAC7B,UAAU,CA2BZ;AAGD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,EAAE,EAClB,OAAO,EAAE,qBAAqB,GAC7B,UAAU,CA+BZ;AAwBD,wBAAsB,eAAe,CACnC,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAMjB"}
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ /**
3
+ * spec-generator — 从扫描结果生成 VERIFY_SPEC.yaml
4
+ *
5
+ * v8.3.57+ 新增
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.generateSpecFromRoutes = generateSpecFromRoutes;
9
+ exports.generateSpecFromPages = generateSpecFromPages;
10
+ exports.writeVerifySpec = writeVerifySpec;
11
+ const fs_extra_1 = require("fs-extra");
12
+ const path_1 = require("path");
13
+ // ── 从路由扫描结果生成规格 ──
14
+ function generateSpecFromRoutes(routes, options) {
15
+ const scenarios = [];
16
+ for (const route of routes) {
17
+ if (route.path.includes(':') || route.path.includes('*')) {
18
+ // 跳过动态路由和通配符(需要手动配置具体参数)
19
+ continue;
20
+ }
21
+ const scenario = createScenarioForRoute(route, options.baseUrl);
22
+ if (scenario)
23
+ scenarios.push(scenario);
24
+ if (route.children) {
25
+ for (const child of route.children) {
26
+ if (child.path.includes(':') || child.path.includes('*'))
27
+ continue;
28
+ const childScenario = createScenarioForRoute(child, options.baseUrl);
29
+ if (childScenario)
30
+ scenarios.push(childScenario);
31
+ }
32
+ }
33
+ }
34
+ return {
35
+ name: options.name || `${options.platform} UI 验证`,
36
+ platform: options.platform,
37
+ url: options.baseUrl,
38
+ scenarios,
39
+ };
40
+ }
41
+ // ── 从页面扫描结果生成规格 ──
42
+ function generateSpecFromPages(pages, options) {
43
+ const scenarios = [];
44
+ for (const page of pages) {
45
+ if (!page.routePath || page.routePath.includes(':') || page.routePath.includes('*')) {
46
+ continue;
47
+ }
48
+ const scenarioName = page.module
49
+ ? `${page.module} - ${page.name}`
50
+ : page.name;
51
+ scenarios.push({
52
+ name: scenarioName,
53
+ description: `页面: ${page.filePath}`,
54
+ actions: [
55
+ { type: 'navigate' },
56
+ { type: 'wait', delay: 1000 },
57
+ ],
58
+ assertions: [
59
+ { type: 'visible', selector: 'body', description: '页面已加载' },
60
+ ],
61
+ });
62
+ }
63
+ return {
64
+ name: options.name || `${options.platform} UI 验证`,
65
+ platform: options.platform,
66
+ url: options.baseUrl,
67
+ scenarios,
68
+ };
69
+ }
70
+ // ── 为单个路由创建 scenario ──
71
+ function createScenarioForRoute(route, baseUrl) {
72
+ const path = route.path;
73
+ if (!path || path === '/')
74
+ return null;
75
+ const displayName = route.name || route.component || path;
76
+ const moduleName = route.module || 'default';
77
+ return {
78
+ name: `${moduleName} - ${displayName}`,
79
+ description: `路由: ${path}`,
80
+ actions: [
81
+ { type: 'navigate' },
82
+ { type: 'wait', delay: 1000 },
83
+ ],
84
+ assertions: [
85
+ { type: 'visible', selector: 'body', description: '页面已加载' },
86
+ ],
87
+ };
88
+ }
89
+ // ── 写入规格文件 ──
90
+ async function writeVerifySpec(spec, outputPath) {
91
+ await (0, fs_extra_1.ensureDir)((0, path_1.join)(outputPath, '..'));
92
+ const yaml = specToYaml(spec);
93
+ await (0, fs_extra_1.writeFile)(outputPath, yaml, 'utf-8');
94
+ return outputPath;
95
+ }
96
+ // ── VerifySpec → YAML 字符串 ──
97
+ function specToYaml(spec) {
98
+ const lines = [];
99
+ lines.push(`name: ${spec.name}`);
100
+ lines.push(`platform: ${spec.platform}`);
101
+ lines.push(`url: ${spec.url}`);
102
+ lines.push('');
103
+ lines.push('scenarios:');
104
+ for (const s of spec.scenarios) {
105
+ lines.push(` - name: ${s.name}`);
106
+ if (s.description)
107
+ lines.push(` description: ${s.description}`);
108
+ lines.push(' actions:');
109
+ for (const a of s.actions) {
110
+ lines.push(` - type: ${a.type}`);
111
+ if (a.selector)
112
+ lines.push(` selector: ${a.selector}`);
113
+ if (a.value)
114
+ lines.push(` value: ${a.value}`);
115
+ if (a.delay)
116
+ lines.push(` delay: ${a.delay}`);
117
+ if (a.key)
118
+ lines.push(` key: ${a.key}`);
119
+ if (a.waitFor)
120
+ lines.push(` waitFor: ${a.waitFor}`);
121
+ }
122
+ lines.push(' assertions:');
123
+ for (const ass of s.assertions) {
124
+ lines.push(` - type: ${ass.type}`);
125
+ if (ass.selector)
126
+ lines.push(` selector: ${ass.selector}`);
127
+ if (ass.description)
128
+ lines.push(` description: ${ass.description}`);
129
+ if (ass.contains)
130
+ lines.push(` contains: ${ass.contains}`);
131
+ if (ass.equals)
132
+ lines.push(` equals: ${ass.equals}`);
133
+ if (ass.threshold)
134
+ lines.push(` threshold: ${ass.threshold}`);
135
+ }
136
+ lines.push('');
137
+ }
138
+ return lines.join('\n');
139
+ }
140
+ //# sourceMappingURL=spec-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-generator.js","sourceRoot":"","sources":["../../../src/core/ui-verify/spec-generator.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speccore",
3
- "version": "8.3.55",
3
+ "version": "8.3.57",
4
4
  "description": "SpecCore - Code by Spec, Not by Vibe.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",