create-bunli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +302 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +310 -0
  4. package/dist/create-project.d.ts +13 -0
  5. package/dist/create.d.ts +13 -0
  6. package/dist/index.d.ts +4 -0
  7. package/dist/index.js +217 -0
  8. package/dist/template-engine.d.ts +27 -0
  9. package/dist/templates/advanced/README.md +114 -0
  10. package/dist/templates/advanced/package.json +36 -0
  11. package/dist/templates/advanced/src/commands/config.ts +145 -0
  12. package/dist/templates/advanced/src/commands/init.ts +153 -0
  13. package/dist/templates/advanced/src/commands/serve.ts +176 -0
  14. package/dist/templates/advanced/src/commands/validate.ts +116 -0
  15. package/dist/templates/advanced/src/index.ts +44 -0
  16. package/dist/templates/advanced/src/utils/config.ts +83 -0
  17. package/dist/templates/advanced/src/utils/constants.ts +12 -0
  18. package/dist/templates/advanced/src/utils/glob.ts +49 -0
  19. package/dist/templates/advanced/src/utils/validator.ts +131 -0
  20. package/dist/templates/advanced/template.json +37 -0
  21. package/dist/templates/advanced/test/commands.test.ts +34 -0
  22. package/dist/templates/advanced/tsconfig.json +23 -0
  23. package/dist/templates/basic/README.md +41 -0
  24. package/dist/templates/basic/package.json +29 -0
  25. package/dist/templates/basic/src/commands/hello.ts +29 -0
  26. package/dist/templates/basic/src/index.ts +13 -0
  27. package/dist/templates/basic/template.json +31 -0
  28. package/dist/templates/basic/test/hello.test.ts +26 -0
  29. package/dist/templates/basic/tsconfig.json +19 -0
  30. package/dist/templates/monorepo/README.md +74 -0
  31. package/dist/templates/monorepo/package.json +28 -0
  32. package/dist/templates/monorepo/packages/cli/package.json +34 -0
  33. package/dist/templates/monorepo/packages/cli/src/index.ts +22 -0
  34. package/dist/templates/monorepo/packages/cli/tsconfig.json +15 -0
  35. package/dist/templates/monorepo/packages/core/package.json +32 -0
  36. package/dist/templates/monorepo/packages/core/scripts/build.ts +18 -0
  37. package/dist/templates/monorepo/packages/core/src/commands/analyze.ts +84 -0
  38. package/dist/templates/monorepo/packages/core/src/commands/process.ts +64 -0
  39. package/dist/templates/monorepo/packages/core/src/index.ts +3 -0
  40. package/dist/templates/monorepo/packages/core/src/types.ts +21 -0
  41. package/dist/templates/monorepo/packages/core/tsconfig.json +15 -0
  42. package/dist/templates/monorepo/packages/utils/package.json +26 -0
  43. package/dist/templates/monorepo/packages/utils/scripts/build.ts +17 -0
  44. package/dist/templates/monorepo/packages/utils/src/format.ts +27 -0
  45. package/dist/templates/monorepo/packages/utils/src/index.ts +3 -0
  46. package/dist/templates/monorepo/packages/utils/src/json.ts +11 -0
  47. package/dist/templates/monorepo/packages/utils/src/logger.ts +19 -0
  48. package/dist/templates/monorepo/packages/utils/tsconfig.json +12 -0
  49. package/dist/templates/monorepo/template.json +24 -0
  50. package/dist/templates/monorepo/tsconfig.json +14 -0
  51. package/dist/templates/monorepo/turbo.json +28 -0
  52. package/dist/types.d.ts +48 -0
  53. package/package.json +57 -0
  54. package/templates/advanced/README.md +114 -0
  55. package/templates/advanced/package.json +36 -0
  56. package/templates/advanced/src/commands/config.ts +145 -0
  57. package/templates/advanced/src/commands/init.ts +153 -0
  58. package/templates/advanced/src/commands/serve.ts +176 -0
  59. package/templates/advanced/src/commands/validate.ts +116 -0
  60. package/templates/advanced/src/index.ts +44 -0
  61. package/templates/advanced/src/utils/config.ts +83 -0
  62. package/templates/advanced/src/utils/constants.ts +12 -0
  63. package/templates/advanced/src/utils/glob.ts +49 -0
  64. package/templates/advanced/src/utils/validator.ts +131 -0
  65. package/templates/advanced/template.json +37 -0
  66. package/templates/advanced/test/commands.test.ts +34 -0
  67. package/templates/advanced/tsconfig.json +23 -0
  68. package/templates/basic/README.md +41 -0
  69. package/templates/basic/package.json +29 -0
  70. package/templates/basic/src/commands/hello.ts +29 -0
  71. package/templates/basic/src/index.ts +13 -0
  72. package/templates/basic/template.json +31 -0
  73. package/templates/basic/test/hello.test.ts +26 -0
  74. package/templates/basic/tsconfig.json +19 -0
  75. package/templates/monorepo/README.md +74 -0
  76. package/templates/monorepo/package.json +28 -0
  77. package/templates/monorepo/packages/cli/package.json +34 -0
  78. package/templates/monorepo/packages/cli/src/index.ts +22 -0
  79. package/templates/monorepo/packages/cli/tsconfig.json +15 -0
  80. package/templates/monorepo/packages/core/package.json +32 -0
  81. package/templates/monorepo/packages/core/scripts/build.ts +18 -0
  82. package/templates/monorepo/packages/core/src/commands/analyze.ts +84 -0
  83. package/templates/monorepo/packages/core/src/commands/process.ts +64 -0
  84. package/templates/monorepo/packages/core/src/index.ts +3 -0
  85. package/templates/monorepo/packages/core/src/types.ts +21 -0
  86. package/templates/monorepo/packages/core/tsconfig.json +15 -0
  87. package/templates/monorepo/packages/utils/package.json +26 -0
  88. package/templates/monorepo/packages/utils/scripts/build.ts +17 -0
  89. package/templates/monorepo/packages/utils/src/format.ts +27 -0
  90. package/templates/monorepo/packages/utils/src/index.ts +3 -0
  91. package/templates/monorepo/packages/utils/src/json.ts +11 -0
  92. package/templates/monorepo/packages/utils/src/logger.ts +19 -0
  93. package/templates/monorepo/packages/utils/tsconfig.json +12 -0
  94. package/templates/monorepo/template.json +24 -0
  95. package/templates/monorepo/tsconfig.json +14 -0
  96. package/templates/monorepo/turbo.json +28 -0
