From b81e275d33e49aec816b7db1f633c99f1764c6bc Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 14 Oct 2024 22:31:59 +0200 Subject: [PATCH] chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip --- .editorconfig | 9 ++ .gitattributes | 2 + .github/CODE_OF_CONDUCT.md | 83 +++++++++++++ .github/SECURITY.md | 70 +++++++++++ .github/art/cover.png | Bin 0 -> 9280 bytes .github/renovate.json | 3 + .github/stale.yml | 14 +++ .github/workflows/README.md | 13 ++ .github/workflows/ci.yml | 84 +++++++++++++ .github/workflows/release.yml | 43 +++++++ .gitignore | 14 +++ .vscode/dictionary.txt | 41 +++++++ .vscode/extensions.json | 9 ++ .vscode/settings.json | 145 ++++++++++++++++++++++ .zed/settings.json | 139 +++++++++++++++++++++ CHANGELOG.md | 68 +++++++++++ LICENSE.md | 21 ++++ README.md | 128 ++++++++++++++++++++ bin/cli.ts | 24 ++++ build.ts | 23 ++++ bun.lockb | Bin 0 -> 199374 bytes bunfig.toml | 3 + commitlint.config.js | 77 ++++++++++++ docs/.vitepress/config.ts | 26 ++++ docs/api-examples.md | 49 ++++++++ docs/index.md | 24 ++++ docs/markdown-examples.md | 85 +++++++++++++ dts | 2 + dts.config.ts | 10 ++ eslint.config.js | 12 ++ fixtures/input/example-1.ts | 32 +++++ fixtures/input/example-2.ts | 33 +++++ fixtures/input/example-3.ts | 34 ++++++ fixtures/input/example-4.ts | 30 +++++ fixtures/input/example-5.ts | 30 +++++ fixtures/output/examples-1-5.d.ts | 63 ++++++++++ package.json | 107 ++++++++++++++++ pkgx.yaml | 2 + src/config.ts | 16 +++ src/generate.ts | 194 ++++++++++++++++++++++++++++++ src/index.ts | 3 + src/types.ts | 11 ++ test.ts | 4 + test/dts.test.ts | 29 +++++ tsconfig.json | 25 ++++ 45 files changed, 1834 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/CODE_OF_CONDUCT.md create mode 100644 .github/SECURITY.md create mode 100644 .github/art/cover.png create mode 100644 .github/renovate.json create mode 100644 .github/stale.yml create mode 100644 .github/workflows/README.md create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 .vscode/dictionary.txt create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 .zed/settings.json create mode 100644 CHANGELOG.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 bin/cli.ts create mode 100644 build.ts create mode 100755 bun.lockb create mode 100644 bunfig.toml create mode 100644 commitlint.config.js create mode 100644 docs/.vitepress/config.ts create mode 100644 docs/api-examples.md create mode 100644 docs/index.md create mode 100644 docs/markdown-examples.md create mode 100755 dts create mode 100644 dts.config.ts create mode 100644 eslint.config.js create mode 100644 fixtures/input/example-1.ts create mode 100644 fixtures/input/example-2.ts create mode 100644 fixtures/input/example-3.ts create mode 100644 fixtures/input/example-4.ts create mode 100644 fixtures/input/example-5.ts create mode 100644 fixtures/output/examples-1-5.d.ts create mode 100644 package.json create mode 100644 pkgx.yaml create mode 100644 src/config.ts create mode 100644 src/generate.ts create mode 100644 src/index.ts create mode 100644 src/types.ts create mode 100644 test.ts create mode 100644 test/dts.test.ts create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9d08a1a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6f28e15 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto +*.lockb binary diff=lockb diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..68282da --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,83 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at chris@stacksjs.org. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..1139343 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,70 @@ +# Security Policy + +**PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).** + +## Supported Versions + +Only the latest major version receives security fixes. + +## Reporting a Vulnerability + +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. + +### Public PGP Key + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: OpenPGP v2.0.8 +Comment: https://sela.io/pgp/ + +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 +HF/6SiI= +=le/X +-----END PGP PUBLIC KEY BLOCK----- +``` diff --git a/.github/art/cover.png b/.github/art/cover.png new file mode 100644 index 0000000000000000000000000000000000000000..3989237c39cb72233475a45565c2baa7f675f5f1 GIT binary patch literal 9280 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 literal 0 HcmV?d00001 diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..66937d2 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,3 @@ +{ + "extends": ["@ow3"] +} diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..ece9846 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,14 @@ +daysUntilStale: 60 +daysUntilClose: 7 +exemptLabels: + - pinned + - security + - no-stale + - no stale + - pr welcome +staleLabel: stale +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. + Thank you for your contributions. +closeComment: false diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..79d40a0 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,13 @@ +# GitHub Actions + +This folder contains the following GitHub Actions: + +- [CI][CI] - all CI jobs for the project + - lints the code + - `typecheck`s the code + - runs test suite + - runs on `ubuntu-latest` +- [Release][Release] - automates the release process & changelog generation + +[CI]: ./workflows/ci.yml +[Release]: ./workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d0ab6fe --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,84 @@ +name: CI + +on: + push: + branches: + - main + + pull_request: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Bun + uses: oven-sh/setup-bun@v2 + + - name: Use cached node_modules + uses: actions/cache@v4 + with: + path: node_modules + key: node-modules-${{ hashFiles('**/bun.lockb') }} + restore-keys: | + node-modules- + + - name: Install Dependencies + run: bun install + + - name: Lint + run: bun run lint + + typecheck: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Bun + uses: oven-sh/setup-bun@v2 + + - name: Use cached node_modules + uses: actions/cache@v4 + with: + path: node_modules + key: node-modules-${{ hashFiles('**/bun.lockb') }} + restore-keys: | + node-modules- + + - name: Install Dependencies + run: bun install + + - name: Typecheck + run: bun --bun run typecheck + + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Bun + uses: oven-sh/setup-bun@v2 + + - name: Use cached node_modules + uses: actions/cache@v4 + with: + path: node_modules + key: node-modules-${{ hashFiles('**/bun.lockb') }} + restore-keys: | + node-modules- + + - name: Install Dependencies + run: bun install + + - name: Unit Test + run: bun test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e808da4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +name: CI + +on: + push: + tags: + - 'v*' + +jobs: + release: + name: release + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Bun + uses: oven-sh/setup-bun@v2 + + - name: Use cached node_modules + uses: actions/cache@v4 + with: + path: node_modules + key: node-modules-${{ hashFiles('**/bun.lockb') }} + restore-keys: | + node-modules- + + - name: Install Dependencies + run: bun install + + - name: Build the release + run: bun run build + + - name: Publish to npm + run: bun publish --access public + env: + BUN_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + + - name: Create GitHub release + run: bunx changelogithub + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a572eb1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.cache +.DS_Store +.idea +*.log +*.tgz +*.pem +coverage +dist +lib-cov +logs +node_modules +temp +docs/.vitepress/cache +storage diff --git a/.vscode/dictionary.txt b/.vscode/dictionary.txt new file mode 100644 index 0000000..5973a3a --- /dev/null +++ b/.vscode/dictionary.txt @@ -0,0 +1,41 @@ +antfu +biomejs +booleanish +bumpp +bunx +changelogen +changelogithub +codecov +commitlint +commitlintrc +composables +davidanson +degit +deps +destructurable +entrypoints +heroicons +lockb +mkcert +openweb +outdir +outfile +pausable +pkgx +Postcardware +postcompile +prefetch +preinstall +socio +Solana +stacksjs +typecheck +unplugin +unref +upath +vite +vitebook +vitejs +vitepress +vue-demi +vueus diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a4d6a99 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "biomejs.biome", + "streetsidesoftware.code-spell-checker", + "davidanson.vscode-markdownlint" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ab5fe8e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,145 @@ +{ + // Disable the default formatter, use eslint instead + "prettier.enable": false, + "biome.enabled": false, + "editor.formatOnSave": false, + + // Auto fix + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.organizeImports": "never" + }, + + // Silent the stylistic rules in you IDE, but still auto fix them + "eslint.rules.customizations": [ + { "rule": "style/*", "severity": "off", "fixable": true }, + { "rule": "format/*", "severity": "off", "fixable": true }, + { "rule": "*-indent", "severity": "off", "fixable": true }, + { "rule": "*-spacing", "severity": "off", "fixable": true }, + { "rule": "*-spaces", "severity": "off", "fixable": true }, + { "rule": "*-order", "severity": "off", "fixable": true }, + { "rule": "*-dangle", "severity": "off", "fixable": true }, + { "rule": "*-newline", "severity": "off", "fixable": true }, + { "rule": "*quotes", "severity": "off", "fixable": true }, + { "rule": "*semi", "severity": "off", "fixable": true } + ], + + // Enable eslint for all supported languages + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "vue", + "html", + "markdown", + "json", + "jsonc", + "yaml", + "toml", + "xml", + "gql", + "graphql", + "astro", + "svelte", + "css", + "less", + "scss", + "pcss", + "postcss" + ], + + "[stx]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + + // TypeScript + "typescript.tsdk": "${workspaceFolder}/node_modules/typescript/lib", + "unocss.root": "${workspaceFolder}/storage/framework/core/ui/src/uno.config.ts", + // Shell + "[shellscript]": { + "editor.defaultFormatter": "foxundermoon.shell-format" + }, + + // Markdown + "[markdown]": { + "editor.defaultFormatter": "DavidAnson.vscode-markdownlint", + "editor.formatOnSave": true + }, + + "[dockerfile]": { + "editor.defaultFormatter": "foxundermoon.shell-format" + }, + + "markdownlint.config": { + "default": true, + "MD033": { + "allowed_elements": [ + "details", + "summary", + "VPTeamPage", + "VPTeamPageTitle", + "VPTeamMembers", + "script" + ] + }, + "MD041": false + }, + + // Stacks + "vue.inlayHints.missingProps": true, + "typescript.preferGoToSourceDefinition": true, + "files.associations": { + "buddy": "typescript", + "*.stx": "vue" + }, + "editor.quickSuggestions": { + "strings": true + }, + "vsicons.associations.files": [ + { + "icon": "${workspaceFolder}/public/favicon.svg", + "extensions": ["stx"], + "format": "svg" + } + ], + "git.enableSmartCommit": true, + "npm.enableRunFromFolder": true, + "npm.packageManager": "bun", + "editor.gotoLocation.multipleDefinitions": "goto", + "search.exclude": { + "**/node_modules": true, + "**/cdk.out": true, + "**/dist": true, + "**/storage/public": true, + "CHANGELOG.md": true + }, + "explorer.confirmDragAndDrop": false, + "todo-tree.highlights.enabled": true, + "cSpell.ignorePaths": [ + "node_modules", + "lang/de.yml" + ], + "cSpell.dictionaries": [ + "custom-dictionary" + ], + "cSpell.diagnosticLevel": "Hint", + "cSpell.customDictionaries": { + "stacks": { + "name": "custom-dictionary", + "path": "./.vscode/dictionary.txt", + "scope": "user", + "addWords": true + }, + "custom": true // enable the `custom` dictionary + }, + "terminal.integrated.scrollback": 10000, + "grammarly.files.include": [ + "**/README.md", + "**/readme.md", + "**/*.txt" + ], + "grammarly.files.exclude": [ + "**/dictionary.txt" + ] +} diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000..30b4eb3 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,139 @@ +// For a full list of overridable settings, and general information on folder-specific settings, +// see the documentation: https://zed.dev/docs/configuring-zed#settings-files +{ + "languages": { + "JavaScript": { + "formatter": { + "code_actions": { + "source.fixAll.eslint": true + } + } + }, + "TypeScript": { + "formatter": { + "code_actions": { + "source.fixAll.eslint": true + } + } + }, + "HTML": { + "formatter": { + "code_actions": { + "source.fixAll.eslint": true + } + } + }, + "CSS": { + "formatter": { + "code_actions": { + "source.fixAll.eslint": true + } + } + }, + "Markdown": { + "formatter": { + "code_actions": { + "source.fixAll.eslint": true + } + } + }, + "JSON": { + "formatter": { + "code_actions": { + "source.fixAll.eslint": true + } + } + }, + "JSONC": { + "formatter": { + "code_actions": { + "source.fixAll.eslint": true + } + } + }, + "YAML": { + "formatter": { + "code_actions": { + "source.fixAll.eslint": true + } + } + }, + "XML": { + "formatter": { + "code_actions": { + "source.fixAll.eslint": true + } + } + }, + "TOML": { + "formatter": { + "code_actions": { + "source.fixAll.eslint": true + } + } + } + }, + "lsp": { + "eslint": { + "settings": { + "rulesCustomizations": [ + { + "rule": "style/*", + "severity": "off", + "fixable": true + }, + { + "rule": "format/*", + "severity": "off", + "fixable": true + }, + { + "rule": "*-indent", + "severity": "off", + "fixable": true + }, + { + "rule": "*-spacing", + "severity": "off", + "fixable": true + }, + { + "rule": "*-spaces", + "severity": "off", + "fixable": true + }, + { + "rule": "*-order", + "severity": "off", + "fixable": true + }, + { + "rule": "*-dangle", + "severity": "off", + "fixable": true + }, + { + "rule": "*-newline", + "severity": "off", + "fixable": true + }, + { + "rule": "*quotes", + "severity": "off", + "fixable": true + }, + { + "rule": "*semi", + "severity": "off", + "fixable": true + } + ] + } + } + }, + "file_types": { + "JavaScript": [ + "buddy" + ] + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ec90a7a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,68 @@ +# Changelog + + +## v0.0.1...main + +[compare changes](https://github.com/stacksjs/reverse-proxy/compare/v0.0.1...main) + +### 🏡 Chore + +- Wip ([c5e31d5](https://github.com/stacksjs/reverse-proxy/commit/c5e31d5)) +- Wip ([6020df1](https://github.com/stacksjs/reverse-proxy/commit/6020df1)) +- Wip ([be3dde1](https://github.com/stacksjs/reverse-proxy/commit/be3dde1)) +- Wip ([e9e0feb](https://github.com/stacksjs/reverse-proxy/commit/e9e0feb)) +- Wip ([383854c](https://github.com/stacksjs/reverse-proxy/commit/383854c)) +- Wip ([363445b](https://github.com/stacksjs/reverse-proxy/commit/363445b)) +- Add `rp` ([beced3c](https://github.com/stacksjs/reverse-proxy/commit/beced3c)) +- Wip ([99cf0df](https://github.com/stacksjs/reverse-proxy/commit/99cf0df)) +- Wip ([c9341a4](https://github.com/stacksjs/reverse-proxy/commit/c9341a4)) +- Use `bun publish` ([6f6ae9d](https://github.com/stacksjs/reverse-proxy/commit/6f6ae9d)) +- Add tests ([da19c51](https://github.com/stacksjs/reverse-proxy/commit/da19c51)) +- Ignore docs cache ([81f2296](https://github.com/stacksjs/reverse-proxy/commit/81f2296)) +- Use bunx ([ec65717](https://github.com/stacksjs/reverse-proxy/commit/ec65717)) +- Adjust examples ([d4745fc](https://github.com/stacksjs/reverse-proxy/commit/d4745fc)) +- Adjust build process ([1e5c63c](https://github.com/stacksjs/reverse-proxy/commit/1e5c63c)) +- Remove postcompile ([52a9bc6](https://github.com/stacksjs/reverse-proxy/commit/52a9bc6)) +- Remove lint:fix-unsafe ([91ad947](https://github.com/stacksjs/reverse-proxy/commit/91ad947)) + +### ❤️ Contributors + +- Chris + +## ...main + + +### 🏡 Chore + +- Initial commit ([beb4d96](https://github.com/stacksjs/reverse-proxy/commit/beb4d96)) +- Wip ([8e3fce6](https://github.com/stacksjs/reverse-proxy/commit/8e3fce6)) +- Wip ([bbb6783](https://github.com/stacksjs/reverse-proxy/commit/bbb6783)) +- Wip ([2cfb363](https://github.com/stacksjs/reverse-proxy/commit/2cfb363)) +- Wip ([6bb85ac](https://github.com/stacksjs/reverse-proxy/commit/6bb85ac)) +- Wip ([602c9e1](https://github.com/stacksjs/reverse-proxy/commit/602c9e1)) +- Wip ([5986105](https://github.com/stacksjs/reverse-proxy/commit/5986105)) +- Wip ([c2bfec6](https://github.com/stacksjs/reverse-proxy/commit/c2bfec6)) +- Wip ([454dd58](https://github.com/stacksjs/reverse-proxy/commit/454dd58)) +- Wip ([b55ae41](https://github.com/stacksjs/reverse-proxy/commit/b55ae41)) +- Wip ([e2f1350](https://github.com/stacksjs/reverse-proxy/commit/e2f1350)) +- Wip ([61b2aa5](https://github.com/stacksjs/reverse-proxy/commit/61b2aa5)) +- Wip ([a80283b](https://github.com/stacksjs/reverse-proxy/commit/a80283b)) +- Wip ([97b9b16](https://github.com/stacksjs/reverse-proxy/commit/97b9b16)) +- Wip ([fc8d633](https://github.com/stacksjs/reverse-proxy/commit/fc8d633)) +- Wip ([e924f9c](https://github.com/stacksjs/reverse-proxy/commit/e924f9c)) +- Wip ([249e8fa](https://github.com/stacksjs/reverse-proxy/commit/249e8fa)) +- Wip ([1045bb1](https://github.com/stacksjs/reverse-proxy/commit/1045bb1)) +- Wip ([c0a8bad](https://github.com/stacksjs/reverse-proxy/commit/c0a8bad)) +- Wip ([f28b118](https://github.com/stacksjs/reverse-proxy/commit/f28b118)) +- Wip ([712a5bf](https://github.com/stacksjs/reverse-proxy/commit/712a5bf)) +- Wip ([2786e8d](https://github.com/stacksjs/reverse-proxy/commit/2786e8d)) +- Wip ([1290366](https://github.com/stacksjs/reverse-proxy/commit/1290366)) +- Wip ([030a8b7](https://github.com/stacksjs/reverse-proxy/commit/030a8b7)) +- Wip ([2116f75](https://github.com/stacksjs/reverse-proxy/commit/2116f75)) +- Wip ([5352f7a](https://github.com/stacksjs/reverse-proxy/commit/5352f7a)) +- Wip ([1b99dd0](https://github.com/stacksjs/reverse-proxy/commit/1b99dd0)) + +### ❤️ Contributors + +- Chris + diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..1aef080 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 Open Web Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ef0410 --- /dev/null +++ b/README.md @@ -0,0 +1,128 @@ +

