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.js CHANGED
@@ -4973,6 +4973,41 @@ async function loadDslForSpec(specFilePath) {
4973
4973
  // core/frontend-context-loader.ts
4974
4974
  var fs7 = __toESM(require("fs-extra"));
4975
4975
  var path5 = __toESM(require("path"));
4976
+ function parseImportStatements(content) {
4977
+ const stripped = content.replace(/\/\*[\s\S]*?\*\//g, (m) => "\n".repeat(m.split("\n").length - 1));
4978
+ const collapsed = stripped.replace(/import\s*\{[^}]*\}/gs, (m) => m.replace(/\n\s*/g, " "));
4979
+ const results = [];
4980
+ for (const rawLine of collapsed.split("\n")) {
4981
+ const line = rawLine.trim();
4982
+ if (!line) continue;
4983
+ if (/^import\s+type\b/.test(line)) continue;
4984
+ if (!line.startsWith("import")) continue;
4985
+ const match = line.match(/^(import\s+([\s\S]+?)\s+from\s+['"]([^'"]+)['"])/);
4986
+ if (!match) continue;
4987
+ results.push({
4988
+ line: match[1],
4989
+ modulePath: match[3],
4990
+ specifiers: match[2]
4991
+ });
4992
+ }
4993
+ return results;
4994
+ }
4995
+ var HTTP_MODULE_PATTERNS = [
4996
+ // Project path aliases (@/, @@/, ~/, #/) — catches '@/utils/request', '~/lib/http', etc.
4997
+ /^(?:@{1,2}|~|#)[/\\]/,
4998
+ // Well-known HTTP libraries (exact name match)
4999
+ /^(?:axios|ky(?:-universal)?|undici|node-fetch|cross-fetch|got|superagent|alova|openapi-fetch)$/,
5000
+ // Relative imports whose path contains an HTTP-utility keyword
5001
+ /\.{1,2}\/[^'"]*(?:http|request|fetch|client|api)[^'"]*/
5002
+ ];
5003
+ function findHttpClientImport(content) {
5004
+ for (const stmt of parseImportStatements(content)) {
5005
+ if (HTTP_MODULE_PATTERNS.some((p) => p.test(stmt.modulePath))) {
5006
+ return stmt.line;
5007
+ }
5008
+ }
5009
+ return void 0;
5010
+ }
4976
5011
  var STATE_MANAGEMENT_LIBS = [
4977
5012
  "zustand",
4978
5013
  "redux",
@@ -5161,13 +5196,12 @@ ${preview}`);
5161
5196
  } catch {
5162
5197
  }
5163
5198
  }
5164
- 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;
5165
5199
  for (const relPath of ctx.existingApiFiles.slice(0, 5)) {
5166
5200
  try {
5167
5201
  const content = await fs7.readFile(path5.join(projectRoot, relPath), "utf-8");
5168
- const match = content.match(httpImportRegex);
5169
- if (match) {
5170
- ctx.httpClientImport = match[0].trim();
5202
+ const found = findHttpClientImport(content);
5203
+ if (found) {
5204
+ ctx.httpClientImport = found;
5171
5205
  break;
5172
5206
  }
5173
5207
  } catch {
@@ -5297,13 +5331,28 @@ async function extractRouteModuleContext(projectRoot, ctx) {
5297
5331
  moduleFiles.push(...files);
5298
5332
  }
5299
5333
  if (moduleFiles.length === 0) return;
5300
- const layoutImportRegex = /^(?:const\s+Layout\s*=.*import\(['"][^'"]+['"]\)|import\s+Layout\s+from\s+['"][^'"]+['"])/m;
5334
+ const dynamicLayoutRegex = /const\s+Layout\s*=\s*(?:defineAsyncComponent\s*\(\s*)?(?:\(\s*\))?\s*(?:=>|function[^(]*\()\s*(?:[^)]*\))?\s*(?:=>)?\s*import\s*\(\s*['"]([^'"]+)['"]\s*\)/;
5301
5335
  for (const relPath of moduleFiles) {
5302
5336
  try {
5303
5337
  const content = await fs7.readFile(path5.join(projectRoot, relPath), "utf-8");
5304
- const match = content.match(layoutImportRegex);
5305
- if (match) {
5306
- ctx.layoutImport = match[0].trim();
5338
+ const stmts = parseImportStatements(content);
5339
+ const staticLayout = stmts.find(
5340
+ (s) => /\bLayout\b/.test(s.specifiers) && /layout/i.test(s.modulePath)
5341
+ );
5342
+ if (staticLayout) {
5343
+ ctx.layoutImport = staticLayout.line;
5344
+ const preview = content.split("\n").slice(0, 100).join("\n");
5345
+ ctx.routeModuleExample = { path: relPath, content: preview };
5346
+ break;
5347
+ }
5348
+ const singleLine = content.replace(
5349
+ /const\s+Layout\s*=[\s\S]*?import\s*\([^)]+\)/gm,
5350
+ (m) => m.replace(/\n\s*/g, " ")
5351
+ );
5352
+ const dynMatch = singleLine.match(dynamicLayoutRegex);
5353
+ if (dynMatch) {
5354
+ const constMatch = content.match(/^const\s+Layout\s*=.+/m);
5355
+ ctx.layoutImport = constMatch ? constMatch[0].trim() : dynMatch[0].trim();
5307
5356
  const preview = content.split("\n").slice(0, 100).join("\n");
5308
5357
  ctx.routeModuleExample = { path: relPath, content: preview };
5309
5358
  break;