@flightdev/helpers 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/detect/index.d.ts +42 -0
- package/dist/detect/index.js +257 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +287 -0
- package/dist/index.js.map +1 -0
- package/dist/suggest/index.d.ts +43 -0
- package/dist/suggest/index.js +300 -0
- package/dist/suggest/index.js.map +1 -0
- package/dist/types-0ONEhDBI.d.ts +43 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Flight Contributors
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# @flight-framework/helpers
|
|
2
|
+
|
|
3
|
+
Optional helper utilities for Flight Framework. **Suggestions, not impositions.**
|
|
4
|
+
|
|
5
|
+
## Philosophy
|
|
6
|
+
|
|
7
|
+
This package provides utilities that **suggest** configurations based on your project. It never applies anything automatically. You decide whether to use the suggestions or not.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @flight-framework/helpers
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Detect UI Framework
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { detectFramework } from '@flight-framework/helpers/detect';
|
|
21
|
+
|
|
22
|
+
const result = await detectFramework();
|
|
23
|
+
|
|
24
|
+
console.log(result);
|
|
25
|
+
// {
|
|
26
|
+
// framework: 'react',
|
|
27
|
+
// confidence: 'high',
|
|
28
|
+
// source: 'package.json',
|
|
29
|
+
// reasoning: 'Found react and react-dom in dependencies'
|
|
30
|
+
// }
|
|
31
|
+
|
|
32
|
+
// You decide what to do with this information
|
|
33
|
+
if (result.framework) {
|
|
34
|
+
console.log(`Detected: ${result.framework}`);
|
|
35
|
+
} else {
|
|
36
|
+
console.log('No framework detected, using vanilla');
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Detect Deployment Target
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { detectDeploymentTarget } from '@flight-framework/helpers/detect';
|
|
44
|
+
|
|
45
|
+
const result = await detectDeploymentTarget();
|
|
46
|
+
|
|
47
|
+
console.log(result);
|
|
48
|
+
// {
|
|
49
|
+
// adapter: 'vercel',
|
|
50
|
+
// confidence: 'high',
|
|
51
|
+
// source: 'environment',
|
|
52
|
+
// reasoning: 'VERCEL environment variable detected'
|
|
53
|
+
// }
|
|
54
|
+
|
|
55
|
+
// You decide whether to use this
|
|
56
|
+
console.log(`Suggested adapter: ${result.adapter}`);
|
|
57
|
+
console.log(`To install: npm install @flight-framework/adapter-${result.adapter}`);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Suggest Defaults
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { suggestDefaults } from '@flight-framework/helpers/suggest';
|
|
64
|
+
|
|
65
|
+
const suggestions = await suggestDefaults();
|
|
66
|
+
|
|
67
|
+
console.log(suggestions);
|
|
68
|
+
// {
|
|
69
|
+
// framework: 'react',
|
|
70
|
+
// adapter: 'vercel',
|
|
71
|
+
// rendering: 'ssr',
|
|
72
|
+
// bundler: 'vite',
|
|
73
|
+
// confidence: {
|
|
74
|
+
// framework: 'high',
|
|
75
|
+
// adapter: 'high'
|
|
76
|
+
// }
|
|
77
|
+
// }
|
|
78
|
+
|
|
79
|
+
// Use in your config if you want
|
|
80
|
+
// flight.config.ts
|
|
81
|
+
import { defineConfig } from '@flight-framework/core';
|
|
82
|
+
|
|
83
|
+
export default defineConfig({
|
|
84
|
+
ui: {
|
|
85
|
+
// Use suggestion or override
|
|
86
|
+
framework: suggestions.framework ?? 'react',
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## API Reference
|
|
92
|
+
|
|
93
|
+
### detectFramework(root?: string)
|
|
94
|
+
|
|
95
|
+
Detects the UI framework used in the project.
|
|
96
|
+
|
|
97
|
+
**Returns:**
|
|
98
|
+
```typescript
|
|
99
|
+
interface FrameworkDetection {
|
|
100
|
+
framework: 'react' | 'vue' | 'svelte' | 'solid' | 'preact' | 'qwik' | 'lit' | 'htmx' | 'angular' | null;
|
|
101
|
+
confidence: 'high' | 'medium' | 'low';
|
|
102
|
+
source: string;
|
|
103
|
+
reasoning: string;
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### detectDeploymentTarget(root?: string)
|
|
108
|
+
|
|
109
|
+
Detects the deployment environment.
|
|
110
|
+
|
|
111
|
+
**Returns:**
|
|
112
|
+
```typescript
|
|
113
|
+
interface DeploymentDetection {
|
|
114
|
+
adapter: 'node' | 'vercel' | 'netlify' | 'cloudflare' | 'aws' | 'docker' | 'fly' | 'deno' | 'bun' | null;
|
|
115
|
+
confidence: 'high' | 'medium' | 'low';
|
|
116
|
+
source: string;
|
|
117
|
+
reasoning: string;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### suggestDefaults(root?: string)
|
|
122
|
+
|
|
123
|
+
Returns suggested configuration based on detected context.
|
|
124
|
+
|
|
125
|
+
**Returns:**
|
|
126
|
+
```typescript
|
|
127
|
+
interface SuggestedDefaults {
|
|
128
|
+
framework: string | null;
|
|
129
|
+
adapter: string | null;
|
|
130
|
+
rendering: 'ssr' | 'csr' | 'ssg';
|
|
131
|
+
bundler: 'vite' | 'esbuild' | 'rolldown';
|
|
132
|
+
confidence: {
|
|
133
|
+
framework: 'high' | 'medium' | 'low';
|
|
134
|
+
adapter: 'high' | 'medium' | 'low';
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Important
|
|
140
|
+
|
|
141
|
+
This package:
|
|
142
|
+
- **Never** applies configuration automatically
|
|
143
|
+
- **Never** installs packages
|
|
144
|
+
- **Never** modifies files
|
|
145
|
+
- Only **returns information** for you to use
|
|
146
|
+
|
|
147
|
+
You are always in control.
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
MIT
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { F as FrameworkDetection, D as DeploymentDetection } from '../types-0ONEhDBI.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Detection utilities for Flight Framework
|
|
5
|
+
*
|
|
6
|
+
* These functions DETECT and REPORT. They never apply or install anything.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Detect the UI framework used in the project.
|
|
11
|
+
*
|
|
12
|
+
* This function ONLY detects and reports. It never installs or configures anything.
|
|
13
|
+
*
|
|
14
|
+
* @param root - Project root directory (defaults to current working directory)
|
|
15
|
+
* @returns Detection result with framework, confidence, and reasoning
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const result = await detectFramework();
|
|
20
|
+
* console.log(result.framework); // 'react' | 'vue' | null | ...
|
|
21
|
+
* console.log(result.reasoning); // 'Found react in package.json dependencies'
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare function detectFramework(root?: string): Promise<FrameworkDetection>;
|
|
25
|
+
/**
|
|
26
|
+
* Detect the deployment target/environment.
|
|
27
|
+
*
|
|
28
|
+
* This function ONLY detects and reports. It never installs or configures anything.
|
|
29
|
+
*
|
|
30
|
+
* @param root - Project root directory (defaults to current working directory)
|
|
31
|
+
* @returns Detection result with adapter, confidence, and reasoning
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const result = await detectDeploymentTarget();
|
|
36
|
+
* console.log(result.adapter); // 'vercel' | 'node' | null | ...
|
|
37
|
+
* console.log(result.reasoning); // 'VERCEL environment variable detected'
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare function detectDeploymentTarget(root?: string): Promise<DeploymentDetection>;
|
|
41
|
+
|
|
42
|
+
export { detectDeploymentTarget, detectFramework };
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// src/detect/index.ts
|
|
2
|
+
import { readFile, access } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
async function exists(path) {
|
|
5
|
+
try {
|
|
6
|
+
await access(path);
|
|
7
|
+
return true;
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async function readPackageJson(root) {
|
|
13
|
+
try {
|
|
14
|
+
const content = await readFile(join(root, "package.json"), "utf-8");
|
|
15
|
+
return JSON.parse(content);
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function getDependencies(pkg) {
|
|
21
|
+
const deps = pkg["dependencies"] ?? {};
|
|
22
|
+
const devDeps = pkg["devDependencies"] ?? {};
|
|
23
|
+
return { ...deps, ...devDeps };
|
|
24
|
+
}
|
|
25
|
+
async function detectFramework(root = process.cwd()) {
|
|
26
|
+
const pkg = await readPackageJson(root);
|
|
27
|
+
if (pkg) {
|
|
28
|
+
const deps = getDependencies(pkg);
|
|
29
|
+
if (deps["react"] && deps["react-dom"]) {
|
|
30
|
+
return {
|
|
31
|
+
framework: "react",
|
|
32
|
+
confidence: "high",
|
|
33
|
+
source: "package.json",
|
|
34
|
+
reasoning: "Found react and react-dom in dependencies"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (deps["vue"]) {
|
|
38
|
+
return {
|
|
39
|
+
framework: "vue",
|
|
40
|
+
confidence: "high",
|
|
41
|
+
source: "package.json",
|
|
42
|
+
reasoning: "Found vue in dependencies"
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (deps["svelte"]) {
|
|
46
|
+
return {
|
|
47
|
+
framework: "svelte",
|
|
48
|
+
confidence: "high",
|
|
49
|
+
source: "package.json",
|
|
50
|
+
reasoning: "Found svelte in dependencies"
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (deps["solid-js"]) {
|
|
54
|
+
return {
|
|
55
|
+
framework: "solid",
|
|
56
|
+
confidence: "high",
|
|
57
|
+
source: "package.json",
|
|
58
|
+
reasoning: "Found solid-js in dependencies"
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (deps["preact"]) {
|
|
62
|
+
return {
|
|
63
|
+
framework: "preact",
|
|
64
|
+
confidence: "high",
|
|
65
|
+
source: "package.json",
|
|
66
|
+
reasoning: "Found preact in dependencies"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (deps["@builder.io/qwik"]) {
|
|
70
|
+
return {
|
|
71
|
+
framework: "qwik",
|
|
72
|
+
confidence: "high",
|
|
73
|
+
source: "package.json",
|
|
74
|
+
reasoning: "Found @builder.io/qwik in dependencies"
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (deps["@angular/core"]) {
|
|
78
|
+
return {
|
|
79
|
+
framework: "angular",
|
|
80
|
+
confidence: "high",
|
|
81
|
+
source: "package.json",
|
|
82
|
+
reasoning: "Found @angular/core in dependencies"
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (deps["lit"]) {
|
|
86
|
+
return {
|
|
87
|
+
framework: "lit",
|
|
88
|
+
confidence: "high",
|
|
89
|
+
source: "package.json",
|
|
90
|
+
reasoning: "Found lit in dependencies"
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (deps["htmx.org"]) {
|
|
94
|
+
return {
|
|
95
|
+
framework: "htmx",
|
|
96
|
+
confidence: "high",
|
|
97
|
+
source: "package.json",
|
|
98
|
+
reasoning: "Found htmx.org in dependencies"
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (await exists(join(root, "svelte.config.js")) || await exists(join(root, "svelte.config.ts"))) {
|
|
103
|
+
return {
|
|
104
|
+
framework: "svelte",
|
|
105
|
+
confidence: "medium",
|
|
106
|
+
source: "config file",
|
|
107
|
+
reasoning: "Found svelte.config.js/ts"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (await exists(join(root, "angular.json"))) {
|
|
111
|
+
return {
|
|
112
|
+
framework: "angular",
|
|
113
|
+
confidence: "medium",
|
|
114
|
+
source: "config file",
|
|
115
|
+
reasoning: "Found angular.json"
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (await exists(join(root, "vue.config.js"))) {
|
|
119
|
+
return {
|
|
120
|
+
framework: "vue",
|
|
121
|
+
confidence: "medium",
|
|
122
|
+
source: "config file",
|
|
123
|
+
reasoning: "Found vue.config.js"
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
framework: null,
|
|
128
|
+
confidence: "low",
|
|
129
|
+
source: "none",
|
|
130
|
+
reasoning: "No UI framework detected. This is fine - Flight works with vanilla JS/HTML too."
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async function detectDeploymentTarget(root = process.cwd()) {
|
|
134
|
+
if (process.env["VERCEL"]) {
|
|
135
|
+
return {
|
|
136
|
+
adapter: "vercel",
|
|
137
|
+
confidence: "high",
|
|
138
|
+
source: "environment",
|
|
139
|
+
reasoning: "VERCEL environment variable detected"
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (process.env["NETLIFY"]) {
|
|
143
|
+
return {
|
|
144
|
+
adapter: "netlify",
|
|
145
|
+
confidence: "high",
|
|
146
|
+
source: "environment",
|
|
147
|
+
reasoning: "NETLIFY environment variable detected"
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (process.env["CF_PAGES"] || process.env["CLOUDFLARE_WORKERS"]) {
|
|
151
|
+
return {
|
|
152
|
+
adapter: "cloudflare",
|
|
153
|
+
confidence: "high",
|
|
154
|
+
source: "environment",
|
|
155
|
+
reasoning: "Cloudflare environment variable detected"
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (process.env["AWS_LAMBDA_FUNCTION_NAME"]) {
|
|
159
|
+
return {
|
|
160
|
+
adapter: "aws",
|
|
161
|
+
confidence: "high",
|
|
162
|
+
source: "environment",
|
|
163
|
+
reasoning: "AWS Lambda environment detected"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (process.env["FLY_APP_NAME"]) {
|
|
167
|
+
return {
|
|
168
|
+
adapter: "fly",
|
|
169
|
+
confidence: "high",
|
|
170
|
+
source: "environment",
|
|
171
|
+
reasoning: "Fly.io environment detected"
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (process.env["DENO_DEPLOYMENT_ID"]) {
|
|
175
|
+
return {
|
|
176
|
+
adapter: "deno",
|
|
177
|
+
confidence: "high",
|
|
178
|
+
source: "environment",
|
|
179
|
+
reasoning: "Deno Deploy environment detected"
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (await exists(join(root, "vercel.json"))) {
|
|
183
|
+
return {
|
|
184
|
+
adapter: "vercel",
|
|
185
|
+
confidence: "medium",
|
|
186
|
+
source: "config file",
|
|
187
|
+
reasoning: "Found vercel.json"
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
if (await exists(join(root, "netlify.toml"))) {
|
|
191
|
+
return {
|
|
192
|
+
adapter: "netlify",
|
|
193
|
+
confidence: "medium",
|
|
194
|
+
source: "config file",
|
|
195
|
+
reasoning: "Found netlify.toml"
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (await exists(join(root, "wrangler.toml"))) {
|
|
199
|
+
return {
|
|
200
|
+
adapter: "cloudflare",
|
|
201
|
+
confidence: "medium",
|
|
202
|
+
source: "config file",
|
|
203
|
+
reasoning: "Found wrangler.toml"
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (await exists(join(root, "fly.toml"))) {
|
|
207
|
+
return {
|
|
208
|
+
adapter: "fly",
|
|
209
|
+
confidence: "medium",
|
|
210
|
+
source: "config file",
|
|
211
|
+
reasoning: "Found fly.toml"
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (await exists(join(root, "Dockerfile"))) {
|
|
215
|
+
return {
|
|
216
|
+
adapter: "docker",
|
|
217
|
+
confidence: "medium",
|
|
218
|
+
source: "config file",
|
|
219
|
+
reasoning: "Found Dockerfile"
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (await exists(join(root, "serverless.yml")) || await exists(join(root, "serverless.yaml"))) {
|
|
223
|
+
return {
|
|
224
|
+
adapter: "aws",
|
|
225
|
+
confidence: "medium",
|
|
226
|
+
source: "config file",
|
|
227
|
+
reasoning: "Found serverless.yml"
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
if (typeof Bun !== "undefined") {
|
|
231
|
+
return {
|
|
232
|
+
adapter: "bun",
|
|
233
|
+
confidence: "high",
|
|
234
|
+
source: "runtime",
|
|
235
|
+
reasoning: "Running in Bun runtime"
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
if (typeof Deno !== "undefined") {
|
|
239
|
+
return {
|
|
240
|
+
adapter: "deno",
|
|
241
|
+
confidence: "high",
|
|
242
|
+
source: "runtime",
|
|
243
|
+
reasoning: "Running in Deno runtime"
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
adapter: "node",
|
|
248
|
+
confidence: "low",
|
|
249
|
+
source: "default",
|
|
250
|
+
reasoning: "No specific deployment target detected. Defaulting to Node.js (works everywhere)."
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
export {
|
|
254
|
+
detectDeploymentTarget,
|
|
255
|
+
detectFramework
|
|
256
|
+
};
|
|
257
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/detect/index.ts"],"sourcesContent":["/**\r\n * Detection utilities for Flight Framework\r\n * \r\n * These functions DETECT and REPORT. They never apply or install anything.\r\n */\r\n\r\nimport { readFile, access } from 'node:fs/promises';\r\nimport { join } from 'node:path';\r\nimport type {\r\n FrameworkDetection,\r\n DeploymentDetection,\r\n UIFramework,\r\n DeploymentAdapter,\r\n} from '../types.js';\r\n\r\n/**\r\n * Check if a file exists\r\n */\r\nasync function exists(path: string): Promise<boolean> {\r\n try {\r\n await access(path);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Read and parse package.json\r\n */\r\nasync function readPackageJson(root: string): Promise<Record<string, unknown> | null> {\r\n try {\r\n const content = await readFile(join(root, 'package.json'), 'utf-8');\r\n return JSON.parse(content) as Record<string, unknown>;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Get all dependencies from package.json\r\n */\r\nfunction getDependencies(pkg: Record<string, unknown>): Record<string, string> {\r\n const deps = (pkg['dependencies'] ?? {}) as Record<string, string>;\r\n const devDeps = (pkg['devDependencies'] ?? {}) as Record<string, string>;\r\n return { ...deps, ...devDeps };\r\n}\r\n\r\n/**\r\n * Detect the UI framework used in the project.\r\n * \r\n * This function ONLY detects and reports. It never installs or configures anything.\r\n * \r\n * @param root - Project root directory (defaults to current working directory)\r\n * @returns Detection result with framework, confidence, and reasoning\r\n * \r\n * @example\r\n * ```typescript\r\n * const result = await detectFramework();\r\n * console.log(result.framework); // 'react' | 'vue' | null | ...\r\n * console.log(result.reasoning); // 'Found react in package.json dependencies'\r\n * ```\r\n */\r\nexport async function detectFramework(root: string = process.cwd()): Promise<FrameworkDetection> {\r\n // Check 1: package.json dependencies (highest confidence)\r\n const pkg = await readPackageJson(root);\r\n if (pkg) {\r\n const deps = getDependencies(pkg);\r\n\r\n // React\r\n if (deps['react'] && deps['react-dom']) {\r\n return {\r\n framework: 'react',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found react and react-dom in dependencies',\r\n };\r\n }\r\n\r\n // Vue\r\n if (deps['vue']) {\r\n return {\r\n framework: 'vue',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found vue in dependencies',\r\n };\r\n }\r\n\r\n // Svelte\r\n if (deps['svelte']) {\r\n return {\r\n framework: 'svelte',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found svelte in dependencies',\r\n };\r\n }\r\n\r\n // Solid\r\n if (deps['solid-js']) {\r\n return {\r\n framework: 'solid',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found solid-js in dependencies',\r\n };\r\n }\r\n\r\n // Preact\r\n if (deps['preact']) {\r\n return {\r\n framework: 'preact',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found preact in dependencies',\r\n };\r\n }\r\n\r\n // Qwik\r\n if (deps['@builder.io/qwik']) {\r\n return {\r\n framework: 'qwik',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found @builder.io/qwik in dependencies',\r\n };\r\n }\r\n\r\n // Angular\r\n if (deps['@angular/core']) {\r\n return {\r\n framework: 'angular',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found @angular/core in dependencies',\r\n };\r\n }\r\n\r\n // Lit\r\n if (deps['lit']) {\r\n return {\r\n framework: 'lit',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found lit in dependencies',\r\n };\r\n }\r\n\r\n // HTMX\r\n if (deps['htmx.org']) {\r\n return {\r\n framework: 'htmx',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found htmx.org in dependencies',\r\n };\r\n }\r\n }\r\n\r\n // Check 2: Config files (medium confidence)\r\n if (await exists(join(root, 'svelte.config.js')) || await exists(join(root, 'svelte.config.ts'))) {\r\n return {\r\n framework: 'svelte',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found svelte.config.js/ts',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'angular.json'))) {\r\n return {\r\n framework: 'angular',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found angular.json',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'vue.config.js'))) {\r\n return {\r\n framework: 'vue',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found vue.config.js',\r\n };\r\n }\r\n\r\n // No framework detected\r\n return {\r\n framework: null,\r\n confidence: 'low',\r\n source: 'none',\r\n reasoning: 'No UI framework detected. This is fine - Flight works with vanilla JS/HTML too.',\r\n };\r\n}\r\n\r\n/**\r\n * Detect the deployment target/environment.\r\n * \r\n * This function ONLY detects and reports. It never installs or configures anything.\r\n * \r\n * @param root - Project root directory (defaults to current working directory)\r\n * @returns Detection result with adapter, confidence, and reasoning\r\n * \r\n * @example\r\n * ```typescript\r\n * const result = await detectDeploymentTarget();\r\n * console.log(result.adapter); // 'vercel' | 'node' | null | ...\r\n * console.log(result.reasoning); // 'VERCEL environment variable detected'\r\n * ```\r\n */\r\nexport async function detectDeploymentTarget(root: string = process.cwd()): Promise<DeploymentDetection> {\r\n // Check 1: Environment variables (highest confidence - we're running in the environment)\r\n if (process.env['VERCEL']) {\r\n return {\r\n adapter: 'vercel',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'VERCEL environment variable detected',\r\n };\r\n }\r\n\r\n if (process.env['NETLIFY']) {\r\n return {\r\n adapter: 'netlify',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'NETLIFY environment variable detected',\r\n };\r\n }\r\n\r\n if (process.env['CF_PAGES'] || process.env['CLOUDFLARE_WORKERS']) {\r\n return {\r\n adapter: 'cloudflare',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'Cloudflare environment variable detected',\r\n };\r\n }\r\n\r\n if (process.env['AWS_LAMBDA_FUNCTION_NAME']) {\r\n return {\r\n adapter: 'aws',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'AWS Lambda environment detected',\r\n };\r\n }\r\n\r\n if (process.env['FLY_APP_NAME']) {\r\n return {\r\n adapter: 'fly',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'Fly.io environment detected',\r\n };\r\n }\r\n\r\n if (process.env['DENO_DEPLOYMENT_ID']) {\r\n return {\r\n adapter: 'deno',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'Deno Deploy environment detected',\r\n };\r\n }\r\n\r\n // Check 2: Config files (medium confidence - user intent)\r\n if (await exists(join(root, 'vercel.json'))) {\r\n return {\r\n adapter: 'vercel',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found vercel.json',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'netlify.toml'))) {\r\n return {\r\n adapter: 'netlify',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found netlify.toml',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'wrangler.toml'))) {\r\n return {\r\n adapter: 'cloudflare',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found wrangler.toml',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'fly.toml'))) {\r\n return {\r\n adapter: 'fly',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found fly.toml',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'Dockerfile'))) {\r\n return {\r\n adapter: 'docker',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found Dockerfile',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'serverless.yml')) || await exists(join(root, 'serverless.yaml'))) {\r\n return {\r\n adapter: 'aws',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found serverless.yml',\r\n };\r\n }\r\n\r\n // Check 3: Runtime detection\r\n // @ts-expect-error - Bun global\r\n if (typeof Bun !== 'undefined') {\r\n return {\r\n adapter: 'bun',\r\n confidence: 'high',\r\n source: 'runtime',\r\n reasoning: 'Running in Bun runtime',\r\n };\r\n }\r\n\r\n // @ts-expect-error - Deno global\r\n if (typeof Deno !== 'undefined') {\r\n return {\r\n adapter: 'deno',\r\n confidence: 'high',\r\n source: 'runtime',\r\n reasoning: 'Running in Deno runtime',\r\n };\r\n }\r\n\r\n // Default: Node.js (always available)\r\n return {\r\n adapter: 'node',\r\n confidence: 'low',\r\n source: 'default',\r\n reasoning: 'No specific deployment target detected. Defaulting to Node.js (works everywhere).',\r\n };\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
// src/detect/index.ts
|
|
2
|
+
import { readFile, access } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
async function exists(path) {
|
|
5
|
+
try {
|
|
6
|
+
await access(path);
|
|
7
|
+
return true;
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async function readPackageJson(root) {
|
|
13
|
+
try {
|
|
14
|
+
const content = await readFile(join(root, "package.json"), "utf-8");
|
|
15
|
+
return JSON.parse(content);
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function getDependencies(pkg) {
|
|
21
|
+
const deps = pkg["dependencies"] ?? {};
|
|
22
|
+
const devDeps = pkg["devDependencies"] ?? {};
|
|
23
|
+
return { ...deps, ...devDeps };
|
|
24
|
+
}
|
|
25
|
+
async function detectFramework(root = process.cwd()) {
|
|
26
|
+
const pkg = await readPackageJson(root);
|
|
27
|
+
if (pkg) {
|
|
28
|
+
const deps = getDependencies(pkg);
|
|
29
|
+
if (deps["react"] && deps["react-dom"]) {
|
|
30
|
+
return {
|
|
31
|
+
framework: "react",
|
|
32
|
+
confidence: "high",
|
|
33
|
+
source: "package.json",
|
|
34
|
+
reasoning: "Found react and react-dom in dependencies"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (deps["vue"]) {
|
|
38
|
+
return {
|
|
39
|
+
framework: "vue",
|
|
40
|
+
confidence: "high",
|
|
41
|
+
source: "package.json",
|
|
42
|
+
reasoning: "Found vue in dependencies"
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (deps["svelte"]) {
|
|
46
|
+
return {
|
|
47
|
+
framework: "svelte",
|
|
48
|
+
confidence: "high",
|
|
49
|
+
source: "package.json",
|
|
50
|
+
reasoning: "Found svelte in dependencies"
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (deps["solid-js"]) {
|
|
54
|
+
return {
|
|
55
|
+
framework: "solid",
|
|
56
|
+
confidence: "high",
|
|
57
|
+
source: "package.json",
|
|
58
|
+
reasoning: "Found solid-js in dependencies"
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (deps["preact"]) {
|
|
62
|
+
return {
|
|
63
|
+
framework: "preact",
|
|
64
|
+
confidence: "high",
|
|
65
|
+
source: "package.json",
|
|
66
|
+
reasoning: "Found preact in dependencies"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (deps["@builder.io/qwik"]) {
|
|
70
|
+
return {
|
|
71
|
+
framework: "qwik",
|
|
72
|
+
confidence: "high",
|
|
73
|
+
source: "package.json",
|
|
74
|
+
reasoning: "Found @builder.io/qwik in dependencies"
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (deps["@angular/core"]) {
|
|
78
|
+
return {
|
|
79
|
+
framework: "angular",
|
|
80
|
+
confidence: "high",
|
|
81
|
+
source: "package.json",
|
|
82
|
+
reasoning: "Found @angular/core in dependencies"
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (deps["lit"]) {
|
|
86
|
+
return {
|
|
87
|
+
framework: "lit",
|
|
88
|
+
confidence: "high",
|
|
89
|
+
source: "package.json",
|
|
90
|
+
reasoning: "Found lit in dependencies"
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (deps["htmx.org"]) {
|
|
94
|
+
return {
|
|
95
|
+
framework: "htmx",
|
|
96
|
+
confidence: "high",
|
|
97
|
+
source: "package.json",
|
|
98
|
+
reasoning: "Found htmx.org in dependencies"
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (await exists(join(root, "svelte.config.js")) || await exists(join(root, "svelte.config.ts"))) {
|
|
103
|
+
return {
|
|
104
|
+
framework: "svelte",
|
|
105
|
+
confidence: "medium",
|
|
106
|
+
source: "config file",
|
|
107
|
+
reasoning: "Found svelte.config.js/ts"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (await exists(join(root, "angular.json"))) {
|
|
111
|
+
return {
|
|
112
|
+
framework: "angular",
|
|
113
|
+
confidence: "medium",
|
|
114
|
+
source: "config file",
|
|
115
|
+
reasoning: "Found angular.json"
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (await exists(join(root, "vue.config.js"))) {
|
|
119
|
+
return {
|
|
120
|
+
framework: "vue",
|
|
121
|
+
confidence: "medium",
|
|
122
|
+
source: "config file",
|
|
123
|
+
reasoning: "Found vue.config.js"
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
framework: null,
|
|
128
|
+
confidence: "low",
|
|
129
|
+
source: "none",
|
|
130
|
+
reasoning: "No UI framework detected. This is fine - Flight works with vanilla JS/HTML too."
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async function detectDeploymentTarget(root = process.cwd()) {
|
|
134
|
+
if (process.env["VERCEL"]) {
|
|
135
|
+
return {
|
|
136
|
+
adapter: "vercel",
|
|
137
|
+
confidence: "high",
|
|
138
|
+
source: "environment",
|
|
139
|
+
reasoning: "VERCEL environment variable detected"
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (process.env["NETLIFY"]) {
|
|
143
|
+
return {
|
|
144
|
+
adapter: "netlify",
|
|
145
|
+
confidence: "high",
|
|
146
|
+
source: "environment",
|
|
147
|
+
reasoning: "NETLIFY environment variable detected"
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (process.env["CF_PAGES"] || process.env["CLOUDFLARE_WORKERS"]) {
|
|
151
|
+
return {
|
|
152
|
+
adapter: "cloudflare",
|
|
153
|
+
confidence: "high",
|
|
154
|
+
source: "environment",
|
|
155
|
+
reasoning: "Cloudflare environment variable detected"
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (process.env["AWS_LAMBDA_FUNCTION_NAME"]) {
|
|
159
|
+
return {
|
|
160
|
+
adapter: "aws",
|
|
161
|
+
confidence: "high",
|
|
162
|
+
source: "environment",
|
|
163
|
+
reasoning: "AWS Lambda environment detected"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (process.env["FLY_APP_NAME"]) {
|
|
167
|
+
return {
|
|
168
|
+
adapter: "fly",
|
|
169
|
+
confidence: "high",
|
|
170
|
+
source: "environment",
|
|
171
|
+
reasoning: "Fly.io environment detected"
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (process.env["DENO_DEPLOYMENT_ID"]) {
|
|
175
|
+
return {
|
|
176
|
+
adapter: "deno",
|
|
177
|
+
confidence: "high",
|
|
178
|
+
source: "environment",
|
|
179
|
+
reasoning: "Deno Deploy environment detected"
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (await exists(join(root, "vercel.json"))) {
|
|
183
|
+
return {
|
|
184
|
+
adapter: "vercel",
|
|
185
|
+
confidence: "medium",
|
|
186
|
+
source: "config file",
|
|
187
|
+
reasoning: "Found vercel.json"
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
if (await exists(join(root, "netlify.toml"))) {
|
|
191
|
+
return {
|
|
192
|
+
adapter: "netlify",
|
|
193
|
+
confidence: "medium",
|
|
194
|
+
source: "config file",
|
|
195
|
+
reasoning: "Found netlify.toml"
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (await exists(join(root, "wrangler.toml"))) {
|
|
199
|
+
return {
|
|
200
|
+
adapter: "cloudflare",
|
|
201
|
+
confidence: "medium",
|
|
202
|
+
source: "config file",
|
|
203
|
+
reasoning: "Found wrangler.toml"
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (await exists(join(root, "fly.toml"))) {
|
|
207
|
+
return {
|
|
208
|
+
adapter: "fly",
|
|
209
|
+
confidence: "medium",
|
|
210
|
+
source: "config file",
|
|
211
|
+
reasoning: "Found fly.toml"
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (await exists(join(root, "Dockerfile"))) {
|
|
215
|
+
return {
|
|
216
|
+
adapter: "docker",
|
|
217
|
+
confidence: "medium",
|
|
218
|
+
source: "config file",
|
|
219
|
+
reasoning: "Found Dockerfile"
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (await exists(join(root, "serverless.yml")) || await exists(join(root, "serverless.yaml"))) {
|
|
223
|
+
return {
|
|
224
|
+
adapter: "aws",
|
|
225
|
+
confidence: "medium",
|
|
226
|
+
source: "config file",
|
|
227
|
+
reasoning: "Found serverless.yml"
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
if (typeof Bun !== "undefined") {
|
|
231
|
+
return {
|
|
232
|
+
adapter: "bun",
|
|
233
|
+
confidence: "high",
|
|
234
|
+
source: "runtime",
|
|
235
|
+
reasoning: "Running in Bun runtime"
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
if (typeof Deno !== "undefined") {
|
|
239
|
+
return {
|
|
240
|
+
adapter: "deno",
|
|
241
|
+
confidence: "high",
|
|
242
|
+
source: "runtime",
|
|
243
|
+
reasoning: "Running in Deno runtime"
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
adapter: "node",
|
|
248
|
+
confidence: "low",
|
|
249
|
+
source: "default",
|
|
250
|
+
reasoning: "No specific deployment target detected. Defaulting to Node.js (works everywhere)."
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// src/suggest/index.ts
|
|
255
|
+
async function suggestDefaults(root = process.cwd()) {
|
|
256
|
+
const [frameworkResult, adapterResult] = await Promise.all([
|
|
257
|
+
detectFramework(root),
|
|
258
|
+
detectDeploymentTarget(root)
|
|
259
|
+
]);
|
|
260
|
+
let rendering = "ssr";
|
|
261
|
+
if (frameworkResult.framework === "htmx") {
|
|
262
|
+
rendering = "ssr";
|
|
263
|
+
}
|
|
264
|
+
if (frameworkResult.framework === "qwik") {
|
|
265
|
+
rendering = "ssr";
|
|
266
|
+
}
|
|
267
|
+
if (adapterResult.adapter === "static") {
|
|
268
|
+
rendering = "ssg";
|
|
269
|
+
}
|
|
270
|
+
const bundler = "vite";
|
|
271
|
+
return {
|
|
272
|
+
framework: frameworkResult.framework,
|
|
273
|
+
adapter: adapterResult.adapter,
|
|
274
|
+
rendering,
|
|
275
|
+
bundler,
|
|
276
|
+
confidence: {
|
|
277
|
+
framework: frameworkResult.confidence,
|
|
278
|
+
adapter: adapterResult.confidence
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
export {
|
|
283
|
+
detectDeploymentTarget,
|
|
284
|
+
detectFramework,
|
|
285
|
+
suggestDefaults
|
|
286
|
+
};
|
|
287
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/detect/index.ts","../src/suggest/index.ts"],"sourcesContent":["/**\r\n * Detection utilities for Flight Framework\r\n * \r\n * These functions DETECT and REPORT. They never apply or install anything.\r\n */\r\n\r\nimport { readFile, access } from 'node:fs/promises';\r\nimport { join } from 'node:path';\r\nimport type {\r\n FrameworkDetection,\r\n DeploymentDetection,\r\n UIFramework,\r\n DeploymentAdapter,\r\n} from '../types.js';\r\n\r\n/**\r\n * Check if a file exists\r\n */\r\nasync function exists(path: string): Promise<boolean> {\r\n try {\r\n await access(path);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Read and parse package.json\r\n */\r\nasync function readPackageJson(root: string): Promise<Record<string, unknown> | null> {\r\n try {\r\n const content = await readFile(join(root, 'package.json'), 'utf-8');\r\n return JSON.parse(content) as Record<string, unknown>;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Get all dependencies from package.json\r\n */\r\nfunction getDependencies(pkg: Record<string, unknown>): Record<string, string> {\r\n const deps = (pkg['dependencies'] ?? {}) as Record<string, string>;\r\n const devDeps = (pkg['devDependencies'] ?? {}) as Record<string, string>;\r\n return { ...deps, ...devDeps };\r\n}\r\n\r\n/**\r\n * Detect the UI framework used in the project.\r\n * \r\n * This function ONLY detects and reports. It never installs or configures anything.\r\n * \r\n * @param root - Project root directory (defaults to current working directory)\r\n * @returns Detection result with framework, confidence, and reasoning\r\n * \r\n * @example\r\n * ```typescript\r\n * const result = await detectFramework();\r\n * console.log(result.framework); // 'react' | 'vue' | null | ...\r\n * console.log(result.reasoning); // 'Found react in package.json dependencies'\r\n * ```\r\n */\r\nexport async function detectFramework(root: string = process.cwd()): Promise<FrameworkDetection> {\r\n // Check 1: package.json dependencies (highest confidence)\r\n const pkg = await readPackageJson(root);\r\n if (pkg) {\r\n const deps = getDependencies(pkg);\r\n\r\n // React\r\n if (deps['react'] && deps['react-dom']) {\r\n return {\r\n framework: 'react',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found react and react-dom in dependencies',\r\n };\r\n }\r\n\r\n // Vue\r\n if (deps['vue']) {\r\n return {\r\n framework: 'vue',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found vue in dependencies',\r\n };\r\n }\r\n\r\n // Svelte\r\n if (deps['svelte']) {\r\n return {\r\n framework: 'svelte',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found svelte in dependencies',\r\n };\r\n }\r\n\r\n // Solid\r\n if (deps['solid-js']) {\r\n return {\r\n framework: 'solid',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found solid-js in dependencies',\r\n };\r\n }\r\n\r\n // Preact\r\n if (deps['preact']) {\r\n return {\r\n framework: 'preact',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found preact in dependencies',\r\n };\r\n }\r\n\r\n // Qwik\r\n if (deps['@builder.io/qwik']) {\r\n return {\r\n framework: 'qwik',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found @builder.io/qwik in dependencies',\r\n };\r\n }\r\n\r\n // Angular\r\n if (deps['@angular/core']) {\r\n return {\r\n framework: 'angular',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found @angular/core in dependencies',\r\n };\r\n }\r\n\r\n // Lit\r\n if (deps['lit']) {\r\n return {\r\n framework: 'lit',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found lit in dependencies',\r\n };\r\n }\r\n\r\n // HTMX\r\n if (deps['htmx.org']) {\r\n return {\r\n framework: 'htmx',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found htmx.org in dependencies',\r\n };\r\n }\r\n }\r\n\r\n // Check 2: Config files (medium confidence)\r\n if (await exists(join(root, 'svelte.config.js')) || await exists(join(root, 'svelte.config.ts'))) {\r\n return {\r\n framework: 'svelte',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found svelte.config.js/ts',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'angular.json'))) {\r\n return {\r\n framework: 'angular',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found angular.json',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'vue.config.js'))) {\r\n return {\r\n framework: 'vue',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found vue.config.js',\r\n };\r\n }\r\n\r\n // No framework detected\r\n return {\r\n framework: null,\r\n confidence: 'low',\r\n source: 'none',\r\n reasoning: 'No UI framework detected. This is fine - Flight works with vanilla JS/HTML too.',\r\n };\r\n}\r\n\r\n/**\r\n * Detect the deployment target/environment.\r\n * \r\n * This function ONLY detects and reports. It never installs or configures anything.\r\n * \r\n * @param root - Project root directory (defaults to current working directory)\r\n * @returns Detection result with adapter, confidence, and reasoning\r\n * \r\n * @example\r\n * ```typescript\r\n * const result = await detectDeploymentTarget();\r\n * console.log(result.adapter); // 'vercel' | 'node' | null | ...\r\n * console.log(result.reasoning); // 'VERCEL environment variable detected'\r\n * ```\r\n */\r\nexport async function detectDeploymentTarget(root: string = process.cwd()): Promise<DeploymentDetection> {\r\n // Check 1: Environment variables (highest confidence - we're running in the environment)\r\n if (process.env['VERCEL']) {\r\n return {\r\n adapter: 'vercel',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'VERCEL environment variable detected',\r\n };\r\n }\r\n\r\n if (process.env['NETLIFY']) {\r\n return {\r\n adapter: 'netlify',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'NETLIFY environment variable detected',\r\n };\r\n }\r\n\r\n if (process.env['CF_PAGES'] || process.env['CLOUDFLARE_WORKERS']) {\r\n return {\r\n adapter: 'cloudflare',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'Cloudflare environment variable detected',\r\n };\r\n }\r\n\r\n if (process.env['AWS_LAMBDA_FUNCTION_NAME']) {\r\n return {\r\n adapter: 'aws',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'AWS Lambda environment detected',\r\n };\r\n }\r\n\r\n if (process.env['FLY_APP_NAME']) {\r\n return {\r\n adapter: 'fly',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'Fly.io environment detected',\r\n };\r\n }\r\n\r\n if (process.env['DENO_DEPLOYMENT_ID']) {\r\n return {\r\n adapter: 'deno',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'Deno Deploy environment detected',\r\n };\r\n }\r\n\r\n // Check 2: Config files (medium confidence - user intent)\r\n if (await exists(join(root, 'vercel.json'))) {\r\n return {\r\n adapter: 'vercel',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found vercel.json',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'netlify.toml'))) {\r\n return {\r\n adapter: 'netlify',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found netlify.toml',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'wrangler.toml'))) {\r\n return {\r\n adapter: 'cloudflare',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found wrangler.toml',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'fly.toml'))) {\r\n return {\r\n adapter: 'fly',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found fly.toml',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'Dockerfile'))) {\r\n return {\r\n adapter: 'docker',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found Dockerfile',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'serverless.yml')) || await exists(join(root, 'serverless.yaml'))) {\r\n return {\r\n adapter: 'aws',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found serverless.yml',\r\n };\r\n }\r\n\r\n // Check 3: Runtime detection\r\n // @ts-expect-error - Bun global\r\n if (typeof Bun !== 'undefined') {\r\n return {\r\n adapter: 'bun',\r\n confidence: 'high',\r\n source: 'runtime',\r\n reasoning: 'Running in Bun runtime',\r\n };\r\n }\r\n\r\n // @ts-expect-error - Deno global\r\n if (typeof Deno !== 'undefined') {\r\n return {\r\n adapter: 'deno',\r\n confidence: 'high',\r\n source: 'runtime',\r\n reasoning: 'Running in Deno runtime',\r\n };\r\n }\r\n\r\n // Default: Node.js (always available)\r\n return {\r\n adapter: 'node',\r\n confidence: 'low',\r\n source: 'default',\r\n reasoning: 'No specific deployment target detected. Defaulting to Node.js (works everywhere).',\r\n };\r\n}\r\n","/**\r\n * Suggestion utilities for Flight Framework\r\n * \r\n * These functions SUGGEST configurations based on detected context.\r\n * They never apply anything automatically. You decide.\r\n */\r\n\r\nimport { detectFramework, detectDeploymentTarget } from '../detect/index.js';\r\nimport type { SuggestedDefaults } from '../types.js';\r\n\r\n/**\r\n * Suggest default configuration based on project analysis.\r\n * \r\n * This function ONLY suggests. It never applies, installs, or modifies anything.\r\n * You are free to use these suggestions, modify them, or ignore them entirely.\r\n * \r\n * @param root - Project root directory (defaults to current working directory)\r\n * @returns Suggested defaults with confidence levels\r\n * \r\n * @example\r\n * ```typescript\r\n * const suggestions = await suggestDefaults();\r\n * \r\n * // Use suggestions in your config (optional)\r\n * export default {\r\n * ui: { framework: suggestions.framework ?? 'react' },\r\n * };\r\n * \r\n * // Or ignore them entirely\r\n * export default {\r\n * ui: { framework: 'vue' },\r\n * };\r\n * ```\r\n */\r\nexport async function suggestDefaults(root: string = process.cwd()): Promise<SuggestedDefaults> {\r\n // Detect context\r\n const [frameworkResult, adapterResult] = await Promise.all([\r\n detectFramework(root),\r\n detectDeploymentTarget(root),\r\n ]);\r\n\r\n // Determine rendering mode based on framework\r\n let rendering: 'ssr' | 'csr' | 'ssg' = 'ssr';\r\n\r\n // HTMX and static sites are typically SSR/SSG\r\n if (frameworkResult.framework === 'htmx') {\r\n rendering = 'ssr';\r\n }\r\n\r\n // Qwik uses resumability, SSR is recommended\r\n if (frameworkResult.framework === 'qwik') {\r\n rendering = 'ssr';\r\n }\r\n\r\n // Static adapters should use SSG\r\n if (adapterResult.adapter === 'static') {\r\n rendering = 'ssg';\r\n }\r\n\r\n // Determine bundler\r\n // Vite is the most universal choice\r\n const bundler = 'vite' as const;\r\n\r\n return {\r\n framework: frameworkResult.framework,\r\n adapter: adapterResult.adapter,\r\n rendering,\r\n bundler,\r\n confidence: {\r\n framework: frameworkResult.confidence,\r\n adapter: adapterResult.confidence,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Log suggestions to console in a helpful format.\r\n * Useful for CLI tools.\r\n * \r\n * @param suggestions - Suggested defaults from suggestDefaults()\r\n */\r\nexport function logSuggestions(suggestions: SuggestedDefaults): void {\r\n console.log('\\n📋 Flight Suggestions (optional)\\n');\r\n\r\n if (suggestions.framework) {\r\n console.log(` UI Framework: ${suggestions.framework} (${suggestions.confidence.framework} confidence)`);\r\n } else {\r\n console.log(' UI Framework: none detected (vanilla JS/HTML works fine)');\r\n }\r\n\r\n if (suggestions.adapter) {\r\n console.log(` Deployment: ${suggestions.adapter} (${suggestions.confidence.adapter} confidence)`);\r\n }\r\n\r\n console.log(` Rendering: ${suggestions.rendering}`);\r\n console.log(` Bundler: ${suggestions.bundler}`);\r\n\r\n console.log('\\n💡 These are suggestions only. You can override any of these in flight.config.ts\\n');\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { S as SuggestedDefaults } from '../types-0ONEhDBI.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Suggestion utilities for Flight Framework
|
|
5
|
+
*
|
|
6
|
+
* These functions SUGGEST configurations based on detected context.
|
|
7
|
+
* They never apply anything automatically. You decide.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Suggest default configuration based on project analysis.
|
|
12
|
+
*
|
|
13
|
+
* This function ONLY suggests. It never applies, installs, or modifies anything.
|
|
14
|
+
* You are free to use these suggestions, modify them, or ignore them entirely.
|
|
15
|
+
*
|
|
16
|
+
* @param root - Project root directory (defaults to current working directory)
|
|
17
|
+
* @returns Suggested defaults with confidence levels
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const suggestions = await suggestDefaults();
|
|
22
|
+
*
|
|
23
|
+
* // Use suggestions in your config (optional)
|
|
24
|
+
* export default {
|
|
25
|
+
* ui: { framework: suggestions.framework ?? 'react' },
|
|
26
|
+
* };
|
|
27
|
+
*
|
|
28
|
+
* // Or ignore them entirely
|
|
29
|
+
* export default {
|
|
30
|
+
* ui: { framework: 'vue' },
|
|
31
|
+
* };
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
declare function suggestDefaults(root?: string): Promise<SuggestedDefaults>;
|
|
35
|
+
/**
|
|
36
|
+
* Log suggestions to console in a helpful format.
|
|
37
|
+
* Useful for CLI tools.
|
|
38
|
+
*
|
|
39
|
+
* @param suggestions - Suggested defaults from suggestDefaults()
|
|
40
|
+
*/
|
|
41
|
+
declare function logSuggestions(suggestions: SuggestedDefaults): void;
|
|
42
|
+
|
|
43
|
+
export { logSuggestions, suggestDefaults };
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// src/detect/index.ts
|
|
2
|
+
import { readFile, access } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
async function exists(path) {
|
|
5
|
+
try {
|
|
6
|
+
await access(path);
|
|
7
|
+
return true;
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async function readPackageJson(root) {
|
|
13
|
+
try {
|
|
14
|
+
const content = await readFile(join(root, "package.json"), "utf-8");
|
|
15
|
+
return JSON.parse(content);
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function getDependencies(pkg) {
|
|
21
|
+
const deps = pkg["dependencies"] ?? {};
|
|
22
|
+
const devDeps = pkg["devDependencies"] ?? {};
|
|
23
|
+
return { ...deps, ...devDeps };
|
|
24
|
+
}
|
|
25
|
+
async function detectFramework(root = process.cwd()) {
|
|
26
|
+
const pkg = await readPackageJson(root);
|
|
27
|
+
if (pkg) {
|
|
28
|
+
const deps = getDependencies(pkg);
|
|
29
|
+
if (deps["react"] && deps["react-dom"]) {
|
|
30
|
+
return {
|
|
31
|
+
framework: "react",
|
|
32
|
+
confidence: "high",
|
|
33
|
+
source: "package.json",
|
|
34
|
+
reasoning: "Found react and react-dom in dependencies"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (deps["vue"]) {
|
|
38
|
+
return {
|
|
39
|
+
framework: "vue",
|
|
40
|
+
confidence: "high",
|
|
41
|
+
source: "package.json",
|
|
42
|
+
reasoning: "Found vue in dependencies"
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (deps["svelte"]) {
|
|
46
|
+
return {
|
|
47
|
+
framework: "svelte",
|
|
48
|
+
confidence: "high",
|
|
49
|
+
source: "package.json",
|
|
50
|
+
reasoning: "Found svelte in dependencies"
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (deps["solid-js"]) {
|
|
54
|
+
return {
|
|
55
|
+
framework: "solid",
|
|
56
|
+
confidence: "high",
|
|
57
|
+
source: "package.json",
|
|
58
|
+
reasoning: "Found solid-js in dependencies"
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (deps["preact"]) {
|
|
62
|
+
return {
|
|
63
|
+
framework: "preact",
|
|
64
|
+
confidence: "high",
|
|
65
|
+
source: "package.json",
|
|
66
|
+
reasoning: "Found preact in dependencies"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (deps["@builder.io/qwik"]) {
|
|
70
|
+
return {
|
|
71
|
+
framework: "qwik",
|
|
72
|
+
confidence: "high",
|
|
73
|
+
source: "package.json",
|
|
74
|
+
reasoning: "Found @builder.io/qwik in dependencies"
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (deps["@angular/core"]) {
|
|
78
|
+
return {
|
|
79
|
+
framework: "angular",
|
|
80
|
+
confidence: "high",
|
|
81
|
+
source: "package.json",
|
|
82
|
+
reasoning: "Found @angular/core in dependencies"
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (deps["lit"]) {
|
|
86
|
+
return {
|
|
87
|
+
framework: "lit",
|
|
88
|
+
confidence: "high",
|
|
89
|
+
source: "package.json",
|
|
90
|
+
reasoning: "Found lit in dependencies"
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (deps["htmx.org"]) {
|
|
94
|
+
return {
|
|
95
|
+
framework: "htmx",
|
|
96
|
+
confidence: "high",
|
|
97
|
+
source: "package.json",
|
|
98
|
+
reasoning: "Found htmx.org in dependencies"
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (await exists(join(root, "svelte.config.js")) || await exists(join(root, "svelte.config.ts"))) {
|
|
103
|
+
return {
|
|
104
|
+
framework: "svelte",
|
|
105
|
+
confidence: "medium",
|
|
106
|
+
source: "config file",
|
|
107
|
+
reasoning: "Found svelte.config.js/ts"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (await exists(join(root, "angular.json"))) {
|
|
111
|
+
return {
|
|
112
|
+
framework: "angular",
|
|
113
|
+
confidence: "medium",
|
|
114
|
+
source: "config file",
|
|
115
|
+
reasoning: "Found angular.json"
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (await exists(join(root, "vue.config.js"))) {
|
|
119
|
+
return {
|
|
120
|
+
framework: "vue",
|
|
121
|
+
confidence: "medium",
|
|
122
|
+
source: "config file",
|
|
123
|
+
reasoning: "Found vue.config.js"
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
framework: null,
|
|
128
|
+
confidence: "low",
|
|
129
|
+
source: "none",
|
|
130
|
+
reasoning: "No UI framework detected. This is fine - Flight works with vanilla JS/HTML too."
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async function detectDeploymentTarget(root = process.cwd()) {
|
|
134
|
+
if (process.env["VERCEL"]) {
|
|
135
|
+
return {
|
|
136
|
+
adapter: "vercel",
|
|
137
|
+
confidence: "high",
|
|
138
|
+
source: "environment",
|
|
139
|
+
reasoning: "VERCEL environment variable detected"
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (process.env["NETLIFY"]) {
|
|
143
|
+
return {
|
|
144
|
+
adapter: "netlify",
|
|
145
|
+
confidence: "high",
|
|
146
|
+
source: "environment",
|
|
147
|
+
reasoning: "NETLIFY environment variable detected"
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (process.env["CF_PAGES"] || process.env["CLOUDFLARE_WORKERS"]) {
|
|
151
|
+
return {
|
|
152
|
+
adapter: "cloudflare",
|
|
153
|
+
confidence: "high",
|
|
154
|
+
source: "environment",
|
|
155
|
+
reasoning: "Cloudflare environment variable detected"
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (process.env["AWS_LAMBDA_FUNCTION_NAME"]) {
|
|
159
|
+
return {
|
|
160
|
+
adapter: "aws",
|
|
161
|
+
confidence: "high",
|
|
162
|
+
source: "environment",
|
|
163
|
+
reasoning: "AWS Lambda environment detected"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (process.env["FLY_APP_NAME"]) {
|
|
167
|
+
return {
|
|
168
|
+
adapter: "fly",
|
|
169
|
+
confidence: "high",
|
|
170
|
+
source: "environment",
|
|
171
|
+
reasoning: "Fly.io environment detected"
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (process.env["DENO_DEPLOYMENT_ID"]) {
|
|
175
|
+
return {
|
|
176
|
+
adapter: "deno",
|
|
177
|
+
confidence: "high",
|
|
178
|
+
source: "environment",
|
|
179
|
+
reasoning: "Deno Deploy environment detected"
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (await exists(join(root, "vercel.json"))) {
|
|
183
|
+
return {
|
|
184
|
+
adapter: "vercel",
|
|
185
|
+
confidence: "medium",
|
|
186
|
+
source: "config file",
|
|
187
|
+
reasoning: "Found vercel.json"
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
if (await exists(join(root, "netlify.toml"))) {
|
|
191
|
+
return {
|
|
192
|
+
adapter: "netlify",
|
|
193
|
+
confidence: "medium",
|
|
194
|
+
source: "config file",
|
|
195
|
+
reasoning: "Found netlify.toml"
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (await exists(join(root, "wrangler.toml"))) {
|
|
199
|
+
return {
|
|
200
|
+
adapter: "cloudflare",
|
|
201
|
+
confidence: "medium",
|
|
202
|
+
source: "config file",
|
|
203
|
+
reasoning: "Found wrangler.toml"
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (await exists(join(root, "fly.toml"))) {
|
|
207
|
+
return {
|
|
208
|
+
adapter: "fly",
|
|
209
|
+
confidence: "medium",
|
|
210
|
+
source: "config file",
|
|
211
|
+
reasoning: "Found fly.toml"
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (await exists(join(root, "Dockerfile"))) {
|
|
215
|
+
return {
|
|
216
|
+
adapter: "docker",
|
|
217
|
+
confidence: "medium",
|
|
218
|
+
source: "config file",
|
|
219
|
+
reasoning: "Found Dockerfile"
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (await exists(join(root, "serverless.yml")) || await exists(join(root, "serverless.yaml"))) {
|
|
223
|
+
return {
|
|
224
|
+
adapter: "aws",
|
|
225
|
+
confidence: "medium",
|
|
226
|
+
source: "config file",
|
|
227
|
+
reasoning: "Found serverless.yml"
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
if (typeof Bun !== "undefined") {
|
|
231
|
+
return {
|
|
232
|
+
adapter: "bun",
|
|
233
|
+
confidence: "high",
|
|
234
|
+
source: "runtime",
|
|
235
|
+
reasoning: "Running in Bun runtime"
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
if (typeof Deno !== "undefined") {
|
|
239
|
+
return {
|
|
240
|
+
adapter: "deno",
|
|
241
|
+
confidence: "high",
|
|
242
|
+
source: "runtime",
|
|
243
|
+
reasoning: "Running in Deno runtime"
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
adapter: "node",
|
|
248
|
+
confidence: "low",
|
|
249
|
+
source: "default",
|
|
250
|
+
reasoning: "No specific deployment target detected. Defaulting to Node.js (works everywhere)."
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// src/suggest/index.ts
|
|
255
|
+
async function suggestDefaults(root = process.cwd()) {
|
|
256
|
+
const [frameworkResult, adapterResult] = await Promise.all([
|
|
257
|
+
detectFramework(root),
|
|
258
|
+
detectDeploymentTarget(root)
|
|
259
|
+
]);
|
|
260
|
+
let rendering = "ssr";
|
|
261
|
+
if (frameworkResult.framework === "htmx") {
|
|
262
|
+
rendering = "ssr";
|
|
263
|
+
}
|
|
264
|
+
if (frameworkResult.framework === "qwik") {
|
|
265
|
+
rendering = "ssr";
|
|
266
|
+
}
|
|
267
|
+
if (adapterResult.adapter === "static") {
|
|
268
|
+
rendering = "ssg";
|
|
269
|
+
}
|
|
270
|
+
const bundler = "vite";
|
|
271
|
+
return {
|
|
272
|
+
framework: frameworkResult.framework,
|
|
273
|
+
adapter: adapterResult.adapter,
|
|
274
|
+
rendering,
|
|
275
|
+
bundler,
|
|
276
|
+
confidence: {
|
|
277
|
+
framework: frameworkResult.confidence,
|
|
278
|
+
adapter: adapterResult.confidence
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
function logSuggestions(suggestions) {
|
|
283
|
+
console.log("\n\u{1F4CB} Flight Suggestions (optional)\n");
|
|
284
|
+
if (suggestions.framework) {
|
|
285
|
+
console.log(` UI Framework: ${suggestions.framework} (${suggestions.confidence.framework} confidence)`);
|
|
286
|
+
} else {
|
|
287
|
+
console.log(" UI Framework: none detected (vanilla JS/HTML works fine)");
|
|
288
|
+
}
|
|
289
|
+
if (suggestions.adapter) {
|
|
290
|
+
console.log(` Deployment: ${suggestions.adapter} (${suggestions.confidence.adapter} confidence)`);
|
|
291
|
+
}
|
|
292
|
+
console.log(` Rendering: ${suggestions.rendering}`);
|
|
293
|
+
console.log(` Bundler: ${suggestions.bundler}`);
|
|
294
|
+
console.log("\n\u{1F4A1} These are suggestions only. You can override any of these in flight.config.ts\n");
|
|
295
|
+
}
|
|
296
|
+
export {
|
|
297
|
+
logSuggestions,
|
|
298
|
+
suggestDefaults
|
|
299
|
+
};
|
|
300
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/detect/index.ts","../../src/suggest/index.ts"],"sourcesContent":["/**\r\n * Detection utilities for Flight Framework\r\n * \r\n * These functions DETECT and REPORT. They never apply or install anything.\r\n */\r\n\r\nimport { readFile, access } from 'node:fs/promises';\r\nimport { join } from 'node:path';\r\nimport type {\r\n FrameworkDetection,\r\n DeploymentDetection,\r\n UIFramework,\r\n DeploymentAdapter,\r\n} from '../types.js';\r\n\r\n/**\r\n * Check if a file exists\r\n */\r\nasync function exists(path: string): Promise<boolean> {\r\n try {\r\n await access(path);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Read and parse package.json\r\n */\r\nasync function readPackageJson(root: string): Promise<Record<string, unknown> | null> {\r\n try {\r\n const content = await readFile(join(root, 'package.json'), 'utf-8');\r\n return JSON.parse(content) as Record<string, unknown>;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Get all dependencies from package.json\r\n */\r\nfunction getDependencies(pkg: Record<string, unknown>): Record<string, string> {\r\n const deps = (pkg['dependencies'] ?? {}) as Record<string, string>;\r\n const devDeps = (pkg['devDependencies'] ?? {}) as Record<string, string>;\r\n return { ...deps, ...devDeps };\r\n}\r\n\r\n/**\r\n * Detect the UI framework used in the project.\r\n * \r\n * This function ONLY detects and reports. It never installs or configures anything.\r\n * \r\n * @param root - Project root directory (defaults to current working directory)\r\n * @returns Detection result with framework, confidence, and reasoning\r\n * \r\n * @example\r\n * ```typescript\r\n * const result = await detectFramework();\r\n * console.log(result.framework); // 'react' | 'vue' | null | ...\r\n * console.log(result.reasoning); // 'Found react in package.json dependencies'\r\n * ```\r\n */\r\nexport async function detectFramework(root: string = process.cwd()): Promise<FrameworkDetection> {\r\n // Check 1: package.json dependencies (highest confidence)\r\n const pkg = await readPackageJson(root);\r\n if (pkg) {\r\n const deps = getDependencies(pkg);\r\n\r\n // React\r\n if (deps['react'] && deps['react-dom']) {\r\n return {\r\n framework: 'react',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found react and react-dom in dependencies',\r\n };\r\n }\r\n\r\n // Vue\r\n if (deps['vue']) {\r\n return {\r\n framework: 'vue',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found vue in dependencies',\r\n };\r\n }\r\n\r\n // Svelte\r\n if (deps['svelte']) {\r\n return {\r\n framework: 'svelte',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found svelte in dependencies',\r\n };\r\n }\r\n\r\n // Solid\r\n if (deps['solid-js']) {\r\n return {\r\n framework: 'solid',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found solid-js in dependencies',\r\n };\r\n }\r\n\r\n // Preact\r\n if (deps['preact']) {\r\n return {\r\n framework: 'preact',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found preact in dependencies',\r\n };\r\n }\r\n\r\n // Qwik\r\n if (deps['@builder.io/qwik']) {\r\n return {\r\n framework: 'qwik',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found @builder.io/qwik in dependencies',\r\n };\r\n }\r\n\r\n // Angular\r\n if (deps['@angular/core']) {\r\n return {\r\n framework: 'angular',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found @angular/core in dependencies',\r\n };\r\n }\r\n\r\n // Lit\r\n if (deps['lit']) {\r\n return {\r\n framework: 'lit',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found lit in dependencies',\r\n };\r\n }\r\n\r\n // HTMX\r\n if (deps['htmx.org']) {\r\n return {\r\n framework: 'htmx',\r\n confidence: 'high',\r\n source: 'package.json',\r\n reasoning: 'Found htmx.org in dependencies',\r\n };\r\n }\r\n }\r\n\r\n // Check 2: Config files (medium confidence)\r\n if (await exists(join(root, 'svelte.config.js')) || await exists(join(root, 'svelte.config.ts'))) {\r\n return {\r\n framework: 'svelte',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found svelte.config.js/ts',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'angular.json'))) {\r\n return {\r\n framework: 'angular',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found angular.json',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'vue.config.js'))) {\r\n return {\r\n framework: 'vue',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found vue.config.js',\r\n };\r\n }\r\n\r\n // No framework detected\r\n return {\r\n framework: null,\r\n confidence: 'low',\r\n source: 'none',\r\n reasoning: 'No UI framework detected. This is fine - Flight works with vanilla JS/HTML too.',\r\n };\r\n}\r\n\r\n/**\r\n * Detect the deployment target/environment.\r\n * \r\n * This function ONLY detects and reports. It never installs or configures anything.\r\n * \r\n * @param root - Project root directory (defaults to current working directory)\r\n * @returns Detection result with adapter, confidence, and reasoning\r\n * \r\n * @example\r\n * ```typescript\r\n * const result = await detectDeploymentTarget();\r\n * console.log(result.adapter); // 'vercel' | 'node' | null | ...\r\n * console.log(result.reasoning); // 'VERCEL environment variable detected'\r\n * ```\r\n */\r\nexport async function detectDeploymentTarget(root: string = process.cwd()): Promise<DeploymentDetection> {\r\n // Check 1: Environment variables (highest confidence - we're running in the environment)\r\n if (process.env['VERCEL']) {\r\n return {\r\n adapter: 'vercel',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'VERCEL environment variable detected',\r\n };\r\n }\r\n\r\n if (process.env['NETLIFY']) {\r\n return {\r\n adapter: 'netlify',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'NETLIFY environment variable detected',\r\n };\r\n }\r\n\r\n if (process.env['CF_PAGES'] || process.env['CLOUDFLARE_WORKERS']) {\r\n return {\r\n adapter: 'cloudflare',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'Cloudflare environment variable detected',\r\n };\r\n }\r\n\r\n if (process.env['AWS_LAMBDA_FUNCTION_NAME']) {\r\n return {\r\n adapter: 'aws',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'AWS Lambda environment detected',\r\n };\r\n }\r\n\r\n if (process.env['FLY_APP_NAME']) {\r\n return {\r\n adapter: 'fly',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'Fly.io environment detected',\r\n };\r\n }\r\n\r\n if (process.env['DENO_DEPLOYMENT_ID']) {\r\n return {\r\n adapter: 'deno',\r\n confidence: 'high',\r\n source: 'environment',\r\n reasoning: 'Deno Deploy environment detected',\r\n };\r\n }\r\n\r\n // Check 2: Config files (medium confidence - user intent)\r\n if (await exists(join(root, 'vercel.json'))) {\r\n return {\r\n adapter: 'vercel',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found vercel.json',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'netlify.toml'))) {\r\n return {\r\n adapter: 'netlify',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found netlify.toml',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'wrangler.toml'))) {\r\n return {\r\n adapter: 'cloudflare',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found wrangler.toml',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'fly.toml'))) {\r\n return {\r\n adapter: 'fly',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found fly.toml',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'Dockerfile'))) {\r\n return {\r\n adapter: 'docker',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found Dockerfile',\r\n };\r\n }\r\n\r\n if (await exists(join(root, 'serverless.yml')) || await exists(join(root, 'serverless.yaml'))) {\r\n return {\r\n adapter: 'aws',\r\n confidence: 'medium',\r\n source: 'config file',\r\n reasoning: 'Found serverless.yml',\r\n };\r\n }\r\n\r\n // Check 3: Runtime detection\r\n // @ts-expect-error - Bun global\r\n if (typeof Bun !== 'undefined') {\r\n return {\r\n adapter: 'bun',\r\n confidence: 'high',\r\n source: 'runtime',\r\n reasoning: 'Running in Bun runtime',\r\n };\r\n }\r\n\r\n // @ts-expect-error - Deno global\r\n if (typeof Deno !== 'undefined') {\r\n return {\r\n adapter: 'deno',\r\n confidence: 'high',\r\n source: 'runtime',\r\n reasoning: 'Running in Deno runtime',\r\n };\r\n }\r\n\r\n // Default: Node.js (always available)\r\n return {\r\n adapter: 'node',\r\n confidence: 'low',\r\n source: 'default',\r\n reasoning: 'No specific deployment target detected. Defaulting to Node.js (works everywhere).',\r\n };\r\n}\r\n","/**\r\n * Suggestion utilities for Flight Framework\r\n * \r\n * These functions SUGGEST configurations based on detected context.\r\n * They never apply anything automatically. You decide.\r\n */\r\n\r\nimport { detectFramework, detectDeploymentTarget } from '../detect/index.js';\r\nimport type { SuggestedDefaults } from '../types.js';\r\n\r\n/**\r\n * Suggest default configuration based on project analysis.\r\n * \r\n * This function ONLY suggests. It never applies, installs, or modifies anything.\r\n * You are free to use these suggestions, modify them, or ignore them entirely.\r\n * \r\n * @param root - Project root directory (defaults to current working directory)\r\n * @returns Suggested defaults with confidence levels\r\n * \r\n * @example\r\n * ```typescript\r\n * const suggestions = await suggestDefaults();\r\n * \r\n * // Use suggestions in your config (optional)\r\n * export default {\r\n * ui: { framework: suggestions.framework ?? 'react' },\r\n * };\r\n * \r\n * // Or ignore them entirely\r\n * export default {\r\n * ui: { framework: 'vue' },\r\n * };\r\n * ```\r\n */\r\nexport async function suggestDefaults(root: string = process.cwd()): Promise<SuggestedDefaults> {\r\n // Detect context\r\n const [frameworkResult, adapterResult] = await Promise.all([\r\n detectFramework(root),\r\n detectDeploymentTarget(root),\r\n ]);\r\n\r\n // Determine rendering mode based on framework\r\n let rendering: 'ssr' | 'csr' | 'ssg' = 'ssr';\r\n\r\n // HTMX and static sites are typically SSR/SSG\r\n if (frameworkResult.framework === 'htmx') {\r\n rendering = 'ssr';\r\n }\r\n\r\n // Qwik uses resumability, SSR is recommended\r\n if (frameworkResult.framework === 'qwik') {\r\n rendering = 'ssr';\r\n }\r\n\r\n // Static adapters should use SSG\r\n if (adapterResult.adapter === 'static') {\r\n rendering = 'ssg';\r\n }\r\n\r\n // Determine bundler\r\n // Vite is the most universal choice\r\n const bundler = 'vite' as const;\r\n\r\n return {\r\n framework: frameworkResult.framework,\r\n adapter: adapterResult.adapter,\r\n rendering,\r\n bundler,\r\n confidence: {\r\n framework: frameworkResult.confidence,\r\n adapter: adapterResult.confidence,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Log suggestions to console in a helpful format.\r\n * Useful for CLI tools.\r\n * \r\n * @param suggestions - Suggested defaults from suggestDefaults()\r\n */\r\nexport function logSuggestions(suggestions: SuggestedDefaults): void {\r\n console.log('\\n📋 Flight Suggestions (optional)\\n');\r\n\r\n if (suggestions.framework) {\r\n console.log(` UI Framework: ${suggestions.framework} (${suggestions.confidence.framework} confidence)`);\r\n } else {\r\n console.log(' UI Framework: none detected (vanilla JS/HTML works fine)');\r\n }\r\n\r\n if (suggestions.adapter) {\r\n console.log(` Deployment: ${suggestions.adapter} (${suggestions.confidence.adapter} confidence)`);\r\n }\r\n\r\n console.log(` Rendering: ${suggestions.rendering}`);\r\n console.log(` Bundler: ${suggestions.bundler}`);\r\n\r\n console.log('\\n💡 These are suggestions only. You can override any of these in flight.config.ts\\n');\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for detection utilities
|
|
3
|
+
*/
|
|
4
|
+
type ConfidenceLevel = 'high' | 'medium' | 'low';
|
|
5
|
+
type UIFramework = 'react' | 'vue' | 'svelte' | 'solid' | 'preact' | 'qwik' | 'lit' | 'htmx' | 'angular' | 'vanilla';
|
|
6
|
+
type DeploymentAdapter = 'node' | 'vercel' | 'netlify' | 'cloudflare' | 'aws' | 'docker' | 'fly' | 'deno' | 'bun' | 'static';
|
|
7
|
+
interface FrameworkDetection {
|
|
8
|
+
/** Detected framework, null if none found */
|
|
9
|
+
framework: UIFramework | null;
|
|
10
|
+
/** Confidence level of detection */
|
|
11
|
+
confidence: ConfidenceLevel;
|
|
12
|
+
/** Where the detection came from */
|
|
13
|
+
source: string;
|
|
14
|
+
/** Human-readable explanation */
|
|
15
|
+
reasoning: string;
|
|
16
|
+
}
|
|
17
|
+
interface DeploymentDetection {
|
|
18
|
+
/** Detected deployment target, null if none found */
|
|
19
|
+
adapter: DeploymentAdapter | null;
|
|
20
|
+
/** Confidence level of detection */
|
|
21
|
+
confidence: ConfidenceLevel;
|
|
22
|
+
/** Where the detection came from */
|
|
23
|
+
source: string;
|
|
24
|
+
/** Human-readable explanation */
|
|
25
|
+
reasoning: string;
|
|
26
|
+
}
|
|
27
|
+
interface SuggestedDefaults {
|
|
28
|
+
/** Suggested UI framework */
|
|
29
|
+
framework: UIFramework | null;
|
|
30
|
+
/** Suggested deployment adapter */
|
|
31
|
+
adapter: DeploymentAdapter | null;
|
|
32
|
+
/** Suggested rendering mode */
|
|
33
|
+
rendering: 'ssr' | 'csr' | 'ssg';
|
|
34
|
+
/** Suggested bundler */
|
|
35
|
+
bundler: 'vite' | 'esbuild' | 'rolldown';
|
|
36
|
+
/** Confidence levels for each suggestion */
|
|
37
|
+
confidence: {
|
|
38
|
+
framework: ConfidenceLevel;
|
|
39
|
+
adapter: ConfidenceLevel;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type { ConfidenceLevel as C, DeploymentDetection as D, FrameworkDetection as F, SuggestedDefaults as S };
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flightdev/helpers",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Optional helper utilities for Flight Framework. Suggestions, not impositions.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./detect": {
|
|
15
|
+
"types": "./dist/detect/index.d.ts",
|
|
16
|
+
"import": "./dist/detect/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./suggest": {
|
|
19
|
+
"types": "./dist/suggest/index.d.ts",
|
|
20
|
+
"import": "./dist/suggest/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"flight",
|
|
29
|
+
"framework",
|
|
30
|
+
"helpers",
|
|
31
|
+
"utilities",
|
|
32
|
+
"detection"
|
|
33
|
+
],
|
|
34
|
+
"author": "",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"peerDependencies": {},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"tsup": "^8.0.0",
|
|
39
|
+
"typescript": "^5.3.0",
|
|
40
|
+
"vitest": "^1.0.0"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsup",
|
|
44
|
+
"dev": "tsup --watch",
|
|
45
|
+
"test": "vitest",
|
|
46
|
+
"typecheck": "tsc --noEmit"
|
|
47
|
+
}
|
|
48
|
+
}
|