@thallylabs/migrate 0.2.44 → 0.2.45

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.d.ts CHANGED
@@ -118,7 +118,6 @@ declare function detectRepositoryPlatform(repositoryDir: string, docsDir?: strin
118
118
  declare function detectRepositoryDocsDir(repositoryDir: string): string;
119
119
  /** Enumerate generated endpoint routes using the same spec visibility, tab ids and slugs as migration linking. */
120
120
  declare function migrationApiRoutes(bundle: Pick<MigrationBundle, 'docsConfig' | 'assets'>): Array<string>;
121
- /** Import an already-available repository directory into a canonical bundle. */
122
121
  declare function migrateRepository(options: RepositoryMigrationOptions): MigrationBundle;
123
122
 
124
123
  /**
package/dist/index.js CHANGED
@@ -8217,7 +8217,122 @@ function propertyStart(source, name) {
8217
8217
  }
8218
8218
  return -1;
8219
8219
  }
8220
- function staticStringBindings(source) {
8220
+ function staticModulePath(repositoryRoot, specifier) {
8221
+ if (!specifier.startsWith(".")) return null;
8222
+ try {
8223
+ const relativePath = specifier.replace(/^\.\/+/, "");
8224
+ return ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".json"].map((extension) => withinRealRoot(resolveWithin(repositoryRoot, `${relativePath}${extension}`), repositoryRoot)).find((candidate) => existsSync4(candidate) && lstatSync4(candidate).isFile()) ?? null;
8225
+ } catch {
8226
+ return null;
8227
+ }
8228
+ }
8229
+ function staticObjectStrings(objectText) {
8230
+ const fields = /* @__PURE__ */ new Map();
8231
+ try {
8232
+ const parsed = JSON5.parse(objectText);
8233
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return fields;
8234
+ for (const [key, value] of Object.entries(parsed)) {
8235
+ if (typeof value === "string") fields.set(key, value);
8236
+ }
8237
+ } catch {
8238
+ return fields;
8239
+ }
8240
+ return fields;
8241
+ }
8242
+ function defaultExportObjectLiteralText(source) {
8243
+ const exported = /\bexport\s+default\s+/.exec(source);
8244
+ if (!exported) return null;
8245
+ const start = exported.index + exported[0].length;
8246
+ const literal = matchingObjectLiteral(source, start);
8247
+ if (literal) return literal;
8248
+ const identifier = source.slice(start).match(/^([A-Za-z_$][\w$]*)/)?.[1];
8249
+ if (!identifier) return null;
8250
+ const declaration = new RegExp(
8251
+ `\\b(?:const|let|var)\\s+${identifier}\\b(?:\\s*:\\s*[^=;]+)?\\s*=\\s*`
8252
+ ).exec(source);
8253
+ return declaration ? matchingObjectLiteral(source, declaration.index + declaration[0].length) : null;
8254
+ }
8255
+ function namedExportStringText(source, name) {
8256
+ const match = new RegExp(
8257
+ `\\bexport\\s+(?:const|let|var)\\s+${name}\\b(?:\\s*:\\s*[^=;]+)?\\s*=\\s*`
8258
+ ).exec(source);
8259
+ if (!match) return void 0;
8260
+ const quoted = source.slice(match.index + match[0].length).match(/^("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')/);
8261
+ if (!quoted) return void 0;
8262
+ try {
8263
+ const parsed = JSON5.parse(quoted[1]);
8264
+ return typeof parsed === "string" ? parsed : void 0;
8265
+ } catch {
8266
+ return void 0;
8267
+ }
8268
+ }
8269
+ function staticImportBindings(source, repositoryRoot) {
8270
+ const bindings = /* @__PURE__ */ new Map();
8271
+ const addObject = (local, specifier, exported) => {
8272
+ const modulePath = staticModulePath(repositoryRoot, specifier);
8273
+ if (!modulePath) return;
8274
+ const moduleSource = readBoundedText(modulePath);
8275
+ const objectText = extname5(modulePath).toLowerCase() === ".json" ? moduleSource : exported === "default" ? defaultExportObjectLiteralText(moduleSource) : namedExportObjectLiteralText(moduleSource, exported);
8276
+ if (!objectText) return;
8277
+ for (const [key, value] of staticObjectStrings(objectText)) {
8278
+ bindings.set(`${local}.${key}`, value);
8279
+ }
8280
+ };
8281
+ const addString = (local, specifier, exported) => {
8282
+ const modulePath = staticModulePath(repositoryRoot, specifier);
8283
+ if (!modulePath || extname5(modulePath).toLowerCase() === ".json") return;
8284
+ const value = namedExportStringText(readBoundedText(modulePath), exported);
8285
+ if (value !== void 0) bindings.set(local, value);
8286
+ };
8287
+ const addNamespace = (local, specifier) => {
8288
+ const modulePath = staticModulePath(repositoryRoot, specifier);
8289
+ if (!modulePath) return;
8290
+ const moduleSource = readBoundedText(modulePath);
8291
+ if (extname5(modulePath).toLowerCase() === ".json") {
8292
+ for (const [key, value] of staticObjectStrings(moduleSource)) {
8293
+ bindings.set(`${local}.${key}`, value);
8294
+ }
8295
+ return;
8296
+ }
8297
+ const defaultText = defaultExportObjectLiteralText(moduleSource);
8298
+ if (defaultText) {
8299
+ for (const [key, value] of staticObjectStrings(defaultText)) {
8300
+ bindings.set(`${local}.default.${key}`, value);
8301
+ }
8302
+ }
8303
+ for (const match of moduleSource.matchAll(/\bexport\s+(?:const|let|var)\s+([A-Za-z_$][\w$]*)\b/g)) {
8304
+ const name = match[1];
8305
+ const value = namedExportStringText(moduleSource, name);
8306
+ if (value !== void 0) bindings.set(`${local}.${name}`, value);
8307
+ const objectText = namedExportObjectLiteralText(moduleSource, name);
8308
+ if (!objectText) continue;
8309
+ for (const [key, objectValue5] of staticObjectStrings(objectText)) {
8310
+ bindings.set(`${local}.${name}.${key}`, objectValue5);
8311
+ }
8312
+ }
8313
+ };
8314
+ for (const match of source.matchAll(
8315
+ /\bimport\s+([A-Za-z_$][\w$]*)\s*(?:,\s*\{[^}]*\})?\s+from\s*(['"])([^'"]+)\2/g
8316
+ )) {
8317
+ addObject(match[1], match[3], "default");
8318
+ }
8319
+ for (const match of source.matchAll(
8320
+ /\bimport\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s*(['"])([^'"]+)\2/g
8321
+ )) {
8322
+ addNamespace(match[1], match[3]);
8323
+ }
8324
+ for (const match of source.matchAll(/\bimport\s*\{([^}]*)\}\s*from\s*(['"])([^'"]+)\2/g)) {
8325
+ for (const entry of match[1].split(",")) {
8326
+ const [imported, alias] = entry.split(/\s+as\s+/).map((part) => part.trim());
8327
+ if (!imported || !/^[A-Za-z_$][\w$]*$/.test(imported)) continue;
8328
+ const local = alias && /^[A-Za-z_$][\w$]*$/.test(alias) ? alias : imported;
8329
+ addObject(local, match[3], imported);
8330
+ addString(local, match[3], imported);
8331
+ }
8332
+ }
8333
+ return bindings;
8334
+ }
8335
+ function staticStringBindings(source, repositoryRoot) {
8221
8336
  const bindings = /* @__PURE__ */ new Map();
8222
8337
  for (const match of source.matchAll(/\bconst\s+([A-Z][A-Z0-9_]*)\s*=\s*((?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'))/g)) {
8223
8338
  try {
@@ -8226,6 +8341,11 @@ function staticStringBindings(source) {
8226
8341
  } catch {
8227
8342
  }
8228
8343
  }
8344
+ if (repositoryRoot) {
8345
+ for (const [reference, value] of staticImportBindings(source, repositoryRoot)) {
8346
+ bindings.set(reference, value);
8347
+ }
8348
+ }
8229
8349
  return bindings;
8230
8350
  }
8231
8351
  function staticArrayField(source, name) {
@@ -8293,8 +8413,8 @@ function staticStringField(source, name, bindings) {
8293
8413
  if (start < 0) return void 0;
8294
8414
  const quoted = source.slice(start).match(/^("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')/);
8295
8415
  if (!quoted) {
8296
- const binding = source.slice(start).match(/^([A-Z][A-Z0-9_]*)\b/)?.[1];
8297
- return binding ? bindings?.get(binding) : void 0;
8416
+ const reference = source.slice(start).match(/^([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/)?.[1];
8417
+ return reference ? bindings?.get(reference) : void 0;
8298
8418
  }
8299
8419
  try {
8300
8420
  const parsed = JSON5.parse(quoted[1]);
@@ -8308,10 +8428,10 @@ function readDocusaurusSiteSettings(repositoryRoot) {
8308
8428
  const configPath = findDocusaurusConfigPath(repositoryRoot);
8309
8429
  if (!configPath) return empty2;
8310
8430
  const source = readBoundedText(configPath);
8311
- const bindings = staticStringBindings(source);
8431
+ const bindings = staticStringBindings(source, repositoryRoot);
8312
8432
  const presets = staticArrayField(source, "presets");
8313
8433
  const classicDocs = presets && [...presets.matchAll(/["']?docs["']?\s*:\s*/g)].map((match) => matchingObjectLiteral(presets, (match.index ?? 0) + match[0].length)).find((object3) => Boolean(object3));
8314
- const docsRouteBasePath = classicDocs && staticStringField(classicDocs, "routeBasePath") || "docs";
8434
+ const docsRouteBasePath = classicDocs && staticStringField(classicDocs, "routeBasePath", bindings) || "docs";
8315
8435
  const themeStart = propertyStart(source, "themeConfig");
8316
8436
  const theme = themeStart < 0 ? null : matchingObjectLiteral(source, themeStart);
8317
8437
  const colorModeStart = theme ? propertyStart(theme, "colorMode") : -1;
@@ -8354,21 +8474,29 @@ function readDocusaurusSiteSettings(repositoryRoot) {
8354
8474
  const announcement = announcementStart < 0 ? null : matchingObjectLiteral(theme, announcementStart);
8355
8475
  const announcementContent = announcement && staticStringField(announcement, "content") || announcement?.slice(propertyStart(announcement, "content")).match(/^`([^`]+)`/)?.[1];
8356
8476
  const bannerContent = announcementContent ? announcementMarkdown(announcementContent) : "";
8477
+ const name = staticStringField(source, "title", bindings);
8478
+ const description = staticStringField(source, "tagline", bindings);
8479
+ const navbarTitle = navbar ? staticStringField(navbar, "title", bindings) : void 0;
8480
+ const unresolvedIdentity = [];
8481
+ if (!name && propertyStart(source, "title") >= 0) unresolvedIdentity.push("title");
8482
+ if (!description && propertyStart(source, "tagline") >= 0) unresolvedIdentity.push("tagline");
8483
+ if (!navbarTitle && navbar && propertyStart(navbar, "title") >= 0) unresolvedIdentity.push("navbarTitle");
8357
8484
  return {
8358
8485
  ...bannerContent ? { banner: { content: bannerContent, dismissible: !/isCloseable\s*:\s*false/.test(announcement), ...staticStringField(announcement, "id") ? { id: staticStringField(announcement, "id") } : {} } } : {},
8359
- name: staticStringField(source, "title"),
8360
- description: staticStringField(source, "tagline"),
8361
- ...navbar && staticStringField(navbar, "title") ? { navbarTitle: staticStringField(navbar, "title") } : {},
8486
+ ...name ? { name } : {},
8487
+ ...description ? { description } : {},
8488
+ ...navbarTitle ? { navbarTitle } : {},
8489
+ ...unresolvedIdentity.length > 0 ? { unresolvedIdentity } : {},
8362
8490
  defaultColorMode,
8363
8491
  docsRouteBasePath,
8364
- ...logo && staticStringField(logo, "src") ? {
8492
+ ...logo && staticStringField(logo, "src", bindings) ? {
8365
8493
  logo: {
8366
- light: staticStringField(logo, "src"),
8367
- ...staticStringField(logo, "srcDark") ? { dark: staticStringField(logo, "srcDark") } : {},
8368
- showTitle: Boolean(navbar && staticStringField(navbar, "title"))
8494
+ light: staticStringField(logo, "src", bindings),
8495
+ ...staticStringField(logo, "srcDark", bindings) ? { dark: staticStringField(logo, "srcDark", bindings) } : {},
8496
+ showTitle: Boolean(navbarTitle)
8369
8497
  }
8370
8498
  } : {},
8371
- ...staticStringField(source, "favicon") ? { favicon: staticStringField(source, "favicon") } : {},
8499
+ ...staticStringField(source, "favicon", bindings) ? { favicon: staticStringField(source, "favicon", bindings) } : {},
8372
8500
  navbarLinks,
8373
8501
  footerLinks,
8374
8502
  ...copyright ? { copyright } : {}
@@ -15838,6 +15966,46 @@ function componentSourceIdentity(sourceUrl, repositoryDir, siteRoot, namespace)
15838
15966
  const docsRoot = relative6(repositoryDir, siteRoot).replace(/\\/g, "/");
15839
15967
  return JSON.stringify(namespace ? [repository, docsRoot, namespace] : [repository, docsRoot]);
15840
15968
  }
15969
+ function sourcePackageName(repositoryDir) {
15970
+ try {
15971
+ const path = withinRealRoot(resolveWithin(repositoryDir, "package.json"), repositoryDir);
15972
+ const metadata = lstatSync6(path);
15973
+ if (!metadata.isFile() || metadata.size > MAX_PAGE_BYTES) return void 0;
15974
+ const parsed = JSON.parse(readFileSync6(path, "utf8"));
15975
+ if (typeof parsed.name !== "string") return void 0;
15976
+ return parsed.name.split("/").pop()?.trim() || void 0;
15977
+ } catch {
15978
+ return void 0;
15979
+ }
15980
+ }
15981
+ function docusaurusProjectName(settings, repositoryDir, sourceUrl) {
15982
+ const configured = settings.navbarTitle ?? settings.name;
15983
+ if (configured) return { name: configured };
15984
+ const packageName = sourcePackageName(repositoryDir);
15985
+ if (packageName) return { name: packageName, origin: "the source package.json name" };
15986
+ const sourceName = (() => {
15987
+ try {
15988
+ const segment = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop();
15989
+ return segment ? decodeURIComponent(segment).replace(/\.git$/i, "") : void 0;
15990
+ } catch {
15991
+ return void 0;
15992
+ }
15993
+ })();
15994
+ if (sourceName) return { name: sourceName, origin: "the source repository name" };
15995
+ const sourceHost = (() => {
15996
+ try {
15997
+ return new URL(sourceUrl).hostname || void 0;
15998
+ } catch {
15999
+ return void 0;
16000
+ }
16001
+ })();
16002
+ return sourceHost ? { name: sourceHost, origin: "the source host" } : void 0;
16003
+ }
16004
+ var DOCUSAURUS_IDENTITY_LABELS = {
16005
+ title: "site title",
16006
+ tagline: "site tagline",
16007
+ navbarTitle: "navbar title"
16008
+ };
15841
16009
  function migrateRepository(options) {
15842
16010
  const repositoryDir = options.repositoryDir;
15843
16011
  const platform = options.platform ?? detectRepositoryPlatform(repositoryDir, options.docsDir);
@@ -17506,7 +17674,16 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
17506
17674
  const isTopLevelDocusaurus = platform === "docusaurus" && docusaurusProjectRoot && !options.docusaurusSkipRedirects;
17507
17675
  const docusaurusSettings = isTopLevelDocusaurus ? readDocusaurusSiteSettings(docusaurusProjectRoot) : void 0;
17508
17676
  const presentation = docusaurusSettings ? readDocusaurusPresentation(docusaurusProjectRoot) : void 0;
17677
+ const docusaurusIdentity = docusaurusSettings ? docusaurusProjectName(docusaurusSettings, repositoryDir, options.sourceUrl) : void 0;
17509
17678
  if (docusaurusSettings) {
17679
+ for (const field of docusaurusSettings.unresolvedIdentity ?? []) {
17680
+ const namesTheProject = field === "title" || field === "navbarTitle";
17681
+ const fallback = namesTheProject && docusaurusIdentity?.origin ? ` The project name was taken from ${docusaurusIdentity.origin}.` : "";
17682
+ warnings.push({
17683
+ code: "unsupported-config",
17684
+ message: `The Docusaurus ${DOCUSAURUS_IDENTITY_LABELS[field]} could not be read without running the config and was left out of the migration.${fallback} Use a string literal, or plain data in an imported module, to import it.`
17685
+ });
17686
+ }
17510
17687
  if (presentation) {
17511
17688
  assets.push({ path: "_thally/source-theme.css", content: Buffer.from(presentation.css) });
17512
17689
  docsConfig = { ...docsConfig, stylesheets: [...docsConfig.stylesheets ?? [], "/_thally/source-theme.css"], ...presentation.headingFont ? { fonts: { ...docsConfig.fonts, heading: { family: presentation.headingFont, weight: ["400", "500", "600", "700"] } } } : {} };
@@ -17753,9 +17930,9 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
17753
17930
  ...typeof fernRawConfig.title === "string" ? { name: fernRawConfig.title } : {},
17754
17931
  ...themeColors ? { colors: themeColors } : {}
17755
17932
  }
17756
- } : docusaurusSettings && (docusaurusSettings.name || docusaurusSettings.description || themeColors) ? {
17933
+ } : docusaurusSettings && (docusaurusIdentity?.name || docusaurusSettings.description || themeColors) ? {
17757
17934
  site: {
17758
- ...docusaurusSettings.navbarTitle || docusaurusSettings.name ? { name: docusaurusSettings.navbarTitle ?? docusaurusSettings.name } : {},
17935
+ ...docusaurusIdentity?.name ? { name: docusaurusIdentity.name } : {},
17759
17936
  ...docusaurusSettings.description ? { description: docusaurusSettings.description } : {},
17760
17937
  ...themeColors ? { colors: themeColors } : {}
17761
17938
  }