Social Card of this repo

+ +[![npm version][npm-version-src]][npm-version-href] +[![GitHub Actions][github-actions-src]][github-actions-href] +[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) + + + +## Features + +- Fast .d.ts generation via isolatedDeclaration +- Configurability +- Cross-platform binary +- Bun-powered + +## Install + +```bash +bun install -d dts-generation +``` + + + +## Get Started + +There are two ways of using this dts generation tool: _as a library or as a CLI._ + +### Library + +Given the npm package is installed: + +```js +import { generate } from 'dts-generation' + +generate() +``` + +### CLI + +```bash +dts-generation ... +dts-generation --help +dts-generation --version +``` + +## Configuration + +The Reverse Proxy can be configured using a `dts.config.ts` _(or `dts.config.js`)_ file and it will be automatically loaded when running the `dts-generation` command. + +```ts +// dts.config.ts (or dts.config.js) +export default { + cwd: './', + root: './src', + outdir: './dist', + keepComments: true, +} +``` + +_Then run:_ + +```bash +dts-generation generate +``` + +To learn more, head over to the [documentation](https://dts-generation.sh/). + +## Testing + +```bash +bun test +``` + +## Changelog + +Please see our [releases](https://github.com/stacksjs/stacks/releases) page for more information on what has changed recently. + +## Contributing + +Please review the [Contributing Guide](https://github.com/stacksjs/contributing) for details. + +## Community + +For help, discussion about best practices, or any other conversation that would benefit from being searchable: + +[Discussions on GitHub](https://github.com/stacksjs/stacks/discussions) + +For casual chit-chat with others using this package: + +[Join the Stacks Discord Server](https://discord.gg/stacksjs) + +## Postcardware + +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_ + +Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094 + +## Sponsors + +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. + +- [JetBrains](https://www.jetbrains.com/) +- [The Solana Foundation](https://solana.com/) + +## Credits + +- [Chris Breuer](https://github.com/chrisbbreuer) +- [All Contributors](../../contributors) + +## License + +The MIT License (MIT). Please see [LICENSE](https://github.com/stacksjs/stacks/tree/main/LICENSE.md) for more information. + +Made with 💙 + + +[npm-version-src]: https://img.shields.io/npm/v/@stacksjs/reverse-proxy?style=flat-square +[npm-version-href]: https://npmjs.com/package/@stacksjs/reverse-proxy +[github-actions-src]: https://img.shields.io/github/actions/workflow/status/stacksjs/reverse-proxy/ci.yml?style=flat-square&branch=main +[github-actions-href]: https://github.com/stacksjs/reverse-proxy/actions?query=workflow%3Aci + + diff --git a/bin/cli.ts b/bin/cli.ts new file mode 100644 index 0000000..2d2f39b --- /dev/null +++ b/bin/cli.ts @@ -0,0 +1,24 @@ +import { CAC } from '@stacksjs/cli' +import { version } from '../package.json' + +// import { generate } from '../src/generate' + +const cli = new CAC('dts') + +cli + .command('generate', 'Start the Reverse Proxy Server') + .option('--from ', 'The URL to proxy from') + .option('--verbose', 'Enable verbose logging', { default: false }) + .example('') + // .action(async (options?: DtsGenerationOption) => { + .action(async () => { + // + }) + +cli.command('version', 'Show the version of the Reverse Proxy CLI').action(() => { + console.log(version) +}) + +cli.version(version) +cli.help() +cli.parse() diff --git a/build.ts b/build.ts new file mode 100644 index 0000000..b6c669a --- /dev/null +++ b/build.ts @@ -0,0 +1,23 @@ +import { log } from '@stacksjs/cli' + +// import { $ } from 'bun' + +log.info('Building...') + +await Bun.build({ + entrypoints: ['./src/index.ts', './bin/cli.ts'], + outdir: './dist', + format: 'esm', + target: 'bun', +}) + +// tigger dts generation here + +// await $`cp ./dist/src/index.js ./dist/index.js` +// await $`rm -rf ./dist/src` +// await $`cp ./dist/bin/cli.js ./dist/cli.js` +// await $`rm -rf ./dist/bin` +// await $`cp ./bin/cli.d.ts ./dist/cli.d.ts` +// await $`rm ./bin/cli.d.ts` + +log.success('Built') diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..869016deff57c6527266fb8653ae589ad5ef3915 GIT binary patch literal 199374 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 literal 0 HcmV?d00001 diff --git a/bunfig.toml b/bunfig.toml new file mode 100644 index 0000000..d5feee3 --- /dev/null +++ b/bunfig.toml @@ -0,0 +1,3 @@ +[install] +registry = { url = "https://registry.npmjs.org/", token = "$BUN_AUTH_TOKEN" } +peer = true diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..b0f407c --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,77 @@ +const scopes = ['', 'ci', 'deps', 'dx', 'example', 'release', 'readme', 'build'] + +const config = { + rules: { + 'scope-enum': [2, 'always', scopes], + }, + prompt: { + messages: { + type: 'Select the type of change that you\'re committing:', + scope: 'Select the SCOPE of this change (optional):', + customScope: 'Select the SCOPE of this change:', + subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n', + body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n', + breaking: 'List any BREAKING CHANGES (optional). Use "|" to break new line:\n', + footerPrefixesSelect: 'Select the ISSUES type of changeList by this change (optional):', + customFooterPrefixes: 'Input ISSUES prefix:', + footer: 'List any ISSUES by this change. E.g.: #31, #34:\n', + confirmCommit: 'Are you sure you want to proceed with the commit above?', + }, + types: [ + { value: 'feat', name: 'feat: ✨ A new feature', emoji: ':sparkles:' }, + { value: 'fix', name: 'fix: 🐛 A bug fix', emoji: ':bug:' }, + { value: 'docs', name: 'docs: 📝 Documentation only changes', emoji: ':memo:' }, + { value: 'style', name: 'style: 💄 Changes that do not affect the meaning of the code', emoji: ':lipstick:' }, + { + value: 'refactor', + name: 'refactor: ♻️ A code change that neither fixes a bug nor adds a feature', + emoji: ':recycle:', + }, + { value: 'perf', name: 'perf: ⚡️ A code change that improves performance', emoji: ':zap:' }, + { + value: 'test', + name: 'test: ✅ Adding missing tests or adjusting existing tests', + emoji: ':white_check_mark:', + }, + { + value: 'build', + name: 'build: 📦️ Changes that affect the build system or external dependencies', + emoji: ':package:', + }, + { value: 'ci', name: 'ci: 🎡 Changes to our CI configuration files and scripts', emoji: ':ferris_wheel:' }, + { value: 'chore', name: 'chore: 🔨 Other changes that don\'t modify src or test files', emoji: ':hammer:' }, + { value: 'revert', name: 'revert: ⏪️ Reverts a previous commit', emoji: ':rewind:' }, + ], + useEmoji: false, + themeColorCode: '', + scopes, + allowCustomScopes: true, + allowEmptyScopes: true, + customScopesAlign: 'bottom', + customScopesAlias: 'custom', + emptyScopesAlias: 'empty', + upperCaseSubject: false, + allowBreakingChanges: ['feat', 'fix'], + breaklineNumber: 100, + breaklineChar: '|', + skipQuestions: [], + issuePrefixes: [{ value: 'closed', name: 'closed: ISSUES has been processed' }], + customIssuePrefixesAlign: 'top', + emptyIssuePrefixesAlias: 'skip', + customIssuePrefixesAlias: 'custom', + allowCustomIssuePrefixes: true, + allowEmptyIssuePrefixes: true, + confirmColorize: true, + maxHeaderLength: Number.POSITIVE_INFINITY, + maxSubjectLength: Number.POSITIVE_INFINITY, + minSubjectLength: 0, + scopeOverrides: undefined, + defaultBody: '', + defaultIssues: '', + defaultScope: '', + defaultSubject: '', + }, +} + +/** @type {import('cz-git').UserConfig} */ +export default config diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 0000000..5047942 --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from 'vitepress' + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: 'Reverse Proxy', + description: 'A better developer environment.', + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + nav: [ + { text: 'Home', link: '/' }, + { text: 'Examples', link: '/markdown-examples' }, + ], + + sidebar: [ + { + text: 'Examples', + items: [ + { text: 'Markdown Examples', link: '/markdown-examples' }, + { text: 'Runtime API Examples', link: '/api-examples' }, + ], + }, + ], + + socialLinks: [{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }], + }, +}) diff --git a/docs/api-examples.md b/docs/api-examples.md new file mode 100644 index 0000000..6bd8bb5 --- /dev/null +++ b/docs/api-examples.md @@ -0,0 +1,49 @@ +--- +outline: deep +--- + +# Runtime API Examples + +This page demonstrates usage of some of the runtime APIs provided by VitePress. + +The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files: + +```md + + +## Results + +### Theme Data +
{{ theme }}
+ +### Page Data +
{{ page }}
+ +### Page Frontmatter +
{{ frontmatter }}
+``` + + + +## Results + +### Theme Data +
{{ theme }}
+ +### Page Data +
{{ page }}
+ +### Page Frontmatter +
{{ frontmatter }}
+ +## More + +Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata). diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..c7a7353 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,24 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: "Reverse Proxy" + text: "A better developer environment." + tagline: My great project tagline + actions: + - theme: brand + text: Markdown Examples + link: /markdown-examples + - theme: alt + text: API Examples + link: /api-examples + +features: + - title: Feature A + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit + - title: Feature B + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit + - title: Feature C + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit +--- diff --git a/docs/markdown-examples.md b/docs/markdown-examples.md new file mode 100644 index 0000000..f9258a5 --- /dev/null +++ b/docs/markdown-examples.md @@ -0,0 +1,85 @@ +# Markdown Extension Examples + +This page demonstrates some of the built-in markdown extensions provided by VitePress. + +## Syntax Highlighting + +VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting: + +**Input** + +````md +```js{4} +export default { + data () { + return { + msg: 'Highlighted!' + } + } +} +``` +```` + +**Output** + +```js{4} +export default { + data () { + return { + msg: 'Highlighted!' + } + } +} +``` + +## Custom Containers + +**Input** + +```md +::: info +This is an info box. +::: + +::: tip +This is a tip. +::: + +::: warning +This is a warning. +::: + +::: danger +This is a dangerous warning. +::: + +::: details +This is a details block. +::: +``` + +**Output** + +::: info +This is an info box. +::: + +::: tip +This is a tip. +::: + +::: warning +This is a warning. +::: + +::: danger +This is a dangerous warning. +::: + +::: details +This is a details block. +::: + +## More + +Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown). diff --git a/dts b/dts new file mode 100755 index 0000000..c3d8286 --- /dev/null +++ b/dts @@ -0,0 +1,2 @@ +#!/usr/bin/env bun +import('./bin/cli') diff --git a/dts.config.ts b/dts.config.ts new file mode 100644 index 0000000..39fb029 --- /dev/null +++ b/dts.config.ts @@ -0,0 +1,10 @@ +export default { + cwd: './', + root: './src', + outdir: './dist', + keepComments: true, + clean: true, + + // bundle: true, + // minify: true, +} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..44b7d05 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,12 @@ +import stacks from '@stacksjs/eslint-config' + +export default stacks({ + stylistic: { + indent: 2, + quotes: 'single', + }, + + typescript: true, + jsonc: true, + yaml: true, +}) diff --git a/fixtures/input/example-1.ts b/fixtures/input/example-1.ts new file mode 100644 index 0000000..2280d8c --- /dev/null +++ b/fixtures/input/example-1.ts @@ -0,0 +1,32 @@ +/** + * Example of const declaration + */ +export const config: { [key: string]: string } = { + apiUrl: 'https://api.example.com', + timeout: '5000', +} + +/** + * Example of interface declaration + */ +export interface User { + id: number + name: string + email: string +} + +/** + * Example of type declaration + */ +export interface ResponseData { + success: boolean + data: User[] +} + +/** + * Example of function declaration + */ +export function fetchUsers(): Promise { + return fetch(config.apiUrl) + .then(response => response.json()) as Promise +} diff --git a/fixtures/input/example-2.ts b/fixtures/input/example-2.ts new file mode 100644 index 0000000..cd39dfe --- /dev/null +++ b/fixtures/input/example-2.ts @@ -0,0 +1,33 @@ +/** + * Example of another const declaration + */ +export const settings: { [key: string]: any } = { + theme: 'dark', + language: 'en', +} + +/** + * Example of interface declaration + */ +export interface Product { + id: number + name: string + price: number +} + +/** + * Example of type declaration + */ +export interface ApiResponse { + status: number + message: string + data: T +} + +/** + * Example of function declaration + */ +export function getProduct(id: number): Promise> { + return fetch(`${settings.apiUrl}/products/${id}`) + .then(response => response.json()) as Promise> +} diff --git a/fixtures/input/example-3.ts b/fixtures/input/example-3.ts new file mode 100644 index 0000000..d3ee491 --- /dev/null +++ b/fixtures/input/example-3.ts @@ -0,0 +1,34 @@ +/** + * Example of const declaration + */ +export const endpoints = { + getUsers: '/users', + getProducts: '/products', +} + +/** + * Example of interface declaration + */ +export interface Order { + orderId: number + userId: number + productIds: number[] +} + +/** + * Example of type declaration + */ +export interface OrderResponse { + success: boolean + order: Order +} + +/** + * Example of function declaration + */ +export async function createOrder(order: Order): Promise { + return fetch(endpoints.getProducts, { + method: 'POST', + body: JSON.stringify(order), + }).then(response => response.json()) as Promise +} diff --git a/fixtures/input/example-4.ts b/fixtures/input/example-4.ts new file mode 100644 index 0000000..1383251 --- /dev/null +++ b/fixtures/input/example-4.ts @@ -0,0 +1,30 @@ +/** + * Example of const declaration + */ +export const apiKeys = { + google: 'GOOGLE_API_KEY', + facebook: 'FACEBOOK_API_KEY', +} + +/** + * Example of interface declaration + */ +export interface AuthResponse { + token: string + expiresIn: number +} + +/** + * Example of type declaration + */ +export type AuthStatus = 'authenticated' | 'unauthenticated' + +/** + * Example of function declaration + */ +export function authenticate(user: string, password: string): Promise { + return fetch('/auth/login', { + method: 'POST', + body: JSON.stringify({ user, password }), + }).then(response => response.json()) as Promise +} diff --git a/fixtures/input/example-5.ts b/fixtures/input/example-5.ts new file mode 100644 index 0000000..b08740c --- /dev/null +++ b/fixtures/input/example-5.ts @@ -0,0 +1,30 @@ +/** + * Example of const declaration + */ +export const defaultHeaders = { + 'Content-Type': 'application/json', +} + +/** + * Example of interface declaration + */ +export interface Comment { + id: number + postId: number + body: string +} + +/** + * Example of type declaration + */ +export interface CommentsResponse { + comments: Comment[] +} + +/** + * Example of function declaration + */ +export function fetchComments(postId: number): Promise { + return fetch(`/posts/${postId}/comments`) + .then(response => response.json()) as Promise +} diff --git a/fixtures/output/examples-1-5.d.ts b/fixtures/output/examples-1-5.d.ts new file mode 100644 index 0000000..0f09cdc --- /dev/null +++ b/fixtures/output/examples-1-5.d.ts @@ -0,0 +1,63 @@ +export declare const config: { [key: string]: string }; +export interface User { + id: number; + name: string; + email: string; +} +export type ResponseData = { + success: boolean; + data: User[]; +}; +export declare function fetchUsers(): Promise; + +export declare const settings: { [key: string]: any }; +export interface Product { + id: number; + name: string; + price: number; +} +export type ApiResponse = { + status: number; + message: string; + data: T; +}; +export declare function getProduct(id: number): Promise>; + +export declare const endpoints: { + getUsers: string; + getProducts: string; +}; +export interface Order { + orderId: number; + userId: number; + productIds: number[]; +} +export type OrderResponse = { + success: boolean; + order: Order; +}; +export declare function createOrder(order: Order): Promise; + +export declare const apiKeys: { + google: string; + facebook: string; +}; +export interface AuthResponse { + token: string; + expiresIn: number; +} +export type AuthStatus = "authenticated" | "unauthenticated"; +export declare function authenticate(user: string, password: string): Promise; + +export declare const defaultHeaders: { + "Content-Type": string; +}; +export interface Comment { + id: number; + postId: number; + body: string; +} +export type CommentsResponse = { + comments: Comment[]; +}; +export declare function fetchComments(postId: number): Promise; diff --git a/package.json b/package.json new file mode 100644 index 0000000..4613fb7 --- /dev/null +++ b/package.json @@ -0,0 +1,107 @@ +{ + "name": "dts-generation", + "type": "module", + "version": "0.1.0", + "description": "A modern, fast .d.ts generation tool, powered by Bun.", + "author": "Chris Breuer ", + "license": "MIT", + "homepage": "https://github.com/stacksjs/dts-generation#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/stacksjs/dts-generation.git" + }, + "bugs": { + "url": "https://github.com/stacksjs/dts-generation/issues" + }, + "keywords": [ + "dts", + "generation", + "development", + "environment", + "bun", + "stacks", + "typescript", + "javascript" + ], + "exports": { + ".": { + "import": "./dist/index.js" + }, + "./*": { + "import": "./dist/*" + } + }, + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "bin": { + "dts": "./dist/cli.js" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "bun build.ts && bun run compile", + "compile": "bun build ./bin/cli.ts --compile --minify --outfile dist/dts", + "lint": "bunx eslint .", + "lint:fix": "bunx eslint . --fix", + "fresh": "bunx rimraf node_modules/ bun.lock && bun i", + "commit": "git cz", + "changelog": "bunx changelogen --output CHANGELOG.md", + "prepublishOnly": "bun --bun run build", + "release": "bun run changelog && bunx bumpp package.json --all", + "test": "bun test", + "typecheck": "bunx tsc --noEmit", + "docs:dev": "vitepress dev docs", + "docs:build": "vitepress build docs", + "docs:preview": "vitepress preview docs" + }, + "devDependencies": { + "@eslint-community/eslint-plugin-eslint-comments": "^4.4.0", + "@eslint/markdown": "^6.1.0", + "@prettier/plugin-xml": "^3.4.1", + "@stacksjs/cli": "^0.65.0", + "@stacksjs/development": "^0.65.0", + "@stacksjs/eslint-config": "^3.7.3-stacks-1.12", + "@stacksjs/eslint-plugin": ">=0.1.1", + "@stacksjs/storage": "^0.65.0", + "@stylistic/eslint-plugin": "^2.8.0", + "@types/bun": "^1.1.10", + "@typescript-eslint/eslint-plugin": "^8.7.0", + "@typescript-eslint/parser": "^8.7.0", + "@vitest/eslint-plugin": "^1.1.4", + "c12": "^2.0.1", + "eslint": "^9.10.0", + "eslint-config-flat-gitignore": "^0.3.0", + "eslint-flat-config-utils": "^0.4.0", + "eslint-merge-processors": "^0.1.0", + "eslint-plugin-antfu": "^2.7.0", + "eslint-plugin-command": "^0.2.6", + "eslint-plugin-format": ">=0.1.0", + "eslint-plugin-import-x": "^4.3.0", + "eslint-plugin-jsdoc": "^50.3.0", + "eslint-plugin-jsonc": "^2.16.0", + "eslint-plugin-n": "^17.10.3", + "eslint-plugin-no-only-tests": "^3.3.0", + "eslint-plugin-perfectionist": "^3.7.0", + "eslint-plugin-regexp": "^2.6.0", + "eslint-plugin-toml": "^0.11.1", + "eslint-plugin-unicorn": "^55.0.0", + "eslint-plugin-unused-imports": "^4.1.4", + "eslint-plugin-yml": "^1.14.0", + "local-pkg": "^0.5.0", + "neverthrow": "^8.0.0", + "vitepress": "^1.4.0" + }, + "simple-git-hooks": { + "pre-commit": "bunx lint-staged", + "commit-msg": "bunx --no -- commitlint --edit $1" + }, + "lint-staged": { + "*.{js,jsx,ts,tsx,vue}": "bunx eslint . --fix" + }, + "config": { + "commitizen": { + "path": "node_modules/cz-git" + } + } +} diff --git a/pkgx.yaml b/pkgx.yaml new file mode 100644 index 0000000..b51a299 --- /dev/null +++ b/pkgx.yaml @@ -0,0 +1,2 @@ +dependencies: + bun.sh: ^1.1.30 diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..5981d17 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,16 @@ +import type { DtsGenerationConfig } from './types' +import process from 'node:process' +import { loadConfig } from 'c12' + +// Get loaded config +// eslint-disable-next-line antfu/no-top-level-await +export const config: DtsGenerationConfig = (await loadConfig({ + name: 'dts', + defaultConfig: { + cwd: process.cwd(), + root: './src', + outdir: './dist', + keepComments: true, + clean: true, + }, +})).config diff --git a/src/generate.ts b/src/generate.ts new file mode 100644 index 0000000..19be32c --- /dev/null +++ b/src/generate.ts @@ -0,0 +1,194 @@ +import type { Result } from 'neverthrow' +import type { DtsGenerationConfig, DtsGenerationOption } from './types' +import { readdir, readFile, rm, mkdir } from 'node:fs/promises' +import { extname, join, relative, dirname } from 'node:path' +import { err, ok } from 'neverthrow' +import { config } from './config' + +function validateOptions(options: unknown): Result { + if (typeof options === 'object' && options !== null) { + return ok(options as DtsGenerationOption) + } + + return err(new Error('Invalid options')) +} + +async function extractTypeFromSource(filePath: string): Promise { + const fileContent = await readFile(filePath, 'utf-8') + let declarations = '' + let imports = new Set() + + // Handle exports + const exportRegex = /export\s+((?:interface|type|const|function|async function)\s+\w+(?:\s*=\s*[^;]+|\s*\{[^}]*\}|\s*\([^)]*\)[^;]*));?/gs + let match + while ((match = exportRegex.exec(fileContent)) !== null) { + const declaration = match[1].trim() + if (declaration.startsWith('interface') || declaration.startsWith('type')) { + declarations += `export ${declaration}\n\n` + } else if (declaration.startsWith('const')) { + const [, name, type] = declaration.match(/const\s+(\w+):\s*([^=]+)/) || [] + if (name && type) { + declarations += `export declare const ${name}: ${type.trim()}\n\n` + } + } else if (declaration.startsWith('function') || declaration.startsWith('async function')) { + const funcMatch = declaration.match(/(async\s+)?function\s+(\w+)\s*\(([^)]*)\)\s*:\s*([^{]+)/) + if (funcMatch) { + const [, isAsync, name, params, returnType] = funcMatch + // Remove default values in parameters + const cleanParams = params.replace(/\s*=\s*[^,)]+/g, '') + declarations += `export declare ${isAsync || ''}function ${name}(${cleanParams}): ${returnType.trim()}\n\n` + } + } + + // Check for types used in the declaration and add them to imports + const usedTypes = declaration.match(/\b([A-Z]\w+)\b/g) || [] + usedTypes.forEach(type => imports.add(type)) + } + + // Only include imports for types that are actually used + const importRegex = /import\s+type\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g + let importDeclarations = '' + while ((match = importRegex.exec(fileContent)) !== null) { + const types = match[1].split(',').map(t => t.trim()) + const from = match[2] + const usedTypes = types.filter(type => imports.has(type)) + if (usedTypes.length > 0) { + importDeclarations += `import type { ${usedTypes.join(', ')} } from '${from}'\n` + } + } + + if (importDeclarations) { + declarations = importDeclarations + '\n\n' + declarations // Add two newlines here + } + + // Add a special marker between imports and exports + return declarations.replace(/\n(export)/, '\n###LINEBREAK###$1').trim() + '\n' +} + +async function extractConfigTypeFromSource(filePath: string): Promise { + const fileContent = await readFile(filePath, 'utf-8') + let declarations = '' + + // Handle type imports + const importRegex = /import\s+type\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g + let importMatch + while ((importMatch = importRegex.exec(fileContent)) !== null) { + const types = importMatch[1].split(',').map(t => t.trim()) + const from = importMatch[2] + declarations += `import type { ${types.join(', ')} } from '${from}'\n\n` // Add two newlines here + } + + // Handle exports + const exportRegex = /export\s+const\s+(\w+)\s*:\s*([^=]+)\s*=/g + let exportMatch + while ((exportMatch = exportRegex.exec(fileContent)) !== null) { + const [, name, type] = exportMatch + declarations += `export declare const ${name}: ${type.trim()}\n` + } + + return declarations.trim() + '\n' +} + +async function extractIndexTypeFromSource(filePath: string): Promise { + const fileContent = await readFile(filePath, 'utf-8') + let declarations = '' + + // Handle re-exports + const reExportRegex = /export\s*(?:\*|\{[^}]*\})\s*from\s*['"]([^'"]+)['"]/g + let match + while ((match = reExportRegex.exec(fileContent)) !== null) { + declarations += `${match[0]}\n` + } + + return declarations.trim() + '\n' +} + +function formatDeclarations(declarations: string, isConfigFile: boolean): string { + if (isConfigFile) { + // Special formatting for config.d.ts + return declarations + .replace(/\n{3,}/g, '\n\n') // Remove excess newlines, but keep doubles + .replace(/(\w+):\s+/g, '$1: ') // Ensure single space after colon + .trim() + '\n' // Ensure final newline + } + + // Regular formatting for other files + return declarations + .replace(/\n{3,}/g, '\n\n') // Remove excess newlines, but keep doubles + .replace(/(\w+):\s+/g, '$1: ') // Ensure single space after colon + .replace(/\s*\n\s*/g, '\n') // Remove extra spaces around newlines + .replace(/\{\s*\n\s*\n/g, '{\n') // Remove extra newline after opening brace + .replace(/\n\s*\}/g, '\n}') // Remove extra space before closing brace + .replace(/;\s*\n/g, '\n') // Remove semicolons at end of lines + .replace(/export interface ([^\{]+)\{/g, 'export interface $1{ ') // Add space after opening brace for interface + .replace(/^(\s*\w+:.*(?:\n|$))/gm, ' $1') // Ensure all properties in interface are indented + .replace(/}\n\n(?=export (interface|type))/g, '}\n') // Remove extra newline between interface/type declarations + .replace(/^(import .*\n)+/m, match => match.trim() + '\n') // Ensure imports are grouped + .replace(/###LINEBREAK###/g, '\n') // Replace the special marker with a newline + .replace(/\n{3,}/g, '\n\n') // Final pass to remove any triple newlines + .trim() + '\n' // Ensure final newline +} + +export async function generateDeclarationsFromFiles(options: DtsGenerationConfig = config): Promise { + if (options.clean) { + console.log('Cleaning output directory...') + await rm(options.outdir, { recursive: true, force: true }) + } + + const validationResult = validateOptions(options) + + if (validationResult.isErr()) { + console.error(validationResult.error.message) + return + } + + const files = await getAllTypeScriptFiles(options.root) + console.log('Found the following TypeScript files:', files) + + for (const file of files) { + console.log(`Processing file: ${file}`) + let fileDeclarations + const isConfigFile = file.endsWith('config.ts') + const isIndexFile = file.endsWith('index.ts') + if (isConfigFile) { + fileDeclarations = await extractConfigTypeFromSource(file) + } else if (isIndexFile) { + fileDeclarations = await extractIndexTypeFromSource(file) + } else { + fileDeclarations = await extractTypeFromSource(file) + } + + if (fileDeclarations) { + const relativePath = relative(options.root, file) + const outputPath = join(options.outdir, relativePath.replace(/\.ts$/, '.d.ts')) + + // Ensure the directory exists + await mkdir(dirname(outputPath), { recursive: true }) + + // Format and write the declarations + const formattedDeclarations = formatDeclarations(fileDeclarations, isConfigFile) + await writeToFile(outputPath, formattedDeclarations) + + console.log(`Generated ${outputPath}`) + } + } + + + console.log('Declaration file generation complete') +} + +async function getAllTypeScriptFiles(directory?: string): Promise { + const dir = directory ?? config.root + const entries = await readdir(dir, { withFileTypes: true }) + + const files = await Promise.all(entries.map((entry) => { + const res = join(dir, entry.name) + return entry.isDirectory() ? getAllTypeScriptFiles(res) : res + })) + + return Array.prototype.concat(...files).filter(file => extname(file) === '.ts') +} + +async function writeToFile(filePath: string, content: string): Promise { + await Bun.write(filePath, content) +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..6d3e6fb --- /dev/null +++ b/src/index.ts @@ -0,0 +1,3 @@ +export { config } from './config' +export * from './generate' +export * from './types' diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..1d4fccf --- /dev/null +++ b/src/types.ts @@ -0,0 +1,11 @@ +export interface DtsGenerationConfig { + cwd: string + root: string + outdir: string + keepComments: boolean + clean: boolean +} + +export type DtsGenerationOption = Partial + +export type DtsGenerationOptions = DtsGenerationOption | DtsGenerationOption[] diff --git a/test.ts b/test.ts new file mode 100644 index 0000000..e5e94c2 --- /dev/null +++ b/test.ts @@ -0,0 +1,4 @@ +import { generateDeclarationsFromFiles } from './src' +// Example usage +generateDeclarationsFromFiles('./src'); + diff --git a/test/dts.test.ts b/test/dts.test.ts new file mode 100644 index 0000000..5e4c768 --- /dev/null +++ b/test/dts.test.ts @@ -0,0 +1,29 @@ +import { afterEach, beforeAll, describe, expect, it } from 'bun:test' +import { join } from 'node:path' +import { generateDeclarationsFromFiles } from '../src/generate' + +describe('dts-generation', () => { + beforeAll(() => { + process.env.APP_ENV = 'test' + }) + + const testDir = join(__dirname, '../fixtures/input/') + const expectedOutputPath = join(__dirname, '../fixtures/output/examples-1-5.d.ts') + + it('should generate correct type declarations', async () => { + const output = await generateDeclarationsFromFiles(testDir) + + // Write the output to a file for comparison (optional) + // await fs.writeFile(expectedOutputPath, output); + + // Expected output (you can adjust this based on your actual expected output) + const expectedOutput = Bun.file(expectedOutputPath).text() + + // Compare the generated output with the expected output + expect((output)).toBe(await expectedOutput) + }) + + afterEach(() => { + // Clean up any files or state if necessary + }) +}) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..81a2f14 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "esnext", + "lib": [ + "esnext" + ], + "moduleDetection": "force", + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "allowImportingTsExtensions": true, + "strict": true, + "strictNullChecks": true, + "noFallthroughCasesInSwitch": true, + "declaration": true, + "noEmit": true, + "outDir": "./dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedDeclarations": true, + "verbatimModuleSyntax": true, + "skipDefaultLibCheck": true, + "skipLibCheck": true + } +}