{"version":3,"file":"scaffold.cjs","names":[],"sources":["../../../src/scaffold/scaffold.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, relative, resolve } from \"node:path\";\n\nimport { ScanError } from \"../support/errors.js\";\nimport { toPosixPath } from \"../support/paths.js\";\nimport type { RouteFileMethod } from \"../types.js\";\nimport {\n  buildUrlPath,\n  classifyRouteFile,\n  getMethodFromRouteFile,\n  layoutIdFromPath,\n  normalizeRouteRel,\n  shouldIgnoreRoutePath,\n} from \"../scan/paths.js\";\nimport { createRouteFactoryName } from \"../scan/scan.js\";\n\nconst DEFAULT_EXPORT_PATTERN = /export\\s+default\\s+/;\n\nexport function fileNeedsScaffold(source: string, _kind: \"route\" | \"layout\"): boolean {\n  const trimmed = source.trim();\n  if (trimmed.length === 0) return true;\n  return !DEFAULT_EXPORT_PATTERN.test(source);\n}\n\nexport function routeScaffoldSource(urlPath: string, method: RouteFileMethod): string {\n  const factoryName = createRouteFactoryName(method);\n  const factoryCall =\n    method === \"ANY\" ? `${factoryName}('${urlPath}', ['GET'])` : `${factoryName}('${urlPath}')`;\n\n  return `import { t } from '@taserjs/router';\nimport { json } from '@taserjs/router/reply';\n\nexport default ${factoryCall}.handler((_ctx) => {\n  return json({ ok: true });\n});\n`;\n}\n\nexport function layoutScaffoldSource(layoutId: string): string {\n  return `import { t } from '@taserjs/router';\n\nexport default t.layout('${layoutId}').use((_ctx, next) => next());\n`;\n}\n\nexport type ScaffoldResult = \"written\" | \"skipped\" | \"ignored\";\n\nexport type ScaffoldOptions = {\n  entry?: string | undefined;\n  ignore?: readonly string[] | undefined;\n};\n\nfunction assertPathUnderRoutesDir(routesDir: string, absolutePath: string): void {\n  const resolvedRoutesDir = resolve(routesDir);\n  const resolvedTarget = resolve(absolutePath);\n  const rel = relative(resolvedRoutesDir, resolvedTarget);\n  if (rel.startsWith(\"..\") || isAbsolute(rel)) {\n    throw new ScanError(\"Scaffold path escapes routes directory\", absolutePath);\n  }\n}\n\nexport async function scaffoldRouteFile(\n  routesDir: string,\n  absolutePath: string,\n  options: ScaffoldOptions = {},\n): Promise<ScaffoldResult> {\n  assertPathUnderRoutesDir(routesDir, absolutePath);\n\n  const relativePath = toPosixPath(relative(routesDir, absolutePath));\n  if (shouldIgnoreRoutePath(relativePath, options.ignore)) {\n    return \"ignored\";\n  }\n\n  const kind = classifyRouteFile(relativePath);\n  if (!kind) {\n    return \"ignored\";\n  }\n\n  let source = \"\";\n  try {\n    source = await readFile(absolutePath, \"utf8\");\n  } catch {\n    source = \"\";\n  }\n\n  if (!fileNeedsScaffold(source, kind)) {\n    return \"skipped\";\n  }\n\n  if (kind === \"layout\") {\n    const layoutId = layoutIdFromPath(normalizeRouteRel(relativePath));\n    await writeFile(absolutePath, layoutScaffoldSource(layoutId), \"utf8\");\n    return \"written\";\n  }\n\n  const routeRel = normalizeRouteRel(relativePath);\n  const method = getMethodFromRouteFile(routeRel);\n  const urlPath = buildUrlPath(routeRel);\n  await writeFile(absolutePath, routeScaffoldSource(urlPath, method), \"utf8\");\n  return \"written\";\n}\n\nexport async function scaffoldRouteFileAtPath(\n  routesDir: string,\n  relativePath: string,\n  options: ScaffoldOptions = {},\n): Promise<ScaffoldResult> {\n  const normalized = toPosixPath(relativePath);\n  const absolutePath = resolve(routesDir, normalized);\n  await mkdir(dirname(absolutePath), { recursive: true });\n  return scaffoldRouteFile(routesDir, absolutePath, options);\n}\n"],"mappings":";;;;;;;AAgBA,IAAM,yBAAyB;AAE/B,SAAgB,kBAAkB,QAAgB,OAAoC;CAEpF,IADgB,OAAO,KACnB,CAAA,CAAQ,WAAW,GAAG,OAAO;CACjC,OAAO,CAAC,uBAAuB,KAAK,MAAM;AAC5C;AAEA,SAAgB,oBAAoB,SAAiB,QAAiC;CACpF,MAAM,cAAc,aAAA,uBAAuB,MAAM;CAIjD,OAAO;;;iBAFL,WAAW,QAAQ,GAAG,YAAY,IAAI,QAAQ,eAAe,GAAG,YAAY,IAAI,QAAQ,IAK/D;;;;AAI7B;AAEA,SAAgB,qBAAqB,UAA0B;CAC7D,OAAO;;2BAEkB,SAAS;;AAEpC;AASA,SAAS,yBAAyB,WAAmB,cAA4B;CAG/E,MAAM,OAAA,GAAA,UAAA,SAAA,EAAA,GAAA,UAAA,QAAA,CAF4B,SAEb,IAAA,GAAA,UAAA,QAAA,CADU,YACS,CAAc;CACtD,IAAI,IAAI,WAAW,IAAI,MAAA,GAAA,UAAA,WAAA,CAAgB,GAAG,GACxC,MAAM,IAAI,eAAA,UAAU,0CAA0C,YAAY;AAE9E;AAEA,eAAsB,kBACpB,WACA,cACA,UAA2B,CAAC,GACH;CACzB,yBAAyB,WAAW,YAAY;CAEhD,MAAM,eAAe,cAAA,aAAA,GAAA,UAAA,SAAA,CAAqB,WAAW,YAAY,CAAC;CAClE,IAAI,gBAAA,sBAAsB,cAAc,QAAQ,MAAM,GACpD,OAAO;CAGT,MAAM,OAAO,gBAAA,kBAAkB,YAAY;CAC3C,IAAI,CAAC,MACH,OAAO;CAGT,IAAI,SAAS;CACb,IAAI;EACF,SAAS,OAAA,GAAA,iBAAA,SAAA,CAAe,cAAc,MAAM;CAC9C,QAAQ;EACN,SAAS;CACX;CAEA,IAAI,CAAC,kBAAkB,QAAQ,IAAI,GACjC,OAAO;CAGT,IAAI,SAAS,UAAU;EAErB,OAAA,GAAA,iBAAA,UAAA,CAAgB,cAAc,qBADb,gBAAA,iBAAiB,gBAAA,kBAAkB,YAAY,CACb,CAAQ,GAAG,MAAM;EACpE,OAAO;CACT;CAEA,MAAM,WAAW,gBAAA,kBAAkB,YAAY;CAC/C,MAAM,SAAS,gBAAA,uBAAuB,QAAQ;CAE9C,OAAA,GAAA,iBAAA,UAAA,CAAgB,cAAc,oBADd,gBAAA,aAAa,QACqB,GAAS,MAAM,GAAG,MAAM;CAC1E,OAAO;AACT;AAEA,eAAsB,wBACpB,WACA,cACA,UAA2B,CAAC,GACH;CAEzB,MAAM,gBAAA,GAAA,UAAA,QAAA,CAAuB,WADV,cAAA,YAAY,YACS,CAAU;CAClD,OAAA,GAAA,iBAAA,MAAA,EAAA,GAAA,UAAA,QAAA,CAAoB,YAAY,GAAG,EAAE,WAAW,KAAK,CAAC;CACtD,OAAO,kBAAkB,WAAW,cAAc,OAAO;AAC3D"}