@lukoweb/apitogo 0.1.16 → 0.1.17

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.
Files changed (2) hide show
  1. package/dist/cli/cli.js +317 -66
  2. package/package.json +1 -1
package/dist/cli/cli.js CHANGED
@@ -131,7 +131,7 @@ import { stat } from "node:fs/promises";
131
131
  var fileExists;
132
132
  var init_file_exists = __esm({
133
133
  "src/config/file-exists.ts"() {
134
- fileExists = (path32) => stat(path32).then(() => true).catch(() => false);
134
+ fileExists = (path33) => stat(path33).then(() => true).catch(() => false);
135
135
  }
136
136
  });
137
137
 
@@ -3822,7 +3822,7 @@ import {
3822
3822
  // package.json
3823
3823
  var package_default = {
3824
3824
  name: "@lukoweb/apitogo",
3825
- version: "0.1.16",
3825
+ version: "0.1.17",
3826
3826
  type: "module",
3827
3827
  sideEffects: [
3828
3828
  "**/*.css",
@@ -4533,14 +4533,14 @@ var flattenAllOf = (schema2) => {
4533
4533
  };
4534
4534
 
4535
4535
  // src/lib/util/traverse.ts
4536
- var traverse = (specification, transform, path32 = []) => {
4537
- const transformed = transform(specification, path32);
4536
+ var traverse = (specification, transform, path33 = []) => {
4537
+ const transformed = transform(specification, path33);
4538
4538
  if (typeof transformed !== "object" || transformed === null) {
4539
4539
  return transformed;
4540
4540
  }
4541
4541
  const result = Array.isArray(transformed) ? [] : {};
4542
4542
  for (const [key, value] of Object.entries(transformed)) {
4543
- const currentPath = [...path32, key];
4543
+ const currentPath = [...path33, key];
4544
4544
  if (Array.isArray(value)) {
4545
4545
  result[key] = value.map(
4546
4546
  (item, index) => typeof item === "object" && item != null ? traverse(item, transform, [...currentPath, index.toString()]) : item
@@ -4568,9 +4568,9 @@ var resolveLocalRef = (schema2, ref) => {
4568
4568
  if (schemaCache?.has(ref)) {
4569
4569
  return schemaCache.get(ref);
4570
4570
  }
4571
- const path32 = ref.split("/").slice(1);
4571
+ const path33 = ref.split("/").slice(1);
4572
4572
  let current = schema2;
4573
- for (const segment of path32) {
4573
+ for (const segment of path33) {
4574
4574
  if (!current || typeof current !== "object") {
4575
4575
  current = null;
4576
4576
  }
@@ -4589,7 +4589,7 @@ var dereference = async (schema2, resolvers = []) => {
4589
4589
  }
4590
4590
  const cloned = structuredClone(schema2);
4591
4591
  const visited = /* @__PURE__ */ new Set();
4592
- const resolve = async (current, path32) => {
4592
+ const resolve = async (current, path33) => {
4593
4593
  if (isIndexableObject(current)) {
4594
4594
  if (visited.has(current)) {
4595
4595
  return CIRCULAR_REF;
@@ -4597,7 +4597,7 @@ var dereference = async (schema2, resolvers = []) => {
4597
4597
  visited.add(current);
4598
4598
  if (Array.isArray(current)) {
4599
4599
  for (let index = 0; index < current.length; index++) {
4600
- current[index] = await resolve(current[index], `${path32}/${index}`);
4600
+ current[index] = await resolve(current[index], `${path33}/${index}`);
4601
4601
  }
4602
4602
  } else {
4603
4603
  if ("$ref" in current && typeof current.$ref === "string") {
@@ -4608,13 +4608,13 @@ var dereference = async (schema2, resolvers = []) => {
4608
4608
  for (const resolver of resolvers) {
4609
4609
  const resolved = await resolver($ref);
4610
4610
  if (resolved) {
4611
- result2 = await resolve(resolved, path32);
4611
+ result2 = await resolve(resolved, path33);
4612
4612
  break;
4613
4613
  }
4614
4614
  }
4615
4615
  if (result2 === void 0) {
4616
4616
  const resolved = await resolveLocalRef(cloned, $ref);
4617
- result2 = await resolve(resolved, path32);
4617
+ result2 = await resolve(resolved, path33);
4618
4618
  }
4619
4619
  if (hasSiblings) {
4620
4620
  if (result2 === CIRCULAR_REF) {
@@ -4627,7 +4627,7 @@ var dereference = async (schema2, resolvers = []) => {
4627
4627
  return result2;
4628
4628
  }
4629
4629
  for (const key in current) {
4630
- current[key] = await resolve(current[key], `${path32}/${key}`);
4630
+ current[key] = await resolve(current[key], `${path33}/${key}`);
4631
4631
  }
4632
4632
  }
4633
4633
  visited.delete(current);
@@ -4666,9 +4666,9 @@ var upgradeSchema = (schema2) => {
4666
4666
  }
4667
4667
  return sub;
4668
4668
  });
4669
- schema2 = traverse(schema2, (sub, path32) => {
4669
+ schema2 = traverse(schema2, (sub, path33) => {
4670
4670
  if (sub.example !== void 0) {
4671
- if (isSchemaPath(path32 ?? [])) {
4671
+ if (isSchemaPath(path33 ?? [])) {
4672
4672
  sub.examples = [sub.example];
4673
4673
  } else {
4674
4674
  sub.examples = {
@@ -4681,11 +4681,11 @@ var upgradeSchema = (schema2) => {
4681
4681
  }
4682
4682
  return sub;
4683
4683
  });
4684
- schema2 = traverse(schema2, (schema3, path32) => {
4684
+ schema2 = traverse(schema2, (schema3, path33) => {
4685
4685
  if (schema3.type === "object" && schema3.properties !== void 0) {
4686
- const parentPath = path32?.slice(0, -1);
4686
+ const parentPath = path33?.slice(0, -1);
4687
4687
  const isMultipart = parentPath?.some((segment, index) => {
4688
- return segment === "content" && path32?.[index + 1] === "multipart/form-data";
4688
+ return segment === "content" && path33?.[index + 1] === "multipart/form-data";
4689
4689
  });
4690
4690
  if (isMultipart) {
4691
4691
  const entries = Object.entries(schema3.properties);
@@ -4699,8 +4699,8 @@ var upgradeSchema = (schema2) => {
4699
4699
  }
4700
4700
  return schema3;
4701
4701
  });
4702
- schema2 = traverse(schema2, (schema3, path32) => {
4703
- if (path32?.includes("content") && path32.includes("application/octet-stream")) {
4702
+ schema2 = traverse(schema2, (schema3, path33) => {
4703
+ if (path33?.includes("content") && path33.includes("application/octet-stream")) {
4704
4704
  return {};
4705
4705
  }
4706
4706
  if (schema3.type === "string" && schema3.format === "binary") {
@@ -4726,11 +4726,11 @@ var upgradeSchema = (schema2) => {
4726
4726
  }
4727
4727
  return sub;
4728
4728
  });
4729
- schema2 = traverse(schema2, (schema3, path32) => {
4729
+ schema2 = traverse(schema2, (schema3, path33) => {
4730
4730
  if (schema3.type === "string" && schema3.format === "byte") {
4731
- const parentPath = path32?.slice(0, -1);
4731
+ const parentPath = path33?.slice(0, -1);
4732
4732
  const contentMediaType = parentPath?.find(
4733
- (_, index) => path32?.[index - 1] === "content"
4733
+ (_, index) => path33?.[index - 1] === "content"
4734
4734
  );
4735
4735
  return {
4736
4736
  type: "string",
@@ -4742,7 +4742,7 @@ var upgradeSchema = (schema2) => {
4742
4742
  });
4743
4743
  return schema2;
4744
4744
  };
4745
- function isSchemaPath(path32) {
4745
+ function isSchemaPath(path33) {
4746
4746
  const schemaLocations = [
4747
4747
  ["components", "schemas"],
4748
4748
  "properties",
@@ -4755,10 +4755,10 @@ function isSchemaPath(path32) {
4755
4755
  ];
4756
4756
  return schemaLocations.some((location) => {
4757
4757
  if (Array.isArray(location)) {
4758
- return location.every((segment, index) => path32[index] === segment);
4758
+ return location.every((segment, index) => path33[index] === segment);
4759
4759
  }
4760
- return path32.includes(location);
4761
- }) || path32.includes("schema") || path32.some((segment) => segment.endsWith("Schema"));
4760
+ return path33.includes(location);
4761
+ }) || path33.includes("schema") || path33.some((segment) => segment.endsWith("Schema"));
4762
4762
  }
4763
4763
 
4764
4764
  // src/lib/oas/parser/index.ts
@@ -4840,13 +4840,13 @@ var OPENAPI_PROPS = /* @__PURE__ */ new Set([
4840
4840
  "anyOf",
4841
4841
  "oneOf"
4842
4842
  ]);
4843
- var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path32 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
4843
+ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path33 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
4844
4844
  if (obj === null || typeof obj !== "object") return obj;
4845
4845
  const refPath = obj.__$ref;
4846
4846
  const isCircular = currentPath.has(obj) || typeof refPath === "string" && currentRefPaths.has(refPath);
4847
4847
  if (isCircular) {
4848
4848
  if (typeof refPath === "string") return SCHEMA_REF_PREFIX + refPath;
4849
- const circularProp = path32.find((p) => !OPENAPI_PROPS.has(p)) || path32[0];
4849
+ const circularProp = path33.find((p) => !OPENAPI_PROPS.has(p)) || path33[0];
4850
4850
  return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
4851
4851
  }
4852
4852
  if (refs.has(obj)) return refs.get(obj);
@@ -4856,7 +4856,7 @@ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs
4856
4856
  value,
4857
4857
  currentPath,
4858
4858
  refs,
4859
- [...path32, key],
4859
+ [...path33, key],
4860
4860
  currentRefPaths
4861
4861
  );
4862
4862
  const result = Array.isArray(obj) ? obj.map((item, i) => recurse(item, i.toString())) : Object.fromEntries(
@@ -4891,7 +4891,7 @@ var resolveExtensions = (obj) => Object.fromEntries(
4891
4891
  var getAllTags = (schema2) => {
4892
4892
  const rootTags = schema2.tags ?? [];
4893
4893
  const operations = Object.values(schema2.paths ?? {}).flatMap(
4894
- (path32) => HttpMethods.map((k) => path32?.[k]).filter((op) => op != null)
4894
+ (path33) => HttpMethods.map((k) => path33?.[k]).filter((op) => op != null)
4895
4895
  );
4896
4896
  const operationTags = new Set(operations.flatMap((op) => op.tags ?? []));
4897
4897
  const hasUntaggedOperations = operations.some(
@@ -4946,7 +4946,7 @@ var getAllSlugs = (ops, schemaTags = []) => {
4946
4946
  var getOperationSlugKey = (op) => [op.path, op.method, op.operationId, op.summary].filter(Boolean).join("-");
4947
4947
  var getAllOperations = (paths) => {
4948
4948
  const operations = Object.entries(paths ?? {}).flatMap(
4949
- ([path32, value]) => HttpMethods.flatMap((method) => {
4949
+ ([path33, value]) => HttpMethods.flatMap((method) => {
4950
4950
  if (!value?.[method]) return [];
4951
4951
  const operation = value[method];
4952
4952
  const pathParameters = value.parameters ?? [];
@@ -4966,7 +4966,7 @@ var getAllOperations = (paths) => {
4966
4966
  return {
4967
4967
  ...operation,
4968
4968
  method,
4969
- path: path32,
4969
+ path: path33,
4970
4970
  parameters,
4971
4971
  servers,
4972
4972
  tags: operation.tags ?? []
@@ -5324,8 +5324,8 @@ var Schema = builder.objectRef("Schema").implement({
5324
5324
  }),
5325
5325
  paths: t.field({
5326
5326
  type: [PathItem],
5327
- resolve: (root) => Object.entries(root.paths ?? {}).map(([path32, value]) => ({
5328
- path: path32,
5327
+ resolve: (root) => Object.entries(root.paths ?? {}).map(([path33, value]) => ({
5328
+ path: path33,
5329
5329
  // biome-ignore lint/style/noNonNullAssertion: value is guaranteed to be defined
5330
5330
  methods: Object.keys(value)
5331
5331
  }))
@@ -5472,7 +5472,7 @@ init_joinUrl();
5472
5472
 
5473
5473
  // src/vite/api/schema-codegen.ts
5474
5474
  var unescapeJsonPointer = (uri) => decodeURIComponent(uri.replace(/~1/g, "/").replace(/~0/g, "~"));
5475
- var getSegmentsFromPath = (path32) => path32.split("/").slice(1).map(unescapeJsonPointer);
5475
+ var getSegmentsFromPath = (path33) => path33.split("/").slice(1).map(unescapeJsonPointer);
5476
5476
  var createLocalRefMap = (obj) => {
5477
5477
  const refMap = /* @__PURE__ */ new Map();
5478
5478
  const siblingsMap = /* @__PURE__ */ new Map();
@@ -5503,16 +5503,16 @@ var replaceMarkers = (code, mergedRefs) => code.replace(/"__refMap:(.*?)"/g, '__
5503
5503
  /"__refMap\+Siblings:(.*?)"/g,
5504
5504
  (_, key) => mergedRefs.get(key) ?? `__refMap["${key}"]`
5505
5505
  );
5506
- var lookup = (schema2, path32, filePath) => {
5507
- const parts = getSegmentsFromPath(path32);
5506
+ var lookup = (schema2, path33, filePath) => {
5507
+ const parts = getSegmentsFromPath(path33);
5508
5508
  let val = schema2;
5509
5509
  for (const part of parts) {
5510
5510
  while (val.$ref?.startsWith("#/")) {
5511
- val = val.$ref === path32 ? val : lookup(schema2, val.$ref, filePath);
5511
+ val = val.$ref === path33 ? val : lookup(schema2, val.$ref, filePath);
5512
5512
  }
5513
5513
  if (val[part] === void 0) {
5514
5514
  throw new Error(
5515
- `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path32}`
5515
+ `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path33}`
5516
5516
  );
5517
5517
  }
5518
5518
  val = val[part];
@@ -5757,8 +5757,8 @@ var SchemaManager = class {
5757
5757
  }
5758
5758
  }
5759
5759
  };
5760
- getLatestSchema = (path32) => this.processedSchemas[path32]?.at(0);
5761
- getSchemasForPath = (path32) => this.processedSchemas[path32];
5760
+ getLatestSchema = (path33) => this.processedSchemas[path33]?.at(0);
5761
+ getSchemasForPath = (path33) => this.processedSchemas[path33];
5762
5762
  getSchemaImports = () => Object.values(this.processedSchemas).flat().filter((s) => s.importKey);
5763
5763
  getUrlToFilePathMap = () => {
5764
5764
  const map = /* @__PURE__ */ new Map();
@@ -7847,14 +7847,14 @@ async function generateSitemap({
7847
7847
 
7848
7848
  // src/vite/prerender/utils.ts
7849
7849
  init_joinUrl();
7850
- var resolveRoutePath = (path32) => {
7851
- const segments = path32.split("/");
7850
+ var resolveRoutePath = (path33) => {
7851
+ const segments = path33.split("/");
7852
7852
  if (segments.some((s) => s.startsWith(":") && !s.endsWith("?"))) {
7853
7853
  return void 0;
7854
7854
  }
7855
7855
  return segments.filter((s) => !s.startsWith(":")).join("/") || void 0;
7856
7856
  };
7857
- var isSkipped = (path32) => path32.includes("*") || /^\d+$/.test(path32);
7857
+ var isSkipped = (path33) => path33.includes("*") || /^\d+$/.test(path33);
7858
7858
  var resolveRoutes = (routes, parentPath = "") => routes.flatMap((route) => {
7859
7859
  if (route.path && isSkipped(route.path)) return [];
7860
7860
  const routePath = route.path ? resolveRoutePath(route.path) : void 0;
@@ -9145,9 +9145,230 @@ var dev_default = {
9145
9145
  };
9146
9146
 
9147
9147
  // src/cli/make-config/handler.ts
9148
- import { readFile as readFile5, writeFile as writeFile7 } from "node:fs/promises";
9148
+ import { readFile as readFile6, writeFile as writeFile8 } from "node:fs/promises";
9149
+ import path31 from "node:path";
9150
+ import { glob as glob5 } from "glob";
9151
+
9152
+ // src/cli/make-config/scaffold-project.ts
9153
+ init_package_json();
9154
+ import { access as access3, readFile as readFile5, writeFile as writeFile7 } from "node:fs/promises";
9155
+ import { constants as constants2 } from "node:fs";
9149
9156
  import path30 from "node:path";
9150
9157
  import { glob as glob4 } from "glob";
9158
+ var OPENAPI_GLOBS = [
9159
+ "apis/openapi.json",
9160
+ "apis/openapi.yaml",
9161
+ "apis/openapi.yml",
9162
+ "openapi.json",
9163
+ "openapi.yaml",
9164
+ "openapi.yml"
9165
+ ];
9166
+ var findMatchingCurly = (source, startIndex) => {
9167
+ let depth = 0;
9168
+ let inSingleQuote = false;
9169
+ let inDoubleQuote = false;
9170
+ let inTemplate = false;
9171
+ let inLineComment = false;
9172
+ let inBlockComment = false;
9173
+ for (let index = startIndex; index < source.length; index++) {
9174
+ const char = source[index];
9175
+ const next = source[index + 1];
9176
+ const prev = source[index - 1];
9177
+ if (inLineComment) {
9178
+ if (char === "\n") inLineComment = false;
9179
+ continue;
9180
+ }
9181
+ if (inBlockComment) {
9182
+ if (prev === "*" && char === "/") inBlockComment = false;
9183
+ continue;
9184
+ }
9185
+ if (!inSingleQuote && !inDoubleQuote && !inTemplate) {
9186
+ if (char === "/" && next === "/") {
9187
+ inLineComment = true;
9188
+ index++;
9189
+ continue;
9190
+ }
9191
+ if (char === "/" && next === "*") {
9192
+ inBlockComment = true;
9193
+ index++;
9194
+ continue;
9195
+ }
9196
+ }
9197
+ if (!inDoubleQuote && !inTemplate && char === "'" && prev !== "\\") {
9198
+ inSingleQuote = !inSingleQuote;
9199
+ continue;
9200
+ }
9201
+ if (!inSingleQuote && !inTemplate && char === '"' && prev !== "\\") {
9202
+ inDoubleQuote = !inDoubleQuote;
9203
+ continue;
9204
+ }
9205
+ if (!inSingleQuote && !inDoubleQuote && char === "`" && prev !== "\\") {
9206
+ inTemplate = !inTemplate;
9207
+ continue;
9208
+ }
9209
+ if (inSingleQuote || inDoubleQuote || inTemplate) continue;
9210
+ if (char === "{") depth++;
9211
+ if (char === "}") depth--;
9212
+ if (depth === 0) return index;
9213
+ }
9214
+ throw new Error("Could not find matching closing brace for object.");
9215
+ };
9216
+ var toPosix = (p) => p.split(path30.sep).join("/");
9217
+ var sanitizePackageName = (dir) => {
9218
+ const base = path30.basename(path30.resolve(dir));
9219
+ const s = base.toLowerCase().replace(/[^a-z0-9-_.]/g, "-").replace(/^-+|-+$/g, "");
9220
+ return s || "apitogo-site";
9221
+ };
9222
+ var apitogoVersionRange = () => {
9223
+ const v = getZudokuPackageJson()?.version;
9224
+ return v ? `^${v}` : "latest";
9225
+ };
9226
+ async function findOpenApiSpecPath(dir) {
9227
+ for (const rel of OPENAPI_GLOBS) {
9228
+ const full = path30.join(dir, rel);
9229
+ try {
9230
+ await access3(full, constants2.R_OK);
9231
+ return toPosix(rel);
9232
+ } catch {
9233
+ }
9234
+ }
9235
+ const extra = await glob4("apis/**/*.{json,yaml,yml}", {
9236
+ cwd: dir,
9237
+ posix: true,
9238
+ ignore: ["**/node_modules/**"]
9239
+ });
9240
+ return extra[0] ? toPosix(extra[0]) : null;
9241
+ }
9242
+ async function ensurePackageJson(dir) {
9243
+ const pkgPath = path30.join(dir, "package.json");
9244
+ const apitogoVer = apitogoVersionRange();
9245
+ const baseDeps = {
9246
+ react: ">=19.0.0",
9247
+ "react-dom": ">=19.0.0",
9248
+ "@lukoweb/apitogo": apitogoVer
9249
+ };
9250
+ const baseScripts = {
9251
+ dev: "apitogo dev",
9252
+ build: "apitogo build",
9253
+ preview: "apitogo preview"
9254
+ };
9255
+ try {
9256
+ await access3(pkgPath, constants2.R_OK);
9257
+ } catch (err) {
9258
+ const code = err.code;
9259
+ if (code !== "ENOENT") throw err;
9260
+ const pkg2 = {
9261
+ name: sanitizePackageName(dir),
9262
+ version: "0.1.0",
9263
+ private: true,
9264
+ type: "module",
9265
+ scripts: baseScripts,
9266
+ dependencies: baseDeps,
9267
+ devDependencies: {
9268
+ "@types/node": "^22",
9269
+ "@types/react": "^19",
9270
+ "@types/react-dom": "^19",
9271
+ typescript: "^5"
9272
+ }
9273
+ };
9274
+ await writeFile7(pkgPath, `${JSON.stringify(pkg2, null, 2)}
9275
+ `, "utf8");
9276
+ return true;
9277
+ }
9278
+ const raw = await readFile5(pkgPath, "utf8");
9279
+ let pkg;
9280
+ try {
9281
+ pkg = JSON.parse(raw);
9282
+ } catch {
9283
+ throw new Error("package.json exists but is not valid JSON; fix or remove it and run again.");
9284
+ }
9285
+ pkg.scripts = {
9286
+ ...typeof pkg.scripts === "object" && pkg.scripts !== null ? pkg.scripts : {}
9287
+ };
9288
+ const scripts = pkg.scripts;
9289
+ for (const [k, v] of Object.entries(baseScripts)) {
9290
+ if (!scripts[k]) scripts[k] = v;
9291
+ }
9292
+ pkg.dependencies = {
9293
+ ...typeof pkg.dependencies === "object" && pkg.dependencies !== null ? pkg.dependencies : {}
9294
+ };
9295
+ const deps = pkg.dependencies;
9296
+ for (const [k, v] of Object.entries(baseDeps)) {
9297
+ if (!deps[k]) deps[k] = v;
9298
+ }
9299
+ await writeFile7(pkgPath, `${JSON.stringify(pkg, null, 2)}
9300
+ `, "utf8");
9301
+ return false;
9302
+ }
9303
+ async function ensureTsconfigJson(dir) {
9304
+ const tsPath = path30.join(dir, "tsconfig.json");
9305
+ try {
9306
+ await access3(tsPath, constants2.R_OK);
9307
+ return false;
9308
+ } catch {
9309
+ const tsconfig = {
9310
+ compilerOptions: {
9311
+ target: "ES2022",
9312
+ lib: ["ESNext", "DOM", "DOM.Iterable", "WebWorker"],
9313
+ module: "ESNext",
9314
+ moduleResolution: "Bundler",
9315
+ useDefineForClassFields: true,
9316
+ skipLibCheck: true,
9317
+ skipDefaultLibCheck: true,
9318
+ resolveJsonModule: true,
9319
+ isolatedModules: true,
9320
+ useUnknownInCatchVariables: false,
9321
+ jsx: "react-jsx"
9322
+ },
9323
+ include: [
9324
+ "*.config.ts",
9325
+ "*.config.tsx",
9326
+ "*.config.jsx",
9327
+ "*.config.js",
9328
+ "*.config.mjs",
9329
+ "pages"
9330
+ ]
9331
+ };
9332
+ await writeFile7(tsPath, `${JSON.stringify(tsconfig, null, 2)}
9333
+ `, "utf8");
9334
+ return true;
9335
+ }
9336
+ }
9337
+ function insertApisIfMissing(source, openapiInput) {
9338
+ if (/\bapis\s*:/.test(source)) return source;
9339
+ const apisBlock = [
9340
+ " apis: {",
9341
+ ' type: "file",',
9342
+ ` input: "${openapiInput.replace(/"/g, '\\"')}",`,
9343
+ ' path: "api",',
9344
+ " },"
9345
+ ].join("\n");
9346
+ const docsMatch = source.match(/\bdocs\s*:\s*\{/);
9347
+ if (!docsMatch || docsMatch.index === void 0) {
9348
+ const m = source.match(/(const\s+config\s*:\s*ApitogoConfig\s*=\s*\{)/);
9349
+ if (!m || m.index === void 0) {
9350
+ return source;
9351
+ }
9352
+ const open = m.index + m[0].length;
9353
+ return `${source.slice(0, open)}
9354
+ ${apisBlock}
9355
+ ${source.slice(open)}`;
9356
+ }
9357
+ const openBrace = source.indexOf("{", docsMatch.index);
9358
+ const closeBrace = findMatchingCurly(source, openBrace);
9359
+ let p = closeBrace + 1;
9360
+ while (p < source.length && /\s/.test(source[p])) p++;
9361
+ if (source[p] === ",") p++;
9362
+ while (p < source.length && /\s/.test(source[p])) p++;
9363
+ return `${source.slice(0, p)}${apisBlock}
9364
+ ${source.slice(p)}`;
9365
+ }
9366
+ function openapiInputForConfig(specRelativePosix) {
9367
+ if (specRelativePosix.startsWith("./")) return specRelativePosix;
9368
+ return `./${specRelativePosix}`;
9369
+ }
9370
+
9371
+ // src/cli/make-config/handler.ts
9151
9372
  var CONFIG_FILENAMES = [
9152
9373
  "apitogo.config.tsx",
9153
9374
  "apitogo.config.ts",
@@ -9162,7 +9383,7 @@ var CONFIG_FILENAMES = [
9162
9383
  ];
9163
9384
  var DEFAULT_NEW_CONFIG_FILENAME = "apitogo.config.tsx";
9164
9385
  var createTreeNode = () => ({ docs: [], children: /* @__PURE__ */ new Map() });
9165
- var toPosixPath2 = (value) => value.split(path30.sep).join(path30.posix.sep);
9386
+ var toPosixPath2 = (value) => value.split(path31.sep).join(path31.posix.sep);
9166
9387
  var toRoutePath = (relativeFile, pagesDir) => {
9167
9388
  const relativeNoExt = relativeFile.replace(/\.mdx?$/, "");
9168
9389
  const withoutPagesPrefix = relativeNoExt.replace(
@@ -9384,14 +9605,20 @@ var ensureNavigationAndRedirectsForUpdate = (source) => {
9384
9605
  "Found 'redirects' but not 'navigation'. Add a navigation: [...] array manually."
9385
9606
  );
9386
9607
  };
9387
- var buildNewConfigContents = (pagesDir) => {
9388
- const filesGlob = `/${pagesDir}/**/*.mdx`;
9608
+ var buildNewConfigContents = (pagesDir, openApiSpecRelative) => {
9609
+ const filesGlob = `/${pagesDir}/**/*.{md,mdx}`;
9610
+ const apisSection = openApiSpecRelative == null ? "" : `
9611
+ apis: {
9612
+ type: "file",
9613
+ input: "${openapiInputForConfig(openApiSpecRelative)}",
9614
+ path: "api",
9615
+ },`;
9389
9616
  return `import type { ApitogoConfig } from "@lukoweb/apitogo";
9390
9617
 
9391
9618
  const config: ApitogoConfig = {
9392
9619
  docs: {
9393
9620
  files: "${filesGlob}",
9394
- },
9621
+ },${apisSection}
9395
9622
  navigation: [],
9396
9623
  redirects: [],
9397
9624
  };
@@ -9401,9 +9628,9 @@ export default config;
9401
9628
  };
9402
9629
  var findExistingConfigPath = async (dir) => {
9403
9630
  for (const filename of CONFIG_FILENAMES) {
9404
- const fullPath = path30.join(dir, filename);
9631
+ const fullPath = path31.join(dir, filename);
9405
9632
  try {
9406
- await readFile5(fullPath, "utf8");
9633
+ await readFile6(fullPath, "utf8");
9407
9634
  return fullPath;
9408
9635
  } catch {
9409
9636
  }
@@ -9411,20 +9638,33 @@ var findExistingConfigPath = async (dir) => {
9411
9638
  return null;
9412
9639
  };
9413
9640
  async function makeConfig(argv) {
9414
- const dir = path30.resolve(process.cwd(), argv.dir);
9641
+ const dir = path31.resolve(process.cwd(), argv.dir);
9415
9642
  const pagesDir = toPosixPath2(
9416
9643
  argv.pagesDir.replace(/^[./]+/, "").replace(/\/+$/, "")
9417
9644
  );
9418
9645
  try {
9646
+ const openApiSpecPath = await findOpenApiSpecPath(dir);
9647
+ const createdPackageJson = await ensurePackageJson(dir);
9648
+ const createdTsconfig = await ensureTsconfigJson(dir);
9649
+ if (createdPackageJson) {
9650
+ printDiagnosticsToConsole("Created package.json with dev, build, and preview scripts.");
9651
+ }
9652
+ if (createdTsconfig) {
9653
+ printDiagnosticsToConsole("Created tsconfig.json.");
9654
+ }
9419
9655
  let configPath = await findExistingConfigPath(dir);
9420
9656
  let createdNew = false;
9421
9657
  if (!configPath) {
9422
- configPath = path30.join(dir, DEFAULT_NEW_CONFIG_FILENAME);
9423
- await writeFile7(configPath, buildNewConfigContents(pagesDir), "utf8");
9658
+ configPath = path31.join(dir, DEFAULT_NEW_CONFIG_FILENAME);
9659
+ await writeFile8(
9660
+ configPath,
9661
+ buildNewConfigContents(pagesDir, openApiSpecPath),
9662
+ "utf8"
9663
+ );
9424
9664
  createdNew = true;
9425
9665
  printDiagnosticsToConsole(`Created ${DEFAULT_NEW_CONFIG_FILENAME}`);
9426
9666
  }
9427
- const pageFiles = await glob4(`${pagesDir}/**/*.{md,mdx}`, {
9667
+ const pageFiles = await glob5(`${pagesDir}/**/*.{md,mdx}`, {
9428
9668
  cwd: dir,
9429
9669
  ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**"],
9430
9670
  posix: true
@@ -9435,7 +9675,13 @@ async function makeConfig(argv) {
9435
9675
  if (routePaths.length === 0) {
9436
9676
  throw new Error(`No .md or .mdx files found under '${pagesDir}'.`);
9437
9677
  }
9438
- let originalConfig = await readFile5(configPath, "utf8");
9678
+ let originalConfig = await readFile6(configPath, "utf8");
9679
+ if (!createdNew && openApiSpecPath) {
9680
+ originalConfig = insertApisIfMissing(
9681
+ originalConfig,
9682
+ openapiInputForConfig(openApiSpecPath)
9683
+ );
9684
+ }
9439
9685
  originalConfig = ensureNavigationAndRedirectsForUpdate(originalConfig);
9440
9686
  const withNavigation = replaceArrayProperty(
9441
9687
  originalConfig,
@@ -9447,11 +9693,16 @@ async function makeConfig(argv) {
9447
9693
  "redirects",
9448
9694
  buildRedirectsCode(routePaths[0])
9449
9695
  );
9450
- await writeFile7(configPath, withRedirects, "utf8");
9696
+ await writeFile8(configPath, withRedirects, "utf8");
9451
9697
  const action = createdNew ? "Initialized" : "Updated";
9452
9698
  printResultToConsole(
9453
- `${action} ${path30.basename(configPath)} from ${pagesDir}/ (navigation and redirects only; other settings unchanged)`
9699
+ `${action} ${path31.basename(configPath)} from ${pagesDir}/ (navigation and redirects; other top-level settings preserved unless newly scaffolded).`
9454
9700
  );
9701
+ if (createdPackageJson) {
9702
+ printDiagnosticsToConsole(
9703
+ "Next: run npm install (or pnpm install / yarn) in this directory, then npm run dev."
9704
+ );
9705
+ }
9455
9706
  } catch (error) {
9456
9707
  await printCriticalFailureToConsoleAndExit(
9457
9708
  error instanceof Error ? error.message : String(error)
@@ -9504,7 +9755,7 @@ var preview_default = previewCommand;
9504
9755
 
9505
9756
  // src/cli/common/outdated.ts
9506
9757
  import { existsSync as existsSync2, mkdirSync } from "node:fs";
9507
- import { readFile as readFile6, writeFile as writeFile8 } from "node:fs/promises";
9758
+ import { readFile as readFile7, writeFile as writeFile9 } from "node:fs/promises";
9508
9759
  import { join } from "node:path";
9509
9760
  import colors10 from "picocolors";
9510
9761
  import { gt } from "semver";
@@ -9554,12 +9805,12 @@ function box(message, {
9554
9805
 
9555
9806
  // src/cli/common/xdg/lib.ts
9556
9807
  import { homedir } from "node:os";
9557
- import path31 from "node:path";
9808
+ import path32 from "node:path";
9558
9809
  function defineDirectoryWithFallback(xdgName, fallback) {
9559
9810
  if (process.env[xdgName]) {
9560
9811
  return process.env[xdgName];
9561
9812
  } else {
9562
- return path31.join(homedir(), fallback);
9813
+ return path32.join(homedir(), fallback);
9563
9814
  }
9564
9815
  }
9565
9816
  var XDG_CONFIG_HOME = defineDirectoryWithFallback(
@@ -9574,15 +9825,15 @@ var XDG_STATE_HOME = defineDirectoryWithFallback(
9574
9825
  "XDG_DATA_HOME",
9575
9826
  ".local/state"
9576
9827
  );
9577
- var ZUDOKU_XDG_CONFIG_HOME = path31.join(
9828
+ var ZUDOKU_XDG_CONFIG_HOME = path32.join(
9578
9829
  XDG_CONFIG_HOME,
9579
9830
  CLI_XDG_FOLDER_NAME
9580
9831
  );
9581
- var ZUDOKU_XDG_DATA_HOME = path31.join(
9832
+ var ZUDOKU_XDG_DATA_HOME = path32.join(
9582
9833
  XDG_DATA_HOME,
9583
9834
  CLI_XDG_FOLDER_NAME
9584
9835
  );
9585
- var ZUDOKU_XDG_STATE_HOME = path31.join(
9836
+ var ZUDOKU_XDG_STATE_HOME = path32.join(
9586
9837
  XDG_STATE_HOME,
9587
9838
  CLI_XDG_FOLDER_NAME
9588
9839
  );
@@ -9634,7 +9885,7 @@ async function getVersionCheckInfo() {
9634
9885
  let versionCheckInfo;
9635
9886
  if (existsSync2(versionCheckPath)) {
9636
9887
  try {
9637
- versionCheckInfo = await readFile6(versionCheckPath, "utf-8").then(
9888
+ versionCheckInfo = await readFile7(versionCheckPath, "utf-8").then(
9638
9889
  JSON.parse
9639
9890
  );
9640
9891
  } catch {
@@ -9659,7 +9910,7 @@ async function getVersionCheckInfo() {
9659
9910
  lastCheck: Date.now(),
9660
9911
  latestVersion
9661
9912
  };
9662
- await writeFile8(
9913
+ await writeFile9(
9663
9914
  versionCheckPath,
9664
9915
  JSON.stringify(versionCheckInfo),
9665
9916
  "utf-8"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukoweb/apitogo",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "**/*.css",