@wrikka/create-docs 0.1.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/README.md +137 -0
- package/bin/cli.js +408 -0
- package/dist/index.cjs +20 -0
- package/dist/index.d.cts +475 -0
- package/dist/index.d.ts +475 -0
- package/dist/index.js +20 -0
- package/docs/_dir.yml +2 -0
- package/docs/config.md +75 -0
- package/docs/data-sources.md +88 -0
- package/docs/deploy.md +38 -0
- package/docs/features.md +51 -0
- package/docs/getting-started.md +42 -0
- package/docs/index.md +34 -0
- package/docs/markdown.md +154 -0
- package/docs/theming.md +53 -0
- package/package.json +142 -0
- package/scripts/generate-docs-index.ts +111 -0
- package/scripts/github-pull.ts +124 -0
- package/src/adapters/config/index.ts +1 -0
- package/src/adapters/config/node-config-loader.ts +36 -0
- package/src/adapters/fs/fs-docs-loader.ts +31 -0
- package/src/adapters/fs/index.ts +12 -0
- package/src/adapters/fs/memory-fs.ts +60 -0
- package/src/adapters/fs/node-fs.ts +116 -0
- package/src/adapters/git/index.ts +164 -0
- package/src/adapters/github/github-pull.ts +340 -0
- package/src/adapters/index.ts +6 -0
- package/src/adapters/velite.ts +112 -0
- package/src/adapters/vite/docs-watcher.ts +36 -0
- package/src/adapters/vite/index.ts +2 -0
- package/src/adapters/vite/polling-watcher.ts +89 -0
- package/src/code-block-enhancements/index.ts +3 -0
- package/src/config/index.ts +15 -0
- package/src/content/index.ts +11 -0
- package/src/content-validation/index.ts +5 -0
- package/src/index.ts +174 -0
- package/src/live-editor/index.ts +7 -0
- package/src/modules/analytics/application/plausible-adapter.ts +103 -0
- package/src/modules/analytics/application/umami-adapter.ts +109 -0
- package/src/modules/analytics/domain/events/index.ts +37 -0
- package/src/modules/analytics/domain/models/index.ts +35 -0
- package/src/modules/analytics/domain/operations/analytics-operations.ts +67 -0
- package/src/modules/analytics/domain/validators/index.ts +50 -0
- package/src/modules/analytics/index.ts +9 -0
- package/src/modules/analytics/ports/analytics-port.ts +17 -0
- package/src/modules/analytics/types/analytics.ts +16 -0
- package/src/modules/api-docs/application/type-docs-adapter.ts +34 -0
- package/src/modules/api-docs/domain/events/index.ts +42 -0
- package/src/modules/api-docs/domain/models/index.ts +40 -0
- package/src/modules/api-docs/domain/operations/api-docs-operations.ts +59 -0
- package/src/modules/api-docs/domain/validators/index.ts +56 -0
- package/src/modules/api-docs/index.ts +8 -0
- package/src/modules/api-docs/ports/api-docs-port.ts +21 -0
- package/src/modules/api-docs/types/api-docs.ts +15 -0
- package/src/modules/api-reference/openapi.ts +166 -0
- package/src/modules/api-reference/orpc.ts +94 -0
- package/src/modules/code-block-enhancements/application/usecases/index.ts +39 -0
- package/src/modules/code-block-enhancements/domain/code-operations.ts +72 -0
- package/src/modules/code-block-enhancements/domain/events/index.ts +58 -0
- package/src/modules/code-block-enhancements/domain/index.ts +11 -0
- package/src/modules/code-block-enhancements/domain/models/index.ts +36 -0
- package/src/modules/code-block-enhancements/domain/validators/index.ts +50 -0
- package/src/modules/code-block-enhancements/index.ts +10 -0
- package/src/modules/code-block-enhancements/ports/index.ts +18 -0
- package/src/modules/code-block-enhancements/types/index.ts +37 -0
- package/src/modules/code-execution/application/sandbox-adapter.ts +44 -0
- package/src/modules/code-execution/domain/events/index.ts +58 -0
- package/src/modules/code-execution/domain/models/index.ts +33 -0
- package/src/modules/code-execution/domain/operations/execution-operations.ts +60 -0
- package/src/modules/code-execution/domain/validators/index.ts +50 -0
- package/src/modules/code-execution/index.ts +8 -0
- package/src/modules/code-execution/ports/execution-port.ts +15 -0
- package/src/modules/code-execution/types/execution.ts +15 -0
- package/src/modules/comments/application/giscus-adapter.ts +55 -0
- package/src/modules/comments/domain/events/index.ts +55 -0
- package/src/modules/comments/domain/models/index.ts +30 -0
- package/src/modules/comments/domain/operations/comment-operations.ts +46 -0
- package/src/modules/comments/domain/validators/index.ts +50 -0
- package/src/modules/comments/index.ts +8 -0
- package/src/modules/comments/ports/comment-port.ts +18 -0
- package/src/modules/comments/types/comments.ts +19 -0
- package/src/modules/config/application/usecases/index.ts +1 -0
- package/src/modules/config/application/usecases/loadConfig.ts +38 -0
- package/src/modules/config/application/workflows/index.ts +1 -0
- package/src/modules/config/application/workflows/validateConfig.ts +14 -0
- package/src/modules/config/domain/events/index.ts +50 -0
- package/src/modules/config/domain/models/index.ts +9 -0
- package/src/modules/config/domain/operations/defaults.ts +74 -0
- package/src/modules/config/domain/operations/index.ts +2 -0
- package/src/modules/config/domain/operations/resolve.ts +40 -0
- package/src/modules/config/domain/validators/index.ts +152 -0
- package/src/modules/config/index.ts +23 -0
- package/src/modules/config/ports/index.ts +15 -0
- package/src/modules/config/types/index.ts +113 -0
- package/src/modules/config/types/public.ts +19 -0
- package/src/modules/content/application/cache/index.ts +6 -0
- package/src/modules/content/application/cache/parse-cache.ts +6 -0
- package/src/modules/content/application/cache/parseCache.ts +56 -0
- package/src/modules/content/application/usecases/index.ts +2 -0
- package/src/modules/content/application/usecases/load-doc-page.ts +1 -0
- package/src/modules/content/application/usecases/loadDocPage.ts +111 -0
- package/src/modules/content/application/usecases/scanDocsDir.ts +105 -0
- package/src/modules/content/application/workflows/index.ts +1 -0
- package/src/modules/content/application/workflows/processDocs.ts +51 -0
- package/src/modules/content/domain/events/index.ts +61 -0
- package/src/modules/content/domain/models/index.ts +13 -0
- package/src/modules/content/domain/operations/build-page.ts +146 -0
- package/src/modules/content/domain/operations/buildPage.ts +93 -0
- package/src/modules/content/domain/operations/index.ts +17 -0
- package/src/modules/content/domain/operations/parse.ts +241 -0
- package/src/modules/content/domain/validators/frontmatter.ts +82 -0
- package/src/modules/content/domain/validators/index.ts +6 -0
- package/src/modules/content/index.ts +27 -0
- package/src/modules/content/ports/index.ts +45 -0
- package/src/modules/content/ports/velite.ts +134 -0
- package/src/modules/content/types/index.ts +76 -0
- package/src/modules/content/types/public.ts +1 -0
- package/src/modules/content-linting/application/builtin-linting-adapter.ts +82 -0
- package/src/modules/content-linting/domain/events/index.ts +58 -0
- package/src/modules/content-linting/domain/models/index.ts +46 -0
- package/src/modules/content-linting/domain/operations/linting-operations.ts +82 -0
- package/src/modules/content-linting/domain/validators/index.ts +50 -0
- package/src/modules/content-linting/index.ts +8 -0
- package/src/modules/content-linting/ports/linting-port.ts +21 -0
- package/src/modules/content-linting/types/linting.ts +18 -0
- package/src/modules/content-validation/application/usecases/index.ts +18 -0
- package/src/modules/content-validation/domain/events/index.ts +7 -0
- package/src/modules/content-validation/domain/index.ts +16 -0
- package/src/modules/content-validation/domain/models/index.ts +33 -0
- package/src/modules/content-validation/domain/operations/index.ts +157 -0
- package/src/modules/content-validation/domain/types/index.ts +17 -0
- package/src/modules/content-validation/domain/validators/index.ts +8 -0
- package/src/modules/content-validation/index.ts +9 -0
- package/src/modules/content-validation/ports/index.ts +15 -0
- package/src/modules/content-validation/types/index.ts +5 -0
- package/src/modules/export/application/puppeteer-export-adapter.ts +63 -0
- package/src/modules/export/domain/events/index.ts +55 -0
- package/src/modules/export/domain/models/index.ts +38 -0
- package/src/modules/export/domain/operations/export-operations.ts +56 -0
- package/src/modules/export/domain/validators/index.ts +52 -0
- package/src/modules/export/index.ts +8 -0
- package/src/modules/export/ports/export-port.ts +15 -0
- package/src/modules/export/types/export.ts +15 -0
- package/src/modules/external-search/application/algolia-adapter.ts +182 -0
- package/src/modules/external-search/application/meilisearch-adapter.ts +161 -0
- package/src/modules/external-search/domain/events/index.ts +42 -0
- package/src/modules/external-search/domain/models/index.ts +42 -0
- package/src/modules/external-search/domain/operations/search-operations.ts +53 -0
- package/src/modules/external-search/domain/validators/index.ts +55 -0
- package/src/modules/external-search/index.ts +9 -0
- package/src/modules/external-search/ports/external-search-port.ts +23 -0
- package/src/modules/external-search/types/search.ts +19 -0
- package/src/modules/git-history/application/simple-git-adapter.ts +46 -0
- package/src/modules/git-history/domain/events/index.ts +34 -0
- package/src/modules/git-history/domain/models/index.ts +25 -0
- package/src/modules/git-history/domain/operations/git-history-operations.ts +56 -0
- package/src/modules/git-history/domain/validators/index.ts +52 -0
- package/src/modules/git-history/index.ts +8 -0
- package/src/modules/git-history/ports/git-history-port.ts +21 -0
- package/src/modules/git-history/types/git-history.ts +15 -0
- package/src/modules/i18n/application/fs-locale-loader.ts +39 -0
- package/src/modules/i18n/domain/events/index.ts +34 -0
- package/src/modules/i18n/domain/models/index.ts +34 -0
- package/src/modules/i18n/domain/operations/locale-operations.ts +74 -0
- package/src/modules/i18n/domain/validators/index.ts +52 -0
- package/src/modules/i18n/index.ts +8 -0
- package/src/modules/i18n/ports/locale-loader-port.ts +18 -0
- package/src/modules/i18n/types/locale.ts +17 -0
- package/src/modules/image-optimization/application/sharp-adapter.ts +58 -0
- package/src/modules/image-optimization/domain/events/index.ts +39 -0
- package/src/modules/image-optimization/domain/models/index.ts +27 -0
- package/src/modules/image-optimization/domain/operations/image-operations.ts +65 -0
- package/src/modules/image-optimization/domain/validators/index.ts +52 -0
- package/src/modules/image-optimization/index.ts +8 -0
- package/src/modules/image-optimization/ports/image-optimizer-port.ts +15 -0
- package/src/modules/image-optimization/types/image.ts +17 -0
- package/src/modules/live-editor/application/usecases/index.ts +60 -0
- package/src/modules/live-editor/domain/events/index.ts +37 -0
- package/src/modules/live-editor/domain/gitOperations.ts +110 -0
- package/src/modules/live-editor/domain/index.ts +15 -0
- package/src/modules/live-editor/domain/models/index.ts +21 -0
- package/src/modules/live-editor/domain/validators/index.ts +55 -0
- package/src/modules/live-editor/index.ts +14 -0
- package/src/modules/live-editor/ports/index.ts +49 -0
- package/src/modules/live-editor/types/index.ts +80 -0
- package/src/modules/live-preview/application/vite-preview-adapter.ts +20 -0
- package/src/modules/live-preview/domain/operations/preview-operations.ts +56 -0
- package/src/modules/live-preview/index.ts +8 -0
- package/src/modules/live-preview/ports/preview-port.ts +20 -0
- package/src/modules/live-preview/types/preview.ts +16 -0
- package/src/modules/mdx/application/mdx-js-adapter.ts +38 -0
- package/src/modules/mdx/domain/operations/parse-mdx.ts +43 -0
- package/src/modules/mdx/index.ts +8 -0
- package/src/modules/mdx/ports/mdx-parser-port.ts +15 -0
- package/src/modules/mdx/types/mdx.ts +14 -0
- package/src/modules/navigation/application/usecases/buildNav.ts +15 -0
- package/src/modules/navigation/application/usecases/buildSidebar.ts +45 -0
- package/src/modules/navigation/application/usecases/index.ts +2 -0
- package/src/modules/navigation/domain/events/index.ts +30 -0
- package/src/modules/navigation/domain/models/index.ts +7 -0
- package/src/modules/navigation/domain/operations/group.ts +79 -0
- package/src/modules/navigation/domain/operations/index.ts +10 -0
- package/src/modules/navigation/domain/operations/sort.ts +27 -0
- package/src/modules/navigation/domain/shared/utils/array.ts +39 -0
- package/src/modules/navigation/domain/validators/index.ts +88 -0
- package/src/modules/navigation/index.ts +15 -0
- package/src/modules/navigation/ports/index.ts +9 -0
- package/src/modules/navigation/types/index.ts +38 -0
- package/src/modules/navigation/types/public.ts +9 -0
- package/src/modules/openapi/application/swagger-parser-adapter.ts +178 -0
- package/src/modules/openapi/domain/operations/parse-openapi.ts +46 -0
- package/src/modules/openapi/index.ts +8 -0
- package/src/modules/openapi/ports/openapi-parser-port.ts +15 -0
- package/src/modules/openapi/types/openapi.ts +37 -0
- package/src/modules/plugin/application/usecases/build-virtual-modules.ts +53 -0
- package/src/modules/plugin/application/usecases/index.ts +1 -0
- package/src/modules/plugin/application/workflows/build-docs.ts +79 -0
- package/src/modules/plugin/application/workflows/index.ts +1 -0
- package/src/modules/plugin/domain/events/index.ts +62 -0
- package/src/modules/plugin/domain/models/index.ts +1 -0
- package/src/modules/plugin/domain/operations/build-virtual.ts +76 -0
- package/src/modules/plugin/domain/operations/index.ts +11 -0
- package/src/modules/plugin/domain/validators/index.ts +30 -0
- package/src/modules/plugin/index.ts +14 -0
- package/src/modules/plugin/ports/index.ts +21 -0
- package/src/modules/plugin/types/index.ts +27 -0
- package/src/modules/plugin/types/public.ts +1 -0
- package/src/modules/search/application/usecases/index.ts +1 -0
- package/src/modules/search/application/usecases/indexPages.ts +15 -0
- package/src/modules/search/domain/events/index.ts +32 -0
- package/src/modules/search/domain/models/index.ts +1 -0
- package/src/modules/search/domain/operations/build-index.ts +6 -0
- package/src/modules/search/domain/operations/buildIndex.ts +70 -0
- package/src/modules/search/domain/operations/index.ts +7 -0
- package/src/modules/search/domain/operations/query.ts +186 -0
- package/src/modules/search/domain/validators/index.ts +32 -0
- package/src/modules/search/index.ts +9 -0
- package/src/modules/search/types/index.ts +22 -0
- package/src/modules/search/types/public.ts +1 -0
- package/src/modules/search-analytics/application/local-storage-adapter.ts +68 -0
- package/src/modules/search-analytics/domain/operations/search-analytics-operations.ts +74 -0
- package/src/modules/search-analytics/index.ts +8 -0
- package/src/modules/search-analytics/ports/search-analytics-port.ts +20 -0
- package/src/modules/search-analytics/types/search-analytics.ts +16 -0
- package/src/modules/search-highlighting/application/dom-highlighting-adapter.ts +36 -0
- package/src/modules/search-highlighting/domain/operations/highlighting-operations.ts +72 -0
- package/src/modules/search-highlighting/index.ts +8 -0
- package/src/modules/search-highlighting/ports/highlighting-port.ts +14 -0
- package/src/modules/search-highlighting/types/highlighting.ts +15 -0
- package/src/modules/seo-optimization/application/usecases/index.ts +18 -0
- package/src/modules/seo-optimization/domain/index.ts +12 -0
- package/src/modules/seo-optimization/domain/seoOperations.ts +92 -0
- package/src/modules/seo-optimization/index.ts +8 -0
- package/src/modules/seo-optimization/ports/index.ts +18 -0
- package/src/modules/seo-optimization/types/index.ts +41 -0
- package/src/modules/theme/application/css-theme-adapter.ts +50 -0
- package/src/modules/theme/domain/operations/theme-operations.ts +68 -0
- package/src/modules/theme/index.ts +8 -0
- package/src/modules/theme/ports/theme-port.ts +8 -0
- package/src/modules/theme/types/theme.ts +12 -0
- package/src/modules/toc/application/markdown-toc-adapter.ts +106 -0
- package/src/modules/toc/domain/operations/toc-operations.ts +92 -0
- package/src/modules/toc/index.ts +8 -0
- package/src/modules/toc/ports/toc-port.ts +21 -0
- package/src/modules/toc/types/toc.ts +17 -0
- package/src/modules/toc-generator/application/usecases/index.ts +30 -0
- package/src/modules/toc-generator/domain/index.ts +12 -0
- package/src/modules/toc-generator/domain/tocOperations.ts +104 -0
- package/src/modules/toc-generator/index.ts +9 -0
- package/src/modules/toc-generator/ports/index.ts +20 -0
- package/src/modules/toc-generator/types/index.ts +50 -0
- package/src/modules/version-control/domain/events/index.ts +39 -0
- package/src/modules/version-control/domain/models/index.ts +25 -0
- package/src/modules/version-control/domain/validators/index.ts +50 -0
- package/src/modules/versioning/application/fs-version-loader.ts +44 -0
- package/src/modules/versioning/domain/operations/versioning-operations.ts +80 -0
- package/src/modules/versioning/index.ts +8 -0
- package/src/modules/versioning/ports/version-loader-port.ts +18 -0
- package/src/modules/versioning/types/versioning.ts +17 -0
- package/src/modules/workflow/domain/events/index.ts +55 -0
- package/src/modules/workflow/domain/models/index.ts +40 -0
- package/src/modules/workflow/domain/validators/index.ts +50 -0
- package/src/modules/yaml-parser/application/js-yaml-adapter.ts +34 -0
- package/src/modules/yaml-parser/domain/operations/parse-yaml.ts +58 -0
- package/src/modules/yaml-parser/index.ts +7 -0
- package/src/modules/yaml-parser/ports/yaml-parser-port.ts +18 -0
- package/src/navigation/index.ts +9 -0
- package/src/plugin/index.ts +4 -0
- package/src/presentation/index.ts +1 -0
- package/src/presentation/live-editor/index.ts +22 -0
- package/src/presentation/live-editor/live-editor-component.ts +219 -0
- package/src/presentation/live-editor/virtual-module.ts +16 -0
- package/src/presentation/solid/CodeBlock.tsx +120 -0
- package/src/presentation/solid/Toc.tsx +58 -0
- package/src/presentation/solid/index.ts +11 -0
- package/src/presentation/vite-plugin/docs-plugin.ts +212 -0
- package/src/presentation/vite-plugin/index.ts +9 -0
- package/src/presentation/vite-plugin/transform-markdown.ts +26 -0
- package/src/runtime/analytics.ts +59 -0
- package/src/runtime/api-diff.ts +115 -0
- package/src/runtime/app.tsx +32 -0
- package/src/runtime/components/AccentPicker.tsx +114 -0
- package/src/runtime/components/ApiPlayground.tsx +332 -0
- package/src/runtime/components/AskAiDialog.tsx +127 -0
- package/src/runtime/components/BackToTop.tsx +38 -0
- package/src/runtime/components/Banner.tsx +75 -0
- package/src/runtime/components/Breadcrumbs.tsx +42 -0
- package/src/runtime/components/CollectionDropdown.tsx +85 -0
- package/src/runtime/components/CustomizeDrawer.tsx +195 -0
- package/src/runtime/components/DocMarkdown.tsx +579 -0
- package/src/runtime/components/DocPrevNext.tsx +54 -0
- package/src/runtime/components/DocToc.tsx +147 -0
- package/src/runtime/components/DocsDropdown.tsx +184 -0
- package/src/runtime/components/Footer.tsx +52 -0
- package/src/runtime/components/GitHubAuth.tsx +82 -0
- package/src/runtime/components/GitHubStats.tsx +73 -0
- package/src/runtime/components/Head.tsx +225 -0
- package/src/runtime/components/LocaleDropdown.tsx +75 -0
- package/src/runtime/components/MobileBottomNav.tsx +111 -0
- package/src/runtime/components/NotFound.tsx +139 -0
- package/src/runtime/components/PageActions.tsx +144 -0
- package/src/runtime/components/RelatedDocs.tsx +50 -0
- package/src/runtime/components/ScrollProgress.tsx +32 -0
- package/src/runtime/components/SearchPalette.tsx +333 -0
- package/src/runtime/components/ShowcaseCard.tsx +87 -0
- package/src/runtime/components/SidebarNav.tsx +237 -0
- package/src/runtime/components/Skeleton.tsx +39 -0
- package/src/runtime/components/ThemeToggle.tsx +26 -0
- package/src/runtime/components/TopNav.tsx +270 -0
- package/src/runtime/components/VersionDropdown.tsx +189 -0
- package/src/runtime/components/markdown/components.ts +280 -0
- package/src/runtime/config.ts +225 -0
- package/src/runtime/content.ts +451 -0
- package/src/runtime/context.tsx +30 -0
- package/src/runtime/data.ts +93 -0
- package/src/runtime/github.ts +226 -0
- package/src/runtime/icons.ts +32 -0
- package/src/runtime/index.ts +153 -0
- package/src/runtime/layouts/DocsLayout.tsx +144 -0
- package/src/runtime/markdown-content.css +996 -0
- package/src/runtime/pages/AbTestPage.tsx +88 -0
- package/src/runtime/pages/AnalyticsPage.tsx +90 -0
- package/src/runtime/pages/ApiDiffPage.tsx +86 -0
- package/src/runtime/pages/ApiEndpointPage.tsx +248 -0
- package/src/runtime/pages/BuilderPage.tsx +150 -0
- package/src/runtime/pages/ChangelogPage.tsx +210 -0
- package/src/runtime/pages/CollectionPage.tsx +140 -0
- package/src/runtime/pages/CommunityPage.tsx +384 -0
- package/src/runtime/pages/CreatePage.tsx +448 -0
- package/src/runtime/pages/DocPage.tsx +193 -0
- package/src/runtime/pages/EditPage.tsx +201 -0
- package/src/runtime/pages/HomePage.tsx +187 -0
- package/src/runtime/pages/IssuesPage.tsx +140 -0
- package/src/runtime/pages/OAuthCallbackPage.tsx +80 -0
- package/src/runtime/pages/PluginsPage.tsx +249 -0
- package/src/runtime/pages/ShowcasePage.tsx +202 -0
- package/src/runtime/pwa.ts +39 -0
- package/src/runtime/router.tsx +192 -0
- package/src/runtime/seo.ts +192 -0
- package/src/runtime/theme.css +175 -0
- package/src/runtime/theme.ts +224 -0
- package/src/runtime/types.ts +217 -0
- package/src/search/index.ts +6 -0
- package/src/seo-optimization/index.ts +4 -0
- package/src/shared/constants/index.ts +26 -0
- package/src/shared/errors/index.ts +195 -0
- package/src/shared/index.ts +27 -0
- package/src/shared/types/brand.ts +14 -0
- package/src/shared/types/client.d.ts +45 -0
- package/src/shared/types/either.ts +38 -0
- package/src/shared/types/index.ts +42 -0
- package/src/shared/types/option.ts +52 -0
- package/src/shared/types/result.ts +81 -0
- package/src/shared/utils/array.ts +97 -0
- package/src/shared/utils/index.ts +46 -0
- package/src/shared/utils/object.ts +47 -0
- package/src/shared/utils/string.ts +74 -0
- package/src/toc-generator/index.ts +1 -0
- package/src/types/js-yaml.d.ts +42 -0
- package/src/worker.ts +462 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
mkdirSync,
|
|
3
|
+
readdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
statSync,
|
|
6
|
+
writeFileSync,
|
|
7
|
+
} from "node:fs";
|
|
8
|
+
import { join, relative } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { load as parseYaml } from "js-yaml";
|
|
11
|
+
|
|
12
|
+
const root = fileURLToPath(new URL("..", import.meta.url));
|
|
13
|
+
|
|
14
|
+
const collections = [
|
|
15
|
+
{ id: "docs", dir: join(root, "docs") },
|
|
16
|
+
{ id: "api", dir: join(root, "api") },
|
|
17
|
+
{ id: "showcase", dir: join(root, "showcase") },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
function walk(dir: string): string[] {
|
|
21
|
+
let entries: string[] = [];
|
|
22
|
+
try {
|
|
23
|
+
entries = readdirSync(dir);
|
|
24
|
+
} catch {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
const files: string[] = [];
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
const full = join(dir, entry);
|
|
30
|
+
const stat = statSync(full);
|
|
31
|
+
if (stat.isDirectory()) {
|
|
32
|
+
files.push(...walk(full));
|
|
33
|
+
} else if (stat.isFile()) {
|
|
34
|
+
files.push(full);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return files;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function stripMarkdown(md: string): string {
|
|
41
|
+
return md
|
|
42
|
+
.replace(/```[\s\S]*?```/g, " ")
|
|
43
|
+
.replace(/`[^`]*`/g, " ")
|
|
44
|
+
.replace(/!\[[^\]]*\]\([^)]*\)/g, " ")
|
|
45
|
+
.replace(/\[([^\]]*)\]\([^)]*\)/g, "$1")
|
|
46
|
+
.replace(/^#{1,6}\s+/gm, "")
|
|
47
|
+
.replace(/[*_~`]/g, "")
|
|
48
|
+
.replace(/<[^>]+>/g, " ")
|
|
49
|
+
.replace(/\s+/g, " ")
|
|
50
|
+
.trim();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function parseFrontmatter(content: string) {
|
|
54
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
55
|
+
if (!match) {
|
|
56
|
+
return { frontmatter: {} as Record<string, unknown>, body: content };
|
|
57
|
+
}
|
|
58
|
+
let frontmatter: Record<string, unknown> = {};
|
|
59
|
+
try {
|
|
60
|
+
frontmatter = (parseYaml(match[1]) ?? {}) as Record<string, unknown>;
|
|
61
|
+
} catch {
|
|
62
|
+
frontmatter = {};
|
|
63
|
+
}
|
|
64
|
+
return { frontmatter, body: content.slice(match[0].length) };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const docs: Array<{
|
|
68
|
+
collection: string;
|
|
69
|
+
id: string;
|
|
70
|
+
title: string;
|
|
71
|
+
description: string;
|
|
72
|
+
text: string;
|
|
73
|
+
content: string;
|
|
74
|
+
}> = [];
|
|
75
|
+
|
|
76
|
+
for (const collection of collections) {
|
|
77
|
+
const files = walk(collection.dir);
|
|
78
|
+
for (const file of files) {
|
|
79
|
+
if (!file.endsWith(".md")) continue;
|
|
80
|
+
const rel = relative(collection.dir, file)
|
|
81
|
+
.replace(/\\/g, "/")
|
|
82
|
+
.replace(/\.md$/, "");
|
|
83
|
+
const raw = readFileSync(file, "utf8");
|
|
84
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
85
|
+
const title =
|
|
86
|
+
typeof frontmatter.title === "string" ? frontmatter.title : rel;
|
|
87
|
+
const description =
|
|
88
|
+
typeof frontmatter.description === "string"
|
|
89
|
+
? frontmatter.description
|
|
90
|
+
: "";
|
|
91
|
+
docs.push({
|
|
92
|
+
collection: collection.id,
|
|
93
|
+
id: rel,
|
|
94
|
+
title,
|
|
95
|
+
description,
|
|
96
|
+
text: stripMarkdown(body),
|
|
97
|
+
content: body,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const outDir = process.argv.includes("--dev")
|
|
103
|
+
? join(root, "dev", "dist")
|
|
104
|
+
: join(root, "dist");
|
|
105
|
+
mkdirSync(outDir, { recursive: true });
|
|
106
|
+
writeFileSync(
|
|
107
|
+
join(outDir, "search-index.json"),
|
|
108
|
+
JSON.stringify({ docs }, null, 2),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
console.log(`Generated ${docs.length} docs index entries`);
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Build-time helper: pull markdown docs from one or more GitHub repositories.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* bun scripts/github-pull.ts --config create-docs.config.ts
|
|
7
|
+
*
|
|
8
|
+
* Config file (create-docs.config.ts):
|
|
9
|
+
* export default {
|
|
10
|
+
* outDir: "./docs-remote",
|
|
11
|
+
* sources: [
|
|
12
|
+
* { id: "rust-packages", repo: "wrikka/rust-packages", branch: "main", docsDir: "docs" },
|
|
13
|
+
* ],
|
|
14
|
+
* };
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { existsSync } from "node:fs";
|
|
18
|
+
import * as path from "node:path";
|
|
19
|
+
import { pathToFileURL } from "node:url";
|
|
20
|
+
import { pullFromGitHub } from "../src/adapters/github/github-pull";
|
|
21
|
+
|
|
22
|
+
function parseArgs(argv: string[]) {
|
|
23
|
+
const args: Record<string, string | undefined> = {};
|
|
24
|
+
let i = 0;
|
|
25
|
+
while (i < argv.length) {
|
|
26
|
+
const a = argv[i];
|
|
27
|
+
if (a === "--config" || a === "-c") {
|
|
28
|
+
args.config = argv[++i];
|
|
29
|
+
} else if (a.startsWith("--config=")) {
|
|
30
|
+
args.config = a.slice("--config=".length);
|
|
31
|
+
} else if (a === "--out" || a === "-o") {
|
|
32
|
+
args.out = argv[++i];
|
|
33
|
+
} else if (a.startsWith("--out=")) {
|
|
34
|
+
args.out = a.slice("--out=".length);
|
|
35
|
+
} else if (a === "--token" || a === "-t") {
|
|
36
|
+
args.token = argv[++i];
|
|
37
|
+
} else if (a.startsWith("--token=")) {
|
|
38
|
+
args.token = a.slice("--token=".length);
|
|
39
|
+
} else if (a === "--help" || a === "-h") {
|
|
40
|
+
args.help = "1";
|
|
41
|
+
}
|
|
42
|
+
i++;
|
|
43
|
+
}
|
|
44
|
+
return args;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function usage() {
|
|
48
|
+
console.log(`
|
|
49
|
+
Usage: bun scripts/github-pull.ts --config <create-docs.config.ts>
|
|
50
|
+
|
|
51
|
+
Options:
|
|
52
|
+
-c, --config Path to the pull config file (default: create-docs.config.ts)
|
|
53
|
+
-o, --out Override output directory from the config
|
|
54
|
+
-t, --token GitHub token (or set GITHUB_TOKEN)
|
|
55
|
+
-h, --help Show this message
|
|
56
|
+
|
|
57
|
+
Config example:
|
|
58
|
+
export default {
|
|
59
|
+
outDir: "./docs-remote",
|
|
60
|
+
sources: [
|
|
61
|
+
{ id: "rust-packages", repo: "wrikka/rust-packages", branch: "main", docsDir: "docs" },
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface PullConfig {
|
|
68
|
+
outDir?: string;
|
|
69
|
+
sources: Array<{
|
|
70
|
+
id: string;
|
|
71
|
+
repo: string;
|
|
72
|
+
branch?: string;
|
|
73
|
+
docsDir?: string;
|
|
74
|
+
label?: string;
|
|
75
|
+
description?: string;
|
|
76
|
+
icon?: string;
|
|
77
|
+
}>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function loadConfig(configPath: string): Promise<PullConfig> {
|
|
81
|
+
const abs = path.isAbsolute(configPath)
|
|
82
|
+
? configPath
|
|
83
|
+
: path.resolve(process.cwd(), configPath);
|
|
84
|
+
if (!existsSync(abs)) {
|
|
85
|
+
throw new Error(`Config not found: ${abs}`);
|
|
86
|
+
}
|
|
87
|
+
const mod = (await import(pathToFileURL(abs).href)) as {
|
|
88
|
+
default?: PullConfig;
|
|
89
|
+
};
|
|
90
|
+
if (!mod.default) {
|
|
91
|
+
throw new Error(`Config must have a default export: ${abs}`);
|
|
92
|
+
}
|
|
93
|
+
return mod.default;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function main() {
|
|
97
|
+
const args = parseArgs(process.argv.slice(2));
|
|
98
|
+
if (args.help) {
|
|
99
|
+
usage();
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const configPath = args.config ?? "create-docs.config.ts";
|
|
104
|
+
const config = await loadConfig(configPath);
|
|
105
|
+
const outDir = args.out ?? config.outDir ?? "docs-remote";
|
|
106
|
+
|
|
107
|
+
const result = await pullFromGitHub({
|
|
108
|
+
outDir,
|
|
109
|
+
sources: config.sources,
|
|
110
|
+
token: args.token ?? process.env.GITHUB_TOKEN,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
console.log(
|
|
114
|
+
`Pulled ${result.filesWritten} files for ${result.collections.length} collection(s) to ${result.outDir}`,
|
|
115
|
+
);
|
|
116
|
+
for (const c of result.collections) {
|
|
117
|
+
console.log(` - ${c.id}: ${c.label}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
main().catch((err) => {
|
|
122
|
+
console.error(err instanceof Error ? err.message : err);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createNodeConfigLoader } from "./node-config-loader";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node FS-backed config loader.
|
|
3
|
+
* Tries to dynamically import `${cwd}/${configPath}` and returns its default export.
|
|
4
|
+
* Returns `null` if the file doesn't exist (caller falls back to defaults).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import type { ConfigLoader, DocsConfig } from "@create-docs/modules/config";
|
|
9
|
+
import { FilePath } from "@create-docs/modules/content/types";
|
|
10
|
+
import type { AppError } from "@create-docs/shared/errors";
|
|
11
|
+
import { parseError } from "@create-docs/shared/errors";
|
|
12
|
+
import { err, ok, type Result } from "@create-docs/shared/types/result";
|
|
13
|
+
import { nodeFileReader } from "../fs";
|
|
14
|
+
|
|
15
|
+
export const createNodeConfigLoader = (): ConfigLoader => ({
|
|
16
|
+
async load(
|
|
17
|
+
cwd: string,
|
|
18
|
+
configPath: string,
|
|
19
|
+
): Promise<Result<Partial<DocsConfig> | null, AppError>> {
|
|
20
|
+
const fullPath = path.isAbsolute(configPath)
|
|
21
|
+
? configPath
|
|
22
|
+
: path.join(cwd, configPath);
|
|
23
|
+
const fp = FilePath(fullPath);
|
|
24
|
+
const exists = await nodeFileReader.exists(fp);
|
|
25
|
+
if (!exists) return ok(null);
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
// Dynamic import — works in ESM context. CJS/TS configs require the bundler to transform.
|
|
29
|
+
const url = new URL(`file:///${fullPath.replace(/\\/g, "/")}`).href;
|
|
30
|
+
const mod: { default?: Partial<DocsConfig> } = await import(url);
|
|
31
|
+
return ok(mod.default ?? {});
|
|
32
|
+
} catch (e) {
|
|
33
|
+
return err(parseError(fullPath, "Failed to load config", e));
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-system-backed DocsLoader — composes the FS adapter with the
|
|
3
|
+
* processDocsWorkflow use case from the content module.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import type { ResolvedDocsConfig } from "@create-docs/modules/config";
|
|
8
|
+
import type { DocPage } from "@create-docs/modules/content";
|
|
9
|
+
import { processDocsWorkflow } from "@create-docs/modules/content";
|
|
10
|
+
import type { DocsLoader } from "@create-docs/modules/plugin";
|
|
11
|
+
import type { AppError } from "@create-docs/shared/errors";
|
|
12
|
+
import type { Result } from "@create-docs/shared/types/result";
|
|
13
|
+
import { nodeDirectoryScanner, nodeFileReader } from "../fs";
|
|
14
|
+
|
|
15
|
+
export const createFsDocsLoader = (): DocsLoader => ({
|
|
16
|
+
async loadAll(
|
|
17
|
+
config: ResolvedDocsConfig,
|
|
18
|
+
): Promise<Result<readonly DocPage[], AppError>> {
|
|
19
|
+
const reader = nodeFileReader;
|
|
20
|
+
const scanner = nodeDirectoryScanner;
|
|
21
|
+
const docsDir = path.isAbsolute(config.docsDir)
|
|
22
|
+
? config.docsDir
|
|
23
|
+
: path.resolve(process.cwd(), config.docsDir);
|
|
24
|
+
return processDocsWorkflow({
|
|
25
|
+
scanner,
|
|
26
|
+
reader,
|
|
27
|
+
docsDir,
|
|
28
|
+
editLink: config.editLink,
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { createFsDocsLoader } from "./fs-docs-loader";
|
|
2
|
+
export {
|
|
3
|
+
createMemoryDirectoryScanner,
|
|
4
|
+
createMemoryFileReader,
|
|
5
|
+
memoryFileSystem,
|
|
6
|
+
} from "./memory-fs";
|
|
7
|
+
export {
|
|
8
|
+
nodeDirectoryScanner,
|
|
9
|
+
nodeFileReader,
|
|
10
|
+
nodeFileWatcher,
|
|
11
|
+
safeJoin,
|
|
12
|
+
} from "./node-fs";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory FS adapter for tests and SSR scenarios.
|
|
3
|
+
* Implements FileReader + DirectoryScanner without touching the disk.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
DirectoryEntry,
|
|
8
|
+
DirectoryScanner,
|
|
9
|
+
FilePath,
|
|
10
|
+
FileReader,
|
|
11
|
+
} from "@create-docs/modules/content";
|
|
12
|
+
import type { AppError } from "@create-docs/shared/errors";
|
|
13
|
+
import { fileNotFound } from "@create-docs/shared/errors";
|
|
14
|
+
import { err, ok, type Result } from "@create-docs/shared/types/result";
|
|
15
|
+
|
|
16
|
+
export interface MemoryFileSystem {
|
|
17
|
+
readonly files: ReadonlyMap<string, string>;
|
|
18
|
+
readonly directories: ReadonlyMap<string, readonly string[]>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const memoryFileSystem = (
|
|
22
|
+
files: ReadonlyMap<string, string>,
|
|
23
|
+
directories: ReadonlyMap<string, readonly string[]>,
|
|
24
|
+
): MemoryFileSystem => ({ files, directories });
|
|
25
|
+
|
|
26
|
+
export const createMemoryFileReader = (fs: MemoryFileSystem): FileReader => ({
|
|
27
|
+
async read(filePath: FilePath): Promise<Result<string, AppError>> {
|
|
28
|
+
const content = fs.files.get(String(filePath));
|
|
29
|
+
if (content === undefined) return err(fileNotFound(String(filePath)));
|
|
30
|
+
return ok(content);
|
|
31
|
+
},
|
|
32
|
+
async exists(filePath: FilePath): Promise<boolean> {
|
|
33
|
+
return fs.files.has(String(filePath));
|
|
34
|
+
},
|
|
35
|
+
async stat(
|
|
36
|
+
filePath: FilePath,
|
|
37
|
+
): Promise<Result<{ mtimeMs: number; size: number }, AppError>> {
|
|
38
|
+
const content = fs.files.get(String(filePath));
|
|
39
|
+
if (content === undefined) return err(fileNotFound(String(filePath)));
|
|
40
|
+
return ok({ mtimeMs: 0, size: content.length });
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const createMemoryDirectoryScanner = (
|
|
45
|
+
fs: MemoryFileSystem,
|
|
46
|
+
): DirectoryScanner => ({
|
|
47
|
+
async list(
|
|
48
|
+
dirPath: string,
|
|
49
|
+
): Promise<Result<readonly DirectoryEntry[], AppError>> {
|
|
50
|
+
const entries = fs.directories.get(dirPath);
|
|
51
|
+
if (entries === undefined) return err(fileNotFound(dirPath));
|
|
52
|
+
return ok(
|
|
53
|
+
entries.map((name) => ({
|
|
54
|
+
name,
|
|
55
|
+
isDirectory: !name.includes("."),
|
|
56
|
+
path: `${dirPath.replace(/\/$/, "")}/${name}`,
|
|
57
|
+
})),
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node FS adapter — concrete implementation of the content module's FileReader
|
|
3
|
+
* and DirectoryScanner ports. This is the ONLY place where node:fs/promises is used.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "node:fs/promises";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import type {
|
|
8
|
+
DirectoryEntry,
|
|
9
|
+
DirectoryScanner,
|
|
10
|
+
FilePath,
|
|
11
|
+
FileReader,
|
|
12
|
+
FileWatcher,
|
|
13
|
+
} from "@create-docs/modules/content";
|
|
14
|
+
import type { AppError } from "@create-docs/shared/errors";
|
|
15
|
+
import { fileNotFound, ioError } from "@create-docs/shared/errors";
|
|
16
|
+
import { err, ok, type Result } from "@create-docs/shared/types/result";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Path-traversal safe join. Rejects any attempt to resolve to a path outside
|
|
20
|
+
* the configured root. Throws an Error containing the absolute resolved path
|
|
21
|
+
* on violation; callers should treat as AppError.io_error upstream.
|
|
22
|
+
*/
|
|
23
|
+
export const safeJoin = (root: string, requested: string): string => {
|
|
24
|
+
const absRoot = path.resolve(root);
|
|
25
|
+
const cleaned = requested.replace(/^[\\/]+/, "");
|
|
26
|
+
const candidate = path.resolve(absRoot, cleaned);
|
|
27
|
+
const rel = path.relative(absRoot, candidate);
|
|
28
|
+
if (rel.startsWith("..") || rel === ".." || path.isAbsolute(rel)) {
|
|
29
|
+
throw new Error(`Path traversal blocked: ${requested} -> ${candidate}`);
|
|
30
|
+
}
|
|
31
|
+
return candidate;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const nodeFileReader: FileReader = {
|
|
35
|
+
async read(filePath: FilePath): Promise<Result<string, AppError>> {
|
|
36
|
+
try {
|
|
37
|
+
const content = await fs.readFile(String(filePath), "utf-8");
|
|
38
|
+
return ok(content);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
const code = (e as NodeJS.ErrnoException).code;
|
|
41
|
+
if (code === "ENOENT") return err(fileNotFound(String(filePath), e));
|
|
42
|
+
return err(ioError(String(filePath), "Failed to read file", e));
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
async exists(filePath: FilePath): Promise<boolean> {
|
|
46
|
+
try {
|
|
47
|
+
await fs.access(String(filePath));
|
|
48
|
+
return true;
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
async stat(
|
|
54
|
+
filePath: FilePath,
|
|
55
|
+
): Promise<Result<{ mtimeMs: number; size: number }, AppError>> {
|
|
56
|
+
try {
|
|
57
|
+
const s = await fs.stat(String(filePath));
|
|
58
|
+
return ok({ mtimeMs: s.mtimeMs, size: s.size });
|
|
59
|
+
} catch (e) {
|
|
60
|
+
const code = (e as NodeJS.ErrnoException).code;
|
|
61
|
+
if (code === "ENOENT") return err(fileNotFound(String(filePath), e));
|
|
62
|
+
return err(ioError(String(filePath), "Failed to stat file", e));
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const nodeDirectoryScanner: DirectoryScanner = {
|
|
68
|
+
async list(
|
|
69
|
+
dirPath: string,
|
|
70
|
+
): Promise<Result<readonly DirectoryEntry[], AppError>> {
|
|
71
|
+
try {
|
|
72
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
73
|
+
return ok(
|
|
74
|
+
entries.map((entry) => ({
|
|
75
|
+
name: entry.name,
|
|
76
|
+
isDirectory: entry.isDirectory(),
|
|
77
|
+
path: path.join(dirPath, entry.name),
|
|
78
|
+
})),
|
|
79
|
+
);
|
|
80
|
+
} catch (e) {
|
|
81
|
+
const code = (e as NodeJS.ErrnoException).code;
|
|
82
|
+
if (code === "ENOENT") return err(fileNotFound(dirPath, e));
|
|
83
|
+
return err(ioError(dirPath, "Failed to read directory", e));
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const nodeFileWatcher: FileWatcher = {
|
|
89
|
+
watch(dir, handlers) {
|
|
90
|
+
const ac = new AbortController();
|
|
91
|
+
const iterator = fs
|
|
92
|
+
.watch(dir, { recursive: true, signal: ac.signal } as fs.WatchOptions)
|
|
93
|
+
[Symbol.asyncIterator]();
|
|
94
|
+
const consume = async (): Promise<void> => {
|
|
95
|
+
try {
|
|
96
|
+
for await (const event of iterator) {
|
|
97
|
+
const filename = (event as { filename?: unknown }).filename;
|
|
98
|
+
if (
|
|
99
|
+
typeof filename === "string" &&
|
|
100
|
+
(filename.endsWith(".md") || filename.endsWith(".mdoc"))
|
|
101
|
+
) {
|
|
102
|
+
handlers.onChange(filename);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
} catch (e) {
|
|
106
|
+
handlers.onError(e);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
void consume();
|
|
110
|
+
return {
|
|
111
|
+
close: () => {
|
|
112
|
+
ac.abort();
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
},
|
|
116
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Adapter
|
|
3
|
+
*
|
|
4
|
+
* Adapter layer for Git operations using simple-git
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import simpleGit, { type SimpleGit } from "simple-git";
|
|
8
|
+
import type {
|
|
9
|
+
CommitOptions,
|
|
10
|
+
GitAdapter,
|
|
11
|
+
GitStatus,
|
|
12
|
+
PushOptions,
|
|
13
|
+
} from "../../modules/live-editor/ports";
|
|
14
|
+
|
|
15
|
+
interface GitFile {
|
|
16
|
+
path: string;
|
|
17
|
+
index: string;
|
|
18
|
+
working_dir: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Git adapter state
|
|
22
|
+
export interface SimpleGitAdapterState {
|
|
23
|
+
readonly git: SimpleGit;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const createSimpleGitAdapterState = (
|
|
27
|
+
cwd: string = process.cwd(),
|
|
28
|
+
): SimpleGitAdapterState => ({
|
|
29
|
+
git: simpleGit(cwd),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Pure functions for git operations
|
|
33
|
+
export const gitGetCurrentBranch = async (
|
|
34
|
+
state: SimpleGitAdapterState,
|
|
35
|
+
): Promise<string> => {
|
|
36
|
+
const branch = await state.git.branch();
|
|
37
|
+
return branch.current;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const gitGetStatus = async (
|
|
41
|
+
state: SimpleGitAdapterState,
|
|
42
|
+
): Promise<GitStatus> => {
|
|
43
|
+
const status = await state.git.status();
|
|
44
|
+
const branch = await gitGetCurrentBranch(state);
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
branch,
|
|
48
|
+
hasChanges: status.files.length > 0,
|
|
49
|
+
untracked: status.files
|
|
50
|
+
.filter((f: GitFile) => f.working_dir === "?")
|
|
51
|
+
.map((f: GitFile) => f.path),
|
|
52
|
+
modified: status.files
|
|
53
|
+
.filter((f: GitFile) => f.working_dir === "M")
|
|
54
|
+
.map((f: GitFile) => f.path),
|
|
55
|
+
staged: status.files
|
|
56
|
+
.filter((f: GitFile) => f.index === "M")
|
|
57
|
+
.map((f: GitFile) => f.path),
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const gitCommit = async (
|
|
62
|
+
state: SimpleGitAdapterState,
|
|
63
|
+
options: CommitOptions,
|
|
64
|
+
): Promise<void> => {
|
|
65
|
+
await state.git.add(".");
|
|
66
|
+
if (options.author && options.email) {
|
|
67
|
+
await state.git.commit([
|
|
68
|
+
options.message,
|
|
69
|
+
"--author",
|
|
70
|
+
`${options.author} <${options.email}>`,
|
|
71
|
+
]);
|
|
72
|
+
} else {
|
|
73
|
+
await state.git.commit(options.message);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const gitPush = async (
|
|
78
|
+
state: SimpleGitAdapterState,
|
|
79
|
+
options: PushOptions = {},
|
|
80
|
+
): Promise<void> => {
|
|
81
|
+
const remote = options.remote || "origin";
|
|
82
|
+
const branch = options.branch || (await gitGetCurrentBranch(state));
|
|
83
|
+
|
|
84
|
+
if (options.force) {
|
|
85
|
+
await state.git.push(["--force", remote, branch]);
|
|
86
|
+
} else {
|
|
87
|
+
await state.git.push(remote, branch);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const gitStageFile = async (
|
|
92
|
+
state: SimpleGitAdapterState,
|
|
93
|
+
path: string,
|
|
94
|
+
): Promise<void> => {
|
|
95
|
+
await state.git.add(path);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const gitUnstageFile = async (
|
|
99
|
+
state: SimpleGitAdapterState,
|
|
100
|
+
path: string,
|
|
101
|
+
): Promise<void> => {
|
|
102
|
+
await state.git.reset(["--mixed", path]);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const gitDiscardChanges = async (
|
|
106
|
+
state: SimpleGitAdapterState,
|
|
107
|
+
path: string,
|
|
108
|
+
): Promise<void> => {
|
|
109
|
+
await state.git.checkout(path, { "--": path });
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* SimpleGit adapter implementation
|
|
114
|
+
*/
|
|
115
|
+
export class SimpleGitAdapter implements GitAdapter {
|
|
116
|
+
private state: SimpleGitAdapterState;
|
|
117
|
+
|
|
118
|
+
constructor(cwd: string = process.cwd()) {
|
|
119
|
+
this.state = createSimpleGitAdapterState(cwd);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getState(): SimpleGitAdapterState {
|
|
123
|
+
return this.state;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
setState(state: SimpleGitAdapterState): void {
|
|
127
|
+
this.state = state;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async getCurrentBranch(): Promise<string> {
|
|
131
|
+
return gitGetCurrentBranch(this.state);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async getStatus(): Promise<GitStatus> {
|
|
135
|
+
return gitGetStatus(this.state);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async commit(options: CommitOptions): Promise<void> {
|
|
139
|
+
return gitCommit(this.state, options);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async push(options: PushOptions = {}): Promise<void> {
|
|
143
|
+
return gitPush(this.state, options);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async stageFile(path: string): Promise<void> {
|
|
147
|
+
return gitStageFile(this.state, path);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async unstageFile(path: string): Promise<void> {
|
|
151
|
+
return gitUnstageFile(this.state, path);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async discardChanges(path: string): Promise<void> {
|
|
155
|
+
return gitDiscardChanges(this.state, path);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Create Git adapter
|
|
161
|
+
*/
|
|
162
|
+
export const createGitAdapter = (cwd?: string): GitAdapter => {
|
|
163
|
+
return new SimpleGitAdapter(cwd);
|
|
164
|
+
};
|