@thallylabs/migrate 0.2.23 → 0.2.25
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/README.md +74 -2
- package/dist/index.d.ts +86 -9
- package/dist/index.js +10486 -9250
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -171,6 +171,54 @@ from Fern MDX pages (`../../components/...`, resolved against the Fern
|
|
|
171
171
|
project root) are migrated the same way Mintlify and Docusaurus components
|
|
172
172
|
are — see "Mintlify compatibility" below.
|
|
173
173
|
|
|
174
|
+
## Mintlify `sourceRef` repositories
|
|
175
|
+
|
|
176
|
+
A Mintlify navigation node `{"sourceRef": "owner/repo"}` mounts the docs of another
|
|
177
|
+
repository. Mintlify does not document where that mount lives, so it cannot be
|
|
178
|
+
derived from `docs.json`; supply it with a repeatable flag:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
create-thally-docs migrate https://github.com/OpenRouterTeam/docs my-docs \
|
|
182
|
+
--source-ref OpenRouterTeam/typescript-sdk=client-sdks/typescript
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Without a mapping the node is skipped with a warning that names the flag.
|
|
186
|
+
|
|
187
|
+
- The repository must be on github.com. Its docs root is the directory holding a
|
|
188
|
+
Mintlify `docs.json` (`docs/` first, then the repository root); without one the
|
|
189
|
+
mapping is skipped with a warning.
|
|
190
|
+
- Every `.md`/`.mdx` file under that root is imported (orphans included) through the
|
|
191
|
+
same pipeline as the main site, under `<mount-path>/...`. Assets are copied under
|
|
192
|
+
`public/<mount-path>/...`. The node is replaced by the referenced `docs.json`
|
|
193
|
+
navigation with page paths prefixed by the mount path; tabs become groups, and the
|
|
194
|
+
parent group keeps its label and icon.
|
|
195
|
+
- Root-absolute links inside those pages (`/models/x`, `/images/x.png`) are prefixed
|
|
196
|
+
with the mount path (sub-site semantics: Mintlify's behavior here is not
|
|
197
|
+
documented, so this is an assumption). Relative links work as-is.
|
|
198
|
+
- Pages, navigation, assets and the referenced repository's custom components are
|
|
199
|
+
imported. Its components are bundled with the main site's under `src/mdx/migrated/`
|
|
200
|
+
and registered in `src/mdx/custom-components.tsx`; their content-hashed names cannot
|
|
201
|
+
clash with the main site's. Branding, colors, redirects, OpenAPI specs and
|
|
202
|
+
access-restricted pages of the referenced repository are ignored (one warning says
|
|
203
|
+
so). Access-restricted pages and the files only they use are withheld from the site
|
|
204
|
+
and are not saved anywhere (the main site saves its own under `migration-quarantine/`;
|
|
205
|
+
a referenced repository's are discarded), so recover them from that repository if
|
|
206
|
+
needed.
|
|
207
|
+
- Safety limits per referenced repository, fixed constants: 5,000 files and 50 MB under
|
|
208
|
+
the docs root. Over a limit the whole repository is refused, never imported
|
|
209
|
+
partially. Symlinks and dot-directories are removed before import, and a docs
|
|
210
|
+
directory that resolves outside the clone is refused. A repository GitHub reports as
|
|
211
|
+
larger than 200 MB is refused before cloning (if the GitHub API is unreachable the
|
|
212
|
+
clone proceeds and the limits above still apply), its submodules are not fetched,
|
|
213
|
+
and a `docs.json` over 1 MB is ignored. `repo` must match `owner/repo`; the mount
|
|
214
|
+
path must be a relative lowercase slug path (no `..`, no leading slash), must not
|
|
215
|
+
start with a name the site itself uses (`api`, `admin`, `_next`, `public`,
|
|
216
|
+
`llms.txt`, `sitemap.xml`, ...), must not collide with an existing page or directory
|
|
217
|
+
of the main site, and mappings must not overlap.
|
|
218
|
+
- A mapping that matches no `sourceRef` in the navigation is reported and imports
|
|
219
|
+
nothing. `migration-report.json` lists each imported repository with its page count
|
|
220
|
+
under `sourceRefs`.
|
|
221
|
+
|
|
174
222
|
## Mintlify compatibility
|
|
175
223
|
|
|
176
224
|
Repository imports preserve named/default local JSX and TSX components and
|
|
@@ -214,8 +262,8 @@ same-length nested fence is widened so the inner fence no longer closes it, and
|
|
|
214
262
|
a bare placeholder tag in prose (`<Feature> requires a plan`) that would stop
|
|
215
263
|
the page compiling is escaped as text rather than losing the page.
|
|
216
264
|
The Mintlify `search-bar-entry` click trigger is mapped to Thally's search
|
|
217
|
-
shortcut. Markdown mixed inside interactive JSX
|
|
218
|
-
|
|
265
|
+
shortcut. Markdown mixed inside interactive JSX and computed imports are
|
|
266
|
+
reported for manual review; unsupported source is
|
|
219
267
|
preserved, not replaced with empty stubs. An external package's JSX usage is
|
|
220
268
|
dropped and replaced with a safe fallback (with a warning); if that package's
|
|
221
269
|
binding is instead referenced outside JSX (an expression, a prop, or an
|
|
@@ -237,6 +285,30 @@ Next) and copied into any extracted client module. A source site's own
|
|
|
237
285
|
passes a page-authored function into a client component needs the client
|
|
238
286
|
wrapper described above; unsupported callback shapes retain their content
|
|
239
287
|
with a warning. An unconfirmed target is warned for review.
|
|
288
|
+
Other relative imports of a copied file are handled the same way: a namespace
|
|
289
|
+
import (`import * as X from './comp.jsx'`) and a dynamic `import('./comp.jsx')`
|
|
290
|
+
point at the copied module, and a relative side-effect import
|
|
291
|
+
(`import './styles.css'`) is removed with a warning, like one from an npm
|
|
292
|
+
package. A page is excluded only when the relative target is not copied (for
|
|
293
|
+
example a Next.js `./metadata` module, or an `export ... from` re-export), with
|
|
294
|
+
a single warning naming it. An MDX expression that names an identifier the page
|
|
295
|
+
never defines (`{missing}`) is removed with a warning, since it would throw at
|
|
296
|
+
render; define the name or escape the braces as `\{ \}` to keep the text.
|
|
297
|
+
A value import from a local snippet (`import { FEE, fee } from
|
|
298
|
+
'/snippets/c.mdx'`) is inlined when each name is a static value (string,
|
|
299
|
+
number, boolean, `null`, or an object/array of those) or a self-contained
|
|
300
|
+
function. Inlined functions may only use pure built-ins (`Math`, `JSON`,
|
|
301
|
+
`String`, `Number`, `Boolean`, `Array`, `Date`, `Intl`, `parseInt`,
|
|
302
|
+
`parseFloat`, `isNaN`, `isFinite`, `encodeURIComponent` and
|
|
303
|
+
`decodeURIComponent`) and may not reach
|
|
304
|
+
`Function`, constructors, `globalThis`, `fetch` or other globals; anything else
|
|
305
|
+
is not inlined. A name the snippet does not export, or one that cannot be
|
|
306
|
+
inlined, is bound to `undefined` (as Mintlify does for a missing export) with a
|
|
307
|
+
warning, while the other names of the same import are still inlined. A snippet
|
|
308
|
+
import that resolves outside the repository through a symlink is refused, and a
|
|
309
|
+
snippet whose frontmatter cannot be read is not inlined (left as a comment with
|
|
310
|
+
a warning). Mintlify `sourceRef` navigation nodes have no Thally equivalent and
|
|
311
|
+
are reported rather than migrated.
|
|
240
312
|
File paths cannot escape the repository checkout; symlinks and oversized
|
|
241
313
|
graphs are rejected. This is compatibility analysis, **not a code sandbox**:
|
|
242
314
|
imported JavaScript executes when the developer builds or runs the resulting
|
package/dist/index.d.ts
CHANGED
|
@@ -81,6 +81,8 @@ interface MigrationDocsConfig {
|
|
|
81
81
|
};
|
|
82
82
|
/** Local site-authored CSS projected from a source docs site, served from public/. */
|
|
83
83
|
stylesheets?: Array<string>;
|
|
84
|
+
/** `false` hides the breadcrumb trail; Mintlify pages show only a group eyebrow. */
|
|
85
|
+
breadcrumbs?: boolean;
|
|
84
86
|
tabs: Array<MigrationNavigationTab>;
|
|
85
87
|
navigation?: {
|
|
86
88
|
/** How sibling documentation collections are presented to readers. */
|
|
@@ -173,6 +175,8 @@ interface MigrationDocsConfig {
|
|
|
173
175
|
playground?: {
|
|
174
176
|
display: 'interactive' | 'simple' | 'none';
|
|
175
177
|
};
|
|
178
|
+
/** `false` hides the visible "OpenAPI specification" line; Mintlify does not show it. */
|
|
179
|
+
specLink?: boolean;
|
|
176
180
|
};
|
|
177
181
|
/** Third-party analytics in Mintlify's `integrations` shape; validated again by the renderer. */
|
|
178
182
|
integrations?: {
|
|
@@ -255,6 +259,18 @@ interface MigrationWarning {
|
|
|
255
259
|
message: string;
|
|
256
260
|
source?: string;
|
|
257
261
|
}
|
|
262
|
+
/** A repository-configured remote OpenAPI spec, downloaded after the bundle is built. */
|
|
263
|
+
interface RemoteApiSpec {
|
|
264
|
+
url: string;
|
|
265
|
+
tabLabel?: string;
|
|
266
|
+
parentTab?: string;
|
|
267
|
+
icon?: string;
|
|
268
|
+
hidden?: boolean;
|
|
269
|
+
/** Operation keys (`get /x`) only access-restricted pages document; marked `x-excluded` after download. */
|
|
270
|
+
withheldOperations?: Array<string>;
|
|
271
|
+
/** Operation keys published pages or docs.json also name; keeps a shared `$ref` path item public. */
|
|
272
|
+
keptOperations?: Array<string>;
|
|
273
|
+
}
|
|
258
274
|
interface MigrationBundle {
|
|
259
275
|
sourceUrl: string;
|
|
260
276
|
sourceKind: 'repository' | 'url';
|
|
@@ -262,19 +278,19 @@ interface MigrationBundle {
|
|
|
262
278
|
pages: Array<MigrationPage>;
|
|
263
279
|
assets: Array<MigrationAsset>;
|
|
264
280
|
/** Repository-configured remote specs awaiting a bounded network fetch by the host. */
|
|
265
|
-
remoteApiSpecs?: Array<
|
|
266
|
-
url: string;
|
|
267
|
-
tabLabel?: string;
|
|
268
|
-
parentTab?: string;
|
|
269
|
-
icon?: string;
|
|
270
|
-
hidden?: boolean;
|
|
271
|
-
}>;
|
|
281
|
+
remoteApiSpecs?: Array<RemoteApiSpec>;
|
|
272
282
|
/** Customer-owned component source and registry; paths are repository-relative. */
|
|
273
283
|
componentFiles?: Array<RenderedMigrationFile>;
|
|
274
284
|
/** Access-restricted source pages, written outside every published path. */
|
|
275
285
|
quarantinedFiles?: Array<RenderedMigrationFile>;
|
|
276
286
|
/** Access-restricted pages the file limit dropped: neither published nor saved in quarantinedFiles. */
|
|
277
287
|
droppedGatedPages?: number;
|
|
288
|
+
/** Mintlify `sourceRef` repositories imported under a mount path, with their page counts. */
|
|
289
|
+
sourceRefs?: Array<{
|
|
290
|
+
repo: string;
|
|
291
|
+
mountPath: string;
|
|
292
|
+
pages: number;
|
|
293
|
+
}>;
|
|
278
294
|
docsConfig: MigrationDocsConfig;
|
|
279
295
|
site?: {
|
|
280
296
|
name?: string;
|
|
@@ -318,6 +334,51 @@ interface RenderedMigrationFile {
|
|
|
318
334
|
content: string | Uint8Array;
|
|
319
335
|
}
|
|
320
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Mintlify `sourceRef` navigation nodes mount the docs of another repository
|
|
339
|
+
* (`{"sourceRef": "owner/repo"}`). The mount path is not derivable from any
|
|
340
|
+
* docs.json, so the caller supplies it with `--source-ref owner/repo=<path>`.
|
|
341
|
+
* The referenced repository is untrusted remote content: it is validated,
|
|
342
|
+
* size-capped, stripped of symlinks and dot-directories, then run through the
|
|
343
|
+
* same repository pipeline as the main site and prefixed with its mount path.
|
|
344
|
+
*/
|
|
345
|
+
|
|
346
|
+
/** Per referenced repository: files and bytes under its docs root. Constants on purpose, not configurable. */
|
|
347
|
+
declare const SOURCE_REF_MAX_FILES = 5000;
|
|
348
|
+
declare const SOURCE_REF_MAX_BYTES = 50000000;
|
|
349
|
+
/** GitHub reports repository size in KB; a larger repository is refused before it is cloned. */
|
|
350
|
+
declare const SOURCE_REF_MAX_REPOSITORY_KB = 200000;
|
|
351
|
+
interface SourceRefMapping {
|
|
352
|
+
/** `owner/repo`, exactly as written in the source navigation. */
|
|
353
|
+
repo: string;
|
|
354
|
+
/** Relative slug path the referenced docs are mounted at, e.g. `client-sdks/typescript`. */
|
|
355
|
+
mountPath: string;
|
|
356
|
+
}
|
|
357
|
+
interface SourceRefImport extends SourceRefMapping {
|
|
358
|
+
pages: Array<MigrationPage>;
|
|
359
|
+
assets: Array<MigrationAsset>;
|
|
360
|
+
/** Navigation entries with every page id already prefixed by the mount path. */
|
|
361
|
+
navigation: Array<string | MigrationNavigationGroup>;
|
|
362
|
+
/** Custom component files (and registry) the mounted pages' `<MigratedXXXX/>` tags need; merged into the main bundle. */
|
|
363
|
+
componentFiles?: Array<RenderedMigrationFile>;
|
|
364
|
+
/** Why the import is empty (or partial), plus forwarded pipeline warnings. */
|
|
365
|
+
warnings: Array<MigrationWarning>;
|
|
366
|
+
}
|
|
367
|
+
/** Parse repeated `owner/repo=mount/path` values; throws on anything unsafe. */
|
|
368
|
+
declare function parseSourceRefFlags(values: ReadonlyArray<string>): Array<SourceRefMapping>;
|
|
369
|
+
/**
|
|
370
|
+
* Why a referenced repository is too large to clone, or null when it is small
|
|
371
|
+
* enough or its size is unknown (GitHub API unreachable, rate-limited or
|
|
372
|
+
* private): an unknown size proceeds, and the post-clone caps still apply.
|
|
373
|
+
*/
|
|
374
|
+
declare function sourceRefOversizeReason(repo: string, fetcher?: MigrationFetcher): Promise<string | null>;
|
|
375
|
+
/**
|
|
376
|
+
* Import one cloned referenced repository as a sub-site under its mount path.
|
|
377
|
+
* `repositoryDir` is a disposable clone: symlinks and dot-directories under
|
|
378
|
+
* its docs root are deleted.
|
|
379
|
+
*/
|
|
380
|
+
declare function importSourceRef(mapping: SourceRefMapping, repositoryDir: string): SourceRefImport;
|
|
381
|
+
|
|
321
382
|
/**
|
|
322
383
|
* Repository adapter for the shared migration engine. Traversal is bounded;
|
|
323
384
|
* `scanFiles` follows a symbolic link only when its resolved real path stays
|
|
@@ -340,6 +401,8 @@ interface RepositoryMigrationOptions {
|
|
|
340
401
|
sourceUrl: string;
|
|
341
402
|
docsDir?: string;
|
|
342
403
|
platform?: MigrationPlatform;
|
|
404
|
+
/** @internal Mount path of a sourceRef import; keeps its component files separate from any other copy of the same source. */
|
|
405
|
+
componentNamespace?: string;
|
|
343
406
|
/** @internal Prefix used by additional Docusaurus docs-plugin instances. */
|
|
344
407
|
docusaurusRoutePrefix?: string;
|
|
345
408
|
/** @internal Prevent recursive discovery while importing one plugin root. */
|
|
@@ -354,6 +417,8 @@ interface RepositoryMigrationOptions {
|
|
|
354
417
|
maxSourceFiles?: number;
|
|
355
418
|
/** @internal Redirects are global config, read once, not per plugin instance. */
|
|
356
419
|
docusaurusSkipRedirects?: boolean;
|
|
420
|
+
/** Mintlify `sourceRef` repositories already fetched and prepared by `importSourceRef`. */
|
|
421
|
+
sourceRefs?: ReadonlyArray<SourceRefImport>;
|
|
357
422
|
}
|
|
358
423
|
/** Parse and validate a public GitHub repository URL. */
|
|
359
424
|
declare function parseGitHubRepositoryUrl(rawUrl: string): GitHubRepositorySource;
|
|
@@ -371,7 +436,11 @@ declare function gitmodulePaths(targetDir: string): Array<string>;
|
|
|
371
436
|
* submodule-fetch-failure warning (this function otherwise returns exactly
|
|
372
437
|
* as before, so existing callers are unaffected).
|
|
373
438
|
*/
|
|
374
|
-
declare function cloneGitHubRepository(source: GitHubRepositorySource, targetDir: string, warnings?: Array<MigrationWarning
|
|
439
|
+
declare function cloneGitHubRepository(source: GitHubRepositorySource, targetDir: string, warnings?: Array<MigrationWarning>,
|
|
440
|
+
/** Untrusted referenced repositories: never follow their `.gitmodules` to further remotes. */
|
|
441
|
+
options?: {
|
|
442
|
+
skipSubmodules?: boolean;
|
|
443
|
+
}): Promise<void>;
|
|
375
444
|
/** Detect a supported repository docs platform from unambiguous config files. */
|
|
376
445
|
declare function detectRepositoryPlatform(repositoryDir: string, docsDir?: string): MigrationPlatform;
|
|
377
446
|
/** Pick the first conventional content root containing Markdown. */
|
|
@@ -400,11 +469,19 @@ interface MintlifyNavigationResult {
|
|
|
400
469
|
pageReferences: Array<MintlifyPageReference>;
|
|
401
470
|
/** Pages under a restricted container; withheld from `docsConfig` and `pageReferences`. */
|
|
402
471
|
gatedReferences: Array<MintlifyGatedReference>;
|
|
472
|
+
/** `sourceRef` mounts under a restricted container; never resolved, so nothing of theirs is imported. */
|
|
473
|
+
gatedSourceRefs: Array<string>;
|
|
403
474
|
warnings: Array<MigrationWarning>;
|
|
404
475
|
}
|
|
405
476
|
interface MintlifyProjectionOptions {
|
|
406
477
|
/** Public URL migrations may expose page hrefs including the docs mount path. */
|
|
407
478
|
pathPrefix?: string;
|
|
479
|
+
/**
|
|
480
|
+
* Resolves a `sourceRef` repository (`owner/repo`) to the navigation entries
|
|
481
|
+
* of its imported docs, already prefixed with their mount path. Returns null
|
|
482
|
+
* when the repository was not mapped with `--source-ref`.
|
|
483
|
+
*/
|
|
484
|
+
resolveSourceRef?: (repo: string) => Array<string | MigrationNavigationGroup> | null;
|
|
408
485
|
}
|
|
409
486
|
/** Preserve Mintlify's implicit `/section` route for section landing pages. */
|
|
410
487
|
declare function addMintlifyDirectoryRedirects(config: MigrationDocsConfig, pages: Array<MigrationPage>): MigrationDocsConfig;
|
|
@@ -583,4 +660,4 @@ declare function migrateUrl(options: UrlMigrationOptions): Promise<MigrationBund
|
|
|
583
660
|
*/
|
|
584
661
|
declare function hydrateRemoteApiSpecs(bundle: MigrationBundle, fetcher?: MigrationFetcher): Promise<MigrationBundle>;
|
|
585
662
|
|
|
586
|
-
export { type GitHubRepositorySource, type MigrationAsset, type MigrationBundle, type MigrationDocsConfig, type MigrationFetchRequest, type MigrationFetchResponse, type MigrationFetcher, type MigrationNavigationGroup, type MigrationNavigationTab, type MigrationPage, type MigrationPlatform, type MigrationWarning, type RenderedMigrationFile, type RepositoryMigrationOptions, type UrlMigrationOptions, addMintlifyDirectoryRedirects, buildNavigationFromPages, cloneGitHubRepository, defaultMigrationFetcher, detectRepositoryDocsDir, detectRepositoryPlatform, gitmodulePaths, hydrateRemoteApiSpecs, mergeMigrationConfig, migrateRepository, migrateUrl, normalizeMdx, parseGitHubRepositoryUrl, parseMarkdownPage, projectFernNavigation, projectMintlifyIntegrations, projectMintlifyNavigation, pruneMissingNavigationPages, readFernConfig, readMintlifyConfig, renderMigrationFiles, validateIntegrations, validateMigrationUrl };
|
|
663
|
+
export { type GitHubRepositorySource, type MigrationAsset, type MigrationBundle, type MigrationDocsConfig, type MigrationFetchRequest, type MigrationFetchResponse, type MigrationFetcher, type MigrationNavigationGroup, type MigrationNavigationTab, type MigrationPage, type MigrationPlatform, type MigrationWarning, type RenderedMigrationFile, type RepositoryMigrationOptions, SOURCE_REF_MAX_BYTES, SOURCE_REF_MAX_FILES, SOURCE_REF_MAX_REPOSITORY_KB, type SourceRefImport, type SourceRefMapping, type UrlMigrationOptions, addMintlifyDirectoryRedirects, buildNavigationFromPages, cloneGitHubRepository, defaultMigrationFetcher, detectRepositoryDocsDir, detectRepositoryPlatform, gitmodulePaths, hydrateRemoteApiSpecs, importSourceRef, mergeMigrationConfig, migrateRepository, migrateUrl, normalizeMdx, parseGitHubRepositoryUrl, parseMarkdownPage, parseSourceRefFlags, projectFernNavigation, projectMintlifyIntegrations, projectMintlifyNavigation, pruneMissingNavigationPages, readFernConfig, readMintlifyConfig, renderMigrationFiles, sourceRefOversizeReason, validateIntegrations, validateMigrationUrl };
|