├── deps.yaml ├── dtsx ├── .gitattributes ├── packages ├── dtsx │ ├── .test-cli │ │ ├── check-test │ │ │ ├── src │ │ │ │ └── check.ts │ │ │ └── tsconfig.json │ │ ├── optimize-test │ │ │ └── test.d.ts │ │ ├── workspace-test │ │ │ └── tsconfig.json │ │ ├── convert-test │ │ │ ├── src │ │ │ │ └── zod-types.ts │ │ │ └── schemas │ │ │ │ └── src │ │ │ │ └── zod-types.schema.ts │ │ └── docs-test │ │ │ ├── src │ │ │ └── documented.ts │ │ │ └── api-docs │ │ │ └── API.md │ ├── test │ │ ├── fixtures │ │ │ ├── input │ │ │ │ ├── enum.ts │ │ │ │ ├── module.ts │ │ │ │ ├── exports.ts │ │ │ │ ├── example │ │ │ │ │ ├── 0001.ts │ │ │ │ │ ├── 0002.ts │ │ │ │ │ ├── 0003.ts │ │ │ │ │ ├── 0006.ts │ │ │ │ │ ├── 0009.ts │ │ │ │ │ ├── 0010.ts │ │ │ │ │ └── 0011.ts │ │ │ │ ├── type-interface-imports.ts │ │ │ │ ├── class.ts │ │ │ │ ├── type-only-imports.ts │ │ │ │ ├── namespace.ts │ │ │ │ ├── interface.ts │ │ │ │ ├── abseil.io.ts │ │ │ │ ├── type.ts │ │ │ │ ├── private-members.ts │ │ │ │ ├── function-types.ts │ │ │ │ └── edge-cases.ts │ │ │ └── output │ │ │ │ ├── enum.d.ts │ │ │ │ ├── example │ │ │ │ ├── 0001.d.ts │ │ │ │ ├── 0002.d.ts │ │ │ │ ├── 0003.d.ts │ │ │ │ ├── 0005.d.ts │ │ │ │ ├── 0009.d.ts │ │ │ │ ├── 0006.d.ts │ │ │ │ ├── 0010.d.ts │ │ │ │ ├── 0007.d.ts │ │ │ │ ├── 0011.d.ts │ │ │ │ ├── 0008.d.ts │ │ │ │ ├── 0012.d.ts │ │ │ │ └── 0004.d.ts │ │ │ │ ├── module.d.ts │ │ │ │ ├── exports.d.ts │ │ │ │ ├── type-interface-imports.d.ts │ │ │ │ ├── class.d.ts │ │ │ │ ├── type-only-imports.d.ts │ │ │ │ ├── interface.d.ts │ │ │ │ ├── function.d.ts │ │ │ │ ├── namespace.d.ts │ │ │ │ ├── private-members.d.ts │ │ │ │ ├── abseil.io.d.ts │ │ │ │ ├── function-types.d.ts │ │ │ │ ├── type.d.ts │ │ │ │ ├── edge-cases.d.ts │ │ │ │ ├── imports.d.ts │ │ │ │ └── variable.d.ts │ │ ├── debug-single.ts │ │ └── dts.test.ts │ ├── src │ │ ├── extractor.ts │ │ ├── processor.ts │ │ ├── processor │ │ │ ├── comments.ts │ │ │ └── cache.ts │ │ ├── plugins │ │ │ ├── index.ts │ │ │ ├── vite.ts │ │ │ ├── tsup.ts │ │ │ ├── bun.ts │ │ │ └── esbuild.ts │ │ └── index.ts │ ├── tsconfig.json │ └── build.ts ├── bun-plugin │ ├── tsconfig.json │ ├── build.ts │ └── package.json ├── vite-plugin │ ├── tsconfig.json │ ├── build.ts │ └── package.json ├── esbuild-plugin │ ├── build.ts │ ├── package.json │ └── README.md ├── tsup-plugin │ ├── build.ts │ └── package.json └── webpack-plugin │ ├── build.ts │ └── package.json ├── .github ├── FUNDING.yml ├── art │ └── cover.jpg ├── renovate.json ├── stale.yml ├── workflows │ ├── README.md │ ├── release.yml │ └── ci.yml └── SECURITY.md ├── docs ├── public │ └── images │ │ ├── logo.png │ │ ├── og-image.png │ │ ├── logo-white.png │ │ ├── logo-mini.svg │ │ ├── logo-transparent.svg │ │ ├── logo-white-transparent.svg │ │ ├── logo.svg │ │ ├── favicon.svg │ │ └── favicon-dark.svg ├── .vitepress │ ├── theme │ │ ├── components │ │ │ ├── contributors.json │ │ │ ├── Home.vue │ │ │ ├── HomeTeam.vue │ │ │ ├── HomeSponsors.vue │ │ │ ├── HomeContributors.vue │ │ │ ├── TeamMember.vue │ │ │ └── contributors.ts │ │ ├── styles │ │ │ ├── overrides.css │ │ │ ├── main.css │ │ │ └── vars.css │ │ └── index.ts │ ├── components.d.ts │ ├── unocss.config.ts │ └── vite.config.ts ├── stargazers.md ├── partners.md ├── postcardware.md ├── team.md ├── license.md ├── index.md ├── intro.md ├── features │ ├── import-optimization.md │ └── type-inference.md ├── _data │ └── team.js └── advanced │ ├── troubleshooting.md │ └── type-processing.md ├── bunfig.toml ├── .editorconfig ├── .cursor ├── mcp.json └── rules │ ├── typescript.mdc │ ├── syntax-formatting.mdc │ ├── documentation.mdc │ ├── testing.mdc │ ├── project-structure.mdc │ ├── key-conventions.mdc │ ├── error-handling.mdc │ └── code-style.mdc ├── .gitignore ├── .vscode ├── extensions.json ├── dictionary.txt └── settings.json ├── dts.config.ts ├── eslint.config.ts ├── scripts ├── generate-dts.ts ├── generate.ts ├── generate-output.ts ├── compare.ts └── publish.sh ├── buddy-bot.config.ts ├── LICENSE.md ├── tsconfig.json ├── package.json └── .zed └── settings.json /deps.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | bun.sh: ^1.3.2 3 | -------------------------------------------------------------------------------- /dtsx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bun 2 | import('./bin/cli') 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.lockb binary diff=lockb 3 | -------------------------------------------------------------------------------- /packages/dtsx/.test-cli/check-test/src/check.ts: -------------------------------------------------------------------------------- 1 | 2 | export const x: number = 1 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [stacksjs, chrisbbreuer] 2 | open_collective: stacksjs 3 | -------------------------------------------------------------------------------- /.github/art/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacksjs/dtsx/HEAD/.github/art/cover.jpg -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "github>ow3org/renovate-config" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /docs/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacksjs/dtsx/HEAD/docs/public/images/logo.png -------------------------------------------------------------------------------- /docs/public/images/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacksjs/dtsx/HEAD/docs/public/images/og-image.png -------------------------------------------------------------------------------- /docs/public/images/logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacksjs/dtsx/HEAD/docs/public/images/logo-white.png -------------------------------------------------------------------------------- /packages/dtsx/.test-cli/optimize-test/test.d.ts: -------------------------------------------------------------------------------- 1 | import { bar } from './bar' 2 | 3 | import { foo } from './foo' 4 | -------------------------------------------------------------------------------- /bunfig.toml: -------------------------------------------------------------------------------- 1 | [install] 2 | registry = { url = "https://registry.npmjs.org/", token = "$BUN_AUTH_TOKEN" } 3 | peer = true 4 | -------------------------------------------------------------------------------- /packages/dtsx/.test-cli/workspace-test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext" 4 | } 5 | } -------------------------------------------------------------------------------- /packages/dtsx/.test-cli/convert-test/src/zod-types.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface Config { 3 | host: string 4 | port: number 5 | debug?: boolean 6 | } 7 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/contributors.json: -------------------------------------------------------------------------------- 1 | { 2 | "chrisbbreuer": true, 3 | "glennmichael123": false, 4 | "cab-mikee": true, 5 | "konkonam": false 6 | } 7 | -------------------------------------------------------------------------------- /docs/stargazers.md: -------------------------------------------------------------------------------- 1 | # Stargazers over time 2 | 3 | [![Stargazers over time](https://starchart.cc/stacksjs/dtsx.svg?variant=adaptive)](https://starchart.cc/stacksjs/dtsx) 4 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/enum.ts: -------------------------------------------------------------------------------- 1 | export enum ExampleEnum { 2 | First = 'first', 3 | Second = 'second', 4 | Third = 'third', 5 | Fourth = 4, 6 | Fifth = 5, 7 | } 8 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/enum.d.ts: -------------------------------------------------------------------------------- 1 | export declare enum ExampleEnum { 2 | First = 'first', 3 | Second = 'second', 4 | Third = 'third', 5 | Fourth = 4, 6 | Fifth = 5, 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /packages/dtsx/.test-cli/convert-test/schemas/src/zod-types.schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | 3 | export const ConfigSchema = z.unknown() 4 | 5 | export type Config = z.infer 6 | -------------------------------------------------------------------------------- /packages/bun-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": [ 7 | "./src/**/*.ts" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /packages/vite-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": [ 7 | "./src/**/*.ts" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.cursor/mcp.json: -------------------------------------------------------------------------------- 1 | { 2 | "mcpServers": { 3 | "context7": { 4 | "command": "bunx", 5 | "args": [ 6 | "-y", 7 | "@upstash/context7-mcp" 8 | ] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/dtsx/src/extractor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Extractor module - re-exports from modular structure 3 | * @deprecated Import from './extractor/index' directly for better tree-shaking 4 | */ 5 | 6 | export * from './extractor/index' 7 | -------------------------------------------------------------------------------- /packages/dtsx/src/processor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processor module - re-exports from modular structure 3 | * @deprecated Import from './processor/index' directly for better tree-shaking 4 | */ 5 | 6 | export * from './processor/index' 7 | -------------------------------------------------------------------------------- /packages/dtsx/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist" 6 | }, 7 | "include": [ 8 | "src/**/*.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/Home.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/styles/overrides.css: -------------------------------------------------------------------------------- 1 | .custom-block-title { 2 | opacity: 0.5; 3 | font-size: 12px; 4 | margin-top: -5px !important; 5 | margin-bottom: -10px !important; 6 | filter: saturate(0.6); 7 | letter-spacing: 0.5px; 8 | } 9 | -------------------------------------------------------------------------------- /packages/dtsx/.test-cli/check-test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "strict": true 7 | }, 8 | "include": [ 9 | "src/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0001.d.ts: -------------------------------------------------------------------------------- 1 | export declare function loadConfig>({ name, cwd, defaultConfig }: ConfigOptions): Promise; 2 | export declare interface ConfigOptions { 3 | name: string 4 | cwd?: string 5 | defaultConfig: T 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .DS_Store 3 | .idea 4 | *.log 5 | *.tgz 6 | *.pem 7 | coverage 8 | dist 9 | lib-cov 10 | logs 11 | node_modules 12 | temp 13 | docs/.vitepress/cache 14 | storage 15 | fixtures/generated 16 | **/bin/dtsx* 17 | /test/temp-output 18 | test/debug 19 | /test/fixtures/generated 20 | -------------------------------------------------------------------------------- /.cursor/rules/typescript.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: TypeScript Usage specifics 3 | globs: docs/**/*.md 4 | --- 5 | ## TypeScript Usage 6 | 7 | - Use TypeScript for all code; prefer interfaces over types 8 | - Avoid enums; use `maps` instead, or `as const` 9 | - Use functional components with TypeScript interfaces -------------------------------------------------------------------------------- /docs/partners.md: -------------------------------------------------------------------------------- 1 | # Partners 2 | 3 | The following companies and organizations are supporting Stacks development through partnerships: 4 | 5 | - [JetBrains](https://www.jetbrains.com/) 6 | - [The Solana Foundation](https://solana.com/) 7 | 8 | If you are interested in becoming a partner, please reach out to us. 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint", 6 | "streetsidesoftware.code-spell-checker", 7 | "davidanson.vscode-markdownlint" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.cursor/rules/syntax-formatting.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Syntax and Formatting specifics 3 | globs: 4 | --- 5 | ## Syntax and Formatting 6 | 7 | - Use the "function" keyword for pure functions 8 | - Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements 9 | - Make sure everything is properly commented -------------------------------------------------------------------------------- /docs/postcardware.md: -------------------------------------------------------------------------------- 1 | # Postcardware 2 | 3 | You will always be free to use any of the Stacks OSS software. We would also love to see which parts of the world Stacks ends up in. _Receiving postcards makes us happy—and we will publish them on our website._ 4 | 5 | Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094, United States 🌎 6 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/module.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@stacksjs/some-module' { 2 | interface DtsGenerationConfig { 3 | customPlugins?: Array<{ 4 | name: string 5 | transform: (code: string) => string 6 | }> 7 | } 8 | interface DtsGenerationResult { 9 | customPluginResults?: Record 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.cursor/rules/documentation.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Documentation specific rules 3 | globs: docs/**/*.md 4 | --- 5 | ## Documentation 6 | 7 | - Write documentation for all functions, types, interfaces, and ensure examples are accurate 8 | - The `./docs` directory is where the vitepress markdown documentation is stored 9 | - Make sure to update the docs markdown files -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/module.ts: -------------------------------------------------------------------------------- 1 | declare module '@stacksjs/some-module' { 2 | interface DtsGenerationConfig { 3 | customPlugins?: Array<{ 4 | name: string 5 | transform: (code: string) => string 6 | }> 7 | } 8 | 9 | interface DtsGenerationResult { 10 | customPluginResults?: Record 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0002.d.ts: -------------------------------------------------------------------------------- 1 | import type { BunPlugin } from 'bun'; 2 | import { generate } from '@stacksjs/dtsx'; 3 | import type { DtsGenerationOption } from '@stacksjs/dtsx'; 4 | export type { DtsGenerationOption }; 5 | export declare function dts(options?: DtsGenerationOption): BunPlugin; 6 | export { generate }; 7 | export default dts; 8 | -------------------------------------------------------------------------------- /.cursor/rules/testing.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Testing specifics 3 | globs: 4 | --- 5 | ## Testing 6 | 7 | - Write tests for all functions, types, interfaces, and ensure examples are accurate 8 | - The `./test` directory is where the tests are stored 9 | - Use `bun test` to run the tests 10 | - Use bun native modules for testing from `import { x, y, z } from 'bun:test'` -------------------------------------------------------------------------------- /.cursor/rules/project-structure.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Project structure information 3 | globs: 4 | --- 5 | ## Project Structure 6 | 7 | - the `./src` directory is the source code 8 | - the `./test` directory is the test code 9 | - the `./bin` directory is the command-line code 10 | - you can also call the CLI via `./clarity ...` 11 | - the `./docs` directory is the documentation 12 | -------------------------------------------------------------------------------- /dts.config.ts: -------------------------------------------------------------------------------- 1 | import type { DtsGenerationOption } from './packages/dtsx/src/types' 2 | 3 | const config: DtsGenerationOption = { 4 | cwd: __dirname, 5 | root: './src', 6 | entrypoints: ['**/*.ts'], 7 | outdir: './dist', 8 | clean: true, 9 | verbose: false, 10 | 11 | // keepComments: true, 12 | // bundle: true, 13 | // minify: true, 14 | } 15 | 16 | export default config 17 | -------------------------------------------------------------------------------- /.cursor/rules/key-conventions.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Key code conventions 3 | globs: 4 | --- 5 | ## Key Conventions 6 | 7 | - If there are two equally valid implementations, the browser version should be preferred 8 | - Aim for 100% test coverage 9 | - Avoid usage of `any` 10 | - Reuse eslint-ignore comments where present, unless not needed 11 | - ensure we log everything properly, including for debug reasons -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | daysUntilStale: 60 2 | daysUntilClose: 7 3 | exemptLabels: 4 | - pinned 5 | - security 6 | - no-stale 7 | - no stale 8 | - pr welcome 9 | staleLabel: stale 10 | markComment: > 11 | This issue has been automatically marked as stale because it has not had 12 | recent activity. It will be closed if no further activity occurs. 13 | Thank you for your contributions. 14 | closeComment: false 15 | -------------------------------------------------------------------------------- /.github/workflows/README.md: -------------------------------------------------------------------------------- 1 | # GitHub Actions 2 | 3 | This folder contains the following GitHub Actions: 4 | 5 | - [CI][CI] - all CI jobs for the project 6 | - lints the code 7 | - `typecheck`s the code 8 | - runs test suite 9 | - runs on `ubuntu-latest` 10 | - [Release][Release] - automates the release process & changelog generation 11 | 12 | [CI]: ./workflows/ci.yml 13 | [Release]: ./workflows/release.yml 14 | -------------------------------------------------------------------------------- /.cursor/rules/error-handling.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Error Handling and Validation specifics 3 | globs: 4 | --- 5 | ## Error Handling and Validation 6 | 7 | - Prioritize error handling: handle errors and edge cases early 8 | - Use early returns and guard clauses 9 | - Implement proper error logging and user-friendly messages 10 | - Use error boundaries for unexpected errors 11 | - when `neverthrow` is available, ensure errors are typed -------------------------------------------------------------------------------- /eslint.config.ts: -------------------------------------------------------------------------------- 1 | import type { ESLintConfig } from '@stacksjs/eslint-config' 2 | import stacks from '@stacksjs/eslint-config' 3 | 4 | const config: ESLintConfig = stacks({ 5 | stylistic: { 6 | indent: 2, 7 | quotes: 'single', 8 | }, 9 | 10 | typescript: true, 11 | jsonc: true, 12 | yaml: true, 13 | ignores: [ 14 | '**/node_modules', 15 | '**/fixtures', 16 | '**/docs', 17 | ], 18 | }) 19 | 20 | export default config 21 | -------------------------------------------------------------------------------- /scripts/generate-dts.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | import { generate } from '../packages/dtsx/src' 3 | 4 | console.log('Generating output...', path.join(__dirname, '..')) 5 | 6 | generate({ 7 | cwd: path.join(__dirname, '..'), 8 | root: path.join(__dirname, '..', 'src'), 9 | outdir: path.join(__dirname, '..', 'dist'), 10 | clean: true, 11 | tsconfigPath: path.join(__dirname, '..', 'tsconfig.json'), 12 | }) 13 | 14 | console.log('Generated') 15 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0003.d.ts: -------------------------------------------------------------------------------- 1 | import type { PluginBuilder } from 'bun'; 2 | import type { UnimportOptions } from 'unimport'; 3 | export declare function autoImports(options: Partial): AutoImportsPlugin; 4 | declare interface AutoImportsPlugin { 5 | name: string 6 | setup: (builder: PluginBuilder) => Promise 7 | } 8 | export type AutoImportsOptions = UnimportOptions; 9 | export default autoImports; 10 | -------------------------------------------------------------------------------- /scripts/generate.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | import { generate } from '../packages/dtsx/src' 3 | 4 | console.log('Generating output...', path.join(__dirname, '..')) 5 | 6 | generate({ 7 | cwd: path.join(__dirname, '..'), 8 | root: path.join(__dirname, '..', 'fixtures/input'), 9 | outdir: path.join(__dirname, '..', 'fixtures/generated'), 10 | clean: true, 11 | tsconfigPath: path.join(__dirname, '..', 'tsconfig.json'), 12 | }) 13 | 14 | console.log('Generated') 15 | -------------------------------------------------------------------------------- /scripts/generate-output.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | import { generate } from '../packages/dtsx/src' 3 | 4 | console.log('Generating output...', path.join(__dirname, '..')) 5 | 6 | generate({ 7 | cwd: path.join(__dirname, '..'), 8 | root: path.join(__dirname, '..', 'test/fixtures/input'), 9 | outdir: path.join(__dirname, '..', 'test/fixtures/output'), 10 | clean: true, 11 | tsconfigPath: path.join(__dirname, '..', 'tsconfig.json'), 12 | }) 13 | 14 | console.log('Generated') 15 | -------------------------------------------------------------------------------- /packages/dtsx/.test-cli/docs-test/src/documented.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * A well-documented function 4 | * @param name - The name to greet 5 | * @returns A greeting string 6 | * @example 7 | * greet('World') // returns 'Hello, World!' 8 | */ 9 | export function greet(name: string): string { 10 | return `Hello, ${name}!` 11 | } 12 | 13 | /** 14 | * User interface 15 | * @category Models 16 | */ 17 | export interface User { 18 | /** User's name */ 19 | name: string 20 | /** User's age */ 21 | age: number 22 | } 23 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/exports.d.ts: -------------------------------------------------------------------------------- 1 | import type { BunPlugin } from 'bun'; 2 | import { dtsConfig } from './config'; 3 | import { generate, something as dts } from './generate'; 4 | import type { SomeOtherType } from '@stacksjs/types'; 5 | export type { SomeOtherType }; 6 | export type { BunRegisterPlugin } from 'bun'; 7 | export { generate, dtsConfig, type BunPlugin }; 8 | export { config } from './config'; 9 | export * from './extract'; 10 | export * from './generate'; 11 | export * from './types'; 12 | export * from './utils'; 13 | export default dts; 14 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/HomeTeam.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 21 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/exports.ts: -------------------------------------------------------------------------------- 1 | import { generate, something as dts } from './generate' 2 | import { dtsConfig } from './config' 3 | import type { SomeOtherType } from '@stacksjs/types'; 4 | import type { BunPlugin } from 'bun'; 5 | 6 | export { generate, dtsConfig, type BunPlugin } 7 | export type { SomeOtherType } 8 | export type { BunRegisterPlugin } from 'bun' 9 | 10 | export default dts 11 | 12 | export { config } from './config' 13 | export * from './extract' 14 | export * from './generate' 15 | export * from './types' 16 | export * from './utils' 17 | -------------------------------------------------------------------------------- /packages/dtsx/src/processor/comments.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Comment formatting utilities for DTS output 3 | */ 4 | 5 | /** 6 | * Format comments for DTS output 7 | */ 8 | export function formatComments(comments: string[] | undefined, keepComments: boolean = true): string { 9 | if (!keepComments || !comments || comments.length === 0) { 10 | return '' 11 | } 12 | 13 | const formattedComments = comments.map((comment) => { 14 | // Ensure proper spacing and formatting 15 | return comment.trim() 16 | }).join('\n') 17 | 18 | return `${formattedComments}\n` 19 | } 20 | -------------------------------------------------------------------------------- /packages/bun-plugin/build.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process' 2 | import dts from './src/index' 3 | 4 | console.log('Building...') 5 | 6 | const result = await Bun.build({ 7 | entrypoints: ['src/index.ts'], 8 | outdir: 'dist', 9 | target: 'bun', 10 | external: ['@stacksjs/dtsx'], 11 | // minify: true, 12 | plugins: [dts()], 13 | }) 14 | 15 | if (!result.success) { 16 | console.error('Build failed') 17 | 18 | for (const message of result.logs) { 19 | console.error(message) 20 | } 21 | 22 | process.exit(1) 23 | } 24 | 25 | console.log('Build complete') 26 | -------------------------------------------------------------------------------- /packages/vite-plugin/build.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process' 2 | import dts from 'bun-plugin-dtsx' 3 | 4 | console.log('Building...') 5 | 6 | const result = await Bun.build({ 7 | entrypoints: ['src/index.ts'], 8 | outdir: 'dist', 9 | target: 'bun', 10 | external: ['@stacksjs/dtsx'], 11 | // minify: true, 12 | plugins: [dts()], 13 | }) 14 | 15 | if (!result.success) { 16 | console.error('Build failed') 17 | 18 | for (const message of result.logs) { 19 | console.error(message) 20 | } 21 | 22 | process.exit(1) 23 | } 24 | 25 | console.log('Build complete') 26 | -------------------------------------------------------------------------------- /packages/esbuild-plugin/build.ts: -------------------------------------------------------------------------------- 1 | import { build } from 'esbuild' 2 | import { generate } from '@stacksjs/dtsx' 3 | 4 | console.log('Building...') 5 | 6 | const result = await build({ 7 | entryPoints: ['src/index.ts'], 8 | outdir: 'dist', 9 | bundle: true, 10 | format: 'esm', 11 | platform: 'node', 12 | external: ['@stacksjs/dtsx', 'esbuild'], 13 | target: 'node18', 14 | }) 15 | 16 | // Generate declaration files 17 | await generate({ 18 | cwd: process.cwd(), 19 | root: './src', 20 | outdir: './dist', 21 | entrypoints: ['index.ts'], 22 | }) 23 | 24 | console.log('Build complete') 25 | -------------------------------------------------------------------------------- /.cursor/rules/code-style.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Code Style & Structure specifics 3 | globs: 4 | --- 5 | ## Code Style & Structure 6 | 7 | - Write concise, technical TypeScript code with accurate examples in the docblock 8 | - If Bun native modules are available, use them 9 | - Use functional and declarative programming patterns; avoid classes unless needed 10 | - Prefer iteration and modularization over code duplication 11 | - Use descriptive variable names with auxiliary verbs (e.g., `isLoading`, `hasError`) 12 | - Use proper jsdoc comments for functions, types, interfaces, and ensure examples are accurate 13 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/HomeSponsors.vue: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /scripts/compare.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | import path from 'node:path' 3 | import { generate } from '../packages/dtsx/src' 4 | 5 | console.log('Generating output for reviewal...', path.join(__dirname, '..')) 6 | 7 | // delete the generated directory 8 | fs.rmdirSync(path.join(__dirname, '..', 'fixtures/generated'), { recursive: true }) 9 | 10 | generate({ 11 | cwd: path.join(__dirname, '..'), 12 | root: path.join(__dirname, '..', 'fixtures/input'), 13 | outdir: path.join(__dirname, '..', 'fixtures/generated'), 14 | clean: true, 15 | tsconfigPath: path.join(__dirname, '..', 'tsconfig.json'), 16 | }) 17 | 18 | console.log('Generated') 19 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/styles/main.css: -------------------------------------------------------------------------------- 1 | html.dark { 2 | color-scheme: dark; 3 | } 4 | 5 | .vp-doc h2 { 6 | border-top: 0; 7 | margin-top: 10px; 8 | } 9 | 10 | .VPMenuLink .link { 11 | line-height: 28px !important; 12 | } 13 | 14 | .VPSidebarGroup .link { 15 | padding: 3px 0 !important; 16 | } 17 | 18 | .vp-doc a:has(> code) { 19 | text-decoration: none; 20 | color: var(--vp-c-brand-1); 21 | } 22 | 23 | .vp-doc a:has(> code):hover { 24 | text-decoration: underline; 25 | } 26 | 27 | #app a:focus-visible, 28 | #app button:focus-visible, 29 | #app input[type='checkbox']:focus-visible { 30 | --at-apply: outline-1 outline-primary ring-2 ring-primary; 31 | } 32 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import type { Theme } from 'vitepress' 2 | import TwoSlashFloatingVue from '@shikijs/vitepress-twoslash/client' 3 | import DefaultTheme from 'vitepress/theme' 4 | import { h } from 'vue' 5 | 6 | import 'uno.css' 7 | 8 | import './styles/main.css' 9 | import './styles/vars.css' 10 | import './styles/overrides.css' 11 | 12 | export default { 13 | ...DefaultTheme, 14 | 15 | enhanceApp(ctx: any) { 16 | ctx.app.use(TwoSlashFloatingVue) 17 | }, 18 | 19 | Layout: () => { 20 | return h(DefaultTheme.Layout, null, { 21 | // https://vitepress.dev/guide/extending-default-theme#layout-slots 22 | }) 23 | }, 24 | } satisfies Theme 25 | -------------------------------------------------------------------------------- /packages/dtsx/build.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs/promises' 2 | import dts from 'bun-plugin-dtsx' 3 | 4 | console.log('Building...') 5 | 6 | await fs.rm('./dist', { recursive: true, force: true }) 7 | 8 | await Bun.build({ 9 | entrypoints: [ 10 | './src/index.ts', 11 | './bin/cli.ts', 12 | './src/plugins/vite.ts', 13 | './src/plugins/bun.ts', 14 | './src/plugins/esbuild.ts', 15 | './src/plugins/tsup.ts', 16 | './src/plugins/webpack.ts', 17 | './src/plugins/index.ts', 18 | ], 19 | outdir: './dist', 20 | format: 'esm', 21 | target: 'bun', 22 | minify: true, 23 | splitting: true, 24 | plugins: [ 25 | dts(), 26 | ], 27 | }) 28 | 29 | console.log('Built!') 30 | -------------------------------------------------------------------------------- /packages/tsup-plugin/build.ts: -------------------------------------------------------------------------------- 1 | import { generate } from '@stacksjs/dtsx' 2 | 3 | console.log('Building...') 4 | 5 | const result = await Bun.build({ 6 | entrypoints: ['src/index.ts'], 7 | outdir: 'dist', 8 | target: 'node', 9 | external: ['@stacksjs/dtsx', 'tsup'], 10 | format: 'esm', 11 | }) 12 | 13 | if (!result.success) { 14 | console.error('Build failed') 15 | for (const message of result.logs) { 16 | console.error(message) 17 | } 18 | process.exit(1) 19 | } 20 | 21 | // Generate declaration files 22 | await generate({ 23 | cwd: process.cwd(), 24 | root: './src', 25 | outdir: './dist', 26 | entrypoints: ['index.ts'], 27 | }) 28 | 29 | console.log('Build complete') 30 | -------------------------------------------------------------------------------- /packages/webpack-plugin/build.ts: -------------------------------------------------------------------------------- 1 | import { generate } from '@stacksjs/dtsx' 2 | 3 | console.log('Building...') 4 | 5 | const result = await Bun.build({ 6 | entrypoints: ['src/index.ts'], 7 | outdir: 'dist', 8 | target: 'node', 9 | external: ['@stacksjs/dtsx', 'webpack'], 10 | format: 'esm', 11 | }) 12 | 13 | if (!result.success) { 14 | console.error('Build failed') 15 | for (const message of result.logs) { 16 | console.error(message) 17 | } 18 | process.exit(1) 19 | } 20 | 21 | // Generate declaration files 22 | await generate({ 23 | cwd: process.cwd(), 24 | root: './src', 25 | outdir: './dist', 26 | entrypoints: ['index.ts'], 27 | }) 28 | 29 | console.log('Build complete') 30 | -------------------------------------------------------------------------------- /.vscode/dictionary.txt: -------------------------------------------------------------------------------- 1 | antfu 2 | audiox 3 | biomejs 4 | booleanish 5 | bumpp 6 | bunfig 7 | bunx 8 | changelogen 9 | changelogithub 10 | codecov 11 | composables 12 | davidanson 13 | degit 14 | deps 15 | destructurable 16 | dnsx 17 | dtsx 18 | entrypoints 19 | heroicons 20 | httx 21 | iconify 22 | imgx 23 | localtunnels 24 | lockb 25 | mkcert 26 | openweb 27 | outdir 28 | outfile 29 | pausable 30 | pkgx 31 | Postcardware 32 | postcompile 33 | prefetch 34 | preinstall 35 | shikijs 36 | socio 37 | softprops 38 | Solana 39 | stacksjs 40 | tlsx 41 | twoslash 42 | typecheck 43 | unconfig 44 | unocss 45 | unplugin 46 | unref 47 | upath 48 | vidx 49 | vite 50 | vitebook 51 | vitejs 52 | vitepress 53 | vue-demi 54 | vueus 55 | whois 56 | -------------------------------------------------------------------------------- /docs/.vitepress/components.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // @ts-nocheck 3 | // Generated by unplugin-vue-components 4 | // Read more: https://github.com/vuejs/core/pull/3399 5 | // biome-ignore lint: disable 6 | export {} 7 | 8 | /* prettier-ignore */ 9 | declare module 'vue' { 10 | export interface GlobalComponents { 11 | Home: typeof import('./theme/components/Home.vue')['default'] 12 | HomeContributors: typeof import('./theme/components/HomeContributors.vue')['default'] 13 | HomeSponsors: typeof import('./theme/components/HomeSponsors.vue')['default'] 14 | HomeTeam: typeof import('./theme/components/HomeTeam.vue')['default'] 15 | TeamMember: typeof import('./theme/components/TeamMember.vue')['default'] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/dtsx/src/plugins/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Build tool plugins for dtsx 3 | * Re-exports all available build tool integrations 4 | */ 5 | 6 | // Vite 7 | export { dts as viteDts, dts as vite, type VitePluginOptions } from './vite' 8 | 9 | // Bun 10 | export { dts as bunDts, dts as bun, type BunPluginOptions } from './bun' 11 | 12 | // esbuild 13 | export { dtsx as esbuildDts, dtsx as esbuild, dts as esbuildPlugin, type EsbuildPluginOptions } from './esbuild' 14 | 15 | // tsup 16 | export { dtsxPlugin as tsupDts, dtsxPlugin as tsup, dts as tsupPlugin, type TsupPluginOptions } from './tsup' 17 | 18 | // webpack 19 | export { DtsxWebpackPlugin, dtsxWebpack as webpackDts, dts as webpackPlugin, type WebpackPluginOptions } from './webpack' 20 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/HomeContributors.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 21 | -------------------------------------------------------------------------------- /packages/dtsx/.test-cli/docs-test/api-docs/API.md: -------------------------------------------------------------------------------- 1 | # API Documentation 2 | 3 | > Generated on 2025-11-30T12:48:29.571Z 4 | 5 | ## Table of Contents 6 | 7 | - [Functions](#functions) 8 | - [Interfaces](#interfaces) 9 | 10 | ## Functions 11 | 12 | ### greet 13 | 14 | ```typescript 15 | export function greet (name: string) : string 16 | ``` 17 | 18 | A well-documented function 19 | 20 | **Parameters:** 21 | 22 | | Name | Type | Description | 23 | |------|------|-------------| 24 | | `name` | `any` | The name to greet | 25 | 26 | **Returns:** 27 | 28 | A greeting string 29 | 30 | **Examples:** 31 | 32 | ```typescript 33 | greet('World') // returns 'Hello, World!' 34 | ``` 35 | 36 | --- 37 | 38 | ## Interfaces 39 | 40 | ### User 41 | 42 | ```typescript 43 | export interface User 44 | ``` 45 | 46 | User interface 47 | 48 | --- 49 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/example/0001.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'node:path' 2 | import process from 'node:process' 3 | import { deepMerge } from './utils' 4 | 5 | export interface ConfigOptions { 6 | name: string 7 | cwd?: string 8 | defaultConfig: T 9 | } 10 | 11 | export async function loadConfig>({ name, cwd, defaultConfig }: ConfigOptions): Promise { 12 | const c = cwd ?? process.cwd() 13 | const configPath = resolve(c, `${name}.config`) 14 | 15 | try { 16 | const importedConfig = await import(configPath) 17 | const loadedConfig = importedConfig.default || importedConfig 18 | return deepMerge(defaultConfig, loadedConfig) 19 | } 20 | catch (error) { 21 | console.error(`Error loading config from ${configPath}:`, error) 22 | return defaultConfig 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/.vitepress/unocss.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineConfig, 3 | presetAttributify, 4 | presetIcons, 5 | presetUno, 6 | transformerDirectives, 7 | transformerVariantGroup, 8 | } from 'unocss' 9 | 10 | export default defineConfig({ 11 | shortcuts: { 12 | 'border-main': 'border-$vp-c-divider', 13 | 'bg-main': 'bg-gray-400', 14 | 'bg-base': 'bg-white dark:bg-hex-1a1a1a', 15 | }, 16 | 17 | presets: [ 18 | presetUno(), 19 | presetAttributify(), 20 | presetIcons({ 21 | scale: 1.2, 22 | warn: true, 23 | }), 24 | ], 25 | 26 | theme: { 27 | colors: { 28 | primary: '#3eaf7c', 29 | }, 30 | 31 | fontFamily: { 32 | mono: 'var(--vp-font-family-mono)', 33 | }, 34 | }, 35 | 36 | transformers: [ 37 | transformerDirectives(), 38 | transformerVariantGroup(), 39 | ], 40 | }) 41 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/type-interface-imports.d.ts: -------------------------------------------------------------------------------- 1 | import type { ParsedPath } from 'node:path'; 2 | /** 3 | * Exported function that returns a type using imported types 4 | */ 5 | export declare function getFileInfo(filePath: string): FileInfo; 6 | /** 7 | * Exported function that uses interface parameter 8 | */ 9 | export declare function processFile(metadata: FileMetadata): void; 10 | /** 11 | * Interface that uses an imported type 12 | */ 13 | declare interface FileMetadata { 14 | parsedPath: ParsedPath 15 | size: number 16 | } 17 | /** 18 | * Exported interface that uses another interface 19 | */ 20 | export declare interface FileDetails extends FileMetadata { 21 | name: string 22 | } 23 | /** 24 | * Internal type that uses an imported type 25 | */ 26 | declare type FileInfo = { 27 | path: ParsedPath 28 | content: string 29 | } 30 | /** 31 | * Exported type alias that uses imported type 32 | */ 33 | export type PathInfo = ParsedPath & { 34 | exists: boolean 35 | } 36 | -------------------------------------------------------------------------------- /docs/team.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Meet the Team 4 | description: A team of incredible people. 5 | sidebar: false 6 | --- 7 | 8 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 36 | 37 | -------------------------------------------------------------------------------- /buddy-bot.config.ts: -------------------------------------------------------------------------------- 1 | import type { BuddyBotConfig } from 'buddy-bot' 2 | 3 | const config: BuddyBotConfig = { 4 | repository: { 5 | owner: 'stacksjs', 6 | name: 'dtsx', 7 | provider: 'github', 8 | // Uses GITHUB_TOKEN by default 9 | }, 10 | dashboard: { 11 | enabled: true, 12 | title: 'Dependency Dashboard', 13 | // issueNumber: undefined, // Auto-generated 14 | }, 15 | workflows: { 16 | enabled: true, 17 | outputDir: '.github/workflows', 18 | templates: { 19 | daily: true, 20 | weekly: true, 21 | monthly: true, 22 | }, 23 | custom: [], 24 | }, 25 | packages: { 26 | strategy: 'all', 27 | ignore: [ 28 | // Add packages to ignore here 29 | // Example: '@types/node', 'eslint' 30 | ], 31 | ignorePaths: [ 32 | // Add file/directory paths to ignore using glob patterns 33 | // Example: 'packages/test-*/**', '**/*test-envs/**', 'apps/legacy/**' 34 | ], 35 | }, 36 | verbose: false, 37 | } 38 | 39 | export default config 40 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/class.d.ts: -------------------------------------------------------------------------------- 1 | export declare class CustomError extends Error { 2 | public readonly code: number; 3 | public readonly metadata: Record; 4 | constructor(message: string, code: number, metadata: Record); 5 | } 6 | export declare class CustomErrorWithMethod extends CustomError { 7 | logError(): void; 8 | } 9 | export declare class CustomErrorWithMethodAndType extends CustomError { 10 | logError(): void; 11 | getError(): Error; 12 | } 13 | export declare class CustomErrorWithMethodAndTypeAndReturn { 14 | public readonly code: number; 15 | public readonly metadata: Record; 16 | constructor(message: string, code: number, metadata: Record); 17 | logError(): void; 18 | getError(): Error; 19 | } 20 | export declare class Result { 21 | readonly value?: T | null; 22 | readonly error?: E | null; 23 | constructor(value?: T | null, error?: E | null); 24 | isOk(): this is { readonly value: T }; 25 | isErr(): this is { readonly error: E }; 26 | } 27 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0005.d.ts: -------------------------------------------------------------------------------- 1 | import type { ProcessingState } from './types'; 2 | /** 3 | * Extracts types from a TypeScript file and generates corresponding .d.ts content 4 | * @param filePath - Path to source TypeScript file 5 | */ 6 | export declare function extract(filePath: string): Promise; 7 | /** 8 | * Processes TypeScript source code and generates declaration types 9 | * @param sourceCode - TypeScript source code 10 | */ 11 | export declare function extractDtsTypes(sourceCode: string): string; 12 | /** 13 | * Check if a given type string represents a function type 14 | */ 15 | export declare function isFunctionType(type: string): boolean; 16 | /** 17 | * Check if a declaration is complete by examining its content 18 | * @param content - Content to check, either as a string or array of lines 19 | */ 20 | export declare function isDeclarationComplete(content: string | string[]): boolean; 21 | export declare function processSpecificDeclaration(declarationWithoutComments: string, fullDeclaration: string, state: ProcessingState): void; 22 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/type-only-imports.d.ts: -------------------------------------------------------------------------------- 1 | // Type-only imports should be preserved 2 | import type { TypeA, TypeB } from './types'; 3 | import type DefaultType from './default-type'; 4 | import { valueFunction, type TypeC } from './mixed-module'; 5 | import { regularValue } from './values'; 6 | 7 | // Type-only re-exports 8 | export type { TypeA, TypeB }; 9 | export type { TypeC as RenamedType }; 10 | export { valueFunction, type TypeD } from './other-module'; 11 | export type * from './all-types'; 12 | 13 | export declare function useTypes(a: TypeA, b: TypeB): TypeC; 14 | 15 | export interface Config { 16 | typeA: TypeA; 17 | typeB: TypeB; 18 | value: typeof regularValue; 19 | } 20 | 21 | export type Combined = TypeA & TypeB; 22 | 23 | export declare class Handler { 24 | private config: Config; 25 | constructor(config: Config); 26 | process(input: TypeA): TypeB; 27 | } 28 | 29 | export declare const instance: DefaultType; 30 | 31 | export type Conditional = T extends TypeA ? TypeB : TypeC; 32 | 33 | export type Mapped = { 34 | [K in keyof TypeA]: TypeB; 35 | }; 36 | -------------------------------------------------------------------------------- /docs/license.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2024 Stacks.js 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0009.d.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from './types'; 2 | /** 3 | * Load Config 4 | * 5 | * @param {object} options - The configuration options. 6 | * @param {string} options.name - The name of the configuration file. 7 | * @param {string} [options.cwd] - The current working directory. 8 | * @param {string} [options.endpoint] - The API endpoint to fetch config from in browser environments. 9 | * @param {string} [options.headers] - The headers to send with the request in browser environments. 10 | * @param {T} options.defaultConfig - The default configuration. 11 | * @returns {Promise} The merged configuration. 12 | * @example ```ts 13 | * // Merges arrays if both configs are arrays, otherwise does object deep merge 14 | * await loadConfig({ 15 | * name: 'example', 16 | * endpoint: '/api/my-custom-config/endpoint', 17 | * defaultConfig: [{ foo: 'bar' }] 18 | * }) 19 | * ``` 20 | */ 21 | export declare function loadConfig({ 22 | name, 23 | cwd, 24 | defaultConfig, 25 | endpoint, 26 | headers, 27 | }: Config): Promise; 28 | export * from './types'; 29 | export * from './utils'; 30 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2024 Open Web Foundation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0006.d.ts: -------------------------------------------------------------------------------- 1 | import { type Collection } from '@stacksjs/collections'; 2 | export declare const quotes: Collection; 3 | export { 4 | align, 5 | box, 6 | centerAlign, 7 | colorize, 8 | colors, 9 | getColor, 10 | leftAlign, 11 | rightAlign, 12 | stripAnsi, 13 | } from 'consola/utils'; 14 | export * as kolorist from 'kolorist'; 15 | export { 16 | ansi256, 17 | ansi256Bg, 18 | bgBlack, 19 | bgBlue, 20 | bgCyan, 21 | bgGray, 22 | bgGreen, 23 | bgLightBlue, 24 | bgLightCyan, 25 | bgLightGray, 26 | bgLightGreen, 27 | bgLightMagenta, 28 | bgLightRed, 29 | bgLightYellow, 30 | bgMagenta, 31 | bgRed, 32 | bgWhite, 33 | bgYellow, 34 | black, 35 | blue, 36 | bold, 37 | cyan, 38 | dim, 39 | gray, 40 | green, 41 | hidden, 42 | inverse, 43 | italic, 44 | lightBlue, 45 | lightCyan, 46 | lightGray, 47 | lightGreen, 48 | lightMagenta, 49 | lightRed, 50 | lightYellow, 51 | link, 52 | magenta, 53 | red, 54 | reset, 55 | strikethrough, 56 | stripColors, 57 | trueColor, 58 | trueColorBg, 59 | underline, 60 | white, 61 | yellow, 62 | } from 'kolorist'; 63 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/example/0002.ts: -------------------------------------------------------------------------------- 1 | import type { DtsGenerationOption } from '@stacksjs/dtsx' 2 | import type { BunPlugin } from 'bun' 3 | import process from 'node:process' 4 | import { generate } from '@stacksjs/dtsx' 5 | 6 | export function dts(options?: DtsGenerationOption): BunPlugin { 7 | return { 8 | name: 'bun-plugin-dtsx', 9 | 10 | async setup(build) { 11 | const cwd = options?.cwd ?? process.cwd() 12 | const root = options?.root ?? build.config.root 13 | const entrypoints = options?.entrypoints ?? build.config.entrypoints 14 | const outdir = options?.outdir ?? build.config.outdir 15 | // const keepComments = options?.keepComments ?? true 16 | const clean = options?.clean ?? false 17 | const tsconfigPath = options?.tsconfigPath ?? './tsconfig.json' 18 | 19 | await generate({ 20 | ...options, 21 | cwd, 22 | root, 23 | entrypoints, 24 | outdir, 25 | // keepComments, 26 | clean, 27 | tsconfigPath, 28 | }) 29 | }, 30 | } 31 | } 32 | 33 | export { generate } 34 | 35 | export type { DtsGenerationOption } 36 | 37 | export default dts 38 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0010.d.ts: -------------------------------------------------------------------------------- 1 | export declare function formatPhone(value: string, options?: FormatPhoneOptions): string; 2 | export declare function unformatPhone(value: string): string; 3 | export declare const DefaultPhoneDelimiter: DelimiterType; 4 | export declare const DefaultPhonePattern: number[]; 5 | export declare const DefaultPhoneRegion: 'US'; 6 | export declare const PHONE_PATTERNS: { 7 | US: readonly [3, 3, 4]; 8 | GB: readonly [4, 3, 3]; 9 | FR: readonly [2, 2, 2, 2, 2]; 10 | DE: readonly [3, 2, 2, 2]; 11 | JP: readonly [3, 4, 4]; 12 | CN: readonly [3, 4, 4]; 13 | IN: readonly [4, 3, 3]; 14 | BR: readonly [2, 4, 4]; 15 | AU: readonly [4, 3, 3]; 16 | CA: readonly [3, 3, 4] 17 | }; 18 | export declare const COUNTRY_CODES: { 19 | US: '+1'; 20 | GB: '+44'; 21 | FR: '+33'; 22 | DE: '+49'; 23 | JP: '+81'; 24 | CN: '+86'; 25 | IN: '+91'; 26 | BR: '+55'; 27 | AU: '+61'; 28 | CA: '+1' 29 | }; 30 | export declare interface FormatPhoneOptions { 31 | delimiter?: string 32 | pattern?: number[] 33 | region?: string 34 | includeCountryCode?: boolean 35 | format?: 'national' | 'international' 36 | } 37 | export type DelimiterType = string; 38 | -------------------------------------------------------------------------------- /docs/public/images/logo-mini.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/interface.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of interface declaration 3 | * with another comment in an extra line 4 | */ 5 | export declare interface User { 6 | id: number 7 | name: string 8 | email: string 9 | } 10 | export declare interface ApiResponse { 11 | status: number 12 | message: string 13 | data: T 14 | } 15 | /** 16 | * Example of an interface declaration 17 | * 18 | * with multiple lines of comments, including an empty line 19 | */ 20 | export declare interface ResponseData { 21 | success: boolean 22 | data: User[] 23 | } 24 | export declare interface Product { 25 | id: number 26 | name: string 27 | price: number 28 | } 29 | export declare interface AuthResponse { 30 | token: string 31 | expiresIn: number 32 | } 33 | // Complex Generic Types 34 | export declare interface ComplexGeneric, K extends keyof T> { 35 | data: T 36 | key: K 37 | value: T[K] 38 | transform: (input: T[K]) => string 39 | nested: Array> 40 | } 41 | // Default Type Parameters 42 | export declare interface DefaultGeneric = Record> { 43 | key: K 44 | value: T 45 | record: V 46 | } 47 | -------------------------------------------------------------------------------- /docs/public/images/logo-transparent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/public/images/logo-white-transparent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "lib": [ 5 | "esnext" 6 | ], 7 | "moduleDetection": "force", 8 | "module": "esnext", 9 | "moduleResolution": "bundler", 10 | "paths": { 11 | "@stacksjs/dtsx": [ 12 | "./packages/dtsx/src/index.ts" 13 | ], 14 | "bun-plugin-dtsx": [ 15 | "./packages/bun-plugin/src/index.ts" 16 | ], 17 | "vite-plugin-dtsx": [ 18 | "./packages/vite-plugin/src/index.ts" 19 | ] 20 | }, 21 | "resolveJsonModule": true, 22 | "allowImportingTsExtensions": true, 23 | "strict": true, 24 | "strictNullChecks": true, 25 | "noFallthroughCasesInSwitch": true, 26 | "declaration": true, 27 | "noEmit": true, 28 | "outDir": "./dist", 29 | "esModuleInterop": true, 30 | "forceConsistentCasingInFileNames": true, 31 | "isolatedDeclarations": true, 32 | "verbatimModuleSyntax": true, 33 | "skipDefaultLibCheck": true, 34 | "skipLibCheck": true 35 | }, 36 | "include": [ 37 | "packages/*/src/**/*.ts" 38 | ], 39 | "exclude": [ 40 | "node_modules", 41 | "**/node_modules", 42 | "**/node_modules/**", 43 | "dist", 44 | "**/dist", 45 | "**/dist/**", 46 | "**/*.d.ts", 47 | "**/build/**", 48 | "**/coverage/**" 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/type-interface-imports.ts: -------------------------------------------------------------------------------- 1 | // Regression test for type/interface imports in d.ts files 2 | // When a type or interface uses an imported type, the import should be included in the d.ts file 3 | 4 | import type { ParsedPath } from 'node:path' 5 | import { readFileSync } from 'node:fs' 6 | 7 | /** 8 | * Internal type that uses an imported type 9 | */ 10 | type FileInfo = { 11 | path: ParsedPath 12 | content: string 13 | } 14 | 15 | /** 16 | * Interface that uses an imported type 17 | */ 18 | interface FileMetadata { 19 | parsedPath: ParsedPath 20 | size: number 21 | } 22 | 23 | /** 24 | * Exported interface that uses another interface 25 | */ 26 | export interface FileDetails extends FileMetadata { 27 | name: string 28 | } 29 | 30 | /** 31 | * Exported function that returns a type using imported types 32 | */ 33 | export function getFileInfo(filePath: string): FileInfo { 34 | return { 35 | path: {} as ParsedPath, 36 | content: readFileSync(filePath, 'utf-8') 37 | } 38 | } 39 | 40 | /** 41 | * Exported function that uses interface parameter 42 | */ 43 | export function processFile(metadata: FileMetadata): void { 44 | console.log(metadata) 45 | } 46 | 47 | /** 48 | * Exported type alias that uses imported type 49 | */ 50 | export type PathInfo = ParsedPath & { 51 | exists: boolean 52 | } 53 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/TeamMember.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 43 | -------------------------------------------------------------------------------- /packages/bun-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bun-plugin-dtsx", 3 | "type": "module", 4 | "version": "0.9.9", 5 | "description": "A Bun Bundler plugin that auto generates your DTS types extremely fast.", 6 | "author": "Chris Breuer ", 7 | "license": "MIT", 8 | "homepage": "https://github.com/stacksjs/dtsx/tree/main/packages/bun-plugin#readme", 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/stacksjs/dtsx.git" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/stacksjs/bun-plugin-dtsx/issues" 15 | }, 16 | "keywords": [ 17 | "dts", 18 | "dtsx", 19 | "emit", 20 | "generation", 21 | "typescript", 22 | "types", 23 | "auto", 24 | "stacks", 25 | "bun", 26 | "plugin", 27 | "package" 28 | ], 29 | "exports": { 30 | ".": { 31 | "types": "./dist/index.d.ts", 32 | "import": "./dist/index.js" 33 | }, 34 | "./*": { 35 | "import": "./dist/*" 36 | } 37 | }, 38 | "module": "./dist/index.js", 39 | "types": "./dist/index.d.ts", 40 | "files": [ 41 | "LICENSE.md", 42 | "README.md", 43 | "dist" 44 | ], 45 | "scripts": { 46 | "build": "bun build.ts", 47 | "prepublishOnly": "bun run build", 48 | "test": "bun test", 49 | "typecheck": "bun tsc --noEmit" 50 | }, 51 | "dependencies": { 52 | "@stacksjs/dtsx": "workspace:*" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "dtsx" 7 | text: "Extremely fast & configurable DTS emitter." 8 | tagline: "For a better developer experience." 9 | image: /images/logo-white.png 10 | actions: 11 | - theme: brand 12 | text: Get Started 13 | link: /intro 14 | - theme: alt 15 | text: View on GitHub 16 | link: https://github.com/stacksjs/dtsx 17 | 18 | features: 19 | - title: "⚡ Fast .d.ts Generation" 20 | icon: "⚡" 21 | details: "Generate TypeScript declaration files quickly and efficiently." 22 | - title: "🔧 Highly Configurable" 23 | icon: "🔧" 24 | details: "Easily adjust settings to fit your project's needs with comprehensive configuration options." 25 | - title: "📦 Lightweight Library" 26 | icon: "📦" 27 | details: "Minimal footprint for seamless & performant integration with focused functionality." 28 | - title: "🌐 Cross-Platform Binary" 29 | icon: "🌐" 30 | details: "Compatible with multiple operating systems including macOS, Linux, and Windows." 31 | - title: "💬 Comment Preservation" 32 | icon: "💬" 33 | details: "Maintains JSDoc and documentation comments in generated declarations by default." 34 | - title: "🧠 Smart Type Inference" 35 | icon: "🧠" 36 | details: "Intelligent type inference for complex structures including narrow types for constants." 37 | --- 38 | 39 | 40 | -------------------------------------------------------------------------------- /packages/dtsx/test/debug-single.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import type { DtsGenerationOption } from '../src/types' 3 | import { writeFile } from 'node:fs/promises' 4 | import { join } from 'node:path' 5 | import process from 'node:process' 6 | import { generate } from '../src/generator' 7 | 8 | async function debugSingle() { 9 | const testDir = join(__dirname, 'fixtures') 10 | const inputDir = join(testDir, 'input') 11 | const generatedDir = join(testDir, 'generated') 12 | 13 | const config: DtsGenerationOption = { 14 | entrypoints: [join(inputDir, 'variable.ts')], 15 | outdir: generatedDir, 16 | clean: false, 17 | tsconfigPath: join(__dirname, '..', 'tsconfig.json'), 18 | outputStructure: 'flat', 19 | verbose: false, 20 | cwd: process.cwd(), 21 | root: '.', 22 | } 23 | 24 | await generate(config) 25 | 26 | const generatedPath = join(generatedDir, 'variable.d.ts') 27 | const outputPath = join(testDir, 'output', 'variable.d.ts') 28 | 29 | const generatedContent = await Bun.file(generatedPath).text() 30 | const expectedContent = await Bun.file(outputPath).text() 31 | 32 | // Save both for comparison 33 | await writeFile('generated-variable.d.ts', generatedContent) 34 | await writeFile('expected-variable.d.ts', expectedContent) 35 | 36 | console.log('Files saved for comparison:') 37 | console.log('- generated-variable.d.ts') 38 | console.log('- expected-variable.d.ts') 39 | } 40 | 41 | debugSingle() 42 | -------------------------------------------------------------------------------- /packages/tsup-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsup-plugin-dtsx", 3 | "type": "module", 4 | "version": "0.9.9", 5 | "description": "A tsup plugin that auto generates your DTS types extremely fast.", 6 | "author": "Chris Breuer ", 7 | "license": "MIT", 8 | "homepage": "https://github.com/stacksjs/dtsx/tree/main/packages/tsup-plugin#readme", 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/stacksjs/dtsx.git" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/stacksjs/dtsx/issues" 15 | }, 16 | "keywords": [ 17 | "dts", 18 | "dtsx", 19 | "emit", 20 | "generation", 21 | "typescript", 22 | "types", 23 | "auto", 24 | "stacks", 25 | "tsup", 26 | "plugin", 27 | "package" 28 | ], 29 | "exports": { 30 | ".": { 31 | "types": "./dist/index.d.ts", 32 | "import": "./dist/index.js" 33 | }, 34 | "./*": { 35 | "import": "./dist/*" 36 | } 37 | }, 38 | "module": "./dist/index.js", 39 | "types": "./dist/index.d.ts", 40 | "files": [ 41 | "LICENSE.md", 42 | "README.md", 43 | "dist" 44 | ], 45 | "scripts": { 46 | "build": "bun build.ts", 47 | "prepublishOnly": "bun run build", 48 | "test": "bun test", 49 | "typecheck": "bun tsc --noEmit" 50 | }, 51 | "dependencies": { 52 | "@stacksjs/dtsx": "workspace:*" 53 | }, 54 | "peerDependencies": { 55 | "tsup": "^6.0.0 || ^7.0.0 || ^8.0.0" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/esbuild-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "esbuild-plugin-dtsx", 3 | "type": "module", 4 | "version": "0.9.9", 5 | "description": "An esbuild plugin that auto generates your DTS types extremely fast.", 6 | "author": "Chris Breuer ", 7 | "license": "MIT", 8 | "homepage": "https://github.com/stacksjs/dtsx/tree/main/packages/esbuild-plugin#readme", 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/stacksjs/dtsx.git" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/stacksjs/dtsx/issues" 15 | }, 16 | "keywords": [ 17 | "dts", 18 | "dtsx", 19 | "emit", 20 | "generation", 21 | "typescript", 22 | "types", 23 | "auto", 24 | "stacks", 25 | "esbuild", 26 | "plugin", 27 | "package" 28 | ], 29 | "exports": { 30 | ".": { 31 | "types": "./dist/index.d.ts", 32 | "import": "./dist/index.js" 33 | }, 34 | "./*": { 35 | "import": "./dist/*" 36 | } 37 | }, 38 | "module": "./dist/index.js", 39 | "types": "./dist/index.d.ts", 40 | "files": [ 41 | "LICENSE.md", 42 | "README.md", 43 | "dist" 44 | ], 45 | "scripts": { 46 | "build": "bun build.ts", 47 | "prepublishOnly": "bun run build", 48 | "test": "bun test", 49 | "typecheck": "bun tsc --noEmit" 50 | }, 51 | "dependencies": { 52 | "@stacksjs/dtsx": "workspace:*" 53 | }, 54 | "peerDependencies": { 55 | "esbuild": ">=0.17.0" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/webpack-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-plugin-dtsx", 3 | "type": "module", 4 | "version": "0.9.9", 5 | "description": "A webpack plugin that auto generates your DTS types extremely fast.", 6 | "author": "Chris Breuer ", 7 | "license": "MIT", 8 | "homepage": "https://github.com/stacksjs/dtsx/tree/main/packages/webpack-plugin#readme", 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/stacksjs/dtsx.git" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/stacksjs/dtsx/issues" 15 | }, 16 | "keywords": [ 17 | "dts", 18 | "dtsx", 19 | "emit", 20 | "generation", 21 | "typescript", 22 | "types", 23 | "auto", 24 | "stacks", 25 | "webpack", 26 | "plugin", 27 | "package" 28 | ], 29 | "exports": { 30 | ".": { 31 | "types": "./dist/index.d.ts", 32 | "import": "./dist/index.js" 33 | }, 34 | "./*": { 35 | "import": "./dist/*" 36 | } 37 | }, 38 | "module": "./dist/index.js", 39 | "types": "./dist/index.d.ts", 40 | "files": [ 41 | "LICENSE.md", 42 | "README.md", 43 | "dist" 44 | ], 45 | "scripts": { 46 | "build": "bun build.ts", 47 | "prepublishOnly": "bun run build", 48 | "test": "bun test", 49 | "typecheck": "bun tsc --noEmit" 50 | }, 51 | "dependencies": { 52 | "@stacksjs/dtsx": "workspace:*" 53 | }, 54 | "peerDependencies": { 55 | "webpack": "^4.0.0 || ^5.0.0" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /docs/.vitepress/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'node:path' 2 | // import Inspect from 'vite-plugin-inspect' 3 | import UnoCSS from 'unocss/vite' 4 | import IconsResolver from 'unplugin-icons/resolver' 5 | import Icons from 'unplugin-icons/vite' 6 | import Components from 'unplugin-vue-components/vite' 7 | import { defineConfig } from 'vite' 8 | 9 | export default defineConfig({ 10 | build: { 11 | assetsDir: 'assets', 12 | rollupOptions: { 13 | output: { 14 | assetFileNames: 'assets/[name].[hash][extname]', 15 | }, 16 | }, 17 | }, 18 | 19 | resolve: { 20 | dedupe: [ 21 | 'vue', 22 | '@vue/runtime-core', 23 | ], 24 | }, 25 | 26 | plugins: [ 27 | // custom 28 | // MarkdownTransform(), 29 | // Contributors(contributions), 30 | 31 | // plugins 32 | Components({ 33 | dirs: resolve(__dirname, 'theme/components'), 34 | include: [/\.vue$/, /\.vue\?vue/, /\.md$/], 35 | resolvers: [ 36 | IconsResolver({ 37 | componentPrefix: '', 38 | }), 39 | ], 40 | dts: resolve(__dirname, 'components.d.ts'), 41 | transformer: 'vue3', 42 | }), 43 | 44 | Icons({ 45 | compiler: 'vue3', 46 | defaultStyle: 'display: inline-block', 47 | }), 48 | 49 | UnoCSS(resolve(__dirname, 'unocss.config.ts')), 50 | 51 | // Inspect(), 52 | ], 53 | 54 | optimizeDeps: { 55 | exclude: [ 56 | // 'vue', 57 | 'body-scroll-lock', 58 | ], 59 | }, 60 | }) 61 | -------------------------------------------------------------------------------- /docs/public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/example/0003.ts: -------------------------------------------------------------------------------- 1 | import type { PluginBuilder } from 'bun' 2 | import type { UnimportOptions } from 'unimport' 3 | 4 | function getLoader(path: string): string { 5 | return path.endsWith('ts') 6 | ? 'ts' 7 | : path.endsWith('js') 8 | ? 'js' 9 | : path.endsWith('tsx') 10 | ? 'tsx' 11 | : 'jsx' 12 | } 13 | 14 | interface AutoImportsPlugin { 15 | name: string 16 | setup: (builder: PluginBuilder) => Promise 17 | } 18 | 19 | export function autoImports(options: Partial): AutoImportsPlugin { 20 | return { 21 | name: 'bun-plugin-auto-imports', 22 | 23 | async setup(builder: PluginBuilder): Promise { 24 | const { createUnimport } = await import('unimport') 25 | const { injectImports, generateTypeDeclarations } = createUnimport({ 26 | ...options, 27 | dts: undefined, 28 | } as UnimportOptions) 29 | 30 | const dtsContent = await generateTypeDeclarations() 31 | Bun.write(options.dts ?? './auto-import.d.ts', dtsContent) 32 | 33 | builder.onLoad({ filter: /.*/ }, async (args) => { 34 | const fileContent = await Bun.file(args.path).text() 35 | const transformedFileContent = await injectImports(fileContent) 36 | 37 | return { 38 | contents: transformedFileContent.code, 39 | loader: getLoader(args.path), 40 | } 41 | }) 42 | }, 43 | } 44 | } 45 | 46 | export type AutoImportsOptions = UnimportOptions 47 | 48 | export default autoImports 49 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/class.ts: -------------------------------------------------------------------------------- 1 | export class CustomError extends Error { 2 | constructor( 3 | message: string, 4 | public readonly code: number, 5 | public readonly metadata: Record 6 | ) { 7 | super(message) 8 | this.name = 'CustomError' 9 | } 10 | } 11 | 12 | export class CustomErrorWithMethod extends CustomError { 13 | logError() { 14 | console.error(`[${this.code}] ${this.message}`) 15 | } 16 | } 17 | 18 | export class CustomErrorWithMethodAndType extends CustomError { 19 | logError(): void { 20 | console.error(`[${this.code}] ${this.message}`) 21 | } 22 | 23 | getError(): Error { 24 | return this 25 | } 26 | } 27 | 28 | export class CustomErrorWithMethodAndTypeAndReturn { 29 | constructor( 30 | private message: string, 31 | public readonly code: number, 32 | public readonly metadata: Record 33 | ) { 34 | this.message = message 35 | this.code = code 36 | this.metadata = metadata 37 | } 38 | 39 | logError(): void { 40 | console.error(`[${this.code}] ${this.message}`) 41 | } 42 | 43 | getError(): Error { 44 | return new Error(this.message) 45 | } 46 | } 47 | 48 | export class Result { 49 | constructor( 50 | readonly value: T | null = null, 51 | readonly error: E | null = null 52 | ) {} 53 | 54 | isOk(): this is { readonly value: T } { 55 | return this.value !== null && this.error === null; 56 | } 57 | 58 | isErr(): this is { readonly error: E } { 59 | return this.error !== null && this.value === null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Releaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | npm: 10 | name: npm 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v6.0.0 15 | with: 16 | fetch-depth: 0 17 | 18 | - name: Install Bun 19 | uses: oven-sh/setup-bun@v2.0.2 20 | # env: 21 | # BUN_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 22 | with: 23 | bun-version: latest 24 | 25 | - name: Use cached node_modules 26 | uses: actions/cache@v4.3.0 27 | with: 28 | path: node_modules 29 | key: node-modules-${{ hashFiles('**/bun.lock') }} 30 | restore-keys: | 31 | node-modules- 32 | 33 | - name: Install Dependencies 34 | run: bun install 35 | 36 | - name: Publish to npm 37 | run: ./scripts/publish.sh 38 | env: 39 | BUN_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 40 | 41 | - name: Create GitHub release 42 | run: bunx changelogithub 43 | env: 44 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 45 | 46 | - name: Attach Binaries 47 | uses: stacksjs/action-releaser@v1.2.7 48 | with: 49 | files: | 50 | packages/dtsx/bin/dtsx-linux-x64.zip 51 | packages/dtsx/bin/dtsx-linux-arm64.zip 52 | packages/dtsx/bin/dtsx-windows-x64.zip 53 | packages/dtsx/bin/dtsx-darwin-x64.zip 54 | packages/dtsx/bin/dtsx-darwin-arm64.zip 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | -------------------------------------------------------------------------------- /docs/public/images/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /scripts/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Exit on error 4 | set -e 5 | 6 | # Enable debug if needed 7 | # set -x 8 | 9 | echo "Publishing all packages..." 10 | 11 | for dir in packages/*/ ; do 12 | if [ -d "$dir" ]; then 13 | package_name=$(basename "$dir") 14 | package_json="$dir/package.json" 15 | 16 | echo "----------------------------------------" 17 | echo "Processing $package_name..." 18 | 19 | # Check if package is private using Bun 20 | if command -v bun >/dev/null 2>&1; then 21 | is_private=$(bun --eval "try { const pkg = JSON.parse(require('fs').readFileSync('$package_json', 'utf8')); console.log(pkg.private === true ? 'true' : 'false'); } catch(e) { console.log('false'); }") 22 | # Then try jq as a fallback 23 | elif command -v jq >/dev/null 2>&1; then 24 | is_private=$(jq -r '.private // false' "$package_json") 25 | # Finally fall back to grep 26 | else 27 | private_check=$(grep -E '"private":\s*true' "$package_json" || echo "") 28 | if [ -n "$private_check" ]; then 29 | is_private="true" 30 | else 31 | is_private="false" 32 | fi 33 | fi 34 | 35 | echo "Package $package_name private status: $is_private" 36 | 37 | if [ "$is_private" = "true" ]; then 38 | echo "Skipping $package_name (private package)" 39 | else 40 | echo "Publishing $package_name..." 41 | cd "$dir" 42 | bun publish --access public 43 | cd - > /dev/null # Suppress the directory change message 44 | fi 45 | 46 | echo "----------------------------------------" 47 | fi 48 | done 49 | 50 | echo "All packages published successfully!" -------------------------------------------------------------------------------- /docs/public/images/favicon-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/type-only-imports.ts: -------------------------------------------------------------------------------- 1 | // Test file for type-only import/export handling 2 | 3 | // Type-only imports 4 | import type { TypeA, TypeB } from './types' 5 | import type DefaultType from './default-type' 6 | 7 | // Mixed imports - value and type 8 | import { valueFunction, type TypeC } from './mixed-module' 9 | 10 | // Regular value imports 11 | import { regularValue } from './values' 12 | 13 | // Type-only re-exports 14 | export type { TypeA, TypeB } 15 | export type { TypeC as RenamedType } 16 | 17 | // Mixed re-exports from module 18 | export { valueFunction, type TypeD } from './other-module' 19 | 20 | // Re-export all types 21 | export type * from './all-types' 22 | 23 | // Regular exports that use imported types 24 | export function useTypes(a: TypeA, b: TypeB): TypeC { 25 | return {} as TypeC 26 | } 27 | 28 | // Interface using imported type 29 | export interface Config { 30 | typeA: TypeA 31 | typeB: TypeB 32 | value: typeof regularValue 33 | } 34 | 35 | // Type alias using imported type 36 | export type Combined = TypeA & TypeB 37 | 38 | // Class using imported types 39 | export class Handler { 40 | private config: Config 41 | 42 | constructor(config: Config) { 43 | this.config = config 44 | } 45 | 46 | process(input: TypeA): TypeB { 47 | return {} as TypeB 48 | } 49 | } 50 | 51 | // Default type usage 52 | export const instance: DefaultType = {} as DefaultType 53 | 54 | // Conditional type with imported types 55 | export type Conditional = T extends TypeA ? TypeB : TypeC 56 | 57 | // Mapped type with imported types 58 | export type Mapped = { 59 | [K in keyof TypeA]: TypeB 60 | } 61 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0007.d.ts: -------------------------------------------------------------------------------- 1 | import forge, { pki, tls } from 'node-forge'; 2 | import type { CAOptions, CertificateOptions, GenerateCertReturn, TlsOption } from './types'; 3 | /** 4 | * Generate a random serial number for the Certificate 5 | * @returns The serial number for the Certificate 6 | */ 7 | export declare function generateRandomSerial(verbose?: boolean): string; 8 | export declare function calculateValidityDates(options: { 9 | validityDays?: number 10 | validityYears?: number 11 | notBeforeDays?: number 12 | verbose?: boolean 13 | }): { notBefore: Date, notAfter: Date }; 14 | export declare function createRootCA(options?: CAOptions): Promise; 15 | export declare function generateCertificate(options: CertificateOptions): Promise; 16 | /** 17 | * Add a certificate to the system trust store and save the certificate to a file 18 | * @param cert 19 | * @param caCert 20 | * @param options 21 | * @returns The path to the stored certificate 22 | */ 23 | export declare function addCertToSystemTrustStoreAndSaveCert(cert: Cert, caCert: string, options?: TlsOption): Promise; 24 | export declare function storeCertificate(cert: Cert, options?: TlsOption): string; 25 | /** 26 | * Store the CA Certificate 27 | * @param caCert - The CA Certificate 28 | * @param options - The options for storing the CA Certificate 29 | * @returns The path to the CA Certificate 30 | */ 31 | export declare function storeCACertificate(caCert: string, options?: TlsOption): string; 32 | export declare interface Cert { 33 | certificate: string 34 | privateKey: string 35 | } 36 | export { forge, pki, tls }; 37 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/function.d.ts: -------------------------------------------------------------------------------- 1 | import type { BunPlugin } from 'bun'; 2 | import type { DtsGenerationOption } from '@stacksjs/dtsx'; 3 | /** 4 | * Example of function declaration 5 | * 6 | * 7 | * with multiple empty lines, including an empty lines 8 | */ 9 | export declare function fetchUsers(): Promise; 10 | /** 11 | * Example of function declaration 12 | */ 13 | export declare function getProduct(id: number): Promise>; 14 | export declare function authenticate(user: string, password: string): Promise; 15 | export declare function dts(options?: DtsGenerationOption): BunPlugin; 16 | export declare function loadConfig>({ name, cwd, defaultConfig }: Options): Promise; 17 | // Complex Function Overloads 18 | export declare function processData(data: string): string; 19 | export declare function processData(data: number): number; 20 | export declare function processData(data: boolean): boolean; 21 | export declare function processData(data: T): T; 22 | // Complex Async Patterns -> due to isolatedDeclarations, we can assume the return type here 23 | export declare function complexAsyncGenerator(): any; 24 | // Type Assertions and Guards 25 | export declare function isUser(value: unknown): value is User; 26 | /** 27 | * Extract complete function signature using regex 28 | */ 29 | export declare function extractFunctionSignature(declaration: string): FunctionSignature; 30 | // Type Inference in Functions 31 | export declare function createApi any>>(endpoints: T): { [K in keyof T]: ReturnType extends Promise ? R : ReturnType }; 32 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/namespace.d.ts: -------------------------------------------------------------------------------- 1 | // Namespace declarations 2 | export declare namespace Utils { 3 | export function formatDate(date: Date): string; 4 | export interface Options { 5 | locale: string 6 | timezone: string 7 | } 8 | export const VERSION: string; 9 | export namespace Validators { 10 | export function isEmail(value: string): boolean; 11 | export function isURL(value: string): boolean; 12 | } 13 | } 14 | // Module declaration 15 | declare module 'custom-module' { 16 | export interface CustomType { 17 | id: string 18 | data: any 19 | } 20 | export function process(input: CustomType): Promise; 21 | } 22 | // Module augmentation 23 | declare module 'existing-module' { 24 | interface ExistingInterface { 25 | newProperty: string 26 | newMethod(): void 27 | } 28 | export function newFunction(): void; 29 | } 30 | // Global augmentation 31 | declare global { 32 | interface Window { 33 | customProperty: string 34 | customMethod(): void 35 | } 36 | namespace NodeJS { 37 | interface ProcessEnv { 38 | CUSTOM_ENV_VAR: string 39 | } 40 | } 41 | } 42 | // Ambient module 43 | declare module '*.css' { 44 | const content: { [className: string]: string }; 45 | export default content; 46 | } 47 | declare module '*.svg' { 48 | const content: string; 49 | export default content; 50 | } 51 | // Namespace with type exports 52 | export declare namespace Types { 53 | export type ID = string | number 54 | export type Nullable = T | null 55 | export type Optional = T | undefined 56 | export interface User { 57 | id: ID 58 | name: string 59 | email: string 60 | } 61 | export enum Status { 62 | Active = 'ACTIVE', 63 | Inactive = 'INACTIVE', 64 | Pending = 'PENDING' 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0011.d.ts: -------------------------------------------------------------------------------- 1 | export declare const bunshPackage: { 2 | name: 'bun'; 3 | domain: 'bun.sh'; 4 | description: 'Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one'; 5 | packageYmlUrl: 'https://github.com/pkgxdev/pantry/tree/main/projects/bun.sh/package.yml'; 6 | homepageUrl: ''; 7 | githubUrl: 'https://github.com/pkgxdev/pantry/'; 8 | installCommand: 'sh <(curl https://pkgx.sh) +bun.sh -- $SHELL -i'; 9 | programs: readonly ['bun', 'bunx']; 10 | companions: readonly []; 11 | dependencies: readonly []; 12 | versions: readonly ['1.2.14', '1.2.13', '1.2.12', '1.2.11', '1.2.10', '1.2.9', '1.2.8', '1.2.7', '1.2.6', '1.2.5', '1.2.4', '1.2.3', '1.2.2', '1.2.1', '1.2.0', '1.1.45', '1.1.44', '1.1.43', '1.1.42', '1.1.41', '1.1.40', '1.1.39', '1.1.38', '1.1.37', '1.1.36', '1.1.35', '1.1.34', '1.1.33', '1.1.32', '1.1.31', '1.1.30', '1.1.29', '1.1.28', '1.1.27', '1.1.26', '1.1.25', '1.1.24', '1.1.23', '1.1.22', '1.1.21', '1.1.20', '1.1.19', '1.1.18', '1.1.17', '1.1.16', '1.1.15', '1.1.14', '1.1.13', '1.1.12', '1.1.11', '1.1.10', '1.1.9', '1.1.8', '1.1.7', '1.1.6', '1.1.5', '1.1.4', '1.1.3', '1.1.2', '1.1.1', '1.1.0', '1.0.36', '1.0.35', '1.0.34', '1.0.33', '1.0.32', '1.0.31', '1.0.30', '1.0.29', '1.0.28', '1.0.27', '1.0.26', '1.0.25', '1.0.24', '1.0.23', '1.0.22', '1.0.21', '1.0.20', '1.0.19', '1.0.18', '1.0.17', '1.0.16', '1.0.14', '1.0.13', '1.0.12', '1.0.11', '1.0.10', '1.0.9', '1.0.8', '1.0.7', '1.0.6', '1.0.5', '1.0.4', '1.0.3', '1.0.2', '1.0.1', '1.0.0', '0.8.1', '0.8.0', '0.7.2', '0.7.1', '0.7.0', '0.6.14', '0.6.13', '0.6.12', '0.6.11', '0.6.10', '0.6.8', '0.6.7', '0.6.6', '0.6.5', '0.6.4', '0.6.3', '0.6.2', '0.6.1', '0.6.0', '0.5.9', '0.5.6']; 13 | fullPath: 'bun.sh'; 14 | aliases: readonly ['bun'] 15 | }; 16 | export type BunshPackage = typeof bunshPackage; 17 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/private-members.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Test fixture for private member handling in class declarations 3 | * Private members should be excluded from .d.ts output 4 | * Modifier order should be: private/protected, static, abstract, readonly 5 | */ 6 | // Class with private static members - should be excluded from d.ts 7 | export declare class CacheManager { 8 | static readonly MAX_SIZE: any; 9 | static get(key: string): unknown; 10 | static set(key: string, value: unknown): void; 11 | static clear(): void; 12 | } 13 | // Class with mixed visibility modifiers 14 | export declare class MixedVisibility { 15 | protected protectedField: string; 16 | publicField: string; 17 | readonly readonlyField: string; 18 | protected static protectedStaticField: number; 19 | static publicStaticField: number; 20 | static readonly staticReadonlyField: number; 21 | protected protectedMethod(): void; 22 | publicMethod(): void; 23 | protected static protectedStaticMethod(): void; 24 | static publicStaticMethod(): void; 25 | } 26 | // Class with private accessors 27 | export declare class PrivateAccessors { 28 | protected get protectedGetter(): number; 29 | protected set protectedSetter(val: number); 30 | get publicGetter(): number; 31 | set publicSetter(val: number); 32 | } 33 | // Class with private constructor parameter properties 34 | export declare class ParameterProperties { 35 | protected protectedParam: string; 36 | public publicParam: string; 37 | readonly readonlyParam: string; 38 | constructor(privateParam: string, protectedParam: string, publicParam: string, readonlyParam: string); 39 | } 40 | // Abstract class with private members 41 | export declare abstract class AbstractWithPrivate { 42 | protected abstract protectedAbstractMethod(): void; 43 | abstract publicAbstractMethod(): void; 44 | } 45 | -------------------------------------------------------------------------------- /docs/intro.md: -------------------------------------------------------------------------------- 1 |

Social Card of this repo

2 | 3 | ## Features 4 | 5 | - Fast .d.ts generation 6 | - Highly configurable 7 | - Lightweight library 8 | - Cross-platform binary 9 | 10 | ## Changelog 11 | 12 | Please see our [releases](https://github.com/stacksjs/stacks/releases) page for more information on what has changed recently. 13 | 14 | ## Contributing 15 | 16 | Please review the [Contributing Guide](https://github.com/stacksjs/contributing) for details. 17 | 18 | ## Stargazers 19 | 20 | [![Stargazers over time](https://starchart.cc/stacksjs/dtsx.svg?variant=adaptive)](https://starchart.cc/stacksjs/dtsx) 21 | 22 | ## Community 23 | 24 | For help, discussion about best practices, or any other conversation that would benefit from being searchable: 25 | 26 | [Discussions on GitHub](https://github.com/stacksjs/stacks/discussions) 27 | 28 | For casual chit-chat with others using this package: 29 | 30 | [Join the Stacks Discord Server](https://discord.gg/stacksjs) 31 | 32 | ## Postcardware 33 | 34 | Two things are true: Stacks OSS will always stay open-source, and we do love to receive postcards from wherever Stacks is used! 🌍 _We also publish them on our website. And thank you, Spatie_ 35 | 36 | Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094 37 | 38 | ## Sponsors 39 | 40 | We would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us. 41 | 42 | - [JetBrains](https://www.jetbrains.com/) 43 | - [The Solana Foundation](https://solana.com/) 44 | 45 | ## Credits 46 | 47 | - [Chris Breuer](https://github.com/chrisbbreuer) 48 | - [All Contributors](https://github.com/stacksjs/dtsx/graphs/contributors) 49 | 50 | ## License 51 | 52 | The MIT License (MIT). Please see [LICENSE](https://github.com/stacksjs/stacks/tree/main/LICENSE.md) for more information. 53 | 54 | Made with 💙 55 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/namespace.ts: -------------------------------------------------------------------------------- 1 | // Namespace declarations 2 | export namespace Utils { 3 | export function formatDate(date: Date): string { 4 | return date.toISOString() 5 | } 6 | 7 | export interface Options { 8 | locale: string 9 | timezone: string 10 | } 11 | 12 | export const VERSION = '1.0.0' 13 | 14 | export namespace Validators { 15 | export function isEmail(value: string): boolean { 16 | return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) 17 | } 18 | 19 | export function isURL(value: string): boolean { 20 | try { 21 | new URL(value) 22 | return true 23 | } catch { 24 | return false 25 | } 26 | } 27 | } 28 | } 29 | 30 | // Module declaration 31 | declare module 'custom-module' { 32 | export interface CustomType { 33 | id: string 34 | data: any 35 | } 36 | 37 | export function process(input: CustomType): Promise 38 | } 39 | 40 | // Module augmentation 41 | declare module 'existing-module' { 42 | interface ExistingInterface { 43 | newProperty: string 44 | newMethod(): void 45 | } 46 | 47 | export function newFunction(): void 48 | } 49 | 50 | // Global augmentation 51 | declare global { 52 | interface Window { 53 | customProperty: string 54 | customMethod(): void 55 | } 56 | 57 | namespace NodeJS { 58 | interface ProcessEnv { 59 | CUSTOM_ENV_VAR: string 60 | } 61 | } 62 | } 63 | 64 | // Ambient module 65 | declare module '*.css' { 66 | const content: { [className: string]: string } 67 | export default content 68 | } 69 | 70 | declare module '*.svg' { 71 | const content: string 72 | export default content 73 | } 74 | 75 | // Namespace with type exports 76 | export namespace Types { 77 | export type ID = string | number 78 | export type Nullable = T | null 79 | export type Optional = T | undefined 80 | 81 | export interface User { 82 | id: ID 83 | name: string 84 | email: string 85 | } 86 | 87 | export enum Status { 88 | Active = 'ACTIVE', 89 | Inactive = 'INACTIVE', 90 | Pending = 'PENDING' 91 | } 92 | } -------------------------------------------------------------------------------- /packages/dtsx/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @stacksjs/dtsx - A modern, fast .d.ts generation tool 3 | * 4 | * This module exports the full API. For minimal bundle size when only 5 | * using the core generator, import directly from './generator'. 6 | * 7 | * Core exports (most commonly used): 8 | * - generate, watch, processFile, processSource from './generator' 9 | * - extractDeclarations, extractDeclarationsAsync from './extractor' 10 | * - processDeclarations from './processor' 11 | * - DtsGenerationConfig, Declaration types from './types' 12 | * 13 | * Optional/Advanced exports are available but may increase bundle size: 14 | * - LSP support: './lsp' 15 | * - Type checking: './checker' 16 | * - Circular dependency detection: './circular' 17 | * - Custom transformers: './transformers' 18 | * - Worker pool: './worker' 19 | */ 20 | 21 | // Common utilities 22 | export * from './branded-types' 23 | export * from './bundler' 24 | export * from './cache' 25 | export * from './checker' 26 | // Advanced features - larger bundle impact 27 | export * from './circular' 28 | export * from './compat' 29 | export * from './config' 30 | 31 | export * from './diff' 32 | export * from './docs' 33 | export * from './errors' 34 | export * from './extractor' 35 | export * from './formats' 36 | export * from './formatter' 37 | // Core API - essential for dts generation 38 | export * from './generator' 39 | export * from './import-sorter' 40 | 41 | export * from './incremental' 42 | export * from './logger' 43 | export * from './lsp' 44 | export * from './memory' 45 | export * from './merger' 46 | export * from './optimizer' 47 | export * from './output-normalizer' 48 | export * from './parallel-processor' 49 | export * from './parser' 50 | export * from './plugins' 51 | export * from './processor' 52 | export * from './profiling' 53 | export * from './security' 54 | export * from './sourcemap' 55 | export * from './tracking' 56 | export * from './transformers' 57 | export * from './tree-shaker' 58 | export * from './type-mappings' 59 | export * from './types' 60 | export * from './utils' 61 | export * from './watcher' 62 | export * from './worker' 63 | export * from './workspace' 64 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/abseil.io.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * **abseil.io** - Abseil Common Libraries (C++) 3 | * 4 | * @domain `abseil.io` 5 | * @version `20250512.0.0` (17 versions available) 6 | * @versions From newest version to oldest. @see https://ts-pkgx.netlify.app/packages/abseil-io.md 7 | * 8 | * @install `sh <(curl https://pkgx.sh) +abseil.io -- $SHELL -i` 9 | * 10 | * @example 11 | * ```typescript 12 | * import { pantry } from 'ts-pkgx' 13 | * 14 | * const pkg = pantry.abseilio 15 | * console.log(pkg.name) // "abseil.io" 16 | * console.log(pkg.description) // "Abseil Common Libraries (C++)" 17 | * console.log(pkg.versions[0]) // "20250512.0.0" (latest) 18 | * ``` 19 | * 20 | * @see https://ts-pkgx.netlify.app/packages/abseil-io.md 21 | * @see https://ts-pkgx.netlify.app/usage 22 | */ 23 | export declare const abseilioPackage: { 24 | /** 25 | * The display name of this package. 26 | */ 27 | name: 'abseil.io'; 28 | /** 29 | * The canonical domain name for this package. 30 | */ 31 | domain: 'abseil.io'; 32 | /** 33 | * Brief description of what this package does. 34 | */ 35 | description: 'Abseil Common Libraries (C++)'; 36 | packageYmlUrl: 'https://github.com/pkgxdev/pantry/tree/main/projects/abseil.io/package.yml'; 37 | homepageUrl: ''; 38 | githubUrl: 'https://github.com/pkgxdev/pantry/'; 39 | /** 40 | * Command to install this package using pkgx. 41 | * @example sh <(curl https://pkgx.sh) +package-name 42 | */ 43 | installCommand: 'sh <(curl https://pkgx.sh) +abseil.io -- $SHELL -i'; 44 | programs: readonly []; 45 | companions: readonly []; 46 | dependencies: readonly []; 47 | /** 48 | * Available versions from newest to oldest. 49 | * @see https://ts-pkgx.netlify.app/usage for installation instructions 50 | */ 51 | versions: readonly ['20250512.0.0', '20250127.1.0', '20250127.0.0', '20240722.1.0', '20240722.0.0', '20240116.3.0', '20240116.2.0', '20240116.1.0', '20240116.0.0', '20230802.3.0', '20230802.2.0', '20230802.1.0', '20230802.0.0', '20230125.4.0', '20230125.3.0', '20230125.2.0', '20220623.2.0']; 52 | aliases: readonly []; 53 | fullPath: 'abseil.io' 54 | }; 55 | export type AbseilioPackage = typeof abseilioPackage; 56 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of interface declaration 3 | * with another comment in an extra line 4 | */ 5 | export interface User { 6 | id: number 7 | name: string 8 | email: string 9 | } 10 | 11 | export interface ApiResponse { 12 | status: number 13 | message: string 14 | data: T 15 | } 16 | 17 | /** 18 | * Example of an interface declaration 19 | * 20 | * with multiple lines of comments, including an empty line 21 | */ 22 | export interface ResponseData { 23 | success: boolean 24 | data: User[] 25 | } 26 | 27 | export interface Product { 28 | id: number 29 | name: string 30 | price: number 31 | } 32 | 33 | export interface AuthResponse { 34 | token: string 35 | expiresIn: number 36 | } 37 | 38 | interface Options { 39 | name: string 40 | cwd?: string 41 | defaultConfig: T 42 | } 43 | 44 | // Complex Generic Types 45 | export interface ComplexGeneric, K extends keyof T> { 46 | data: T 47 | key: K 48 | value: T[K] 49 | transform: (input: T[K]) => string 50 | nested: Array> 51 | } 52 | 53 | // Default Type Parameters 54 | export interface DefaultGeneric< 55 | T = string, 56 | K extends keyof any = string, 57 | V extends Record = Record 58 | > { 59 | key: K 60 | value: T 61 | record: V 62 | } 63 | 64 | /** 65 | * Regular expression patterns used throughout the module 66 | */ 67 | // interface RegexPatterns { 68 | // /** Import type declarations */ 69 | // readonly typeImport: RegExp 70 | // /** Regular import declarations */ 71 | // readonly regularImport: RegExp 72 | // /** Async function declarations */ 73 | // readonly asyncFunction: RegExp 74 | // /** Generic type parameters */ 75 | // readonly functionOverload: RegExp 76 | // /** Module declaration pattern */ 77 | // readonly moduleDeclaration: RegExp 78 | // /** 79 | // * Module augmentation pattern 80 | // */ 81 | // readonly moduleAugmentation: RegExp 82 | // } 83 | 84 | // export interface ImportTrackingState { 85 | // typeImports: Map> 86 | // valueImports: Map> 87 | // usedTypes: Set 88 | // usedValues: Set 89 | // } 90 | -------------------------------------------------------------------------------- /packages/dtsx/src/processor/cache.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Cache utilities for processor 3 | * Handles regex compilation caching and import items caching 4 | */ 5 | 6 | /** 7 | * Maximum cache sizes to prevent memory bloat 8 | */ 9 | const MAX_REGEX_CACHE_SIZE = 500 10 | const MAX_IMPORT_CACHE_SIZE = 200 11 | 12 | /** 13 | * Cache for compiled RegExp patterns to avoid recreation in loops 14 | * Key: escaped pattern string, Value: compiled RegExp with word boundaries 15 | */ 16 | const regexCache = new Map() 17 | 18 | /** 19 | * Cache for extractAllImportedItems results 20 | * Key: import text, Value: array of imported items 21 | */ 22 | const importItemsCache = new Map() 23 | 24 | /** 25 | * Get or create a cached RegExp for word boundary matching 26 | */ 27 | export function getCachedRegex(pattern: string): RegExp { 28 | let cached = regexCache.get(pattern) 29 | if (!cached) { 30 | const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') 31 | cached = new RegExp(`\\b${escaped}\\b`) 32 | regexCache.set(pattern, cached) 33 | 34 | // Evict oldest entries if cache is too large 35 | if (regexCache.size > MAX_REGEX_CACHE_SIZE) { 36 | const firstKey = regexCache.keys().next().value 37 | if (firstKey) { 38 | regexCache.delete(firstKey) 39 | } 40 | } 41 | } 42 | return cached 43 | } 44 | 45 | /** 46 | * Get cached import items or null if not cached 47 | */ 48 | export function getImportItemsFromCache(importText: string): string[] | null { 49 | return importItemsCache.get(importText) ?? null 50 | } 51 | 52 | /** 53 | * Store import items in cache with eviction 54 | */ 55 | export function setImportItemsCache(importText: string, items: string[]): void { 56 | importItemsCache.set(importText, items) 57 | 58 | // Evict oldest entries if cache is too large 59 | if (importItemsCache.size > MAX_IMPORT_CACHE_SIZE) { 60 | const firstKey = importItemsCache.keys().next().value 61 | if (firstKey) { 62 | importItemsCache.delete(firstKey) 63 | } 64 | } 65 | } 66 | 67 | /** 68 | * Clear processor caches (useful for testing or memory management) 69 | */ 70 | export function clearProcessorCaches(): void { 71 | regexCache.clear() 72 | importItemsCache.clear() 73 | } 74 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/function-types.d.ts: -------------------------------------------------------------------------------- 1 | // Function with optional and default parameters 2 | export declare function withOptionalParams(required: string, optional?: number, defaultParam?: any): void; 3 | // Function with rest parameters 4 | export declare function withRestParams(first: string, ...rest: number[]): number; 5 | // Function with destructured parameters 6 | export declare function withDestructuredParams({ name, age, props }: { 7 | name: string 8 | age?: number 9 | [key: string]: any 10 | }): void; 11 | // Function with this parameter 12 | export declare function withThisParam(this: { count: number }, increment: number): number; 13 | // Function with type predicate 14 | export declare function isString(value: unknown): value is string; 15 | // Function with assertion signature 16 | export declare function assertDefined(value: T | undefined): asserts value is T; 17 | // Generator function types 18 | export declare function simpleGenerator(): Generator; 19 | // Arrow function variations 20 | export declare const arrowSimple: () => 'simple'; 21 | export declare const arrowWithParams: (x: number, y: number) => unknown; 22 | export declare const arrowAsync: (url: string) => Promise; 23 | export declare const arrowGeneric: (obj: T) => T; 24 | // Higher order functions 25 | export declare const createMultiplier: (factor: number) => (value: number) => any; 26 | export declare const pipe: (...fns: Array<(value: T) => T>) => (value: T) => T; 27 | // Method decorator pattern 28 | export declare const methodDecorator: (target: any, propertyKey: string, descriptor: PropertyDescriptor) => unknown; 29 | export declare const generatorArrow: (items: T[]) => Generator; 30 | // Constructor function 31 | export declare interface ConstructorExample { 32 | new (name: string): { name: string } 33 | (name: string): string 34 | } 35 | // Various function types and signatures 36 | // Function type aliases 37 | export type SimpleFunction = () => void; 38 | export type ParameterizedFunction = (a: string, b: number) => boolean; 39 | export type GenericFunction = (value: T) => T; 40 | export type AsyncFunction = (id: string) => Promise; 41 | // Callback function type 42 | export type CallbackFunction = (error: Error | null, result?: unknown) => void; 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@stacksjs/dtsx", 3 | "type": "module", 4 | "version": "0.9.9", 5 | "private": true, 6 | "description": "A modern, fast .d.ts generation tool, powered by Bun.", 7 | "author": "Chris Breuer ", 8 | "license": "MIT", 9 | "homepage": "https://github.com/stacksjs/dtsx#readme", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/stacksjs/dtsx.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/stacksjs/dtsx/issues" 16 | }, 17 | "keywords": [ 18 | "dts", 19 | "generation", 20 | "isolated declarations", 21 | "development", 22 | "bun", 23 | "stacks", 24 | "typescript", 25 | "javascript" 26 | ], 27 | "exports": { 28 | ".": { 29 | "import": "./dist/index.js" 30 | }, 31 | "./*": { 32 | "import": "./dist/*" 33 | } 34 | }, 35 | "module": "./dist/index.js", 36 | "types": "./dist/index.d.ts", 37 | "bin": { 38 | "dtsx": "./dist/cli.js" 39 | }, 40 | "files": [ 41 | "dist" 42 | ], 43 | "scripts": { 44 | "build": "bun --filter './packages/dtsx' build", 45 | "test": "bun test", 46 | "lint": "bunx --bun eslint .", 47 | "lint:fix": "bunx --bun eslint . --fix", 48 | "changelog": "bunx logsmith --verbose", 49 | "changelog:generate": "bunx logsmith --output CHANGELOG.md", 50 | "release": "bun run changelog:generate && bunx --bun bumpx prompt --recursive", 51 | "postinstall": "bunx git-hooks", 52 | "typecheck": "bunx tsc --noEmit", 53 | "dev:docs": "bun --bun vitepress dev docs", 54 | "build:docs": "bun --bun vitepress build docs", 55 | "preview:docs": "bun --bun vitepress preview docs" 56 | }, 57 | "devDependencies": { 58 | "@stacksjs/bumpx": "^0.2.4", 59 | "@stacksjs/cli": "^0.70.23", 60 | "@stacksjs/development": "^0.70.23", 61 | "@stacksjs/docs": "^0.70.23", 62 | "@stacksjs/eslint-config": "^4.14.0-beta.3", 63 | "@stacksjs/gitlint": "^0.1.5", 64 | "@stacksjs/logsmith": "^0.2.1", 65 | "@types/bun": "^1.3.3", 66 | "buddy-bot": "^0.9.12", 67 | "bun-git-hooks": "^0.3.1", 68 | "bun-plugin-dtsx": "workspace:*", 69 | "typescript": "^5.9.3", 70 | "unocss": "^66.5.9" 71 | }, 72 | "overrides": { 73 | "unconfig": "0.3.10" 74 | }, 75 | "workspaces": [ 76 | "packages/*" 77 | ] 78 | } 79 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/abseil.io.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * **abseil.io** - Abseil Common Libraries (C++) 3 | * 4 | * @domain `abseil.io` 5 | * @version `20250512.0.0` (17 versions available) 6 | * @versions From newest version to oldest. @see https://ts-pkgx.netlify.app/packages/abseil-io.md 7 | * 8 | * @install `sh <(curl https://pkgx.sh) +abseil.io -- $SHELL -i` 9 | * 10 | * @example 11 | * ```typescript 12 | * import { pantry } from 'ts-pkgx' 13 | * 14 | * const pkg = pantry.abseilio 15 | * console.log(pkg.name) // "abseil.io" 16 | * console.log(pkg.description) // "Abseil Common Libraries (C++)" 17 | * console.log(pkg.versions[0]) // "20250512.0.0" (latest) 18 | * ``` 19 | * 20 | * @see https://ts-pkgx.netlify.app/packages/abseil-io.md 21 | * @see https://ts-pkgx.netlify.app/usage 22 | */ 23 | export const abseilioPackage = { 24 | /** 25 | * The display name of this package. 26 | */ 27 | name: 'abseil.io' as const, 28 | /** 29 | * The canonical domain name for this package. 30 | */ 31 | domain: 'abseil.io' as const, 32 | /** 33 | * Brief description of what this package does. 34 | */ 35 | description: 'Abseil Common Libraries (C++)' as const, 36 | packageYmlUrl: 'https://github.com/pkgxdev/pantry/tree/main/projects/abseil.io/package.yml' as const, 37 | homepageUrl: '' as const, 38 | githubUrl: 'https://github.com/pkgxdev/pantry/' as const, 39 | /** 40 | * Command to install this package using pkgx. 41 | * @example sh <(curl https://pkgx.sh) +package-name 42 | */ 43 | installCommand: 'sh <(curl https://pkgx.sh) +abseil.io -- $SHELL -i' as const, 44 | programs: [] as const, 45 | companions: [] as const, 46 | dependencies: [] as const, 47 | /** 48 | * Available versions from newest to oldest. 49 | * @see https://ts-pkgx.netlify.app/usage for installation instructions 50 | */ 51 | versions: [ 52 | '20250512.0.0', 53 | '20250127.1.0', 54 | '20250127.0.0', 55 | '20240722.1.0', 56 | '20240722.0.0', 57 | '20240116.3.0', 58 | '20240116.2.0', 59 | '20240116.1.0', 60 | '20240116.0.0', 61 | '20230802.3.0', 62 | '20230802.2.0', 63 | '20230802.1.0', 64 | '20230802.0.0', 65 | '20230125.4.0', 66 | '20230125.3.0', 67 | '20230125.2.0', 68 | '20220623.2.0', 69 | ] as const, 70 | aliases: [] as const, 71 | fullPath: 'abseil.io' as const, 72 | } 73 | 74 | export type AbseilioPackage = typeof abseilioPackage 75 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0008.d.ts: -------------------------------------------------------------------------------- 1 | import { pki } from 'node-forge'; 2 | import type { CertDetails } from './types'; 3 | /** 4 | * Checks if a certificate is valid for a given domain. 5 | * @param certPemOrPath - The certificate in PEM format or the path to the certificate file. 6 | * @param domain - The domain to check. 7 | * @returns {boolean} - True if the certificate is valid for the domain, false otherwise. 8 | */ 9 | export declare function isCertValidForDomain(certPemOrPath: string, domain: string): boolean; 10 | /** 11 | * Reads a certificate from a file. 12 | * @param certPath - Path to the certificate file. 13 | * @returns {string} - The certificate content. 14 | */ 15 | export declare function readCertFromFile(certPath: string): string; 16 | /** 17 | * Parses and extracts details from a certificate. 18 | * @param certPemOrPath - The certificate in PEM format or the path to the certificate file. 19 | * @returns {CertDetails} - An object containing certificate details. 20 | */ 21 | export declare function parseCertDetails(certPemOrPath: string): CertDetails; 22 | /** 23 | * Checks if a certificate is expired. 24 | * @param certPemOrPath - The certificate in PEM format or the path to the certificate file. 25 | * @returns {boolean} - True if the certificate is expired, false otherwise. 26 | */ 27 | export declare function isCertExpired(certPemOrPath: string): boolean; 28 | /** 29 | * Gets a certificate from a PEM string or a path to a certificate file. 30 | * @param certPemOrPath - The certificate in PEM format or the path to the certificate file. 31 | * @returns {pki.Certificate} - The certificate object. 32 | */ 33 | export declare function getCertificateFromCertPemOrPath(certPemOrPath: string): pki.Certificate; 34 | /** 35 | * Lists all certificates in a directory. 36 | * By default, it returns the certificates stored in their default locations on each operating system. 37 | * If no certificates are found in the default paths, it checks the fallback path. 38 | * @param dirPath - Path to the directory. If not provided, the default directory for the OS will be used. 39 | * @returns {string[]} - An array of certificate file paths. 40 | */ 41 | export declare function listCertsInDirectory(dirPath?: string): string[]; 42 | export declare function makeNumberPositive(hexString: string): string; 43 | export declare function findFoldersWithFile(rootDir: string, fileName: string): string[]; 44 | export declare function debugLog(category: string, message: string, verbose?: boolean): void; 45 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/type.d.ts: -------------------------------------------------------------------------------- 1 | import type { DtsGenerationOption } from '@stacksjs/dtsx'; 2 | export type { DtsGenerationOption }; 3 | export type AuthStatus = 'authenticated' | 'unauthenticated'; 4 | // Intersection and Union Types 5 | export type ComplexUnionIntersection = | (User & { role: 'admin' }) 6 | | (Product & { category: string }) 7 | & { 8 | metadata: Record 9 | } 10 | // Mapped and Conditional Types 11 | export type ReadonlyDeep = { 12 | readonly [P in keyof T]: T[P] extends object ? ReadonlyDeep : T[P] 13 | } 14 | export type ConditionalResponse = T extends Array 15 | ? ApiResponse 16 | : T extends object 17 | ? ApiResponse 18 | : ApiResponse; 19 | export type EventType = 'click' | 'focus' | 'blur'; 20 | export type ElementType = 'button' | 'input' | 'form'; 21 | export type EventHandler = `on${Capitalize}${Capitalize}`; 22 | // Recursive Types 23 | export type RecursiveObject = { 24 | id: string 25 | children?: RecursiveObject[] 26 | parent?: RecursiveObject 27 | metadata: Record 28 | } 29 | // Branded Types 30 | export type UserId = string & { readonly __brand: unique symbol } 31 | export type ProductId = number & { 32 | readonly __brand: unique symbol 33 | } 34 | // Utility Type Implementations 35 | export type DeepPartial = T extends object ? { 36 | [P in keyof T]?: DeepPartial 37 | } : T; 38 | export type DeepRequired = T extends object ? { 39 | [P in keyof T]-?: DeepRequired 40 | } : T; 41 | // Polymorphic Types 42 | export type PolymorphicComponent

= { 43 | ( 44 | props: { as?: C } & Omit, keyof P> & P 45 | ): React.ReactElement | null 46 | } 47 | // Complex Index Types 48 | export type DynamicRecord = { 49 | [P in K]: P extends number 50 | ? Array 51 | : P extends string 52 | ? Record 53 | : never 54 | } 55 | export type RecordMerge = IsEmptyType extends true 56 | ? T 57 | : [T, U] extends [any[], any[]] 58 | ? U 59 | : [T, U] extends [object, object] 60 | ? { 61 | [K in keyof T | keyof U]: K extends keyof T 62 | ? K extends keyof U 63 | ? RecordMerge 64 | : T[K] 65 | : K extends keyof U 66 | ? U[K] 67 | : never 68 | } 69 | : U; 70 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/example/0006.ts: -------------------------------------------------------------------------------- 1 | import { collect, type Collection } from '@stacksjs/collections' 2 | 3 | export { 4 | align, 5 | box, 6 | centerAlign, 7 | colorize, 8 | colors, 9 | getColor, 10 | leftAlign, 11 | rightAlign, 12 | stripAnsi, 13 | } from 'consola/utils' 14 | 15 | export * as kolorist from 'kolorist' 16 | 17 | export { 18 | ansi256, 19 | ansi256Bg, 20 | bgBlack, 21 | bgBlue, 22 | bgCyan, 23 | bgGray, 24 | bgGreen, 25 | bgLightBlue, 26 | bgLightCyan, 27 | bgLightGray, 28 | bgLightGreen, 29 | bgLightMagenta, 30 | bgLightRed, 31 | bgLightYellow, 32 | bgMagenta, 33 | bgRed, 34 | bgWhite, 35 | bgYellow, 36 | black, 37 | blue, 38 | bold, 39 | cyan, 40 | dim, 41 | gray, 42 | green, 43 | hidden, 44 | inverse, 45 | italic, 46 | lightBlue, 47 | lightCyan, 48 | lightGray, 49 | lightGreen, 50 | lightMagenta, 51 | lightRed, 52 | lightYellow, 53 | link, 54 | magenta, 55 | red, 56 | reset, 57 | strikethrough, 58 | stripColors, 59 | trueColor, 60 | trueColorBg, 61 | underline, 62 | white, 63 | yellow, 64 | } from 'kolorist' 65 | 66 | export const quotes: Collection = collect([ 67 | // could be queried from any API or database 68 | 'The best way to get started is to quit talking and begin doing.', 69 | 'The pessimist sees difficulty in every opportunity. The optimist sees opportunity in every difficulty.', 70 | 'Don’t let yesterday take up too much of today.', 71 | 'You learn more from failure than from success. Don’t let it stop you. Failure builds character.', 72 | 'It’s not whether you get knocked down, it’s whether you get up.', 73 | 'If you are working on something that you really care about, you don’t have to be pushed. The vision pulls you.', 74 | 'People who are crazy enough to think they can change the world, are the ones who do.', 75 | 'Failure will never overtake me if my determination to succeed is strong enough.', 76 | 'Entrepreneurs are great at dealing with uncertainty and also very good at minimizing risk. That’s the classic entrepreneur.', 77 | 'We may encounter many defeats but we must not be defeated.', 78 | 'Knowing is not enough; we must apply. Wishing is not enough; we must do.', 79 | 'Imagine your life is perfect in every respect; what would it look like?', 80 | 'We generate fears while we sit. We overcome them by action.', 81 | 'Whether you think you can or think you can’t, you’re right.', 82 | 'Security is mostly a superstition. Life is either a daring adventure or nothing.', 83 | ]) 84 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/type.ts: -------------------------------------------------------------------------------- 1 | import type { DtsGenerationOption } from '@stacksjs/dtsx' 2 | 3 | export type AuthStatus = 'authenticated' | 'unauthenticated' 4 | 5 | // Intersection and Union Types 6 | export type ComplexUnionIntersection = 7 | | (User & { role: 'admin' }) 8 | | (Product & { category: string }) 9 | & { 10 | metadata: Record 11 | } 12 | 13 | export type { DtsGenerationOption } 14 | 15 | // Mapped and Conditional Types 16 | export type ReadonlyDeep = { 17 | readonly [P in keyof T]: T[P] extends object ? ReadonlyDeep : T[P] 18 | } 19 | 20 | export type ConditionalResponse = T extends Array 21 | ? ApiResponse 22 | : T extends object 23 | ? ApiResponse 24 | : ApiResponse 25 | 26 | export type EventType = 'click' | 'focus' | 'blur' 27 | export type ElementType = 'button' | 'input' | 'form' 28 | export type EventHandler = `on${Capitalize}${Capitalize}` 29 | 30 | // Recursive Types 31 | export type RecursiveObject = { 32 | id: string 33 | children?: RecursiveObject[] 34 | parent?: RecursiveObject 35 | metadata: Record 36 | } 37 | 38 | // Branded Types 39 | export type UserId = string & { readonly __brand: unique symbol } 40 | export type ProductId = number & { 41 | readonly __brand: unique symbol 42 | } 43 | 44 | // Utility Type Implementations 45 | export type DeepPartial = T extends object ? { 46 | [P in keyof T]?: DeepPartial 47 | } : T 48 | 49 | export type DeepRequired = T extends object ? { 50 | [P in keyof T]-?: DeepRequired 51 | } : T 52 | 53 | // Polymorphic Types 54 | export type PolymorphicComponent

= { 55 | ( 56 | props: { as?: C } & Omit, keyof P> & P 57 | ): React.ReactElement | null 58 | } 59 | 60 | // Complex Index Types 61 | export type DynamicRecord = { 62 | [P in K]: P extends number 63 | ? Array 64 | : P extends string 65 | ? Record 66 | : never 67 | } 68 | 69 | export type RecordMerge = IsEmptyType extends true 70 | ? T 71 | : [T, U] extends [any[], any[]] 72 | ? U 73 | : [T, U] extends [object, object] 74 | ? { 75 | [K in keyof T | keyof U]: K extends keyof T 76 | ? K extends keyof U 77 | ? RecordMerge 78 | : T[K] 79 | : K extends keyof U 80 | ? U[K] 81 | : never 82 | } 83 | : U 84 | -------------------------------------------------------------------------------- /docs/features/import-optimization.md: -------------------------------------------------------------------------------- 1 | # Import Optimization 2 | 3 | dtsx provides sophisticated import optimization capabilities to ensure your declaration files are clean and efficient. 4 | 5 | ## Smart Import Tracking 6 | 7 | dtsx tracks imports in several ways: 8 | 9 | - Type imports (`import type`) 10 | - Value imports (`import`) 11 | - Mixed imports 12 | - Default imports 13 | - Namespace imports 14 | 15 | ## Import Optimization Strategies 16 | 17 | ### Type-Only Imports 18 | 19 | ```typescript 20 | // Before optimization 21 | import { User, UserRole, processUser } from './types'; 22 | 23 | // After optimization 24 | import type { User, UserRole } from './types'; 25 | import { processUser } from './types'; 26 | ``` 27 | 28 | ### Unused Import Removal 29 | 30 | ```typescript 31 | // Before optimization 32 | import { User, Role, Permission } from './types'; 33 | // Only User is used in the file 34 | 35 | // After optimization 36 | import { User } from './types'; 37 | ``` 38 | 39 | ### Import Consolidation 40 | 41 | ```typescript 42 | // Before optimization 43 | import { User } from './types'; 44 | import { Role } from './types'; 45 | import { Permission } from './types'; 46 | 47 | // After optimization 48 | import { User, Role, Permission } from './types'; 49 | ``` 50 | 51 | ## Import Tracking Features 52 | 53 | ### Type Usage Tracking 54 | 55 | - Tracks all type references 56 | - Maintains type relationships 57 | - Handles type aliases 58 | - Supports type augmentation 59 | 60 | ### Value Usage Tracking 61 | 62 | - Tracks function calls 63 | - Tracks variable usage 64 | - Handles destructuring 65 | - Supports namespace usage 66 | 67 | ## Optimization Rules 68 | 69 | 1. **Type-Only Rule**: Imports used only as types are converted to type imports 70 | 2. **Unused Removal Rule**: Unused imports are removed 71 | 3. **Consolidation Rule**: Multiple imports from the same module are consolidated 72 | 4. **Namespace Rule**: Namespace imports are optimized based on usage 73 | 5. **Default Import Rule**: Default imports are handled appropriately 74 | 75 | ## Configuration Options 76 | 77 | ```typescript 78 | interface ImportOptimizationConfig { 79 | // Enable/disable import optimization 80 | optimizeImports: boolean; 81 | 82 | // Keep certain imports even if unused 83 | preserveImports: string[]; 84 | 85 | // Custom import transformation rules 86 | transformRules: ImportTransformRule[]; 87 | } 88 | ``` 89 | 90 | ## Best Practices 91 | 92 | 1. Use type imports for type-only usage 93 | 2. Avoid mixing type and value imports when possible 94 | 3. Use namespace imports for large modules 95 | 4. Keep related imports together 96 | 5. Use consistent import styles 97 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/contributors.ts: -------------------------------------------------------------------------------- 1 | import contributors from './contributors.json' 2 | 3 | export interface Contributor { 4 | name: string 5 | avatar: string 6 | } 7 | 8 | export interface CoreTeam { 9 | avatar: string 10 | name: string 11 | github: string 12 | twitter?: string 13 | bluesky?: string 14 | sponsors?: boolean 15 | description: string 16 | packages?: string[] 17 | functions?: string[] 18 | } 19 | 20 | const contributorsAvatars: Record = {} 21 | 22 | function getAvatarUrl(name: string) { 23 | return `https://avatars.githubusercontent.com/${name}?v=4` 24 | } 25 | 26 | const contributorList = (Object.keys(contributors) as string[]).reduce((acc, name) => { 27 | contributorsAvatars[name] = getAvatarUrl(name) 28 | 29 | if (contributors[name]) { 30 | acc.push({ name, avatar: contributorsAvatars[name] }) 31 | } 32 | 33 | return acc 34 | }, [] as Contributor[]) 35 | 36 | const coreTeamMembers: CoreTeam[] = [ 37 | { 38 | avatar: contributorsAvatars.chrisbbreuer || 'default-avatar.png', 39 | name: 'Chris Breuer', 40 | github: 'chrisbbreuer', 41 | twitter: 'chrisbbreuer', 42 | bluesky: 'chrisbreuer.dev', 43 | sponsors: true, 44 | description: 'Open sourceror.
Core Stacks team.
Working at Stacks.js', 45 | packages: ['core'], 46 | functions: ['cloud', 'backend', 'frontend', 'ci/cd'], 47 | }, 48 | { 49 | avatar: contributorsAvatars.glennmichael123 || 'default-avatar.png', 50 | name: 'Glenn', 51 | github: 'glennmichael123', 52 | twitter: 'glennmichael123', 53 | sponsors: false, 54 | packages: ['core'], 55 | functions: ['backend', 'frontend', 'desktop'], 56 | description: 'Open sourceror.
Core Stacks team.
Working at Stacks.js', 57 | }, 58 | 59 | { 60 | avatar: contributorsAvatars['cab-mikee'] || 'default-avatar.png', 61 | name: 'Mike', 62 | github: 'cab-mikee', 63 | twitter: 'cab-mikee', 64 | sponsors: false, 65 | description: 'Open sourceror.
Core Stacks team.
Working at Stacks.js', 66 | packages: ['core'], 67 | functions: ['backend', 'frontend'], 68 | }, 69 | 70 | { 71 | avatar: contributorsAvatars.konkonam || 'default-avatar.png', 72 | name: 'Zoltan', 73 | github: 'konkonam', 74 | sponsors: true, 75 | description: 'Open sourceror.
Core Stacks team.', 76 | packages: ['core'], 77 | functions: ['backend', 'frontend', 'desktop'], 78 | }, 79 | ] 80 | .sort((pre, cur) => { 81 | const contribute = Object.keys(contributors) 82 | return contribute.findIndex(name => name === pre.github) - contribute.findIndex(name => name === cur.github) 83 | }) 84 | 85 | export { contributorList as contributors, coreTeamMembers } 86 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/example/0009.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from './types' 2 | import { resolve } from 'node:path' 3 | import process from 'node:process' 4 | import { deepMerge } from './utils' 5 | 6 | /** 7 | * Load Config 8 | * 9 | * @param {object} options - The configuration options. 10 | * @param {string} options.name - The name of the configuration file. 11 | * @param {string} [options.cwd] - The current working directory. 12 | * @param {string} [options.endpoint] - The API endpoint to fetch config from in browser environments. 13 | * @param {string} [options.headers] - The headers to send with the request in browser environments. 14 | * @param {T} options.defaultConfig - The default configuration. 15 | * @returns {Promise} The merged configuration. 16 | * @example ```ts 17 | * // Merges arrays if both configs are arrays, otherwise does object deep merge 18 | * await loadConfig({ 19 | * name: 'example', 20 | * endpoint: '/api/my-custom-config/endpoint', 21 | * defaultConfig: [{ foo: 'bar' }] 22 | * }) 23 | * ``` 24 | */ 25 | export async function loadConfig({ 26 | name, 27 | cwd, 28 | defaultConfig, 29 | endpoint, 30 | headers = { 31 | 'Accept': 'application/json', 32 | 'Content-Type': 'application/json', 33 | }, 34 | }: Config): Promise { 35 | // If running in a server (Bun) environment, load the config from the file system 36 | if (typeof window === 'undefined') { 37 | // back 3 times to get out of node_modules into the root directory, assuming the config is in the root directory 38 | const configPath = resolve(cwd || '../../../', `${name}.config`) 39 | 40 | try { 41 | const importedConfig = await import(configPath) 42 | const loadedConfig = importedConfig.default || importedConfig 43 | return deepMerge(defaultConfig, loadedConfig) as T 44 | } 45 | // eslint-disable-next-line unused-imports/no-unused-vars 46 | catch (error: any) { 47 | return defaultConfig 48 | } 49 | } 50 | 51 | if (!endpoint) { 52 | console.warn('An API endpoint is required to load the client config.') 53 | return defaultConfig 54 | } 55 | 56 | // If running in a browser environment, load the config from an API endpoint 57 | try { 58 | const response = await fetch(endpoint, { 59 | method: 'GET', 60 | headers, 61 | }) 62 | 63 | if (!response.ok) { 64 | throw new Error(`HTTP error! status: ${response.status}`) 65 | } 66 | 67 | const loadedConfig = await response.json() as T 68 | return deepMerge(defaultConfig, loadedConfig) as T 69 | } 70 | catch (error) { 71 | console.error('Failed to load client config:', error) 72 | return defaultConfig 73 | } 74 | } 75 | 76 | export * from './types' 77 | export * from './utils' 78 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/edge-cases.d.ts: -------------------------------------------------------------------------------- 1 | // Function with complex overloads 2 | export declare function complexOverload(value: string): string; 3 | export declare function complexOverload(value: number): number; 4 | export declare function complexOverload(value: boolean): boolean; 5 | export declare function complexOverload(value: T): T; 6 | // Async generator function 7 | export declare function asyncGenerator(items: T[]): AsyncGenerator; 8 | // Test edge cases for type inference 9 | // BigInt literals 10 | export declare const bigIntLiteral: 123n; 11 | export declare const bigIntExpression: bigint; 12 | // Symbol types 13 | export declare const symbolUnique: symbol; 14 | export declare const symbolFor: symbol; 15 | // Template literals 16 | export declare const templateSimple: `Hello World`; 17 | export declare const templateWithExpression: `Count: ${42}`; 18 | export declare const templateTagged: string; 19 | // Promise types 20 | export declare const promiseResolved: Promise<42>; 21 | export declare const promiseRejected: Promise; 22 | export declare const promiseAll: Promise<[1, 'two']>; 23 | // Date and built-in types 24 | export declare const dateInstance: Date; 25 | export declare const mapInstance: Map; 26 | export declare const setInstance: Set; 27 | export declare const regexInstance: RegExp; 28 | export declare const errorInstance: Error; 29 | // Complex nested structures 30 | export declare const deeplyNested: { 31 | level1: { 32 | level2: { 33 | level3: { 34 | value: 'deep'; 35 | array: readonly [1, readonly [2, readonly [3, readonly [4]]]] 36 | } 37 | } 38 | } 39 | }; 40 | // Mixed type arrays 41 | export declare const mixedTypeArray: readonly ['string', 123, true, null, undefined, { 42 | key: 'value' 43 | }, readonly [1, 2, 3], (() => unknown), Date, Promise<'async'>]; 44 | // Type with conditional and infer 45 | export type ExtractPromise = T extends Promise ? U : never; 46 | export type ExtractArray = T extends (infer U)[] ? U : never; 47 | // Mapped type with template literal 48 | export type Getters = { 49 | [K in keyof T as `get${Capitalize}`]: () => T[K] 50 | } 51 | // Discriminated union 52 | export type Result = | { success: true; data: T; error?: never } 53 | | { success: false; data?: never; error: E } 54 | // Recursive type with constraints 55 | export type DeepReadonly = T extends any[] ? DeepReadonlyArray : 56 | T extends object ? DeepReadonlyObject : 57 | T; 58 | declare type DeepReadonlyArray = ReadonlyArray>; 59 | declare type DeepReadonlyObject = { 60 | readonly [P in keyof T]: DeepReadonly 61 | } 62 | // Class with decorators (as comments for now) 63 | // @sealed 64 | export declare class DecoratedClass { 65 | name: string; 66 | oldMethod(): void; 67 | } 68 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/example/0010.ts: -------------------------------------------------------------------------------- 1 | export type DelimiterType = string 2 | export const DefaultPhoneDelimiter: DelimiterType = '-' 3 | export const DefaultPhonePattern: number[] = [3, 3, 4] 4 | 5 | export interface FormatPhoneOptions { 6 | delimiter?: string 7 | pattern?: number[] 8 | region?: string 9 | includeCountryCode?: boolean 10 | format?: 'national' | 'international' 11 | } 12 | 13 | export const DefaultPhoneRegion = 'US' 14 | 15 | export const PHONE_PATTERNS: Record = { 16 | US: [3, 3, 4], 17 | GB: [4, 3, 3], 18 | FR: [2, 2, 2, 2, 2], 19 | DE: [3, 2, 2, 2], 20 | JP: [3, 4, 4], 21 | CN: [3, 4, 4], 22 | IN: [4, 3, 3], 23 | BR: [2, 4, 4], 24 | AU: [4, 3, 3], 25 | CA: [3, 3, 4], 26 | } as const 27 | 28 | export const COUNTRY_CODES: Record = { 29 | US: '+1', 30 | GB: '+44', 31 | FR: '+33', 32 | DE: '+49', 33 | JP: '+81', 34 | CN: '+86', 35 | IN: '+91', 36 | BR: '+55', 37 | AU: '+61', 38 | CA: '+1', 39 | } 40 | 41 | function handleFormat({ 42 | value, 43 | delimiter, 44 | pattern, 45 | region, 46 | includeCountryCode, 47 | format, 48 | }: { 49 | value: string 50 | delimiter?: string 51 | pattern?: number[] 52 | region?: string 53 | includeCountryCode?: boolean 54 | format?: 'national' | 'international' 55 | }): string { 56 | // Remove all non-digit characters 57 | const digits = value.replace(/\D/g, '') 58 | 59 | // Apply pattern 60 | let result = '' 61 | let digitIndex = 0 62 | 63 | for (let i = 0; i < pattern.length; i++) { 64 | const groupSize = pattern[i] 65 | const group = digits.slice(digitIndex, digitIndex + groupSize) 66 | 67 | if (group) { 68 | if (result) { 69 | result += delimiter 70 | } 71 | result += group 72 | digitIndex += groupSize 73 | } 74 | } 75 | 76 | // Add country code if needed 77 | if (includeCountryCode && format === 'international' && COUNTRY_CODES[region]) { 78 | result = `${COUNTRY_CODES[region]} ${result}` 79 | } 80 | 81 | return result 82 | } 83 | 84 | export function formatPhone(value: string, options?: FormatPhoneOptions): string { 85 | const { 86 | delimiter = DefaultPhoneDelimiter, 87 | pattern, 88 | region = DefaultPhoneRegion, 89 | includeCountryCode = false, 90 | format = 'national', 91 | } = options ?? {} 92 | 93 | // Use region pattern if no custom pattern provided 94 | const selectedPattern = pattern ?? PHONE_PATTERNS[region] ?? DefaultPhonePattern 95 | 96 | return handleFormat({ 97 | value, 98 | delimiter, 99 | pattern: selectedPattern, 100 | region, 101 | includeCountryCode, 102 | format, 103 | }) 104 | } 105 | 106 | export function unformatPhone(value: string): string { 107 | return value.replace(/\D/g, '') 108 | } 109 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 14 | cancel-in-progress: true 15 | 16 | jobs: 17 | lint: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v6.0.0 22 | 23 | - name: Install Bun 24 | uses: oven-sh/setup-bun@v2.0.2 25 | 26 | - name: Use cached node_modules 27 | uses: actions/cache@v4.3.0 28 | with: 29 | path: node_modules 30 | key: node-modules-${{ hashFiles('**/bun.lock') }} 31 | restore-keys: | 32 | node-modules- 33 | 34 | - name: Install Dependencies 35 | run: bun install 36 | 37 | - name: Lint 38 | run: bun run lint 39 | 40 | typecheck: 41 | runs-on: ubuntu-latest 42 | 43 | steps: 44 | - uses: actions/checkout@v6.0.0 45 | 46 | - name: Install Bun 47 | uses: oven-sh/setup-bun@v2.0.2 48 | 49 | - name: Use cached node_modules 50 | uses: actions/cache@v4.3.0 51 | with: 52 | path: node_modules 53 | key: node-modules-${{ hashFiles('**/bun.lock') }} 54 | restore-keys: | 55 | node-modules- 56 | 57 | - name: Install Dependencies 58 | run: bun install 59 | 60 | - name: Typecheck 61 | run: bun --bun run typecheck 62 | 63 | test: 64 | runs-on: ubuntu-latest 65 | 66 | steps: 67 | - uses: actions/checkout@v6.0.0 68 | 69 | - name: Install Bun 70 | uses: oven-sh/setup-bun@v2.0.2 71 | 72 | - name: Use cached node_modules 73 | uses: actions/cache@v4.3.0 74 | with: 75 | path: node_modules 76 | key: node-modules-${{ hashFiles('**/bun.lock') }} 77 | restore-keys: | 78 | node-modules- 79 | 80 | - name: Install Dependencies 81 | run: bun install 82 | 83 | - name: Unit Test 84 | run: bun test 85 | 86 | publish-commit: 87 | runs-on: ubuntu-latest 88 | 89 | steps: 90 | - uses: actions/checkout@v6.0.0 91 | 92 | - name: Install Bun 93 | uses: oven-sh/setup-bun@v2.0.2 94 | 95 | - name: Use cached node_modules 96 | uses: actions/cache@v4.3.0 97 | with: 98 | path: node_modules 99 | key: node-modules-${{ hashFiles('**/bun.lock') }} 100 | restore-keys: | 101 | node-modules- 102 | 103 | - name: Install Dependencies 104 | run: bun install 105 | 106 | - name: Build 107 | run: bun run build 108 | 109 | - name: Publish Commit 110 | run: bunx pkg-pr-new publish './packages/dtsx' './packages/bun-plugin' './packages/vite-plugin' 111 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/private-members.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Test fixture for private member handling in class declarations 3 | * Private members should be excluded from .d.ts output 4 | * Modifier order should be: private/protected, static, abstract, readonly 5 | */ 6 | 7 | // Class with private static members - should be excluded from d.ts 8 | export class CacheManager { 9 | private static cache: Map = new Map() 10 | private static loading: Map> = new Map() 11 | 12 | static readonly MAX_SIZE = 1000 13 | 14 | static get(key: string): unknown { 15 | return this.cache.get(key) 16 | } 17 | 18 | static set(key: string, value: unknown): void { 19 | this.cache.set(key, value) 20 | } 21 | 22 | private static cleanup(): void { 23 | this.cache.clear() 24 | } 25 | 26 | static clear(): void { 27 | this.cleanup() 28 | this.loading.clear() 29 | } 30 | } 31 | 32 | // Class with mixed visibility modifiers 33 | export class MixedVisibility { 34 | private privateField: string = 'private' 35 | protected protectedField: string = 'protected' 36 | public publicField: string = 'public' 37 | readonly readonlyField: string = 'readonly' 38 | 39 | private static privateStaticField: number = 0 40 | protected static protectedStaticField: number = 0 41 | public static publicStaticField: number = 0 42 | static readonly staticReadonlyField: number = 0 43 | 44 | private privateMethod(): void {} 45 | protected protectedMethod(): void {} 46 | public publicMethod(): void {} 47 | 48 | private static privateStaticMethod(): void {} 49 | protected static protectedStaticMethod(): void {} 50 | public static publicStaticMethod(): void {} 51 | } 52 | 53 | // Class with private accessors 54 | export class PrivateAccessors { 55 | private _value: number = 0 56 | 57 | private get privateGetter(): number { 58 | return this._value 59 | } 60 | 61 | private set privateSetter(val: number) { 62 | this._value = val 63 | } 64 | 65 | protected get protectedGetter(): number { 66 | return this._value 67 | } 68 | 69 | protected set protectedSetter(val: number) { 70 | this._value = val 71 | } 72 | 73 | public get publicGetter(): number { 74 | return this._value 75 | } 76 | 77 | public set publicSetter(val: number) { 78 | this._value = val 79 | } 80 | } 81 | 82 | // Class with private constructor parameter properties 83 | export class ParameterProperties { 84 | constructor( 85 | private privateParam: string, 86 | protected protectedParam: string, 87 | public publicParam: string, 88 | readonly readonlyParam: string 89 | ) {} 90 | } 91 | 92 | // Abstract class with private members 93 | export abstract class AbstractWithPrivate { 94 | private privateField: string = '' 95 | protected abstract protectedAbstractMethod(): void 96 | private privateMethod(): void {} 97 | abstract publicAbstractMethod(): void 98 | } 99 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/function-types.ts: -------------------------------------------------------------------------------- 1 | // Various function types and signatures 2 | 3 | // Function type aliases 4 | export type SimpleFunction = () => void 5 | export type ParameterizedFunction = (a: string, b: number) => boolean 6 | export type GenericFunction = (value: T) => T 7 | export type AsyncFunction = (id: string) => Promise 8 | 9 | // Function with optional and default parameters 10 | export function withOptionalParams( 11 | required: string, 12 | optional?: number, 13 | defaultParam = 'default' 14 | ): void { 15 | console.log(required, optional, defaultParam) 16 | } 17 | 18 | // Function with rest parameters 19 | export function withRestParams( 20 | first: string, 21 | ...rest: number[] 22 | ): number { 23 | return rest.reduce((a, b) => a + b, 0) 24 | } 25 | 26 | // Function with destructured parameters 27 | export function withDestructuredParams({ 28 | name, 29 | age = 0, 30 | ...props 31 | }: { 32 | name: string 33 | age?: number 34 | [key: string]: any 35 | }): void { 36 | console.log(name, age, props) 37 | } 38 | 39 | // Arrow function variations 40 | export const arrowSimple = () => 'simple' 41 | export const arrowWithParams = (x: number, y: number) => x + y 42 | export const arrowAsync = async (url: string) => { 43 | const response = await fetch(url) 44 | return response.json() 45 | } 46 | export const arrowGeneric = (obj: T): T => ({ ...obj }) 47 | 48 | // Higher order functions 49 | export const createMultiplier = (factor: number) => (value: number) => value * factor 50 | export const pipe = (...fns: Array<(value: T) => T>) => (value: T) => 51 | fns.reduce((acc, fn) => fn(acc), value) 52 | 53 | // Function with this parameter 54 | export function withThisParam(this: { count: number }, increment: number): number { 55 | return this.count + increment 56 | } 57 | 58 | // Constructor function 59 | export interface ConstructorExample { 60 | new (name: string): { name: string } 61 | (name: string): string 62 | } 63 | 64 | // Function with type predicate 65 | export function isString(value: unknown): value is string { 66 | return typeof value === 'string' 67 | } 68 | 69 | // Function with assertion signature 70 | export function assertDefined(value: T | undefined): asserts value is T { 71 | if (value === undefined) { 72 | throw new Error('Value is undefined') 73 | } 74 | } 75 | 76 | // Callback function type 77 | export type CallbackFunction = (error: Error | null, result?: unknown) => void 78 | 79 | // Method decorator pattern 80 | export const methodDecorator = (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { 81 | return descriptor 82 | } 83 | 84 | // Generator function types 85 | export function* simpleGenerator(): Generator { 86 | yield 1 87 | yield 2 88 | yield 3 89 | } 90 | 91 | export const generatorArrow = function* (items: T[]): Generator { 92 | for (const item of items) { 93 | yield item 94 | } 95 | } -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/example/0011.ts: -------------------------------------------------------------------------------- 1 | export const bunshPackage = { 2 | name: 'bun' as const, 3 | domain: 'bun.sh' as const, 4 | description: 'Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one' as const, 5 | packageYmlUrl: 'https://github.com/pkgxdev/pantry/tree/main/projects/bun.sh/package.yml' as const, 6 | homepageUrl: '' as const, 7 | githubUrl: 'https://github.com/pkgxdev/pantry/' as const, 8 | installCommand: 'sh <(curl https://pkgx.sh) +bun.sh -- $SHELL -i' as const, 9 | programs: [ 10 | 'bun', 11 | 'bunx', 12 | ] as const, 13 | companions: [] as const, 14 | dependencies: [] as const, 15 | versions: [ 16 | '1.2.14', 17 | '1.2.13', 18 | '1.2.12', 19 | '1.2.11', 20 | '1.2.10', 21 | '1.2.9', 22 | '1.2.8', 23 | '1.2.7', 24 | '1.2.6', 25 | '1.2.5', 26 | '1.2.4', 27 | '1.2.3', 28 | '1.2.2', 29 | '1.2.1', 30 | '1.2.0', 31 | '1.1.45', 32 | '1.1.44', 33 | '1.1.43', 34 | '1.1.42', 35 | '1.1.41', 36 | '1.1.40', 37 | '1.1.39', 38 | '1.1.38', 39 | '1.1.37', 40 | '1.1.36', 41 | '1.1.35', 42 | '1.1.34', 43 | '1.1.33', 44 | '1.1.32', 45 | '1.1.31', 46 | '1.1.30', 47 | '1.1.29', 48 | '1.1.28', 49 | '1.1.27', 50 | '1.1.26', 51 | '1.1.25', 52 | '1.1.24', 53 | '1.1.23', 54 | '1.1.22', 55 | '1.1.21', 56 | '1.1.20', 57 | '1.1.19', 58 | '1.1.18', 59 | '1.1.17', 60 | '1.1.16', 61 | '1.1.15', 62 | '1.1.14', 63 | '1.1.13', 64 | '1.1.12', 65 | '1.1.11', 66 | '1.1.10', 67 | '1.1.9', 68 | '1.1.8', 69 | '1.1.7', 70 | '1.1.6', 71 | '1.1.5', 72 | '1.1.4', 73 | '1.1.3', 74 | '1.1.2', 75 | '1.1.1', 76 | '1.1.0', 77 | '1.0.36', 78 | '1.0.35', 79 | '1.0.34', 80 | '1.0.33', 81 | '1.0.32', 82 | '1.0.31', 83 | '1.0.30', 84 | '1.0.29', 85 | '1.0.28', 86 | '1.0.27', 87 | '1.0.26', 88 | '1.0.25', 89 | '1.0.24', 90 | '1.0.23', 91 | '1.0.22', 92 | '1.0.21', 93 | '1.0.20', 94 | '1.0.19', 95 | '1.0.18', 96 | '1.0.17', 97 | '1.0.16', 98 | '1.0.14', 99 | '1.0.13', 100 | '1.0.12', 101 | '1.0.11', 102 | '1.0.10', 103 | '1.0.9', 104 | '1.0.8', 105 | '1.0.7', 106 | '1.0.6', 107 | '1.0.5', 108 | '1.0.4', 109 | '1.0.3', 110 | '1.0.2', 111 | '1.0.1', 112 | '1.0.0', 113 | '0.8.1', 114 | '0.8.0', 115 | '0.7.2', 116 | '0.7.1', 117 | '0.7.0', 118 | '0.6.14', 119 | '0.6.13', 120 | '0.6.12', 121 | '0.6.11', 122 | '0.6.10', 123 | '0.6.8', 124 | '0.6.7', 125 | '0.6.6', 126 | '0.6.5', 127 | '0.6.4', 128 | '0.6.3', 129 | '0.6.2', 130 | '0.6.1', 131 | '0.6.0', 132 | '0.5.9', 133 | '0.5.6', 134 | ] as const, 135 | fullPath: 'bun.sh' as const, 136 | aliases: [ 137 | 'bun', 138 | ] as const, 139 | } 140 | 141 | export type BunshPackage = typeof bunshPackage 142 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/imports.d.ts: -------------------------------------------------------------------------------- 1 | import { basename, delimiter, dirname, extname, isAbsolute, join, normalize, type ParsedPath, relative, resolve, sep, toNamespacedPath } from 'node:path'; 2 | import { generate } from '@stacksjs/dtsx'; 3 | import { something as dts } from './generate'; 4 | import forge, { pki, tls } from 'node-forge'; 5 | /** 6 | * Returns the path to the `actions` directory. The `actions` directory 7 | * contains the core Stacks' actions. 8 | * 9 | * @param path - The relative path to the file or directory. 10 | * @returns The absolute path to the file or directory. 11 | * @example 12 | * ```ts 13 | * import { actionsPath } from '@stacksjs/path' 14 | * 15 | * console.log(actionsPath('path/to/action.ts')) // Outputs the absolute path to 'path/to/action.ts' within the `actions` directory 16 | * ``` 17 | */ 18 | export declare function actionsPath(path?: string): string; 19 | export declare function corePath(path?: string): string; 20 | export declare function frameworkPath(path?: string, options?: { relative?: boolean, cwd?: string }): string; 21 | export declare function storagePath(path?: string): string; 22 | export declare function projectPath(filePath?: any, options?: { relative: boolean }): string; 23 | export declare function userActionsPath(path?: string, options?: { relative: true }): string; 24 | export declare function builtUserActionsPath(path?: string, options?: { relative: boolean }): string; 25 | /** 26 | * Returns the path to the home directory, optionally appending a given path. 27 | * 28 | * @param path - The relative path to append to the home directory path. 29 | * @returns The absolute path to the specified file or directory within the home directory. 30 | */ 31 | export declare function homeDir(path?: string): string; 32 | export declare function libraryEntryPath(type: LibraryType): string; 33 | /** 34 | * Returns the path to the `examples` directory within the framework directory, filtered by type. 35 | * 36 | * @param type - The type of examples to filter by ('vue-components' or 'web-components'). 37 | * @returns The absolute path to the specified type of examples within the `examples` directory. 38 | */ 39 | export declare function examplesPath(type?: 'vue-components' | 'web-components'): string; 40 | export declare const path: Path; 41 | export declare interface Path { 42 | actionsPath: (path?: string) => string 43 | userActionsPath: (path?: string) => string 44 | builtUserActionsPath: (path?: string, option?: { relative: boolean }) => string 45 | examplesPath: (type?: 'vue-components' | 'web-components') => string 46 | libraryEntryPath: (type: LibraryType) => string 47 | homeDir: (path?: string) => string 48 | parse: (path: string) => ParsedPath 49 | sep: () => '/' | '\\' 50 | } 51 | /** 52 | * Returns the path to the library entry file, filtered by library type. 53 | * 54 | * @param type - The type of library ('vue-components', 'web-components', or 'functions'). 55 | * @returns The absolute path to the specified library entry file. 56 | */ 57 | export type LibraryType = 'vue-components' | 'web-components' | 'functions'; 58 | export { basename, forge, generate, pki, tls, delimiter, dirname, dts, extname, isAbsolute, join, normalize, relative, resolve, sep, toNamespacedPath }; 59 | export default forge; 60 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/styles/vars.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Colors 3 | * -------------------------------------------------------------------------- */ 4 | 5 | :root { 6 | --vp-c-brand-1: #2563eb; 7 | --vp-c-brand-2: #1e40af; 8 | --vp-c-brand-3: #172554; 9 | --vp-c-brand-soft: #2563eb50; 10 | 11 | --vp-c-text-dark-1: #ffffff; /* Adding this to ensure light text */ 12 | 13 | --vp-c-text-code: #4a72bf; 14 | 15 | --vp-code-block-bg: rgba(125, 125, 125, 0.04); 16 | --vp-code-copy-code-bg: rgba(125, 125, 125, 0.1); 17 | --vp-code-copy-code-hover-bg: rgba(125, 125, 125, 0.2); 18 | 19 | --vp-c-disabled-bg: rgba(125, 125, 125, 0.2); 20 | --vp-c-text-light-2: rgba(56 56 56 / 70%); 21 | --vp-c-text-dark-2: rgba(56 56 56 / 70%); 22 | 23 | --vp-custom-block-info-bg: transparent; 24 | --vp-custom-block-tip-bg: transparent; 25 | 26 | --vp-custom-block-warning-bg: #d9a40605; 27 | --vp-custom-block-warning-text: #d9a406; 28 | --vp-custom-block-warning-border: #d9a40630; 29 | 30 | --vp-custom-block-tip-bg: #2563eb05; 31 | --vp-custom-block-tip-text: #2563eb; 32 | --vp-custom-block-tip-border: #2563eb30; 33 | 34 | --vp-code-color: #4a72bf; 35 | } 36 | 37 | .dark { 38 | --vp-code-block-bg: var(--vp-c-bg-alt); 39 | --vp-c-text-code: #93c5fd; 40 | --vp-c-text-dark-2: rgba(235, 235, 235, 0.6); 41 | } 42 | 43 | /** 44 | * Component: Code 45 | * -------------------------------------------------------------------------- */ 46 | 47 | :root { 48 | --vp-code-line-highlight-color: rgba(125, 125, 125, 0.2); 49 | } 50 | 51 | .dark { 52 | --vp-code-line-highlight-color: rgba(0, 0, 0, 0.5); 53 | } 54 | 55 | /** 56 | * Component: Button 57 | * -------------------------------------------------------------------------- */ 58 | 59 | :root { 60 | --vp-button-brand-border: var(--vp-c-brand-1); 61 | --vp-button-brand-text: var(--vp-c-text-dark-1); 62 | --vp-button-brand-bg: var(--vp-c-brand-1); 63 | --vp-button-brand-hover-border: var(--vp-c-brand-2); 64 | --vp-button-brand-hover-text: var(--vp-c-text-dark-1); 65 | --vp-button-brand-hover-bg: var(--vp-c-brand-2); 66 | --vp-button-brand-active-border: var(--vp-c-brand-2); 67 | --vp-button-brand-active-text: var(--vp-c-text-dark-1); 68 | --vp-button-brand-active-bg: var(--vp-c-brand-2); 69 | } 70 | 71 | /** 72 | * Component: Home 73 | * -------------------------------------------------------------------------- */ 74 | 75 | :root { 76 | --vp-home-hero-name-color: transparent; 77 | --vp-home-hero-name-background: -webkit-linear-gradient( 78 | 120deg, 79 | #1e40af, 80 | #2563eb 81 | ); 82 | --vp-home-hero-image-background-image: linear-gradient(-45deg, #1e40af 50%, #2563eb 50%); 83 | --vp-home-hero-image-filter: blur(30px); 84 | } 85 | 86 | @media (min-width: 640px) { 87 | :root { 88 | --vp-home-hero-image-filter: blur(56px); 89 | } 90 | } 91 | 92 | @media (min-width: 960px) { 93 | :root { 94 | --vp-home-hero-image-filter: blur(60px); 95 | } 96 | } 97 | 98 | /** 99 | * Component: Algolia 100 | * -------------------------------------------------------------------------- */ 101 | 102 | /* .DocSearch { 103 | --docsearch-primary-color: var(--vp-c-brand) !important; 104 | } */ 105 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "prettier.enable": false, 3 | "biome.enabled": false, 4 | "editor.formatOnSave": false, 5 | 6 | "editor.codeActionsOnSave": { 7 | "source.fixAll.eslint": "explicit", 8 | "source.organizeImports": "never" 9 | }, 10 | 11 | "eslint.rules.customizations": [ 12 | { "rule": "style/*", "severity": "off", "fixable": true }, 13 | { "rule": "format/*", "severity": "off", "fixable": true }, 14 | { "rule": "*-indent", "severity": "off", "fixable": true }, 15 | { "rule": "*-spacing", "severity": "off", "fixable": true }, 16 | { "rule": "*-spaces", "severity": "off", "fixable": true }, 17 | { "rule": "*-order", "severity": "off", "fixable": true }, 18 | { "rule": "*-dangle", "severity": "off", "fixable": true }, 19 | { "rule": "*-newline", "severity": "off", "fixable": true }, 20 | { "rule": "*quotes", "severity": "off", "fixable": true }, 21 | { "rule": "*semi", "severity": "off", "fixable": true } 22 | ], 23 | 24 | "eslint.validate": [ 25 | "javascript", 26 | "typescript", 27 | "vue", 28 | "html", 29 | "markdown", 30 | "json", 31 | "jsonc", 32 | "yaml", 33 | "toml", 34 | "xml", 35 | "css", 36 | "less", 37 | "scss", 38 | "pcss", 39 | "postcss" 40 | ], 41 | 42 | "typescript.tsdk": "${workspaceFolder}/node_modules/typescript/lib", 43 | 44 | "[shellscript]": { 45 | "editor.defaultFormatter": "foxundermoon.shell-format" 46 | }, 47 | 48 | "[markdown]": { 49 | "editor.defaultFormatter": "DavidAnson.vscode-markdownlint", 50 | "editor.formatOnSave": true 51 | }, 52 | 53 | "[dockerfile]": { 54 | "editor.defaultFormatter": "foxundermoon.shell-format" 55 | }, 56 | 57 | "typescript.preferGoToSourceDefinition": true, 58 | "files.associations": { 59 | "buddy": "typescript", 60 | "*.stx": "vue" 61 | }, 62 | "editor.quickSuggestions": { 63 | "strings": true 64 | }, 65 | "vsicons.associations.files": [ 66 | { 67 | "icon": "${workspaceFolder}/public/favicon.svg", 68 | "extensions": ["stx"], 69 | "format": "svg" 70 | } 71 | ], 72 | "git.enableSmartCommit": true, 73 | "npm.enableRunFromFolder": true, 74 | "npm.packageManager": "bun", 75 | "editor.gotoLocation.multipleDefinitions": "goto", 76 | "search.exclude": { 77 | "**/node_modules": true, 78 | "**/cdk.out": true, 79 | "**/dist": true, 80 | "**/storage/public": true, 81 | "CHANGELOG.md": true 82 | }, 83 | "explorer.confirmDragAndDrop": false, 84 | "todo-tree.highlights.enabled": true, 85 | "cSpell.ignorePaths": [ 86 | "node_modules" 87 | ], 88 | "cSpell.dictionaries": [ 89 | "custom-dictionary" 90 | ], 91 | "cSpell.diagnosticLevel": "Hint", 92 | "cSpell.customDictionaries": { 93 | "stacks": { 94 | "name": "custom-dictionary", 95 | "path": "./.vscode/dictionary.txt", 96 | "scope": "user", 97 | "addWords": true 98 | }, 99 | "custom": true 100 | }, 101 | "terminal.integrated.scrollback": 10000, 102 | "grammarly.files.include": [ 103 | "**/README.md", 104 | "**/readme.md", 105 | "**/*.txt" 106 | ], 107 | "grammarly.files.exclude": [ 108 | "**/dictionary.txt" 109 | ] 110 | } 111 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/input/edge-cases.ts: -------------------------------------------------------------------------------- 1 | // Test edge cases for type inference 2 | 3 | // BigInt literals 4 | export const bigIntLiteral = 123n 5 | export const bigIntExpression = BigInt(456) 6 | 7 | // Symbol types 8 | export const symbolUnique = Symbol('unique') 9 | export const symbolFor = Symbol.for('shared') 10 | 11 | // Template literals 12 | export const templateSimple = `Hello World` 13 | export const templateWithExpression = `Count: ${42}` 14 | export const templateTagged = String.raw`C:\path\to\file` 15 | 16 | // Promise types 17 | export const promiseResolved = Promise.resolve(42) 18 | export const promiseRejected = Promise.reject(new Error('fail')) 19 | export const promiseAll = Promise.all([Promise.resolve(1), Promise.resolve('two')]) 20 | 21 | // Date and built-in types 22 | export const dateInstance = new Date() 23 | export const mapInstance = new Map() 24 | export const setInstance = new Set([1, 2, 3]) 25 | export const regexInstance = new RegExp('[a-z]+', 'gi') 26 | export const errorInstance = new Error('test error') 27 | 28 | // Complex nested structures 29 | export const deeplyNested = { 30 | level1: { 31 | level2: { 32 | level3: { 33 | value: 'deep' as const, 34 | array: [1, [2, [3, [4]]]] as const 35 | } 36 | } 37 | } 38 | } as const 39 | 40 | // Mixed type arrays 41 | export const mixedTypeArray = [ 42 | 'string', 43 | 123, 44 | true, 45 | null, 46 | undefined, 47 | { key: 'value' }, 48 | [1, 2, 3], 49 | () => 'function', 50 | new Date(), 51 | Promise.resolve('async') 52 | ] 53 | 54 | // Function with complex overloads 55 | export function complexOverload(value: string): string 56 | export function complexOverload(value: number): number 57 | export function complexOverload(value: boolean): boolean 58 | export function complexOverload(value: T): T 59 | export function complexOverload(value: any): any { 60 | return value 61 | } 62 | 63 | // Async generator function 64 | export async function* asyncGenerator(items: T[]): AsyncGenerator { 65 | for (const item of items) { 66 | yield await Promise.resolve(item) 67 | } 68 | } 69 | 70 | // Class with decorators (as comments for now) 71 | // @sealed 72 | export class DecoratedClass { 73 | // @readonly 74 | name: string = 'decorated' 75 | 76 | // @deprecated 77 | oldMethod() { 78 | return 'deprecated' 79 | } 80 | } 81 | 82 | // Type with conditional and infer 83 | export type ExtractPromise = T extends Promise ? U : never 84 | export type ExtractArray = T extends (infer U)[] ? U : never 85 | 86 | // Mapped type with template literal 87 | export type Getters = { 88 | [K in keyof T as `get${Capitalize}`]: () => T[K] 89 | } 90 | 91 | // Discriminated union 92 | export type Result = 93 | | { success: true; data: T; error?: never } 94 | | { success: false; data?: never; error: E } 95 | 96 | // Recursive type with constraints 97 | export type DeepReadonly = T extends any[] ? DeepReadonlyArray : 98 | T extends object ? DeepReadonlyObject : 99 | T 100 | 101 | type DeepReadonlyArray = ReadonlyArray> 102 | type DeepReadonlyObject = { 103 | readonly [P in keyof T]: DeepReadonly 104 | } -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0012.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Load configuration from file 3 | * @param options - Configuration loading options 4 | * @returns Promise that resolves to the loaded configuration 5 | * @throws {Error} When configuration file is not found 6 | * @example 7 | * ```typescript 8 | * const config = await loadConfig({ 9 | * name: 'myapp', 10 | * cwd: './config', 11 | * defaultConfig: { port: 3000 } 12 | * }) 13 | * ``` 14 | */ 15 | export declare function loadConfig>(options: ConfigOptions): Promise; 16 | /** 17 | * @deprecated Use the new API instead 18 | * @see {@link loadConfig} 19 | */ 20 | export declare function legacyLoadConfig(): void; 21 | /** 22 | * Constants for the application 23 | */ 24 | export declare const APP_CONSTANTS: { 25 | /** Default port number */ 26 | DEFAULT_PORT: 3000; 27 | /** Maximum retry attempts */ 28 | MAX_RETRIES: 3; 29 | /** 30 | * Timeout duration in milliseconds 31 | * @default 5000 32 | */ 33 | TIMEOUT: 5000; 34 | /** Application version */ 35 | VERSION: '1.0.0' 36 | }; 37 | /** Multi-line comment for exported variable */ 38 | export declare const API_VERSION: '2.0.0'; 39 | /* Block comment style */ 40 | export declare const DEBUG_MODE: unknown; 41 | /** 42 | * Main module documentation 43 | * This module demonstrates various comment types 44 | * @author Test Author 45 | * @version 1.0.0 46 | */ 47 | /** 48 | * Configuration options for the application 49 | * @template T - The type of the configuration data 50 | */ 51 | export declare interface ConfigOptions { 52 | name: string 53 | cwd?: string 54 | defaultConfig: T 55 | verbose?: boolean 56 | } 57 | /** 58 | * A utility type for optional properties 59 | * @example 60 | * ```typescript 61 | * type User = Optional<{ name: string; age: number }, 'age'> 62 | * // Result: { name: string; age?: number } 63 | * ``` 64 | */ 65 | export type Optional = Omit & Partial>; 66 | /** 67 | * Application logger class 68 | * @example 69 | * ```typescript 70 | * const logger = new Logger('MyApp') 71 | * logger.info('Application started') 72 | * ``` 73 | */ 74 | export declare class Logger { 75 | constructor(name: string); 76 | info(message: string, data?: any): void; 77 | error(message: string, error?: Error): void; 78 | debug(message: string): void; 79 | } 80 | /** 81 | * Status enumeration for operations 82 | * @enum {string} 83 | */ 84 | export declare enum Status { 85 | /** Operation is pending */ 86 | PENDING = 'pending', 87 | 88 | /** Operation completed successfully */ 89 | SUCCESS = 'success', 90 | 91 | /** Operation failed with error */ 92 | ERROR = 'error', 93 | 94 | /** 95 | * Operation was cancelled 96 | * @deprecated Use ABORTED instead 97 | */ 98 | CANCELLED = 'cancelled', 99 | 100 | /** Operation was aborted */ 101 | ABORTED = 'aborted' 102 | } 103 | /** 104 | * Database connection options 105 | * @namespace Database 106 | */ 107 | export declare namespace Database { 108 | export interface ConnectionConfig { 109 | host: string 110 | port: number 111 | database: string 112 | username: string 113 | password: string 114 | } 115 | export function connect(config: ConnectionConfig): Promise; 116 | } 117 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/variable.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of const declaration 3 | */ 4 | export declare const conf: { 5 | apiUrl: 'https://api.stacksjs.org'; 6 | timeout: '5000' 7 | }; 8 | export declare let test: 'test'; 9 | export declare var helloWorld: 'Hello World'; 10 | export declare const someObject: { 11 | someString: 'Stacks'; 12 | someNumber: 1000; 13 | someBoolean: true; 14 | someFalse: false; 15 | someFunction: () => unknown; 16 | anotherOne: () => unknown; 17 | someArray: readonly [1, 2, 3]; 18 | someNestedArray: readonly [readonly [1, 2, 3], readonly [4, 5, 6, 7, 8, 9, 10]]; 19 | someNestedArray2: readonly [readonly [1, 2, 3], readonly [4, 5, 6, 7, 8, 9, 10], 'dummy value']; 20 | someNestedArray3: readonly [readonly [1, 2, 3], readonly [4, 5, 6, 7, 8, 9, 10], 'dummy value', readonly [11, 12, 13]]; 21 | someOtherNestedArray: readonly [readonly ['some text', 2, unknown, (() => unknown), unknown], readonly [4, 5, 6, 7, 8, 9, 10]]; 22 | someComplexArray: readonly [readonly [{ 23 | key: 'value' 24 | }], readonly [{ 25 | key2: 'value2' 26 | }, 'test', 1000], readonly ['some string', unknown, unknown]]; 27 | someObject: { 28 | key: 'value' 29 | }; 30 | someNestedObject: { key: { nestedKey: 'value' }; otherKey: { nestedKey: unknown; nestedKey2: () => unknown } }; 31 | someNestedObjectArray: readonly [{ 32 | key: 'value' 33 | }, { 34 | key2: 'value2' 35 | }]; 36 | someOtherObject: unknown; 37 | someInlineCall2: unknown; 38 | someInlineCall3: unknown 39 | }; 40 | export declare const defaultHeaders: { 41 | 'Content-Type': 'application/json' 42 | }; 43 | // Complex Arrays and Tuples 44 | export declare const complexArrays: { 45 | matrix: readonly [readonly [1, 2, readonly [3, 4, readonly [5, 6]]], readonly ['a', 'b', readonly ['c', 'd']], readonly [true, readonly [false, readonly [true]]]]; 46 | tuples: readonly [ 47 | readonly [1, 'string', true] | 48 | readonly ['literal', 42, false] 49 | ]; 50 | // TODO: () => unknown 51 | }; 52 | // Nested Object Types with Methods 53 | export declare const complexObject: { 54 | handlers: { 55 | onSuccess(data: T): unknown; 56 | onError(error: Error & { code?: number }): unknown 57 | }; 58 | utils: { formatters: { date: (input: Date) => unknown; currency: (amount: number, currency?) => unknown } } 59 | }; 60 | // Method Decorators and Metadata (declares as unknown, because it should rely on explicit type) 61 | export declare const methodDecorator: ( 62 | target: any, 63 | propertyKey: string, 64 | descriptor: PropertyDescriptor 65 | ) => unknown; 66 | // declares as SomeType 67 | export declare const methodDecoratorWithExplicitType: ( 68 | target: any, 69 | propertyKey: string, 70 | descriptor: PropertyDescriptor 71 | ) => SomeType; 72 | // Complex Constants with Type Inference 73 | export declare const CONFIG_MAP: { 74 | development: { 75 | features: { 76 | auth: { 77 | providers: readonly ['google', 'github']; 78 | settings: { 79 | timeout: 5000; 80 | retries: 3 81 | } 82 | } 83 | } 84 | }; 85 | production: { 86 | features: { 87 | auth: { 88 | providers: readonly ['google', 'github', 'microsoft']; 89 | settings: { 90 | timeout: 3000; 91 | retries: 5 92 | } 93 | } 94 | } 95 | } 96 | }; 97 | export declare const command: { 98 | run: unknown; 99 | runSync: unknown 100 | }; 101 | -------------------------------------------------------------------------------- /packages/vite-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-plugin-dtsx", 3 | "type": "module", 4 | "version": "0.9.9", 5 | "private": true, 6 | "description": "A modern, fast .d.ts generation tool, powered by Bun.", 7 | "author": "Chris Breuer ", 8 | "license": "MIT", 9 | "homepage": "https://github.com/stacksjs/dtsx#readme", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/stacksjs/dtsx.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/stacksjs/dtsx/issues" 16 | }, 17 | "keywords": [ 18 | "dts", 19 | "generation", 20 | "isolated declarations", 21 | "development", 22 | "bun", 23 | "stacks", 24 | "typescript", 25 | "javascript" 26 | ], 27 | "exports": { 28 | ".": { 29 | "import": "./dist/src/index.js" 30 | }, 31 | "./*": { 32 | "import": "./dist/*" 33 | } 34 | }, 35 | "module": "./dist/src/index.js", 36 | "types": "./dist/index.d.ts", 37 | "bin": { 38 | "dtsx": "./dist/bin/cli.js" 39 | }, 40 | "files": [ 41 | "dist" 42 | ], 43 | "scripts": { 44 | "build": "bun build.ts && bun run compile", 45 | "compile": "bun build ./bin/cli.ts --compile --minify --outfile bin/dtsx", 46 | "compile:all": "bun run compile:linux-x64 && bun run compile:linux-arm64 && bun run compile:windows-x64 && bun run compile:darwin-x64 && bun run compile:darwin-arm64", 47 | "compile:linux-x64": "bun build ./bin/cli.ts --compile --minify --target=bun-linux-x64 --outfile bin/dtsx-linux-x64", 48 | "compile:linux-arm64": "bun build ./bin/cli.ts --compile --minify --target=bun-linux-arm64 --outfile bin/dtsx-linux-arm64", 49 | "compile:windows-x64": "bun build ./bin/cli.ts --compile --minify --target=bun-windows-x64 --outfile bin/dtsx-windows-x64.exe", 50 | "compile:darwin-x64": "bun build ./bin/cli.ts --compile --minify --target=bun-darwin-x64 --outfile bin/dtsx-darwin-x64", 51 | "compile:darwin-arm64": "bun build ./bin/cli.ts --compile --minify --target=bun-darwin-arm64 --outfile bin/dtsx-darwin-arm64", 52 | "lint": "bunx --bun eslint .", 53 | "lint:fix": "bunx --bun eslint . --fix", 54 | "fresh": "bunx rimraf node_modules/ bun.lock && bun i", 55 | "changelog": "bunx changelogen --output CHANGELOG.md", 56 | "prepublishOnly": "bun --bun run build && bun run compile:all && bun run zip", 57 | "release": "bun run changelog && bunx bumpp package.json --all", 58 | "test": "bun test", 59 | "typecheck": "bunx tsc --noEmit", 60 | "zip": "bun run zip:all", 61 | "zip:all": "bun run zip:linux-x64 && bun run zip:linux-arm64 && bun run zip:windows-x64 && bun run zip:darwin-x64 && bun run zip:darwin-arm64", 62 | "zip:linux-x64": "zip -j bin/dtsx-linux-x64.zip bin/dtsx-linux-x64", 63 | "zip:linux-arm64": "zip -j bin/dtsx-linux-arm64.zip bin/dtsx-linux-arm64", 64 | "zip:windows-x64": "zip -j bin/dtsx-windows-x64.zip bin/dtsx-windows-x64.exe", 65 | "zip:darwin-x64": "zip -j bin/dtsx-darwin-x64.zip bin/dtsx-darwin-x64", 66 | "zip:darwin-arm64": "zip -j bin/dtsx-darwin-arm64.zip bin/dtsx-darwin-arm64" 67 | }, 68 | "devDependencies": { 69 | "@stacksjs/dtsx": "workspace:*", 70 | "vite": "^5.0.0" 71 | }, 72 | "peerDependencies": { 73 | "vite": "^4.0.0 || ^5.0.0" 74 | }, 75 | "git-hooks": { 76 | "pre-commit": { 77 | "staged-lint": { 78 | "*.{js,ts,json,yaml,yml,md}": "bunx --bun eslint . --fix" 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /docs/features/type-inference.md: -------------------------------------------------------------------------------- 1 | # Type Inference 2 | 3 | dtsx provides powerful type inference capabilities to automatically determine types from your code. 4 | 5 | ## Basic Type Inference 6 | 7 | ### Literal Types 8 | 9 | ```typescript 10 | // String literal 11 | const name = "John"; // type: "John" 12 | 13 | // Number literal 14 | const age = 25; // type: 25 15 | 16 | // Boolean literal 17 | const isActive = true; // type: true 18 | ``` 19 | 20 | ### Array Types 21 | 22 | ```typescript 23 | // Array of numbers 24 | const numbers = [1, 2, 3]; // type: number[] 25 | 26 | // Tuple type 27 | const tuple = [1, "hello"]; // type: [number, string] 28 | ``` 29 | 30 | ### Object Types 31 | 32 | ```typescript 33 | const user = { 34 | name: "John", 35 | age: 25, 36 | active: true 37 | }; // type: { name: string; age: number; active: boolean; } 38 | ``` 39 | 40 | ## Advanced Type Inference 41 | 42 | ### Function Return Types 43 | 44 | ```typescript 45 | function process(input: T) { 46 | return input; 47 | } // Return type: T 48 | 49 | async function fetchData() { 50 | return await api.get('/data'); 51 | } // Return type: Promise 52 | ``` 53 | 54 | ### Generic Type Inference 55 | 56 | ```typescript 57 | function map(arr: T[], fn: (item: T) => U): U[] { 58 | return arr.map(fn); 59 | } 60 | 61 | // Usage 62 | const numbers = [1, 2, 3]; 63 | const strings = map(numbers, n => n.toString()); 64 | // strings type: string[] 65 | ``` 66 | 67 | ### Union Type Inference 68 | 69 | ```typescript 70 | function processValue(value: string | number) { 71 | if (typeof value === 'string') { 72 | return value.toUpperCase(); // type: string 73 | } 74 | return value.toFixed(2); // type: string 75 | } 76 | ``` 77 | 78 | ## Type Inference Features 79 | 80 | ### Contextual Typing 81 | 82 | - Function parameters 83 | - Object literals 84 | - Array literals 85 | - Class members 86 | - Interface implementations 87 | 88 | ### Type Narrowing 89 | 90 | - Type guards 91 | - Control flow analysis 92 | - Discriminated unions 93 | - Property checks 94 | 95 | ### Type Widening 96 | 97 | - Literal to primitive 98 | - Union type expansion 99 | - Const assertions 100 | - Type assertions 101 | 102 | ## Best Practices 103 | 104 | 1. **Use Type Annotations When Needed** 105 | 106 | ```typescript 107 | // When inference might be too specific 108 | const config: Config = { 109 | // ... 110 | }; 111 | ``` 112 | 113 | 2. **Leverage Const Assertions** 114 | 115 | ```typescript 116 | const colors = ['red', 'green', 'blue'] as const; 117 | // type: readonly ["red", "green", "blue"] 118 | ``` 119 | 120 | 3. **Use Type Guards** 121 | 122 | ```typescript 123 | function isUser(value: unknown): value is User { 124 | return typeof value === 'object' && value !== null && 'name' in value; 125 | } 126 | ``` 127 | 128 | 4. **Avoid Type Assertions** 129 | 130 | ```typescript 131 | // Prefer this 132 | const value = process(input); 133 | 134 | // Over this 135 | const value = process(input) as string; 136 | ``` 137 | 138 | ## Configuration 139 | 140 | ```typescript 141 | interface TypeInferenceConfig { 142 | // Enable/disable type inference 143 | enableInference: boolean; 144 | 145 | // Inference strictness level 146 | strictness: 'loose' | 'strict' | 'very-strict'; 147 | 148 | // Custom inference rules 149 | customRules: InferenceRule[]; 150 | } 151 | ``` 152 | -------------------------------------------------------------------------------- /.zed/settings.json: -------------------------------------------------------------------------------- 1 | // For a full list of overridable settings, and general information on folder-specific settings, 2 | // see the documentation: https://zed.dev/docs/configuring-zed#settings-files 3 | { 4 | "languages": { 5 | "JavaScript": { 6 | "formatter": { 7 | "code_actions": { 8 | "source.fixAll.eslint": true 9 | } 10 | } 11 | }, 12 | "TypeScript": { 13 | "formatter": { 14 | "code_actions": { 15 | "source.fixAll.eslint": true 16 | } 17 | } 18 | }, 19 | "HTML": { 20 | "formatter": { 21 | "code_actions": { 22 | "source.fixAll.eslint": true 23 | } 24 | } 25 | }, 26 | "CSS": { 27 | "formatter": { 28 | "code_actions": { 29 | "source.fixAll.eslint": true 30 | } 31 | } 32 | }, 33 | "Markdown": { 34 | "formatter": { 35 | "code_actions": { 36 | "source.fixAll.eslint": true 37 | } 38 | } 39 | }, 40 | "JSON": { 41 | "formatter": { 42 | "code_actions": { 43 | "source.fixAll.eslint": true 44 | } 45 | } 46 | }, 47 | "JSONC": { 48 | "formatter": { 49 | "code_actions": { 50 | "source.fixAll.eslint": true 51 | } 52 | } 53 | }, 54 | "YAML": { 55 | "formatter": { 56 | "code_actions": { 57 | "source.fixAll.eslint": true 58 | } 59 | } 60 | }, 61 | "XML": { 62 | "formatter": { 63 | "code_actions": { 64 | "source.fixAll.eslint": true 65 | } 66 | } 67 | }, 68 | "TOML": { 69 | "formatter": { 70 | "code_actions": { 71 | "source.fixAll.eslint": true 72 | } 73 | } 74 | } 75 | }, 76 | "lsp": { 77 | "eslint": { 78 | "settings": { 79 | "rulesCustomizations": [ 80 | { 81 | "rule": "style/*", 82 | "severity": "off", 83 | "fixable": true 84 | }, 85 | { 86 | "rule": "format/*", 87 | "severity": "off", 88 | "fixable": true 89 | }, 90 | { 91 | "rule": "*-indent", 92 | "severity": "off", 93 | "fixable": true 94 | }, 95 | { 96 | "rule": "*-spacing", 97 | "severity": "off", 98 | "fixable": true 99 | }, 100 | { 101 | "rule": "*-spaces", 102 | "severity": "off", 103 | "fixable": true 104 | }, 105 | { 106 | "rule": "*-order", 107 | "severity": "off", 108 | "fixable": true 109 | }, 110 | { 111 | "rule": "*-dangle", 112 | "severity": "off", 113 | "fixable": true 114 | }, 115 | { 116 | "rule": "*-newline", 117 | "severity": "off", 118 | "fixable": true 119 | }, 120 | { 121 | "rule": "*quotes", 122 | "severity": "off", 123 | "fixable": true 124 | }, 125 | { 126 | "rule": "*semi", 127 | "severity": "off", 128 | "fixable": true 129 | } 130 | ] 131 | } 132 | } 133 | }, 134 | "file_types": { 135 | "JavaScript": [ 136 | "buddy" 137 | ] 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /packages/dtsx/src/plugins/vite.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Vite plugin for dtsx 3 | * Generates TypeScript declaration files during Vite builds 4 | */ 5 | 6 | import type { DtsGenerationConfig, GenerationStats } from '../types' 7 | import { generate } from '../generator' 8 | 9 | /** 10 | * Vite plugin options 11 | */ 12 | export interface VitePluginOptions extends Partial { 13 | /** 14 | * Generate declarations on build start 15 | * @default true 16 | */ 17 | buildStart?: boolean 18 | 19 | /** 20 | * Generate declarations on build end 21 | * @default false 22 | */ 23 | buildEnd?: boolean 24 | 25 | /** 26 | * Generate declarations on writeBundle 27 | * @default false 28 | */ 29 | writeBundle?: boolean 30 | 31 | /** 32 | * Apply plugin only in specific modes 33 | * @example ['production'] 34 | */ 35 | modes?: string[] 36 | 37 | /** 38 | * Callback after generation completes 39 | */ 40 | onGenerated?: (stats: GenerationStats) => void 41 | 42 | /** 43 | * Callback on generation error 44 | */ 45 | onError?: (error: Error) => void 46 | } 47 | 48 | /** 49 | * Vite plugin interface (minimal type for compatibility) 50 | */ 51 | interface VitePlugin { 52 | name: string 53 | apply?: 'build' | 'serve' | ((config: { mode: string }) => boolean) 54 | buildStart?: () => Promise | void 55 | buildEnd?: () => Promise | void 56 | writeBundle?: () => Promise | void 57 | } 58 | 59 | /** 60 | * Create a Vite plugin for dtsx 61 | * 62 | * @example 63 | * ```ts 64 | * // vite.config.ts 65 | * import { dts } from '@stacksjs/dtsx/plugins/vite' 66 | * 67 | * export default { 68 | * plugins: [ 69 | * dts({ 70 | * root: './src', 71 | * outdir: './dist', 72 | * }), 73 | * ], 74 | * } 75 | * ``` 76 | */ 77 | export function dts(options: VitePluginOptions = {}): VitePlugin { 78 | const { 79 | buildStart = true, 80 | buildEnd = false, 81 | writeBundle = false, 82 | modes, 83 | onGenerated, 84 | onError, 85 | ...generateOptions 86 | } = options 87 | 88 | let currentMode: string = 'production' 89 | 90 | const runGenerate = async (): Promise => { 91 | try { 92 | const stats = await generate(generateOptions) 93 | onGenerated?.(stats) 94 | } 95 | catch (error) { 96 | const err = error instanceof Error ? error : new Error(String(error)) 97 | onError?.(err) 98 | if (!onError) { 99 | console.error('[dtsx] Generation failed:', err.message) 100 | } 101 | } 102 | } 103 | 104 | const shouldRun = (): boolean => { 105 | if (!modes || modes.length === 0) 106 | return true 107 | return modes.includes(currentMode) 108 | } 109 | 110 | return { 111 | name: 'dtsx', 112 | 113 | apply(config) { 114 | currentMode = config.mode 115 | return true 116 | }, 117 | 118 | async buildStart() { 119 | if (buildStart && shouldRun()) { 120 | await runGenerate() 121 | } 122 | }, 123 | 124 | async buildEnd() { 125 | if (buildEnd && shouldRun()) { 126 | await runGenerate() 127 | } 128 | }, 129 | 130 | async writeBundle() { 131 | if (writeBundle && shouldRun()) { 132 | await runGenerate() 133 | } 134 | }, 135 | } 136 | } 137 | 138 | /** 139 | * Alias for dts 140 | */ 141 | export const viteDts: typeof dts = dts 142 | 143 | /** 144 | * Default export 145 | */ 146 | export default dts 147 | -------------------------------------------------------------------------------- /packages/esbuild-plugin/README.md: -------------------------------------------------------------------------------- 1 | # esbuild-plugin-dtsx 2 | 3 | An esbuild plugin for automatic TypeScript declaration file generation using dtsx. 4 | 5 | ## Installation 6 | 7 | ```bash 8 | bun add esbuild-plugin-dtsx -d 9 | # or 10 | npm install esbuild-plugin-dtsx --save-dev 11 | ``` 12 | 13 | ## Usage 14 | 15 | ```typescript 16 | import { build } from 'esbuild' 17 | import { dtsx } from 'esbuild-plugin-dtsx' 18 | 19 | await build({ 20 | entryPoints: ['src/index.ts'], 21 | outdir: 'dist', 22 | bundle: true, 23 | format: 'esm', 24 | plugins: [ 25 | dtsx({ 26 | // Options 27 | }), 28 | ], 29 | }) 30 | ``` 31 | 32 | ## Options 33 | 34 | | Option | Type | Default | Description | 35 | |--------|------|---------|-------------| 36 | | `trigger` | `'build' \| 'watch' \| 'both'` | `'build'` | When to generate declarations | 37 | | `entryPointsOnly` | `boolean` | `true` | Only generate for entry points | 38 | | `declarationDir` | `string` | esbuild outdir | Output directory for declarations | 39 | | `bundle` | `boolean` | `false` | Bundle all declarations into one file | 40 | | `bundleOutput` | `string` | `'index.d.ts'` | Bundled output filename | 41 | | `exclude` | `(string \| RegExp)[]` | `[]` | Patterns to exclude | 42 | | `include` | `(string \| RegExp)[]` | `[]` | Patterns to include | 43 | | `emitOnError` | `boolean` | `true` | Emit even with type errors | 44 | 45 | ## Examples 46 | 47 | ### Basic Usage 48 | 49 | ```typescript 50 | import { build } from 'esbuild' 51 | import { dtsx } from 'esbuild-plugin-dtsx' 52 | 53 | await build({ 54 | entryPoints: ['src/index.ts'], 55 | outdir: 'dist', 56 | plugins: [dtsx()], 57 | }) 58 | ``` 59 | 60 | ### With Bundled Declarations 61 | 62 | ```typescript 63 | import { build } from 'esbuild' 64 | import { dtsx } from 'esbuild-plugin-dtsx' 65 | 66 | await build({ 67 | entryPoints: ['src/index.ts'], 68 | outdir: 'dist', 69 | plugins: [ 70 | dtsx({ 71 | bundle: true, 72 | bundleOutput: 'types.d.ts', 73 | }), 74 | ], 75 | }) 76 | ``` 77 | 78 | ### Watch Mode 79 | 80 | ```typescript 81 | import { context } from 'esbuild' 82 | import { dtsx } from 'esbuild-plugin-dtsx' 83 | 84 | const ctx = await context({ 85 | entryPoints: ['src/index.ts'], 86 | outdir: 'dist', 87 | plugins: [ 88 | dtsx({ 89 | trigger: 'both', // Generate on initial build and rebuilds 90 | }), 91 | ], 92 | }) 93 | 94 | await ctx.watch() 95 | ``` 96 | 97 | ### With Callbacks 98 | 99 | ```typescript 100 | import { build } from 'esbuild' 101 | import { dtsx } from 'esbuild-plugin-dtsx' 102 | 103 | await build({ 104 | entryPoints: ['src/index.ts'], 105 | outdir: 'dist', 106 | plugins: [ 107 | dtsx({ 108 | onStart: () => { 109 | console.log('Starting declaration generation...') 110 | }, 111 | onSuccess: (stats) => { 112 | console.log(`Generated ${stats.totalFiles} files in ${stats.totalTime}ms`) 113 | }, 114 | onError: (error) => { 115 | console.error('Failed to generate declarations:', error.message) 116 | }, 117 | }), 118 | ], 119 | }) 120 | ``` 121 | 122 | ## Additional Plugins 123 | 124 | ### Type Checking Only 125 | 126 | ```typescript 127 | import { dtsxCheck } from 'esbuild-plugin-dtsx' 128 | 129 | await build({ 130 | plugins: [dtsxCheck()], 131 | }) 132 | ``` 133 | 134 | ### Watch for Declaration Changes 135 | 136 | ```typescript 137 | import { dtsxWatch } from 'esbuild-plugin-dtsx' 138 | 139 | await build({ 140 | plugins: [ 141 | dtsxWatch({ 142 | onDeclarationChange: (file) => { 143 | console.log(`Declaration changed: ${file}`) 144 | }, 145 | }), 146 | ], 147 | }) 148 | ``` 149 | 150 | ## License 151 | 152 | MIT 153 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | **PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).** 4 | 5 | ## Supported Versions 6 | 7 | Only the latest major version receives security fixes. 8 | 9 | ## Reporting a Vulnerability 10 | 11 | If you discover a security vulnerability within this package, please send an email to Chris Breuer at chris@stacksjs.org. All security vulnerabilities will be promptly addressed. 12 | 13 | ### Public PGP Key 14 | 15 | ``` 16 | -----BEGIN PGP PUBLIC KEY BLOCK----- 17 | Version: OpenPGP v2.0.8 18 | Comment: https://sela.io/pgp/ 19 | 20 | mQINBGEO6uYBEACw8ldEmdK0xR2RjeGnAyNQItT83JG1BQmByttddyikolGHY0w1 21 | MLCSNAwveUT4f5vbDU41sH8QQDda+NBNIWNo+xtFahfWxi3gYpX0xltgPrYkuBIr 22 | P3b6Hz8KsZ5IvGhP4wXI9LA9x8IUjIDMiObx3LyL2MirgF4kHyHwBX444kcsfo3I 23 | 6wk/kfcZ2lY63tIplYrkp3znTxRX3lJyroOkEpCVHyajftw41K+WEKstWVAKvxpc 24 | nHg6TW91AyWCS6TLrsmhdnWYfA9lSULlxbH/NQ0HEYRLb+NoTVGWv5y6WC2OFoJO 25 | SvCae1GOqUIdbW4AC3/lQsqI+i2/nyZvaD5xu+HUrB/qN0d4iw2X+6pj+wsO7XQj 26 | x5qbcIZBmNoUfBkjZH8+ZgH6Kit+0qBMMY8afLjngxCCwrlvfRGmEiC8ehNLP7a5 27 | BjDFbjPBjyjLuZskIerNzHHkJ6XUTQQ8LNfzS32xu8AsF+IknQ/1QuZIfSoRLQdJ 28 | q7s+5hydM0Mtryg8VHL0AN/sXo70EWEl1YgDLEF4iu5cMWWFXlesDmR9wdhDMi8G 29 | S28MRyxx0yitmrEt2WJoGa7D8l9bsVw4ntN5ZP3rd0P67H+lC5FcFqSzFJtxHXLQ 30 | 1JZOv/P7AZ6Ps8mb9gLzgMnwmPXBu07AExJutJQaj4U24hJ4Ko3+D9RQ+QARAQAB 31 | tB1DaHJpcyBCcmV1ZXIgPGNocmlzQG1lZW1hLmlvPokCVAQTAQgAPhYhBHLTi9Xr 32 | 0tFrh0WzUUaA85gSbnQlBQJhDurmAhsDBQkHhh8zBQsJCAcCBhUKCQgLAgQWAgMB 33 | Ah4BAheAAAoJEEaA85gSbnQlhXAQAK+LLp53dQLoYlwOH/L4XQfY+AVtZXhQwg2+ 34 | gSR7tNP8i+XDvw7OA8UeQ9CKSlIarK/jnynzT91WiwWskGr+DeVR0enuG3CFEW/q 35 | X3o0WH8MjSNhJEFQ6Mo2foAMPOO97Fl7R5vyhEhSXIocnGLdAngxP5sYtOuY32c+ 36 | Bu2z72ChIvpGXh2j44ThHs5xsoq+O5OZg5x2xTaMCyndzpgJTSDlAldnzd0wxbtC 37 | OlSvsgmSWdXls/5pZbE7gny6OuxFo5zxpHEcJnWW//e0cZXKgW4Ps3aNzSPmMKDl 38 | va0Mg2toP9H6z+k9c8H0UZm0KKvKBZi9Bvxcvdc5yLcOeR+Rom1YYNcBsxfJc62Q 39 | 6JbaZvDwN3e0RFgitwEyo3Danimp53v1DXbrNfd78FrskES10cX89lBXubSyPpSc 40 | JP1i8IPcooDi8yHw3zAms6qnrEWYFIxCqN8id9gsLxfzwVCRXvUqDhXmzMcZZB2E 41 | wiHP97bq9chlWTQuCkDXrbzHD1SMkaOjbFiVo+w18jNsXdEhHvZKnUQzv0560w2x 42 | DM8NBARGNupmIOc9e4uy5pJIZp4fhKvpGqqih7PpHKFCo8eC+/HgsJh17MpzFTqQ 43 | 5hPaCPCc5fnX/GIGdj3Ax6bATX5fAceEGexvjThpP8tKIPWAWbQFjHnnIay0f/nL 44 | wRmWWqeQuQINBGEO6uYBEADLLrKBJ+4VWmGWlylsUmwRoFmwu/GZokCL60jKWtOu 45 | i2JK9JhptL+MNvqFoGChVs+Okx9CYscEGOxnK38frb+H6FrlOXsABFQmg2DBWjkW 46 | 9VYkXmQ0M9c/ciMj8m55sh4y6E8ITZ4OuNoLF3ElmKWANU29Z2fW+C8Q7OHiawfU 47 | XJ2UwCUVymQntWrtPCSgBLbgh71l/TSTLdwbwGVFWtxQvO7TXeP+nUNNWRG/UMeT 48 | PSHQ7ANMnllkQNsQtuS/Lkcs/BSM+70g0LvZ88loAU80bxV6XCx7vaKKWV19Lxob 49 | 7tu/d7k/kvDq+sGpjPmv0mZCury0F3bk7VHVQ6DKVIt/3R16qUBmGKwECVXDAb2H 50 | zebDcTzMvvICD3fXV5Ye9kCNAeQfMVEXMHf0H14wB1AAr2WAfGyl+g2xwqNRp7DK 51 | Da2JigDvGA14iLwrDFxdpHYIJfMReRngEX6i28WB2GewaIsDGxqsqO0jdwnlJush 52 | 0USUnlN4iwQABM+xqJnfX0wZTVXjpw1Thgh1E/0MSceJF3PgZ0CDX9MIZ/azbqsU 53 | tg06F8KxJcwvKbBdp9jTeN0TRSMPlonyAfZblRVyj0/gPcwlBIB/IajwFPCi4eQ+ 54 | /to/kuVe5dnoDVqrNJ2o7sSNi3xEUc7o02RyJhemCrsnPpYyXFmr0ku7c/J347L1 55 | xQARAQABiQI8BBgBCAAmFiEEctOL1evS0WuHRbNRRoDzmBJudCUFAmEO6uYCGwwF 56 | CQeGHzMACgkQRoDzmBJudCXg/g//VUscqD0h28WYBBffWJb+AAj7T+NNTNcH3I+u 57 | BHcOsvmdH/HSayTHvntqUnV4oVCiAo4U/0xlopJpU45OxPV7vjx66yWAXrwApSJs 58 | BIAa4P/GK2V8q008nP37ha36IHKB11LWZsnKh7/zFOXJ1XlX6FuqvFZkcJNJePCU 59 | sg0RbjlAkRUL7gOFeBktZXGS4cmAzhpUAdDSdZnzVtDpjY4jUswLVn3JZ07CDZx+ 60 | 5RRCZKqbT/+2UgwDDe2f+gmoNCrGmaHfHCrk3S0DYBxR/BBMmWnQe2YiM+eHufB9 61 | MIApvuEgEp0RX68Za/NEdht8vm4LLeZdNxwSG+BgW8vPQRsgT1V+43aNatt5jbHD 62 | hUC5CksIt+i5gy7R9my1xdQ0lqB4jYLcbtBHz0A7E9d9j5kRaGLX3fTr6pOb9KxJ 63 | Ek+KrMLBPp7g4fkn6qUr3xCt1Ss+sDUegHby5PM1ddvs/lbYhZOjq6+7gPvtFkF8 64 | OcFaR3o0xMRuoSk4/zkge4eeND+XR7+2xvA9G9vDBJ7wV8bbxbEnp7PEFWnZVqDR 65 | Lo2polLYC3wvFQl14tyT3OoDH+mkCPcD+GbDwYbWpcb+v6uCkquqAcHTrbYhwhxY 66 | kXSnpSzMVde7LbHMHiVr0Ubl3k4+1uNiKhY7CLW9pLJwJ4mUmG2VX3YPfG4shnYR 67 | HF/6SiI= 68 | =le/X 69 | -----END PGP PUBLIC KEY BLOCK----- 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/_data/team.js: -------------------------------------------------------------------------------- 1 | export const core = [ 2 | { 3 | avatar: 'https://ca.slack-edge.com/TAFCQEYEP-UAFFN6YSE-fb28a6b5d278-512', 4 | name: 'Chris Breuer', 5 | title: 'Creator', 6 | org: 'Stacks', 7 | orgLink: 'https://stacksjs.org/', 8 | desc: 'Independent open source developer, builder in the Stacks ecosystem.', 9 | links: [ 10 | { icon: 'github', link: 'https://github.com/chrisbbreuer' }, 11 | { icon: 'bluesky', link: 'https://bsky.app/profile/chrisbreuer.dev' }, 12 | { icon: 'twitter', link: 'https://twitter.com/chrisbbreuer' }, 13 | ], 14 | sponsor: 'https://github.com/sponsors/chrisbbreuer', 15 | }, 16 | { 17 | avatar: 'https://avatars.githubusercontent.com/u/72235211', 18 | name: 'Blake Ayer', 19 | title: 'Cloud Genius', 20 | org: 'Stacks', 21 | orgLink: 'https://stacksjs.org/', 22 | desc: 'Core team member of Stacks.', 23 | links: [{ icon: 'github', link: 'https://github.com/blakeayer' }], 24 | sponsor: 'https://github.com/sponsors/blakeayer', 25 | }, 26 | { 27 | avatar: 'https://avatars.githubusercontent.com/u/19656966', 28 | name: 'Zoltan', 29 | title: 'Desktop Wizard', 30 | org: 'Stacks', 31 | orgLink: 'https://stacksjs.org/', 32 | desc: 'Core team member of Stacks.', 33 | links: [{ icon: 'github', link: 'https://github.com/konkonam' }], 34 | sponsor: 'https://github.com/sponsors/konkonam', 35 | }, 36 | { 37 | avatar: 'https://www.averyahill.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Favatar.626e0c07.jpg&w=128&q=75', 38 | name: 'Avery Hill', 39 | title: 'Merchandise & Event Planning', 40 | org: 'Stacks', 41 | orgLink: 'https://stacksjs.org/', 42 | desc: 'Core team member of Stacks.', 43 | links: [{ icon: 'github', link: 'https://www.averyahill.com/' }], 44 | }, 45 | { 46 | avatar: 'https://avatars.githubusercontent.com/u/10015302', 47 | name: 'Harlequin Doyon', 48 | title: 'A collaborative being', 49 | org: 'Stacks', 50 | orgLink: 'https://stacksjs.org/', 51 | desc: 'Core team member of Stacks.', 52 | links: [{ icon: 'github', link: 'https://github.com/harlekoy' }], 53 | sponsor: 'https://github.com/sponsors/harlekoy', 54 | }, 55 | { 56 | avatar: 'https://ca.slack-edge.com/TAFCQEYEP-UCX5LQ2NP-g16e383ecf66-512', 57 | name: 'Germaine Abellanosa', 58 | title: 'Social Tech Genius', 59 | org: 'Stacks', 60 | orgLink: 'https://stacksjs.org/', 61 | desc: 'Core team member of Stacks.', 62 | links: [{ icon: 'github', link: 'https://github.com/germikee' }], 63 | sponsor: 'https://github.com/sponsors/germikee', 64 | }, 65 | { 66 | avatar: 'https://avatars.githubusercontent.com/u/58994540', 67 | name: 'Frederik Bußmann', 68 | title: 'A collaborative being', 69 | org: 'Stacks', 70 | orgLink: 'https://stacksjs.org/', 71 | desc: 'Core team member of Stacks.', 72 | links: [{ icon: 'github', link: 'https://github.com/freb97' }], 73 | sponsor: 'https://github.com/sponsors/freb97', 74 | }, 75 | { 76 | avatar: 'https://avatars.githubusercontent.com/u/977413', 77 | name: 'Dorell James', 78 | title: 'A collaborative being', 79 | org: 'Stacks', 80 | orgLink: 'https://stacksjs.org/', 81 | desc: 'Core team member of Stacks.', 82 | links: [ 83 | { icon: 'github', link: 'https://github.com/dorelljames' }, 84 | { icon: 'twitter', link: 'https://twitter.com/dorelljames' }, 85 | ], 86 | sponsor: 'https://github.com/sponsors/dorelljames', 87 | }, 88 | { 89 | avatar: 'https://avatars.githubusercontent.com/u/29087513', 90 | name: 'Glenn Michael', 91 | title: 'Desktop, Mobile, Web', 92 | org: 'Stacks', 93 | orgLink: 'https://stacksjs.org/', 94 | desc: 'Core team member of Stacks.', 95 | links: [{ icon: 'github', link: 'https://github.com/glennmichael123' }], 96 | sponsor: 'https://github.com/sponsors/glennmichael123', 97 | }, 98 | ] 99 | 100 | export const emeriti = [ 101 | // 102 | ] 103 | -------------------------------------------------------------------------------- /packages/dtsx/src/plugins/tsup.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * tsup plugin for dtsx 3 | * Generates TypeScript declaration files during tsup builds 4 | */ 5 | 6 | import type { DtsGenerationConfig, GenerationStats } from '../types' 7 | import { generate } from '../generator' 8 | 9 | /** 10 | * tsup plugin options 11 | */ 12 | export interface TsupPluginOptions extends Partial { 13 | /** 14 | * Generate declarations on build start 15 | * @default false 16 | */ 17 | onBuildStart?: boolean 18 | 19 | /** 20 | * Generate declarations on build end 21 | * @default true 22 | */ 23 | onBuildEnd?: boolean 24 | 25 | /** 26 | * Callback after generation completes 27 | */ 28 | onGenerated?: (stats: GenerationStats) => void 29 | 30 | /** 31 | * Callback on generation error 32 | */ 33 | onError?: (error: Error) => void 34 | } 35 | 36 | /** 37 | * tsup plugin interface 38 | */ 39 | interface TsupPlugin { 40 | name: string 41 | buildStart?: () => void | Promise 42 | buildEnd?: (ctx: { writtenFiles: Array<{ name: string, size: number }> }) => void | Promise 43 | esbuildOptions?: (options: Record) => void 44 | } 45 | 46 | /** 47 | * Create a tsup plugin for dtsx 48 | * 49 | * @example 50 | * ```ts 51 | * // tsup.config.ts 52 | * import { dtsxPlugin } from '@stacksjs/dtsx/plugins/tsup' 53 | * import { defineConfig } from 'tsup' 54 | * 55 | * export default defineConfig({ 56 | * entry: ['./src/index.ts'], 57 | * outDir: './dist', 58 | * plugins: [ 59 | * dtsxPlugin({ 60 | * root: './src', 61 | * outdir: './dist', 62 | * }), 63 | * ], 64 | * }) 65 | * ``` 66 | */ 67 | export function dtsxPlugin(options: TsupPluginOptions = {}): TsupPlugin { 68 | const { 69 | onBuildStart = false, 70 | onBuildEnd = true, 71 | onGenerated, 72 | onError, 73 | ...generateOptions 74 | } = options 75 | 76 | let esbuildOutdir: string | undefined 77 | let esbuildEntryPoints: string[] | undefined 78 | 79 | const runGenerate = async (): Promise => { 80 | // Merge esbuild options if available 81 | const opts = { ...generateOptions } 82 | if (!opts.outdir && esbuildOutdir) { 83 | opts.outdir = esbuildOutdir 84 | } 85 | if (!opts.entrypoints && esbuildEntryPoints) { 86 | opts.entrypoints = esbuildEntryPoints 87 | } 88 | 89 | try { 90 | const stats = await generate(opts) 91 | onGenerated?.(stats) 92 | } 93 | catch (error) { 94 | const err = error instanceof Error ? error : new Error(String(error)) 95 | onError?.(err) 96 | if (!onError) { 97 | console.error('[dtsx] Generation failed:', err.message) 98 | } 99 | } 100 | } 101 | 102 | return { 103 | name: 'dtsx', 104 | 105 | esbuildOptions(esbuildOpts) { 106 | // Capture esbuild options for later use 107 | if (esbuildOpts.outdir && typeof esbuildOpts.outdir === 'string') { 108 | esbuildOutdir = esbuildOpts.outdir 109 | } 110 | if (esbuildOpts.entryPoints) { 111 | if (Array.isArray(esbuildOpts.entryPoints)) { 112 | esbuildEntryPoints = esbuildOpts.entryPoints as string[] 113 | } 114 | else if (typeof esbuildOpts.entryPoints === 'object') { 115 | esbuildEntryPoints = Object.values(esbuildOpts.entryPoints as Record) 116 | } 117 | } 118 | }, 119 | 120 | async buildStart() { 121 | if (onBuildStart) { 122 | await runGenerate() 123 | } 124 | }, 125 | 126 | async buildEnd(_ctx) { 127 | if (onBuildEnd) { 128 | await runGenerate() 129 | } 130 | }, 131 | } 132 | } 133 | 134 | /** 135 | * Alias for dtsxPlugin 136 | */ 137 | export const tsupDts: typeof dtsxPlugin = dtsxPlugin 138 | 139 | /** 140 | * Alias matching common naming convention 141 | */ 142 | export const dts: typeof dtsxPlugin = dtsxPlugin 143 | 144 | /** 145 | * Default export 146 | */ 147 | export default dtsxPlugin 148 | -------------------------------------------------------------------------------- /packages/dtsx/src/plugins/bun.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Bun build plugin for dtsx 3 | * Generates TypeScript declaration files during Bun builds 4 | */ 5 | 6 | import type { DtsGenerationConfig, GenerationStats } from '../types' 7 | import { generate } from '../generator' 8 | 9 | /** 10 | * Bun plugin options 11 | */ 12 | export interface BunPluginOptions extends Partial { 13 | /** 14 | * Generate declarations before build 15 | * @default false 16 | */ 17 | preBuild?: boolean 18 | 19 | /** 20 | * Generate declarations after build 21 | * @default true 22 | */ 23 | postBuild?: boolean 24 | 25 | /** 26 | * Callback after generation completes 27 | */ 28 | onGenerated?: (stats: GenerationStats) => void 29 | 30 | /** 31 | * Callback on generation error 32 | */ 33 | onError?: (error: Error) => void 34 | } 35 | 36 | /** 37 | * Bun plugin interface 38 | */ 39 | interface BunPlugin { 40 | name: string 41 | setup: (build: BunBuild) => void | Promise 42 | } 43 | 44 | /** 45 | * Bun build interface (minimal type) 46 | */ 47 | interface BunBuild { 48 | onStart: (callback: () => void | Promise) => void 49 | onLoad: (options: { filter: RegExp }, callback: (args: { path: string }) => unknown) => void 50 | config: { 51 | entrypoints: string[] 52 | outdir?: string 53 | root?: string 54 | } 55 | } 56 | 57 | /** 58 | * Create a Bun build plugin for dtsx 59 | * 60 | * @example 61 | * ```ts 62 | * // build.ts 63 | * import { dts } from '@stacksjs/dtsx/plugins/bun' 64 | * 65 | * await Bun.build({ 66 | * entrypoints: ['./src/index.ts'], 67 | * outdir: './dist', 68 | * plugins: [ 69 | * dts({ 70 | * root: './src', 71 | * outdir: './dist', 72 | * }), 73 | * ], 74 | * }) 75 | * ``` 76 | */ 77 | export function dts(options: BunPluginOptions = {}): BunPlugin { 78 | const { 79 | preBuild = false, 80 | postBuild = true, 81 | onGenerated, 82 | onError, 83 | ...generateOptions 84 | } = options 85 | 86 | const runGenerate = async (): Promise => { 87 | try { 88 | const stats = await generate(generateOptions) 89 | onGenerated?.(stats) 90 | } 91 | catch (error) { 92 | const err = error instanceof Error ? error : new Error(String(error)) 93 | onError?.(err) 94 | if (!onError) { 95 | console.error('[dtsx] Generation failed:', err.message) 96 | } 97 | } 98 | } 99 | 100 | return { 101 | name: 'dtsx', 102 | 103 | async setup(build) { 104 | // Get config from build if not provided 105 | const config = build.config 106 | if (!generateOptions.entrypoints && config.entrypoints) { 107 | generateOptions.entrypoints = config.entrypoints 108 | } 109 | if (!generateOptions.outdir && config.outdir) { 110 | generateOptions.outdir = config.outdir 111 | } 112 | if (!generateOptions.root && config.root) { 113 | generateOptions.root = config.root 114 | } 115 | 116 | if (preBuild) { 117 | build.onStart(async () => { 118 | await runGenerate() 119 | }) 120 | } 121 | 122 | if (postBuild) { 123 | // Bun doesn't have a native postBuild hook, so we use onLoad with a virtual module 124 | // that triggers at the end of the build process 125 | let hasRun = false 126 | build.onLoad({ filter: /.*/ }, async (_args) => { 127 | // This is a workaround - in practice, postBuild runs after all modules are loaded 128 | if (!hasRun) { 129 | // Schedule to run after build completes 130 | queueMicrotask(async () => { 131 | if (!hasRun) { 132 | hasRun = true 133 | await runGenerate() 134 | } 135 | }) 136 | } 137 | return undefined 138 | }) 139 | } 140 | }, 141 | } 142 | } 143 | 144 | /** 145 | * Alias for dts 146 | */ 147 | export const bunDts: typeof dts = dts 148 | 149 | /** 150 | * Default export 151 | */ 152 | export default dts 153 | -------------------------------------------------------------------------------- /docs/advanced/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | This guide covers common issues and their solutions when using dtsx. 4 | 5 | ## Common Issues 6 | 7 | ### Type Resolution Errors 8 | 9 | ```typescript 10 | // Error: Cannot find type definition for 'User' 11 | import { User } from './types'; 12 | 13 | // Solution: Ensure type definition exists 14 | interface User { 15 | name: string; 16 | age: number; 17 | } 18 | ``` 19 | 20 | ### Import Errors 21 | 22 | ```typescript 23 | // Error: Module not found 24 | import { User } from './types'; 25 | 26 | // Solution: Check file path and extension 27 | import { User } from './types.js'; 28 | // or 29 | import { User } from './types/index.js'; 30 | ``` 31 | 32 | ### Circular Dependencies 33 | 34 | ```typescript 35 | // Error: Circular dependency detected 36 | interface Parent { 37 | children: Child[]; 38 | } 39 | 40 | interface Child { 41 | parent: Parent; 42 | } 43 | 44 | // Solution: Use type references 45 | interface Parent { 46 | children: Child[]; 47 | } 48 | 49 | interface Child { 50 | parent: Parent; 51 | } 52 | ``` 53 | 54 | ## Debugging Techniques 55 | 56 | ### Verbose Logging 57 | 58 | ```typescript 59 | // Enable verbose logging 60 | const config = { 61 | verbose: true, 62 | // or specific categories 63 | verbose: ['imports', 'types', 'processing'], 64 | }; 65 | ``` 66 | 67 | ### Type Tracking 68 | 69 | ```typescript 70 | // Track type usage 71 | const config = { 72 | tracking: { 73 | types: true, 74 | relationships: true, 75 | usage: true, 76 | }, 77 | }; 78 | ``` 79 | 80 | ### Import Tracking 81 | 82 | ```typescript 83 | // Track import usage 84 | const config = { 85 | tracking: { 86 | imports: true, 87 | importUsage: true, 88 | importRelationships: true, 89 | }, 90 | }; 91 | ``` 92 | 93 | ## Performance Profiling 94 | 95 | ### Memory Profiling 96 | 97 | ```typescript 98 | // Enable memory profiling 99 | const config = { 100 | profiling: { 101 | memory: true, 102 | // Memory limit in MB 103 | memoryLimit: 1024, 104 | }, 105 | }; 106 | ``` 107 | 108 | ### CPU Profiling 109 | 110 | ```typescript 111 | // Enable CPU profiling 112 | const config = { 113 | profiling: { 114 | cpu: true, 115 | // CPU sampling interval in ms 116 | samplingInterval: 100, 117 | }, 118 | }; 119 | ``` 120 | 121 | ### I/O Profiling 122 | 123 | ```typescript 124 | // Enable I/O profiling 125 | const config = { 126 | profiling: { 127 | io: true, 128 | // I/O operations to track 129 | trackOperations: ['read', 'write'], 130 | }, 131 | }; 132 | ``` 133 | 134 | ## Type Resolution 135 | 136 | ### Type Inference 137 | 138 | ```typescript 139 | // Enable type inference 140 | const config = { 141 | typeInference: { 142 | enabled: true, 143 | // Inference strictness 144 | strictness: 'strict', 145 | }, 146 | }; 147 | ``` 148 | 149 | ### Type Checking 150 | 151 | ```typescript 152 | // Enable type checking 153 | const config = { 154 | typeChecking: { 155 | enabled: true, 156 | // Type checking strictness 157 | strictness: 'strict', 158 | }, 159 | }; 160 | ``` 161 | 162 | ### Type Validation 163 | 164 | ```typescript 165 | // Enable type validation 166 | const config = { 167 | typeValidation: { 168 | enabled: true, 169 | // Validation rules 170 | rules: { 171 | noAny: true, 172 | noUnknown: true, 173 | noImplicitAny: true, 174 | }, 175 | }, 176 | }; 177 | ``` 178 | 179 | ## Best Practices 180 | 181 | 1. **Error Handling** 182 | - Use try-catch blocks 183 | - Log errors properly 184 | - Provide helpful error messages 185 | - Handle edge cases 186 | 187 | 2. **Debugging** 188 | - Enable verbose logging 189 | - Use debugging tools 190 | - Track type usage 191 | - Monitor performance 192 | 193 | 3. **Performance** 194 | - Profile memory usage 195 | - Profile CPU usage 196 | - Profile I/O operations 197 | - Optimize bottlenecks 198 | 199 | 4. **Type Resolution** 200 | - Use type inference 201 | - Enable type checking 202 | - Validate types 203 | - Handle edge cases 204 | -------------------------------------------------------------------------------- /docs/advanced/type-processing.md: -------------------------------------------------------------------------------- 1 | # Advanced Type Processing 2 | 3 | This guide covers advanced type processing capabilities in dtsx. 4 | 5 | ## Complex Type Inference 6 | 7 | ### Nested Types 8 | 9 | ```typescript 10 | interface User { 11 | profile: { 12 | name: string; 13 | address: { 14 | street: string; 15 | city: string; 16 | country: string; 17 | }; 18 | }; 19 | settings: { 20 | preferences: { 21 | theme: 'light' | 'dark'; 22 | notifications: boolean; 23 | }; 24 | }; 25 | } 26 | ``` 27 | 28 | ### Recursive Types 29 | 30 | ```typescript 31 | interface TreeNode { 32 | value: number; 33 | children: TreeNode[]; 34 | } 35 | 36 | type JsonValue = 37 | | string 38 | | number 39 | | boolean 40 | | null 41 | | JsonValue[] 42 | | { [key: string]: JsonValue }; 43 | ``` 44 | 45 | ## Type Relationship Tracking 46 | 47 | ### Type Dependencies 48 | 49 | ```typescript 50 | // Type dependencies are tracked automatically 51 | interface User { 52 | id: UserId; 53 | role: UserRole; 54 | permissions: Permission[]; 55 | } 56 | 57 | type UserId = string; 58 | type UserRole = 'admin' | 'user'; 59 | interface Permission { 60 | name: string; 61 | level: number; 62 | } 63 | ``` 64 | 65 | ### Circular Dependencies 66 | 67 | ```typescript 68 | // Circular dependencies are handled correctly 69 | interface Node { 70 | next: Node | null; 71 | value: number; 72 | } 73 | 74 | interface Parent { 75 | children: Child[]; 76 | } 77 | 78 | interface Child { 79 | parent: Parent; 80 | } 81 | ``` 82 | 83 | ## Custom Type Transformations 84 | 85 | ### Type Mapping 86 | 87 | ```typescript 88 | // Transform types using type mapping 89 | type ReadonlyDeep = { 90 | readonly [P in keyof T]: T[P] extends object 91 | ? ReadonlyDeep 92 | : T[P]; 93 | }; 94 | 95 | type Nullable = T | null; 96 | type Optional = T | undefined; 97 | ``` 98 | 99 | ### Type Composition 100 | 101 | ```typescript 102 | // Compose types using intersection types 103 | type WithId = T & { id: string }; 104 | type WithTimestamps = T & { 105 | createdAt: Date; 106 | updatedAt: Date; 107 | }; 108 | 109 | type UserWithMetadata = WithId>; 110 | ``` 111 | 112 | ## Type Augmentation 113 | 114 | ### Module Augmentation 115 | 116 | ```typescript 117 | // Augment existing modules 118 | declare module './types' { 119 | interface User { 120 | metadata: { 121 | lastLogin: Date; 122 | preferences: UserPreferences; 123 | }; 124 | } 125 | } 126 | ``` 127 | 128 | ### Interface Merging 129 | 130 | ```typescript 131 | // Merge interfaces 132 | interface User { 133 | name: string; 134 | } 135 | 136 | interface User { 137 | age: number; 138 | } 139 | 140 | // Result: 141 | // interface User { 142 | // name: string; 143 | // age: number; 144 | // } 145 | ``` 146 | 147 | ## Advanced Type Features 148 | 149 | ### Conditional Types 150 | 151 | ```typescript 152 | type TypeName = 153 | T extends string ? "string" : 154 | T extends number ? "number" : 155 | T extends boolean ? "boolean" : 156 | T extends undefined ? "undefined" : 157 | T extends Function ? "function" : 158 | "object"; 159 | ``` 160 | 161 | ### Mapped Types with Constraints 162 | 163 | ```typescript 164 | type PickByType = { 165 | [P in keyof T as T[P] extends U ? P : never]: T[P]; 166 | }; 167 | 168 | type StringProps = PickByType; 169 | ``` 170 | 171 | ## Best Practices 172 | 173 | 1. **Use Type Composition** 174 | - Combine types using intersection types 175 | - Create reusable type utilities 176 | - Keep type definitions modular 177 | 178 | 2. **Handle Circular Dependencies** 179 | - Use interface merging 180 | - Leverage type aliases 181 | - Consider type composition 182 | 183 | 3. **Type Augmentation** 184 | - Use module augmentation for extending types 185 | - Keep augmentations close to their usage 186 | - Document augmented types 187 | 188 | 4. **Type Transformations** 189 | - Create reusable type transformers 190 | - Use conditional types for complex logic 191 | - Leverage mapped types for property transformations 192 | -------------------------------------------------------------------------------- /packages/dtsx/test/fixtures/output/example/0004.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * DtsGenerationConfig 3 | * 4 | * This is the configuration object for the DTS generation process. 5 | */ 6 | export declare interface DtsGenerationConfig { 7 | cwd: string 8 | root: string 9 | entrypoints: string[] 10 | outdir: string 11 | keepComments: boolean 12 | clean: boolean 13 | tsconfigPath: string 14 | verbose: boolean 15 | } 16 | /** 17 | * Regular expression patterns used throughout the module 18 | */ 19 | export declare interface RegexPatterns { 20 | readonly typeImport: RegExp 21 | readonly regularImport: RegExp 22 | readonly bracketOpen: RegExp 23 | readonly bracketClose: RegExp 24 | readonly functionReturn: RegExp 25 | readonly typeAnnotation: RegExp 26 | readonly asyncFunction: RegExp 27 | readonly genericParams: RegExp 28 | readonly functionParams: RegExp 29 | readonly functionReturnType: RegExp 30 | readonly destructuredParams: RegExp 31 | readonly typePattern: RegExp 32 | readonly valueReference: RegExp 33 | readonly typeReference: RegExp 34 | readonly functionName: RegExp 35 | readonly exportCleanup: RegExp 36 | readonly defaultExport: RegExp 37 | readonly complexType: RegExp 38 | readonly unionIntersection: RegExp 39 | readonly mappedType: RegExp 40 | readonly conditionalType: RegExp 41 | readonly genericConstraints: RegExp 42 | readonly functionOverload: RegExp 43 | readonly moduleDeclaration: RegExp 44 | readonly moduleAugmentation: RegExp 45 | } 46 | export declare interface ImportTrackingState { 47 | typeImports: Map> 48 | valueImports: Map> 49 | usedTypes: Set 50 | usedValues: Set 51 | exportedTypes: Set 52 | exportedValues: Set 53 | valueAliases: Map 54 | importSources: Map 55 | typeExportSources: Map 56 | defaultExportValue?: string 57 | } 58 | export declare interface ProcessingState { 59 | dtsLines: string[] 60 | imports: string[] 61 | usedTypes: Set 62 | typeSources: Map 63 | defaultExport: string | null 64 | exportAllStatements: string[] 65 | currentDeclaration: string 66 | lastCommentBlock: string 67 | bracketCount: number 68 | isMultiLineDeclaration: boolean 69 | moduleImports: Map 70 | availableTypes: Map 71 | availableValues: Map 72 | currentIndentation: string 73 | declarationBuffer: { 74 | type: 'interface' | 'type' | 'const' | 'function' | 'import' | 'export' 75 | indent: string 76 | lines: string[] 77 | comments: string[] 78 | } | null 79 | importTracking: ImportTrackingState 80 | defaultExports: Set 81 | currentScope: 'top' | 'function' 82 | } 83 | export declare interface MethodSignature { 84 | name: string 85 | async: boolean 86 | generics: string 87 | params: string 88 | returnType: string 89 | } 90 | /** 91 | * Represents property type information with support for nested structures 92 | */ 93 | export declare interface PropertyInfo { 94 | key: string 95 | value: string 96 | type: string 97 | nested?: PropertyInfo[] 98 | method?: MethodSignature 99 | } 100 | /** 101 | * Import statement metadata and tracking 102 | */ 103 | export declare interface ImportInfo { 104 | kind: 'type' | 'value' | 'mixed' 105 | usedTypes: Set 106 | usedValues: Set 107 | source: string 108 | } 109 | /** 110 | * Function signature components 111 | */ 112 | export declare interface FunctionSignature { 113 | name: string 114 | params: string 115 | returnType: string 116 | generics: string 117 | } 118 | export declare interface ProcessedMethod { 119 | name: string 120 | signature: string 121 | } 122 | /** 123 | * DtsGenerationOption 124 | * 125 | * This is the configuration object for the DTS generation process. 126 | */ 127 | export type DtsGenerationOption = Partial; 128 | /** 129 | * DtsGenerationOptions 130 | * 131 | * This is the configuration object for the DTS generation process. 132 | */ 133 | export type DtsGenerationOptions = DtsGenerationOption | DtsGenerationOption[]; 134 | -------------------------------------------------------------------------------- /packages/dtsx/test/dts.test.ts: -------------------------------------------------------------------------------- 1 | import type { DtsGenerationOption } from '../src/types' 2 | import { afterEach, describe, expect, it } from 'bun:test' 3 | import { rm } from 'node:fs/promises' 4 | import { join } from 'node:path' 5 | import { generate } from '../src/generator' 6 | 7 | describe('dts-generation', () => { 8 | const testDir = join(__dirname, 'fixtures') 9 | const inputDir = join(testDir, 'input') 10 | const outputDir = join(testDir, 'output') 11 | const generatedDir = join(testDir, 'generated') 12 | 13 | // List of all example files to test 14 | const examples = [ 15 | '0001', 16 | '0002', 17 | '0003', 18 | '0004', 19 | '0005', 20 | '0006', 21 | '0007', 22 | '0008', 23 | '0009', 24 | '0010', 25 | '0011', 26 | '0012', 27 | ] 28 | 29 | // List of all fixture files to test 30 | const fixtures = [ 31 | 'abseil.io', 32 | 'class', 33 | 'edge-cases', 34 | 'enum', 35 | 'exports', 36 | 'function', 37 | 'function-types', 38 | 'imports', 39 | 'interface', 40 | 'module', 41 | 'namespace', 42 | 'private-members', 43 | 'type', 44 | 'type-interface-imports', 45 | 'variable', 46 | ] 47 | 48 | // Large fixture files (slower tests) 49 | const largeFixtures = [ 50 | 'checker', 51 | ] 52 | 53 | // Generate a test for each example file 54 | examples.forEach((example) => { 55 | it(`should properly generate types for example ${example}`, async () => { 56 | const config: DtsGenerationOption = { 57 | entrypoints: [join(inputDir, 'example', `${example}.ts`)], 58 | outdir: generatedDir, 59 | clean: false, 60 | tsconfigPath: join(__dirname, '..', 'tsconfig.json'), 61 | outputStructure: 'flat', 62 | } 63 | 64 | await generate(config) 65 | 66 | const outputPath = join(outputDir, 'example', `${example}.d.ts`) 67 | const generatedPath = join(generatedDir, `${example}.d.ts`) 68 | 69 | const expectedContent = await Bun.file(outputPath).text() 70 | const generatedContent = await Bun.file(generatedPath).text() 71 | 72 | expect(generatedContent).toBe(expectedContent) 73 | }) 74 | }) 75 | 76 | // Generate a test for each fixture file 77 | fixtures.forEach((fixture) => { 78 | it(`should properly generate types for fixture ${fixture}`, async () => { 79 | const config: DtsGenerationOption = { 80 | entrypoints: [join(inputDir, `${fixture}.ts`)], 81 | outdir: generatedDir, 82 | clean: false, 83 | tsconfigPath: join(__dirname, '..', 'tsconfig.json'), 84 | outputStructure: 'flat', 85 | } 86 | 87 | await generate(config) 88 | 89 | const outputPath = join(outputDir, `${fixture}.d.ts`) 90 | const generatedPath = join(generatedDir, `${fixture}.d.ts`) 91 | 92 | const expectedContent = await Bun.file(outputPath).text() 93 | const generatedContent = await Bun.file(generatedPath).text() 94 | 95 | expect(generatedContent).toBe(expectedContent) 96 | }) 97 | }) 98 | 99 | // Generate a test for each large fixture file (slower tests) 100 | largeFixtures.forEach((fixture) => { 101 | it(`should properly generate types for large fixture ${fixture}`, async () => { 102 | const config: DtsGenerationOption = { 103 | entrypoints: [join(inputDir, `${fixture}.ts`)], 104 | outdir: generatedDir, 105 | clean: false, 106 | tsconfigPath: join(__dirname, '..', 'tsconfig.json'), 107 | outputStructure: 'flat', 108 | } 109 | 110 | await generate(config) 111 | 112 | const outputPath = join(outputDir, `${fixture}.d.ts`) 113 | const generatedPath = join(generatedDir, `${fixture}.d.ts`) 114 | 115 | const expectedContent = await Bun.file(outputPath).text() 116 | const generatedContent = await Bun.file(generatedPath).text() 117 | 118 | expect(generatedContent).toBe(expectedContent) 119 | }, 30000) // 30 second timeout for large files 120 | }) 121 | 122 | afterEach(async () => { 123 | // Clean up generated files 124 | try { 125 | await rm(generatedDir, { recursive: true, force: true }) 126 | } 127 | catch (error) { 128 | console.error('Error cleaning up generated files:', error) 129 | } 130 | }) 131 | }) 132 | -------------------------------------------------------------------------------- /packages/dtsx/src/plugins/esbuild.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * esbuild plugin for dtsx 3 | * Generates TypeScript declaration files during esbuild builds 4 | */ 5 | 6 | import type { DtsGenerationConfig, GenerationStats } from '../types' 7 | import { generate } from '../generator' 8 | 9 | /** 10 | * esbuild plugin options 11 | */ 12 | export interface EsbuildPluginOptions extends Partial { 13 | /** 14 | * Generate declarations on build start 15 | * @default false 16 | */ 17 | onStart?: boolean 18 | 19 | /** 20 | * Generate declarations on build end 21 | * @default true 22 | */ 23 | onEnd?: boolean 24 | 25 | /** 26 | * Callback after generation completes 27 | */ 28 | onGenerated?: (stats: GenerationStats) => void 29 | 30 | /** 31 | * Callback on generation error 32 | */ 33 | onError?: (error: Error) => void 34 | } 35 | 36 | /** 37 | * esbuild plugin interface 38 | */ 39 | interface EsbuildPlugin { 40 | name: string 41 | setup: (build: EsbuildBuild) => void | Promise 42 | } 43 | 44 | /** 45 | * esbuild build interface (minimal type) 46 | */ 47 | interface EsbuildBuild { 48 | onStart: (callback: () => { errors?: Array<{ text: string }> } | Promise<{ errors?: Array<{ text: string }> } | void> | void) => void 49 | onEnd: (callback: (result: { errors: unknown[] }) => void | Promise) => void 50 | initialOptions: { 51 | entryPoints?: string[] | Record 52 | outdir?: string 53 | outfile?: string 54 | } 55 | } 56 | 57 | /** 58 | * Create an esbuild plugin for dtsx 59 | * 60 | * @example 61 | * ```ts 62 | * // build.ts 63 | * import { dtsx } from '@stacksjs/dtsx/plugins/esbuild' 64 | * import * as esbuild from 'esbuild' 65 | * 66 | * await esbuild.build({ 67 | * entryPoints: ['./src/index.ts'], 68 | * outdir: './dist', 69 | * plugins: [ 70 | * dtsx({ 71 | * root: './src', 72 | * outdir: './dist', 73 | * }), 74 | * ], 75 | * }) 76 | * ``` 77 | */ 78 | export function dtsx(options: EsbuildPluginOptions = {}): EsbuildPlugin { 79 | const { 80 | onStart = false, 81 | onEnd = true, 82 | onGenerated, 83 | onError, 84 | ...generateOptions 85 | } = options 86 | 87 | const runGenerate = async (): Promise => { 88 | try { 89 | const stats = await generate(generateOptions) 90 | onGenerated?.(stats) 91 | } 92 | catch (error) { 93 | const err = error instanceof Error ? error : new Error(String(error)) 94 | onError?.(err) 95 | if (!onError) { 96 | console.error('[dtsx] Generation failed:', err.message) 97 | } 98 | } 99 | } 100 | 101 | return { 102 | name: 'dtsx', 103 | 104 | setup(build) { 105 | // Get config from build if not provided 106 | const opts = build.initialOptions 107 | if (!generateOptions.entrypoints && opts.entryPoints) { 108 | if (Array.isArray(opts.entryPoints)) { 109 | generateOptions.entrypoints = opts.entryPoints 110 | } 111 | else { 112 | generateOptions.entrypoints = Object.values(opts.entryPoints) 113 | } 114 | } 115 | if (!generateOptions.outdir) { 116 | if (opts.outdir) { 117 | generateOptions.outdir = opts.outdir 118 | } 119 | else if (opts.outfile) { 120 | // Extract directory from outfile 121 | const lastSlash = opts.outfile.lastIndexOf('/') 122 | if (lastSlash !== -1) { 123 | generateOptions.outdir = opts.outfile.substring(0, lastSlash) 124 | } 125 | } 126 | } 127 | 128 | if (onStart) { 129 | build.onStart(async () => { 130 | await runGenerate() 131 | }) 132 | } 133 | 134 | if (onEnd) { 135 | build.onEnd(async (result) => { 136 | // Only generate if build succeeded 137 | if (result.errors.length === 0) { 138 | await runGenerate() 139 | } 140 | }) 141 | } 142 | }, 143 | } 144 | } 145 | 146 | /** 147 | * Alias for dtsx 148 | */ 149 | export const esbuildDts: typeof dtsx = dtsx 150 | 151 | /** 152 | * Alias matching common naming convention 153 | */ 154 | export const dts: typeof dtsx = dtsx 155 | 156 | /** 157 | * Default export 158 | */ 159 | export default dtsx 160 | --------------------------------------------------------------------------------