ai-spec-dev 0.29.0 → 0.30.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/dist/index.mjs CHANGED
@@ -4910,6 +4910,41 @@ async function loadDslForSpec(specFilePath) {
4910
4910
  // core/frontend-context-loader.ts
4911
4911
  import * as fs7 from "fs-extra";
4912
4912
  import * as path5 from "path";
4913
+ function parseImportStatements(content) {
4914
+ const stripped = content.replace(/\/\*[\s\S]*?\*\//g, (m) => "\n".repeat(m.split("\n").length - 1));
4915
+ const collapsed = stripped.replace(/import\s*\{[^}]*\}/gs, (m) => m.replace(/\n\s*/g, " "));
4916
+ const results = [];
4917
+ for (const rawLine of collapsed.split("\n")) {
4918
+ const line = rawLine.trim();
4919
+ if (!line) continue;
4920
+ if (/^import\s+type\b/.test(line)) continue;
4921
+ if (!line.startsWith("import")) continue;
4922
+ const match = line.match(/^(import\s+([\s\S]+?)\s+from\s+['"]([^'"]+)['"])/);
4923
+ if (!match) continue;
4924
+ results.push({
4925
+ line: match[1],
4926
+ modulePath: match[3],
4927
+ specifiers: match[2]
4928
+ });
4929
+ }
4930
+ return results;
4931
+ }
4932
+ var HTTP_MODULE_PATTERNS = [
4933
+ // Project path aliases (@/, @@/, ~/, #/) — catches '@/utils/request', '~/lib/http', etc.
4934
+ /^(?:@{1,2}|~|#)[/\\]/,
4935
+ // Well-known HTTP libraries (exact name match)
4936
+ /^(?:axios|ky(?:-universal)?|undici|node-fetch|cross-fetch|got|superagent|alova|openapi-fetch)$/,
4937
+ // Relative imports whose path contains an HTTP-utility keyword
4938
+ /\.{1,2}\/[^'"]*(?:http|request|fetch|client|api)[^'"]*/
4939
+ ];
4940
+ function findHttpClientImport(content) {
4941
+ for (const stmt of parseImportStatements(content)) {
4942
+ if (HTTP_MODULE_PATTERNS.some((p) => p.test(stmt.modulePath))) {
4943
+ return stmt.line;
4944
+ }
4945
+ }
4946
+ return void 0;
4947
+ }
4913
4948
  var STATE_MANAGEMENT_LIBS = [
4914
4949
  "zustand",
4915
4950
  "redux",
@@ -5098,13 +5133,12 @@ ${preview}`);
5098
5133
  } catch {
5099
5134
  }
5100
5135
  }
5101
- const httpImportRegex = /^import(?!\s+type)\s+(?:[\w*]+|\{[^}]+\})\s+from\s+['"]((?:@{1,2}|~|#)[/\\][^'"]+|\.{1,2}\/[^'"]*(?:http|request|fetch|client|api)[^'"]*|axios|ky(?:-universal)?|undici|node-fetch|cross-fetch|got|superagent|alova|openapi-fetch)['"]/im;
5102
5136
  for (const relPath of ctx.existingApiFiles.slice(0, 5)) {
5103
5137
  try {
5104
5138
  const content = await fs7.readFile(path5.join(projectRoot, relPath), "utf-8");
5105
- const match = content.match(httpImportRegex);
5106
- if (match) {
5107
- ctx.httpClientImport = match[0].trim();
5139
+ const found = findHttpClientImport(content);
5140
+ if (found) {
5141
+ ctx.httpClientImport = found;
5108
5142
  break;
5109
5143
  }
5110
5144
  } catch {
@@ -5234,13 +5268,28 @@ async function extractRouteModuleContext(projectRoot, ctx) {
5234
5268
  moduleFiles.push(...files);
5235
5269
  }
5236
5270
  if (moduleFiles.length === 0) return;
5237
- const layoutImportRegex = /^(?:const\s+Layout\s*=.*import\(['"][^'"]+['"]\)|import\s+Layout\s+from\s+['"][^'"]+['"])/m;
5271
+ const dynamicLayoutRegex = /const\s+Layout\s*=\s*(?:defineAsyncComponent\s*\(\s*)?(?:\(\s*\))?\s*(?:=>|function[^(]*\()\s*(?:[^)]*\))?\s*(?:=>)?\s*import\s*\(\s*['"]([^'"]+)['"]\s*\)/;
5238
5272
  for (const relPath of moduleFiles) {
5239
5273
  try {
5240
5274
  const content = await fs7.readFile(path5.join(projectRoot, relPath), "utf-8");
5241
- const match = content.match(layoutImportRegex);
5242
- if (match) {
5243
- ctx.layoutImport = match[0].trim();
5275
+ const stmts = parseImportStatements(content);
5276
+ const staticLayout = stmts.find(
5277
+ (s) => /\bLayout\b/.test(s.specifiers) && /layout/i.test(s.modulePath)
5278
+ );
5279
+ if (staticLayout) {
5280
+ ctx.layoutImport = staticLayout.line;
5281
+ const preview = content.split("\n").slice(0, 100).join("\n");
5282
+ ctx.routeModuleExample = { path: relPath, content: preview };
5283
+ break;
5284
+ }
5285
+ const singleLine = content.replace(
5286
+ /const\s+Layout\s*=[\s\S]*?import\s*\([^)]+\)/gm,
5287
+ (m) => m.replace(/\n\s*/g, " ")
5288
+ );
5289
+ const dynMatch = singleLine.match(dynamicLayoutRegex);
5290
+ if (dynMatch) {
5291
+ const constMatch = content.match(/^const\s+Layout\s*=.+/m);
5292
+ ctx.layoutImport = constMatch ? constMatch[0].trim() : dynMatch[0].trim();
5244
5293
  const preview = content.split("\n").slice(0, 100).join("\n");
5245
5294
  ctx.routeModuleExample = { path: relPath, content: preview };
5246
5295
  break;