@@ -0,0 +1,153 @@
1
+ import { defineCommand, option } from '@bunli/core'
2
+ import { z } from 'zod'
3
+ import { CONFIG_FILE_NAME, DEFAULT_CONFIG } from '../utils/constants.js'
4
+
5
+ export const initCommand = defineCommand({
6
+ name: 'init',
7
+ description: 'Initialize a new configuration file',
8
+ options: {
9
+ force: option(
10
+ z.boolean().default(false),
11
+ {
12
+ short: 'f',
13
+ description: 'Overwrite existing config'
14
+ }
15
+ ),
16
+ template: option(
17
+ z.enum(['minimal', 'default', 'full']).default('default'),
18
+ {
19
+ short: 't',
20
+ description: 'Config template to use'
21
+ }
22
+ )
23
+ },
24
+ handler: async ({ flags, colors, prompt, spinner }) => {
25
+ const configPath = `${process.cwd()}/${CONFIG_FILE_NAME}`
26
+
27
+ // Check if config already exists
28
+ const configFile = Bun.file(configPath)
29
+ if (await configFile.exists() && !flags.force) {
30
+ const overwrite = await prompt.confirm(
31
+ `Config file already exists. Overwrite?`,
32
+ { default: false }
33
+ )
34
+
35
+ if (!overwrite) {
36
+ console.log(colors.yellow('Init cancelled'))
37
+ return
38
+ }
39
+ }
40
+
41
+ const spin = spinner('Creating config file...')
42
+ spin.start()
43
+
44
+ try {
45
+ // Get template content
46
+ const configContent = getConfigTemplate(flags.template)
47
+
48
+ // Write config file
49
+ await Bun.write(configPath, configContent)
50
+
51
+ spin.succeed('Config file created')
52
+ console.log(colors.dim(` ${CONFIG_FILE_NAME}`))
53
+
54
+ // Next steps
55
+ console.log()
56
+ console.log('Next steps:')
57
+ console.log(colors.gray(` 1. Edit ${CONFIG_FILE_NAME} to customize your configuration`))
58
+ console.log(colors.gray(` 2. Run '{{projectName}} validate' to check your files`))
59
+
60
+ } catch (error) {
61
+ spin.fail('Failed to create config file')
62
+ console.error(colors.red(String(error)))
63
+ process.exit(1)
64
+ }
65
+ }
66
+ })
67
+
68
+ function getConfigTemplate(template: 'minimal' | 'default' | 'full'): string {
69
+ const templates = {
70
+ minimal: `export default ${JSON.stringify(DEFAULT_CONFIG, null, 2)}`,
71
+
72
+ default: `export default {
73
+ // Validation rules
74
+ rules: {
75
+ // Add your validation rules here
76
+ noConsoleLog: true,
77
+ requireFileHeader: false,
78
+ },
79
+
80
+ // Server configuration
81
+ server: {
82
+ port: 3000,
83
+ host: 'localhost',
84
+ open: true,
85
+ },
86
+
87
+ // File patterns
88
+ include: ['src/**/*.{js,ts}'],
89
+ exclude: ['node_modules', 'dist', 'test'],
90
+ }`,
91
+
92
+ full: `import { defineConfig } from '{{projectName}}'
93
+
94
+ export default defineConfig({
95
+ // Validation rules
96
+ rules: {
97
+ // Code style rules
98
+ noConsoleLog: true,
99
+ noDebugger: true,
100
+ requireFileHeader: true,
101
+ maxLineLength: 100,
102
+
103
+ // Import rules
104
+ noUnusedImports: true,
105
+ sortImports: true,
106
+
107
+ // Function rules
108
+ maxFunctionLength: 50,
109
+ maxComplexity: 10,
110
+ },
111
+
112
+ // Server configuration
113
+ server: {
114
+ port: process.env.PORT || 3000,
115
+ host: process.env.HOST || 'localhost',
116
+ open: !process.env.CI,
117
+ cors: true,
118
+ },
119
+
120
+ // File patterns
121
+ include: [
122
+ 'src/**/*.{js,ts,jsx,tsx}',
123
+ 'scripts/**/*.{js,ts}',
124
+ ],
125
+ exclude: [
126
+ 'node_modules',
127
+ 'dist',
128
+ 'build',
129
+ 'coverage',
130
+ '**/*.test.{js,ts}',
131
+ '**/*.spec.{js,ts}',
132
+ ],
133
+
134
+ // Caching
135
+ cache: {
136
+ enabled: true,
137
+ directory: '.cache',
138
+ },
139
+
140
+ // Hooks
141
+ hooks: {
142
+ beforeValidate: async (files) => {
143
+ console.log(\`Validating \${files.length} files...\`)
144
+ },
145
+ afterValidate: async (results) => {
146
+ console.log(\`Found \${results.errors} errors and \${results.warnings} warnings\`)
147
+ },
148
+ },
149
+ })`
150
+ }
151
+
152
+ return templates[template]
153
+ }
@@ -0,0 +1,176 @@
1
+ import { defineCommand, option } from '@bunli/core'
2
+ import { z } from 'zod'
3
+ import { loadConfig } from '../utils/config.js'
4
+
5
+ export const serveCommand = defineCommand({
6
+ name: 'serve',
7
+ description: 'Start a development server',
8
+ options: {
9
+ port: option(
10
+ z.number().int().min(1).max(65535).default(3000),
11
+ {
12
+ short: 'p',
13
+ description: 'Port to listen on'
14
+ }
15
+ ),
16
+ host: option(
17
+ z.string().default('localhost'),
18
+ {
19
+ short: 'h',
20
+ description: 'Host to bind to'
21
+ }
22
+ ),
23
+ open: option(
24
+ z.boolean().default(true),
25
+ {
26
+ description: 'Open browser on start'
27
+ }
28
+ )
29
+ },
30
+ handler: async ({ flags, colors, spinner, shell }) => {
31
+ const spin = spinner('Starting server...')
32
+ spin.start()
33
+
34
+ try {
35
+ // Load config
36
+ const config = await loadConfig()
37
+
38
+ // Merge flags with config
39
+ const port = flags.port || config.server?.port || 3000
40
+ const host = flags.host || config.server?.host || 'localhost'
41
+ const shouldOpen = flags.open ?? config.server?.open ?? true
42
+
43
+ // Create server
44
+ const server = Bun.serve({
45
+ port,
46
+ hostname: host,
47
+ fetch(req) {
48
+ const url = new URL(req.url)
49
+
50
+ // Simple router
51
+ if (url.pathname === '/') {
52
+ return new Response(getHomePage(), {
53
+ headers: { 'Content-Type': 'text/html' }
54
+ })
55
+ }
56
+
57
+ if (url.pathname === '/api/status') {
58
+ return Response.json({
59
+ status: 'ok',
60
+ version: '0.1.0',
61
+ uptime: process.uptime()
62
+ })
63
+ }
64
+
65
+ return new Response('Not Found', { status: 404 })
66
+ }
67
+ })
68
+
69
+ spin.succeed(`Server running at http://${host}:${port}`)
70
+
71
+ // Open browser
72
+ if (shouldOpen) {
73
+ const openSpin = spinner('Opening browser...')
74
+ openSpin.start()
75
+
76
+ try {
77
+ const url = `http://${host === '0.0.0.0' ? 'localhost' : host}:${port}`
78
+
79
+ // Platform-specific open commands
80
+ const openCommand = process.platform === 'darwin' ? 'open' :
81
+ process.platform === 'win32' ? 'start' :
82
+ 'xdg-open'
83
+
84
+ await shell`${openCommand} ${url}`.quiet()
85
+ openSpin.succeed('Browser opened')
86
+ } catch {
87
+ openSpin.fail('Failed to open browser')
88
+ }
89
+ }
90
+
91
+ // Keep server running
92
+ console.log()
93
+ console.log(colors.dim('Press Ctrl+C to stop the server'))
94
+
95
+ // Handle shutdown
96
+ process.on('SIGINT', () => {
97
+ console.log()
98
+ console.log(colors.yellow('Shutting down server...'))
99
+ server.stop()
100
+ process.exit(0)
101
+ })
102
+
103
+ } catch (error) {
104
+ spin.fail('Failed to start server')
105
+ console.error(colors.red(String(error)))
106
+ process.exit(1)
107
+ }
108
+ }
109
+ })
110
+
111
+ function getHomePage(): string {
112
+ return `
113
+ <!DOCTYPE html>
114
+ <html>
115
+ <head>
116
+ <title>{{projectName}}</title>
117
+ <style>
118
+ body {
119
+ font-family: system-ui, -apple-system, sans-serif;
120
+ max-width: 800px;
121
+ margin: 0 auto;
122
+ padding: 2rem;
123
+ background: #f5f5f5;
124
+ }
125
+ .container {
126
+ background: white;
127
+ padding: 2rem;
128
+ border-radius: 8px;
129
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
130
+ }
131
+ h1 {
132
+ color: #333;
133
+ margin-top: 0;
134
+ }
135
+ .status {
136
+ display: inline-block;
137
+ padding: 0.25rem 0.5rem;
138
+ background: #10b981;
139
+ color: white;
140
+ border-radius: 4px;
141
+ font-size: 0.875rem;
142
+ }
143
+ code {
144
+ background: #f3f4f6;
145
+ padding: 0.125rem 0.25rem;
146
+ border-radius: 3px;
147
+ font-family: monospace;
148
+ }
149
+ .endpoints {
150
+ margin-top: 2rem;
151
+ padding: 1rem;
152
+ background: #f9fafb;
153
+ border-radius: 4px;
154
+ }
155
+ </style>
156
+ </head>
157
+ <body>
158
+ <div class="container">
159
+ <h1>{{projectName}}</h1>
160
+ <p>{{description}}</p>
161
+ <p><span class="status">Running</span></p>
162
+
163
+ <div class="endpoints">
164
+ <h3>API Endpoints</h3>
165
+ <ul>
166
+ <li><code>GET /</code> - This page</li>
167
+ <li><code>GET /api/status</code> - Server status</li>
168
+ </ul>
169
+ </div>
170
+
171
+ <p>To get started, check out the <a href="https://github.com/AryaLabsHQ/bunli">documentation</a>.</p>
172
+ </div>
173
+ </body>
174
+ </html>
175
+ `.trim()
176
+ }
@@ -0,0 +1,116 @@
1
+ import { defineCommand, option } from '@bunli/core'
2
+ import { z } from 'zod'
3
+ import { loadConfig } from '../utils/config.js'
4
+ import { validateFiles } from '../utils/validator.js'
5
+ import { glob } from '../utils/glob.js'
6
+
7
+ export const validateCommand = defineCommand({
8
+ name: 'validate',
9
+ description: 'Validate files against defined rules',
10
+ args: z.array(z.string()).min(1).describe('Files to validate'),
11
+ options: {
12
+ config: option(
13
+ z.string().optional(),
14
+ {
15
+ short: 'c',
16
+ description: 'Path to config file'
17
+ }
18
+ ),
19
+ fix: option(
20
+ z.boolean().default(false),
21
+ {
22
+ short: 'f',
23
+ description: 'Auto-fix issues'
24
+ }
25
+ ),
26
+ cache: option(
27
+ z.boolean().default(true),
28
+ {
29
+ description: 'Enable caching'
30
+ }
31
+ )
32
+ },
33
+ handler: async ({ args, flags, colors, spinner }) => {
34
+ const spin = spinner('Loading configuration...')
35
+ spin.start()
36
+
37
+ try {
38
+ // Load config
39
+ const config = await loadConfig(flags.config)
40
+ spin.succeed('Configuration loaded')
41
+
42
+ // Resolve files
43
+ const fileSpin = spinner('Resolving files...')
44
+ fileSpin.start()
45
+
46
+ const files = await glob(args, {
47
+ include: config.include,
48
+ exclude: config.exclude
49
+ })
50
+
51
+ fileSpin.succeed(`Found ${files.length} files to validate`)
52
+
53
+ if (files.length === 0) {
54
+ console.log(colors.yellow('No files matched the pattern'))
55
+ return
56
+ }
57
+
58
+ // Run validation
59
+ const validateSpin = spinner('Validating files...')
60
+ validateSpin.start()
61
+
62
+ const results = await validateFiles(files, {
63
+ rules: config.rules,
64
+ fix: flags.fix,
65
+ cache: flags.cache && config.cache?.enabled
66
+ })
67
+
68
+ validateSpin.stop()
69
+
70
+ // Display results
71
+ let hasErrors = false
72
+
73
+ for (const result of results) {
74
+ if (result.errors.length > 0 || result.warnings.length > 0) {
75
+ console.log()
76
+ console.log(colors.bold(result.file))
77
+
78
+ for (const error of result.errors) {
79
+ console.log(colors.red(` ✗ ${error.line}:${error.column} ${error.message}`))
80
+ hasErrors = true
81
+ }
82
+
83
+ for (const warning of result.warnings) {
84
+ console.log(colors.yellow(` ⚠ ${warning.line}:${warning.column} ${warning.message}`))
85
+ }
86
+ }
87
+ }
88
+
89
+ // Summary
90
+ const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0)
91
+ const totalWarnings = results.reduce((sum, r) => sum + r.warnings.length, 0)
92
+
93
+ console.log()
94
+ if (totalErrors === 0 && totalWarnings === 0) {
95
+ console.log(colors.green('✅ All files passed validation!'))
96
+ } else {
97
+ console.log(colors.bold('Summary:'))
98
+ if (totalErrors > 0) {
99
+ console.log(colors.red(` ${totalErrors} error${totalErrors !== 1 ? 's' : ''}`))
100
+ }
101
+ if (totalWarnings > 0) {
102
+ console.log(colors.yellow(` ${totalWarnings} warning${totalWarnings !== 1 ? 's' : ''}`))
103
+ }
104
+
105
+ if (hasErrors) {
106
+ process.exit(1)
107
+ }
108
+ }
109
+
110
+ } catch (error) {
111
+ spin.fail('Validation failed')
112
+ console.error(colors.red(String(error)))
113
+ process.exit(1)
114
+ }
115
+ }
116
+ })
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env bun
2
+ import { createCLI } from '@bunli/core'
3
+ import { initCommand } from './commands/init.js'
4
+ import { validateCommand } from './commands/validate.js'
5
+ import { serveCommand } from './commands/serve.js'
6
+ import { configCommand } from './commands/config.js'
7
+ import { loadConfig } from './utils/config.js'
8
+
9
+ const cli = createCLI({
10
+ name: '{{projectName}}',
11
+ version: '0.1.0',
12
+ description: '{{description}}'
13
+ })
14
+
15
+ // Global options
16
+ cli.option('verbose', {
17
+ type: 'boolean',
18
+ description: 'Enable verbose output'
19
+ })
20
+
21
+ cli.option('quiet', {
22
+ type: 'boolean',
23
+ description: 'Suppress output'
24
+ })
25
+
26
+ // Add commands
27
+ cli.command(initCommand)
28
+ cli.command(validateCommand)
29
+ cli.command(serveCommand)
30
+ cli.command(configCommand)
31
+
32
+ // Load config and run
33
+ async function run() {
34
+ try {
35
+ const config = await loadConfig()
36
+ // Store config in global context if needed
37
+ await cli.run()
38
+ } catch (error) {
39
+ console.error('Failed to start CLI:', error)
40
+ process.exit(1)
41
+ }
42
+ }
43
+
44
+ await run()
@@ -0,0 +1,83 @@
1
+ import { CONFIG_FILE_NAME, DEFAULT_CONFIG } from './constants.js'
2
+ import path from 'node:path'
3
+
4
+ export interface Config {
5
+ rules?: Record<string, any>
6
+ server?: {
7
+ port?: number
8
+ host?: string
9
+ open?: boolean
10
+ cors?: boolean
11
+ }
12
+ include?: string[]
13
+ exclude?: string[]
14
+ cache?: {
15
+ enabled?: boolean
16
+ directory?: string
17
+ }
18
+ hooks?: {
19
+ beforeValidate?: (files: string[]) => Promise<void>
20
+ afterValidate?: (results: any) => Promise<void>
21
+ }
22
+ }
23
+
24
+ let cachedConfig: Config | null = null
25
+
26
+ export async function loadConfig(configPath?: string): Promise<Config> {
27
+ // Return cached config if available
28
+ if (cachedConfig && !configPath) {
29
+ return cachedConfig
30
+ }
31
+
32
+ const finalPath = configPath || path.join(process.cwd(), CONFIG_FILE_NAME)
33
+
34
+ try {
35
+ // Check if config file exists
36
+ const file = Bun.file(finalPath)
37
+ if (!(await file.exists())) {
38
+ return DEFAULT_CONFIG
39
+ }
40
+
41
+ // Import the config file
42
+ const configModule = await import(finalPath)
43
+ const config = configModule.default || configModule
44
+
45
+ // Merge with defaults
46
+ cachedConfig = {
47
+ ...DEFAULT_CONFIG,
48
+ ...config,
49
+ server: {
50
+ ...DEFAULT_CONFIG.server,
51
+ ...(config.server || {})
52
+ }
53
+ }
54
+
55
+ return cachedConfig
56
+ } catch (error) {
57
+ console.warn(`Failed to load config from ${finalPath}:`, error)
58
+ return DEFAULT_CONFIG
59
+ }
60
+ }
61
+
62
+ export async function saveConfig(config: Config): Promise<void> {
63
+ const configPath = path.join(process.cwd(), CONFIG_FILE_NAME)
64
+
65
+ // Convert config to ES module format
66
+ const content = `export default ${JSON.stringify(config, null, 2)}`
67
+
68
+ await Bun.write(configPath, content)
69
+
70
+ // Clear cache
71
+ cachedConfig = null
72
+ }
73
+
74
+ export async function getConfigPath(): Promise<string> {
75
+ const configPath = path.join(process.cwd(), CONFIG_FILE_NAME)
76
+ const file = Bun.file(configPath)
77
+
78
+ if (await file.exists()) {
79
+ return configPath
80
+ }
81
+
82
+ return 'No config file found'
83
+ }
@@ -0,0 +1,12 @@
1
+ export const CONFIG_FILE_NAME = '{{projectName}}.config.js'
2
+
3
+ export const DEFAULT_CONFIG = {
4
+ rules: {},
5
+ server: {
6
+ port: 3000,
7
+ host: 'localhost',
8
+ open: true
9
+ },
10
+ include: ['src/**/*.{js,ts}'],
11
+ exclude: ['node_modules', 'dist']
12
+ }
@@ -0,0 +1,49 @@
1
+ import { Glob } from 'bun'
2
+ import path from 'node:path'
3
+
4
+ export interface GlobOptions {
5
+ include?: string[]
6
+ exclude?: string[]
7
+ }
8
+
9
+ export async function glob(patterns: string[], options: GlobOptions = {}): Promise<string[]> {
10
+ const { include = [], exclude = [] } = options
11
+
12
+ // Combine user patterns with include patterns
13
+ const allPatterns = [...patterns, ...include]
14
+
15
+ // Convert exclude patterns to absolute paths
16
+ const excludePatterns = exclude.map(pattern => {
17
+ if (pattern.startsWith('/')) {
18
+ return pattern
19
+ }
20
+ return path.join(process.cwd(), pattern)
21
+ })
22
+
23
+ const results = new Set<string>()
24
+
25
+ for (const pattern of allPatterns) {
26
+ const glob = new Glob(pattern)
27
+
28
+ for await (const file of glob.scan({
29
+ cwd: process.cwd(),
30
+ absolute: true
31
+ })) {
32
+ // Check if file should be excluded
33
+ let shouldExclude = false
34
+
35
+ for (const excludePattern of excludePatterns) {
36
+ if (file.includes(excludePattern)) {
37
+ shouldExclude = true
38
+ break
39
+ }
40
+ }
41
+
42
+ if (!shouldExclude) {
43
+ results.add(file)
44
+ }
45
+ }
46
+ }
47
+
48
+ return Array.from(results).sort()
49
+ }