@pyreon/cli 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +170 -0
- package/lib/analysis/index.js.html +1 -1
- package/lib/index.js +5 -200
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts +5 -187
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index2.d.ts +3 -39
- package/lib/types/index2.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/context.ts +7 -280
package/README.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# @pyreon/cli
|
|
2
|
+
|
|
3
|
+
Developer tools for Pyreon — project doctor, context generation, and React pattern detection.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add -d @pyreon/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
### `pyreon doctor`
|
|
14
|
+
|
|
15
|
+
Scans your project for React patterns and auto-fixes them to Pyreon equivalents.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pyreon doctor # human-readable output
|
|
19
|
+
pyreon doctor --fix # auto-fix safe transforms
|
|
20
|
+
pyreon doctor --json # structured JSON output for AI tools
|
|
21
|
+
pyreon doctor --ci # exit code 1 on any error (for CI)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
#### What it detects and suggests
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
// BEFORE: React patterns detected by doctor
|
|
28
|
+
import React from "react"
|
|
29
|
+
import { useState, useEffect, useMemo, useCallback } from "react"
|
|
30
|
+
|
|
31
|
+
function Counter() {
|
|
32
|
+
const [count, setCount] = useState(0)
|
|
33
|
+
const doubled = useMemo(() => count * 2, [count])
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
document.title = `Count: ${count}`
|
|
37
|
+
}, [count])
|
|
38
|
+
|
|
39
|
+
const increment = useCallback(() => setCount(c => c + 1), [])
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div className="counter">
|
|
43
|
+
<label htmlFor="display">Count</label>
|
|
44
|
+
<span id="display">{doubled}</span>
|
|
45
|
+
<button onClick={increment}>+1</button>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
// AFTER: Pyreon equivalents
|
|
53
|
+
import { signal, computed, effect } from "@pyreon/reactivity"
|
|
54
|
+
|
|
55
|
+
function Counter() {
|
|
56
|
+
const count = signal(0)
|
|
57
|
+
const doubled = computed(() => count() * 2)
|
|
58
|
+
|
|
59
|
+
effect(() => {
|
|
60
|
+
document.title = `Count: ${count()}`
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div class="counter">
|
|
65
|
+
<label for="display">Count</label>
|
|
66
|
+
<span id="display">{doubled()}</span>
|
|
67
|
+
<button onClick={() => count.update(c => c + 1)}>+1</button>
|
|
68
|
+
</div>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### Detection table
|
|
74
|
+
|
|
75
|
+
| React Pattern | Pyreon Equivalent | Auto-fixable |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `import React from "react"` | `import { h } from "@pyreon/core"` | No |
|
|
78
|
+
| `useState(initial)` | `signal(initial)` | No |
|
|
79
|
+
| `useEffect(fn, deps)` | `effect(fn)` | No |
|
|
80
|
+
| `useMemo(fn, deps)` | `computed(fn)` | No |
|
|
81
|
+
| `useCallback(fn, deps)` | Use function directly | No |
|
|
82
|
+
| `className="..."` | `class="..."` | Yes |
|
|
83
|
+
| `htmlFor="..."` | `for="..."` | Yes |
|
|
84
|
+
|
|
85
|
+
#### CI integration
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
# .github/workflows/ci.yml
|
|
89
|
+
- name: Pyreon Doctor
|
|
90
|
+
run: bunx @pyreon/cli doctor --ci
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### JSON output format
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"passed": false,
|
|
98
|
+
"files": [
|
|
99
|
+
{
|
|
100
|
+
"file": "src/App.tsx",
|
|
101
|
+
"diagnostics": [
|
|
102
|
+
{
|
|
103
|
+
"code": "react-import",
|
|
104
|
+
"line": 1,
|
|
105
|
+
"message": "React import detected",
|
|
106
|
+
"current": "import React from \"react\"",
|
|
107
|
+
"suggested": "import { h } from \"@pyreon/core\"",
|
|
108
|
+
"fixable": false
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"fixed": false
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"summary": {
|
|
115
|
+
"filesScanned": 12,
|
|
116
|
+
"filesWithIssues": 1,
|
|
117
|
+
"totalErrors": 1,
|
|
118
|
+
"totalFixable": 0,
|
|
119
|
+
"totalFixed": 0
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `pyreon context`
|
|
125
|
+
|
|
126
|
+
Generates project context for AI tools.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pyreon context # writes to .pyreon/context.json
|
|
130
|
+
pyreon context --out ./ai.json # custom output path
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### Output example
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"framework": "pyreon",
|
|
138
|
+
"version": "0.5.0",
|
|
139
|
+
"generatedAt": "2026-03-19T12:00:00.000Z",
|
|
140
|
+
"routes": [
|
|
141
|
+
{ "path": "/", "name": "home", "params": [], "hasLoader": false, "hasGuard": false },
|
|
142
|
+
{ "path": "/users/:id", "name": "user", "params": ["id"], "hasLoader": true, "hasGuard": false },
|
|
143
|
+
{ "path": "/admin", "params": [], "hasLoader": false, "hasGuard": true }
|
|
144
|
+
],
|
|
145
|
+
"components": [
|
|
146
|
+
{
|
|
147
|
+
"name": "UserCard",
|
|
148
|
+
"file": "src/components/UserCard.tsx",
|
|
149
|
+
"props": ["user", "showAvatar"],
|
|
150
|
+
"hasSignals": true,
|
|
151
|
+
"signalNames": ["isExpanded"]
|
|
152
|
+
}
|
|
153
|
+
],
|
|
154
|
+
"islands": [
|
|
155
|
+
{ "name": "SearchBar", "file": "src/islands/SearchBar.tsx", "hydrate": "idle" }
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Programmatic API
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import { doctor, generateContext } from "@pyreon/cli"
|
|
164
|
+
|
|
165
|
+
// Run doctor programmatically
|
|
166
|
+
const errorCount = await doctor({ fix: false, json: false, ci: false, cwd: process.cwd() })
|
|
167
|
+
|
|
168
|
+
// Generate context
|
|
169
|
+
const result = generateContext({ cwd: process.cwd(), out: ".pyreon/context.json" })
|
|
170
|
+
```
|
|
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
|
|
|
5386
5386
|
</script>
|
|
5387
5387
|
<script>
|
|
5388
5388
|
/*<!--*/
|
|
5389
|
-
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"abdf3767-1","name":"context.ts"},{"uid":"abdf3767-3","name":"doctor.ts"},{"uid":"abdf3767-5","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"abdf3767-1":{"renderedLength":1323,"gzipLength":627,"brotliLength":0,"metaUid":"abdf3767-0"},"abdf3767-3":{"renderedLength":5128,"gzipLength":1827,"brotliLength":0,"metaUid":"abdf3767-2"},"abdf3767-5":{"renderedLength":1559,"gzipLength":677,"brotliLength":0,"metaUid":"abdf3767-4"}},"nodeMetas":{"abdf3767-0":{"id":"/src/context.ts","moduleParts":{"index.js":"abdf3767-1"},"imported":[{"uid":"abdf3767-6"},{"uid":"abdf3767-7"},{"uid":"abdf3767-8"}],"importedBy":[{"uid":"abdf3767-4"}]},"abdf3767-2":{"id":"/src/doctor.ts","moduleParts":{"index.js":"abdf3767-3"},"imported":[{"uid":"abdf3767-6"},{"uid":"abdf3767-7"},{"uid":"abdf3767-8"}],"importedBy":[{"uid":"abdf3767-4"}]},"abdf3767-4":{"id":"/src/index.ts","moduleParts":{"index.js":"abdf3767-5"},"imported":[{"uid":"abdf3767-0"},{"uid":"abdf3767-2"}],"importedBy":[],"isEntry":true},"abdf3767-6":{"id":"node:fs","moduleParts":{},"imported":[],"importedBy":[{"uid":"abdf3767-0"},{"uid":"abdf3767-2"}]},"abdf3767-7":{"id":"node:path","moduleParts":{},"imported":[],"importedBy":[{"uid":"abdf3767-0"},{"uid":"abdf3767-2"}]},"abdf3767-8":{"id":"@pyreon/compiler","moduleParts":{},"imported":[],"importedBy":[{"uid":"abdf3767-0"},{"uid":"abdf3767-2"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
|
|
5390
5390
|
|
|
5391
5391
|
const run = () => {
|
|
5392
5392
|
const width = window.innerWidth;
|
package/lib/index.js
CHANGED
|
@@ -1,221 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { detectReactPatterns, hasReactPatterns, migrateReactCode } from "@pyreon/compiler";
|
|
4
|
+
import { detectReactPatterns, generateContext as generateContext$1, hasReactPatterns, migrateReactCode } from "@pyreon/compiler";
|
|
5
5
|
|
|
6
6
|
//#region src/context.ts
|
|
7
7
|
/**
|
|
8
8
|
* pyreon context — generates .pyreon/context.json for AI tool consumption
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* - Component inventory (file, props, signals)
|
|
13
|
-
* - Island declarations (name, hydration strategy)
|
|
14
|
-
* - Framework version
|
|
10
|
+
* Delegates scanning to @pyreon/compiler's unified project scanner,
|
|
11
|
+
* then writes the result to disk and ensures .pyreon/ is gitignored.
|
|
15
12
|
*/
|
|
16
13
|
async function generateContext(options) {
|
|
17
|
-
const
|
|
18
|
-
const sourceFiles = collectTsxFiles(options.cwd);
|
|
19
|
-
const routes = extractRoutes(sourceFiles, options.cwd);
|
|
20
|
-
const components = extractComponents(sourceFiles, options.cwd);
|
|
21
|
-
const islands = extractIslands(sourceFiles, options.cwd);
|
|
22
|
-
const context = {
|
|
23
|
-
framework: "pyreon",
|
|
24
|
-
version,
|
|
25
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26
|
-
routes,
|
|
27
|
-
components,
|
|
28
|
-
islands
|
|
29
|
-
};
|
|
14
|
+
const context = generateContext$1(options.cwd);
|
|
30
15
|
const outDir = options.outPath ? path.dirname(options.outPath) : path.join(options.cwd, ".pyreon");
|
|
31
16
|
const outFile = options.outPath ?? path.join(outDir, "context.json");
|
|
32
17
|
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
|
33
18
|
fs.writeFileSync(outFile, JSON.stringify(context, null, 2), "utf-8");
|
|
34
19
|
ensureGitignore(options.cwd);
|
|
35
20
|
const relOut = path.relative(options.cwd, outFile);
|
|
36
|
-
console.log(` ✓ Generated ${relOut} (${components.length} components, ${routes.length} routes, ${islands.length} islands)`);
|
|
21
|
+
console.log(` ✓ Generated ${relOut} (${context.components.length} components, ${context.routes.length} routes, ${context.islands.length} islands)`);
|
|
37
22
|
return context;
|
|
38
23
|
}
|
|
39
|
-
function parseRouteFromBlock(block, routeMatch) {
|
|
40
|
-
const routePath = routeMatch[1] ?? "";
|
|
41
|
-
const params = extractParams(routePath);
|
|
42
|
-
const surroundingStart = Math.max(0, routeMatch.index - 50);
|
|
43
|
-
const surroundingEnd = Math.min(block.length, routeMatch.index + 200);
|
|
44
|
-
const surrounding = block.slice(surroundingStart, surroundingEnd);
|
|
45
|
-
const hasLoader = /loader\s*:/.test(surrounding);
|
|
46
|
-
const hasGuard = /beforeEnter\s*:|beforeLeave\s*:/.test(surrounding);
|
|
47
|
-
return {
|
|
48
|
-
path: routePath,
|
|
49
|
-
name: surrounding.match(/name\s*:\s*["']([^"']+)["']/)?.[1],
|
|
50
|
-
hasLoader,
|
|
51
|
-
hasGuard,
|
|
52
|
-
params
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function extractRoutesFromBlock(block) {
|
|
56
|
-
const routes = [];
|
|
57
|
-
const routeObjRe = /path\s*:\s*["']([^"']+)["']/g;
|
|
58
|
-
let routeMatch;
|
|
59
|
-
while (true) {
|
|
60
|
-
routeMatch = routeObjRe.exec(block);
|
|
61
|
-
if (!routeMatch) break;
|
|
62
|
-
routes.push(parseRouteFromBlock(block, routeMatch));
|
|
63
|
-
}
|
|
64
|
-
return routes;
|
|
65
|
-
}
|
|
66
|
-
function extractRoutes(files, _cwd) {
|
|
67
|
-
const routes = [];
|
|
68
|
-
for (const file of files) {
|
|
69
|
-
let code;
|
|
70
|
-
try {
|
|
71
|
-
code = fs.readFileSync(file, "utf-8");
|
|
72
|
-
} catch {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
const routeArrayRe = /(?:createRouter\s*\(\s*\[|(?:const|let)\s+routes\s*(?::\s*RouteRecord\[\])?\s*=\s*\[)([\s\S]*?)\]/g;
|
|
76
|
-
let match;
|
|
77
|
-
while (true) {
|
|
78
|
-
match = routeArrayRe.exec(code);
|
|
79
|
-
if (!match) break;
|
|
80
|
-
const block = match[1] ?? "";
|
|
81
|
-
for (const route of extractRoutesFromBlock(block)) routes.push(route);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return routes;
|
|
85
|
-
}
|
|
86
|
-
function parseProps(propsStr) {
|
|
87
|
-
return propsStr.split(",").map((p) => p.trim().split(":")[0]?.split("=")[0]?.trim() ?? "").filter((p) => p && p !== "props");
|
|
88
|
-
}
|
|
89
|
-
function collectSignalNames(body) {
|
|
90
|
-
const signalNames = [];
|
|
91
|
-
const signalRe = /(?:const|let)\s+(\w+)\s*=\s*signal\s*[<(]/g;
|
|
92
|
-
let sigMatch;
|
|
93
|
-
while (true) {
|
|
94
|
-
sigMatch = signalRe.exec(body);
|
|
95
|
-
if (!sigMatch) break;
|
|
96
|
-
if (sigMatch[1]) signalNames.push(sigMatch[1]);
|
|
97
|
-
}
|
|
98
|
-
return signalNames;
|
|
99
|
-
}
|
|
100
|
-
function extractComponentsFromCode(code, relFile) {
|
|
101
|
-
const components = [];
|
|
102
|
-
const componentRe = /(?:export\s+)?(?:const|function)\s+([A-Z]\w*)\s*(?::\s*ComponentFn<[^>]+>\s*)?=?\s*\(?(?:\s*\{?\s*([^)]*?)\s*\}?\s*)?\)?\s*(?:=>|{)/g;
|
|
103
|
-
let match;
|
|
104
|
-
while (true) {
|
|
105
|
-
match = componentRe.exec(code);
|
|
106
|
-
if (!match) break;
|
|
107
|
-
const name = match[1] ?? "Unknown";
|
|
108
|
-
const props = parseProps(match[2] ?? "");
|
|
109
|
-
const bodyStart = match.index + match[0].length;
|
|
110
|
-
const signalNames = collectSignalNames(code.slice(bodyStart, Math.min(code.length, bodyStart + 2e3)));
|
|
111
|
-
components.push({
|
|
112
|
-
name,
|
|
113
|
-
file: relFile,
|
|
114
|
-
hasSignals: signalNames.length > 0,
|
|
115
|
-
signalNames,
|
|
116
|
-
props
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
return components;
|
|
120
|
-
}
|
|
121
|
-
function extractComponents(files, _cwd) {
|
|
122
|
-
const components = [];
|
|
123
|
-
for (const file of files) {
|
|
124
|
-
let code;
|
|
125
|
-
try {
|
|
126
|
-
code = fs.readFileSync(file, "utf-8");
|
|
127
|
-
} catch {
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
const relFile = path.relative(_cwd, file);
|
|
131
|
-
for (const comp of extractComponentsFromCode(code, relFile)) components.push(comp);
|
|
132
|
-
}
|
|
133
|
-
return components;
|
|
134
|
-
}
|
|
135
|
-
function extractIslands(files, cwd) {
|
|
136
|
-
const islands = [];
|
|
137
|
-
for (const file of files) {
|
|
138
|
-
let code;
|
|
139
|
-
try {
|
|
140
|
-
code = fs.readFileSync(file, "utf-8");
|
|
141
|
-
} catch {
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
const islandRe = /island\s*\(\s*\(\)\s*=>\s*import\(.+?\)\s*,\s*\{[^}]*name\s*:\s*["']([^"']+)["'][^}]*?(?:hydrate\s*:\s*["']([^"']+)["'])?[^}]*\}/g;
|
|
145
|
-
let match;
|
|
146
|
-
while (true) {
|
|
147
|
-
match = islandRe.exec(code);
|
|
148
|
-
if (!match) break;
|
|
149
|
-
if (match[1]) islands.push({
|
|
150
|
-
name: match[1],
|
|
151
|
-
file: path.relative(cwd, file),
|
|
152
|
-
hydrate: match[2] ?? "load"
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return islands;
|
|
157
|
-
}
|
|
158
|
-
function extractParams(routePath) {
|
|
159
|
-
const params = [];
|
|
160
|
-
const paramRe = /:(\w+)\??/g;
|
|
161
|
-
let match;
|
|
162
|
-
while (true) {
|
|
163
|
-
match = paramRe.exec(routePath);
|
|
164
|
-
if (!match) break;
|
|
165
|
-
if (match[1]) params.push(match[1]);
|
|
166
|
-
}
|
|
167
|
-
return params;
|
|
168
|
-
}
|
|
169
|
-
function readVersion(cwd) {
|
|
170
|
-
try {
|
|
171
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf-8"));
|
|
172
|
-
const deps = {
|
|
173
|
-
...pkg.dependencies,
|
|
174
|
-
...pkg.devDependencies
|
|
175
|
-
};
|
|
176
|
-
for (const [name, version] of Object.entries(deps)) if (name.startsWith("@pyreon/") && typeof version === "string") return version.replace(/^[\^~]/, "");
|
|
177
|
-
return pkg.version || "unknown";
|
|
178
|
-
} catch {
|
|
179
|
-
return "unknown";
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
const tsxExtensions = new Set([
|
|
183
|
-
".tsx",
|
|
184
|
-
".jsx",
|
|
185
|
-
".ts",
|
|
186
|
-
".js"
|
|
187
|
-
]);
|
|
188
|
-
const tsxIgnoreDirs = new Set([
|
|
189
|
-
"node_modules",
|
|
190
|
-
"dist",
|
|
191
|
-
"lib",
|
|
192
|
-
".pyreon",
|
|
193
|
-
".git",
|
|
194
|
-
"build"
|
|
195
|
-
]);
|
|
196
|
-
function shouldSkipEntry(entry) {
|
|
197
|
-
if (!entry.isDirectory()) return false;
|
|
198
|
-
return entry.name.startsWith(".") || tsxIgnoreDirs.has(entry.name);
|
|
199
|
-
}
|
|
200
|
-
function walkTsxFiles(dir, results) {
|
|
201
|
-
let entries;
|
|
202
|
-
try {
|
|
203
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
204
|
-
} catch {
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
for (const entry of entries) {
|
|
208
|
-
if (shouldSkipEntry(entry)) continue;
|
|
209
|
-
const fullPath = path.join(dir, entry.name);
|
|
210
|
-
if (entry.isDirectory()) walkTsxFiles(fullPath, results);
|
|
211
|
-
else if (entry.isFile() && tsxExtensions.has(path.extname(entry.name))) results.push(fullPath);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
function collectTsxFiles(cwd) {
|
|
215
|
-
const results = [];
|
|
216
|
-
walkTsxFiles(cwd, results);
|
|
217
|
-
return results;
|
|
218
|
-
}
|
|
219
24
|
function ensureGitignore(cwd) {
|
|
220
25
|
const gitignorePath = path.join(cwd, ".gitignore");
|
|
221
26
|
try {
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/context.ts","../src/doctor.ts","../src/index.ts"],"sourcesContent":["/**\n * pyreon context — generates .pyreon/context.json for AI tool consumption\n *\n * Scans the project to extract:\n * - Route definitions (paths, params, loaders, guards)\n * - Component inventory (file, props, signals)\n * - Island declarations (name, hydration strategy)\n * - Framework version\n */\n\nimport * as fs from \"node:fs\"\nimport * as path from \"node:path\"\n\nexport interface ContextOptions {\n cwd: string\n outPath?: string | undefined\n}\n\nexport interface RouteInfo {\n path: string\n name?: string | undefined\n component?: string | undefined\n hasLoader: boolean\n hasGuard: boolean\n params: string[]\n children?: RouteInfo[] | undefined\n}\n\nexport interface ComponentInfo {\n name: string\n file: string\n hasSignals: boolean\n signalNames: string[]\n props: string[]\n}\n\nexport interface IslandInfo {\n name: string\n file: string\n hydrate: string\n}\n\nexport interface ProjectContext {\n framework: \"pyreon\"\n version: string\n generatedAt: string\n routes: RouteInfo[]\n components: ComponentInfo[]\n islands: IslandInfo[]\n}\n\nexport async function generateContext(options: ContextOptions): Promise<ProjectContext> {\n const version = readVersion(options.cwd)\n const sourceFiles = collectTsxFiles(options.cwd)\n\n const routes = extractRoutes(sourceFiles, options.cwd)\n const components = extractComponents(sourceFiles, options.cwd)\n const islands = extractIslands(sourceFiles, options.cwd)\n\n const context: ProjectContext = {\n framework: \"pyreon\",\n version,\n generatedAt: new Date().toISOString(),\n routes,\n components,\n islands,\n }\n\n // Write to .pyreon/context.json\n const outDir = options.outPath ? path.dirname(options.outPath) : path.join(options.cwd, \".pyreon\")\n const outFile = options.outPath ?? path.join(outDir, \"context.json\")\n\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true })\n }\n fs.writeFileSync(outFile, JSON.stringify(context, null, 2), \"utf-8\")\n\n // Ensure .pyreon/ is in .gitignore\n ensureGitignore(options.cwd)\n\n const relOut = path.relative(options.cwd, outFile)\n console.log(\n ` ✓ Generated ${relOut} (${components.length} components, ${routes.length} routes, ${islands.length} islands)`,\n )\n\n return context\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Extractors\n// ═══════════════════════════════════════════════════════════════════════════════\n\nfunction parseRouteFromBlock(block: string, routeMatch: RegExpExecArray): RouteInfo {\n const routePath = routeMatch[1] ?? \"\"\n const params = extractParams(routePath)\n\n const surroundingStart = Math.max(0, routeMatch.index - 50)\n const surroundingEnd = Math.min(block.length, routeMatch.index + 200)\n const surrounding = block.slice(surroundingStart, surroundingEnd)\n\n const hasLoader = /loader\\s*:/.test(surrounding)\n const hasGuard = /beforeEnter\\s*:|beforeLeave\\s*:/.test(surrounding)\n const nameMatch = surrounding.match(/name\\s*:\\s*[\"']([^\"']+)[\"']/)\n\n return {\n path: routePath,\n name: nameMatch?.[1],\n hasLoader,\n hasGuard,\n params,\n }\n}\n\nfunction extractRoutesFromBlock(block: string): RouteInfo[] {\n const routes: RouteInfo[] = []\n const routeObjRe = /path\\s*:\\s*[\"']([^\"']+)[\"']/g\n let routeMatch: RegExpExecArray | null\n while (true) {\n routeMatch = routeObjRe.exec(block)\n if (!routeMatch) break\n routes.push(parseRouteFromBlock(block, routeMatch))\n }\n return routes\n}\n\nfunction extractRoutes(files: string[], _cwd: string): RouteInfo[] {\n const routes: RouteInfo[] = []\n\n for (const file of files) {\n let code: string\n try {\n code = fs.readFileSync(file, \"utf-8\")\n } catch {\n continue\n }\n\n const routeArrayRe =\n /(?:createRouter\\s*\\(\\s*\\[|(?:const|let)\\s+routes\\s*(?::\\s*RouteRecord\\[\\])?\\s*=\\s*\\[)([\\s\\S]*?)\\]/g\n let match: RegExpExecArray | null\n while (true) {\n match = routeArrayRe.exec(code)\n if (!match) break\n const block = match[1] ?? \"\"\n for (const route of extractRoutesFromBlock(block)) {\n routes.push(route)\n }\n }\n }\n\n return routes\n}\n\nfunction parseProps(propsStr: string): string[] {\n return propsStr\n .split(\",\")\n .map((p) => p.trim().split(\":\")[0]?.split(\"=\")[0]?.trim() ?? \"\")\n .filter((p) => p && p !== \"props\")\n}\n\nfunction collectSignalNames(body: string): string[] {\n const signalNames: string[] = []\n const signalRe = /(?:const|let)\\s+(\\w+)\\s*=\\s*signal\\s*[<(]/g\n let sigMatch: RegExpExecArray | null\n while (true) {\n sigMatch = signalRe.exec(body)\n if (!sigMatch) break\n if (sigMatch[1]) signalNames.push(sigMatch[1])\n }\n return signalNames\n}\n\nfunction extractComponentsFromCode(code: string, relFile: string): ComponentInfo[] {\n const components: ComponentInfo[] = []\n const componentRe =\n /(?:export\\s+)?(?:const|function)\\s+([A-Z]\\w*)\\s*(?::\\s*ComponentFn<[^>]+>\\s*)?=?\\s*\\(?(?:\\s*\\{?\\s*([^)]*?)\\s*\\}?\\s*)?\\)?\\s*(?:=>|{)/g\n let match: RegExpExecArray | null\n\n while (true) {\n match = componentRe.exec(code)\n if (!match) break\n const name = match[1] ?? \"Unknown\"\n const props = parseProps(match[2] ?? \"\")\n\n const bodyStart = match.index + match[0].length\n const body = code.slice(bodyStart, Math.min(code.length, bodyStart + 2000))\n const signalNames = collectSignalNames(body)\n\n components.push({\n name,\n file: relFile,\n hasSignals: signalNames.length > 0,\n signalNames,\n props,\n })\n }\n\n return components\n}\n\nfunction extractComponents(files: string[], _cwd: string): ComponentInfo[] {\n const components: ComponentInfo[] = []\n\n for (const file of files) {\n let code: string\n try {\n code = fs.readFileSync(file, \"utf-8\")\n } catch {\n continue\n }\n\n const relFile = path.relative(_cwd, file)\n for (const comp of extractComponentsFromCode(code, relFile)) {\n components.push(comp)\n }\n }\n\n return components\n}\n\nfunction extractIslands(files: string[], cwd: string): IslandInfo[] {\n const islands: IslandInfo[] = []\n\n for (const file of files) {\n let code: string\n try {\n code = fs.readFileSync(file, \"utf-8\")\n } catch {\n continue\n }\n\n const islandRe =\n /island\\s*\\(\\s*\\(\\)\\s*=>\\s*import\\(.+?\\)\\s*,\\s*\\{[^}]*name\\s*:\\s*[\"']([^\"']+)[\"'][^}]*?(?:hydrate\\s*:\\s*[\"']([^\"']+)[\"'])?[^}]*\\}/g\n let match: RegExpExecArray | null\n while (true) {\n match = islandRe.exec(code)\n if (!match) break\n if (match[1]) {\n islands.push({\n name: match[1],\n file: path.relative(cwd, file),\n hydrate: match[2] ?? \"load\",\n })\n }\n }\n }\n\n return islands\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Helpers\n// ═══════════════════════════════════════════════════════════════════════════════\n\nfunction extractParams(routePath: string): string[] {\n const params: string[] = []\n const paramRe = /:(\\w+)\\??/g\n let match: RegExpExecArray | null\n while (true) {\n match = paramRe.exec(routePath)\n if (!match) break\n if (match[1]) params.push(match[1])\n }\n return params\n}\n\nfunction readVersion(cwd: string): string {\n try {\n const pkg = JSON.parse(fs.readFileSync(path.join(cwd, \"package.json\"), \"utf-8\"))\n const deps: Record<string, unknown> = { ...pkg.dependencies, ...pkg.devDependencies }\n for (const [name, version] of Object.entries(deps)) {\n if (name.startsWith(\"@pyreon/\") && typeof version === \"string\") {\n return version.replace(/^[\\^~]/, \"\")\n }\n }\n return (pkg.version as string) || \"unknown\"\n } catch {\n return \"unknown\"\n }\n}\n\nconst tsxExtensions = new Set([\".tsx\", \".jsx\", \".ts\", \".js\"])\nconst tsxIgnoreDirs = new Set([\"node_modules\", \"dist\", \"lib\", \".pyreon\", \".git\", \"build\"])\n\nfunction shouldSkipEntry(entry: fs.Dirent): boolean {\n if (!entry.isDirectory()) return false\n return entry.name.startsWith(\".\") || tsxIgnoreDirs.has(entry.name)\n}\n\nfunction walkTsxFiles(dir: string, results: string[]): void {\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return\n }\n\n for (const entry of entries) {\n if (shouldSkipEntry(entry)) continue\n\n const fullPath = path.join(dir, entry.name)\n if (entry.isDirectory()) {\n walkTsxFiles(fullPath, results)\n } else if (entry.isFile() && tsxExtensions.has(path.extname(entry.name))) {\n results.push(fullPath)\n }\n }\n}\n\nfunction collectTsxFiles(cwd: string): string[] {\n const results: string[] = []\n walkTsxFiles(cwd, results)\n return results\n}\n\nfunction ensureGitignore(cwd: string): void {\n const gitignorePath = path.join(cwd, \".gitignore\")\n try {\n const content = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, \"utf-8\") : \"\"\n\n if (!content.includes(\".pyreon/\") && !content.includes(\".pyreon\\n\")) {\n const addition = content.endsWith(\"\\n\") ? \".pyreon/\\n\" : \"\\n.pyreon/\\n\"\n fs.appendFileSync(gitignorePath, addition)\n }\n } catch {\n // Ignore errors with .gitignore\n }\n}\n","/**\n * pyreon doctor — project-wide health check for AI-friendly development\n *\n * Runs a pipeline of checks:\n * 1. React pattern detection (imports, hooks, JSX attributes)\n * 2. Import source validation (@pyreon/* vs react/vue)\n * 3. Common Pyreon mistakes (signal without call, key vs by, etc.)\n *\n * Output modes:\n * - Human-readable (default): colored terminal output\n * - JSON (--json): structured output for AI agent consumption\n * - CI (--ci): exits with code 1 on any error\n *\n * Fix mode (--fix): auto-applies safe transforms via migrateReactCode\n */\n\nimport * as fs from \"node:fs\"\nimport * as path from \"node:path\"\nimport {\n detectReactPatterns,\n hasReactPatterns,\n migrateReactCode,\n type ReactDiagnostic,\n} from \"@pyreon/compiler\"\n\nexport interface DoctorOptions {\n fix: boolean\n json: boolean\n ci: boolean\n cwd: string\n}\n\ninterface FileResult {\n file: string\n diagnostics: ReactDiagnostic[]\n fixed: boolean\n}\n\ninterface DoctorResult {\n passed: boolean\n files: FileResult[]\n summary: {\n filesScanned: number\n filesWithIssues: number\n totalErrors: number\n totalFixable: number\n totalFixed: number\n }\n}\n\nexport async function doctor(options: DoctorOptions): Promise<number> {\n const startTime = performance.now()\n const files = collectSourceFiles(options.cwd)\n const result = runChecks(files, options)\n const elapsed = Math.round(performance.now() - startTime)\n\n if (options.json) {\n printJson(result)\n } else {\n printHuman(result, elapsed)\n }\n\n return result.summary.totalErrors\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// File collection\n// ═══════════════════════════════════════════════════════════════════════════════\n\nconst sourceExtensions = new Set([\".tsx\", \".jsx\", \".ts\", \".js\"])\nconst sourceIgnoreDirs = new Set([\n \"node_modules\",\n \"dist\",\n \"lib\",\n \".pyreon\",\n \".git\",\n \".next\",\n \"build\",\n])\n\nfunction shouldSkipDirEntry(entry: fs.Dirent): boolean {\n if (!entry.isDirectory()) return false\n return entry.name.startsWith(\".\") || sourceIgnoreDirs.has(entry.name)\n}\n\nfunction walkSourceFiles(dir: string, results: string[]): void {\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return\n }\n\n for (const entry of entries) {\n if (shouldSkipDirEntry(entry)) continue\n\n const fullPath = path.join(dir, entry.name)\n if (entry.isDirectory()) {\n walkSourceFiles(fullPath, results)\n } else if (entry.isFile() && sourceExtensions.has(path.extname(entry.name))) {\n results.push(fullPath)\n }\n }\n}\n\nfunction collectSourceFiles(cwd: string): string[] {\n const results: string[] = []\n walkSourceFiles(cwd, results)\n return results\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Check pipeline\n// ═══════════════════════════════════════════════════════════════════════════════\n\nfunction checkFileWithFix(\n file: string,\n relPath: string,\n): { result: FileResult | null; fixCount: number } {\n let code: string\n try {\n code = fs.readFileSync(file, \"utf-8\")\n } catch {\n return { result: null, fixCount: 0 }\n }\n\n if (!hasReactPatterns(code)) return { result: null, fixCount: 0 }\n\n const migrated = migrateReactCode(code, relPath)\n if (migrated.changes.length > 0) {\n fs.writeFileSync(file, migrated.code, \"utf-8\")\n }\n const remaining = detectReactPatterns(migrated.code, relPath)\n if (remaining.length > 0 || migrated.changes.length > 0) {\n return {\n result: { file: relPath, diagnostics: remaining, fixed: migrated.changes.length > 0 },\n fixCount: migrated.changes.length,\n }\n }\n return { result: null, fixCount: 0 }\n}\n\nfunction checkFileDetectOnly(file: string, relPath: string): FileResult | null {\n let code: string\n try {\n code = fs.readFileSync(file, \"utf-8\")\n } catch {\n return null\n }\n\n if (!hasReactPatterns(code)) return null\n\n const diagnostics = detectReactPatterns(code, relPath)\n if (diagnostics.length > 0) {\n return { file: relPath, diagnostics, fixed: false }\n }\n return null\n}\n\nfunction runChecks(files: string[], options: DoctorOptions): DoctorResult {\n const fileResults: FileResult[] = []\n let totalFixed = 0\n\n for (const file of files) {\n const relPath = path.relative(options.cwd, file)\n\n if (options.fix) {\n const { result, fixCount } = checkFileWithFix(file, relPath)\n totalFixed += fixCount\n if (result) fileResults.push(result)\n } else {\n const result = checkFileDetectOnly(file, relPath)\n if (result) fileResults.push(result)\n }\n }\n\n const totalErrors = fileResults.reduce((sum, f) => sum + f.diagnostics.length, 0)\n const totalFixable = fileResults.reduce(\n (sum, f) => sum + f.diagnostics.filter((d) => d.fixable).length,\n 0,\n )\n\n return {\n passed: totalErrors === 0,\n files: fileResults,\n summary: {\n filesScanned: files.length,\n filesWithIssues: fileResults.length,\n totalErrors,\n totalFixable,\n totalFixed,\n },\n }\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Output formatters\n// ═══════════════════════════════════════════════════════════════════════════════\n\nfunction printJson(result: DoctorResult): void {\n console.log(JSON.stringify(result, null, 2))\n}\n\nfunction printFileResult(fileResult: FileResult): void {\n if (fileResult.diagnostics.length === 0) return\n\n console.log(` ${fileResult.file}${fileResult.fixed ? \" (partially fixed)\" : \"\"}`)\n\n for (const diag of fileResult.diagnostics) {\n const fixTag = diag.fixable ? \" [fixable]\" : \"\"\n console.log(` ${diag.line}:${diag.column} — ${diag.message}${fixTag}`)\n console.log(` Current: ${diag.current}`)\n console.log(` Suggested: ${diag.suggested}`)\n console.log(\"\")\n }\n}\n\nfunction printSummary(summary: DoctorResult[\"summary\"]): void {\n console.log(\n ` ${summary.totalErrors} issue${summary.totalErrors === 1 ? \"\" : \"s\"} in ${summary.filesWithIssues} file${summary.filesWithIssues === 1 ? \"\" : \"s\"}`,\n )\n if (summary.totalFixable > 0) {\n console.log(` ${summary.totalFixable} auto-fixable — run 'pyreon doctor --fix' to apply`)\n }\n console.log(\"\")\n}\n\nfunction printHuman(result: DoctorResult, elapsed: number): void {\n const { summary } = result\n\n console.log(\"\")\n console.log(` Pyreon Doctor — scanned ${summary.filesScanned} files in ${elapsed}ms`)\n console.log(\"\")\n\n if (result.passed && summary.totalFixed === 0) {\n console.log(\" ✓ No issues found. Your code is Pyreon-native!\")\n console.log(\"\")\n return\n }\n\n if (summary.totalFixed > 0) {\n console.log(` ✓ Auto-fixed ${summary.totalFixed} issue${summary.totalFixed === 1 ? \"\" : \"s\"}`)\n console.log(\"\")\n }\n\n for (const fileResult of result.files) {\n printFileResult(fileResult)\n }\n\n printSummary(summary)\n}\n","#!/usr/bin/env node\n\n/**\n * @pyreon/cli — Developer tools for Pyreon\n *\n * Commands:\n * pyreon doctor [--fix] [--json] — Scan project for React patterns, bad imports, etc.\n * pyreon context — Generate .pyreon/context.json for AI tools\n */\n\nimport { generateContext } from \"./context\"\nimport { type DoctorOptions, doctor } from \"./doctor\"\n\nconst args = process.argv.slice(2)\nconst command = args[0]\n\nfunction printUsage(): void {\n console.log(`\n pyreon <command> [options]\n\n Commands:\n doctor [--fix] [--json] [--ci] Scan for React patterns, bad imports, and common mistakes\n context [--out <path>] Generate .pyreon/context.json for AI tools\n\n Options:\n --help Show this help message\n --version Show version\n`)\n}\n\nasync function main(): Promise<void> {\n if (!command || command === \"--help\" || command === \"-h\") {\n printUsage()\n return\n }\n\n if (command === \"--version\" || command === \"-v\") {\n console.log(\"0.4.0\")\n return\n }\n\n if (command === \"doctor\") {\n const options: DoctorOptions = {\n fix: args.includes(\"--fix\"),\n json: args.includes(\"--json\"),\n ci: args.includes(\"--ci\"),\n cwd: process.cwd(),\n }\n const exitCode = await doctor(options)\n if (options.ci && exitCode > 0) {\n process.exit(1)\n }\n return\n }\n\n if (command === \"context\") {\n const outIdx = args.indexOf(\"--out\")\n const outPath = outIdx >= 0 ? args[outIdx + 1] : undefined\n await generateContext({ cwd: process.cwd(), outPath })\n return\n }\n\n console.error(`Unknown command: ${command}`)\n printUsage()\n process.exit(1)\n}\n\nmain().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n\nexport type { ContextOptions, ProjectContext } from \"./context\"\nexport type { DoctorOptions } from \"./doctor\"\nexport { doctor, generateContext }\n"],"mappings":";;;;;;;;;;;;;;;AAmDA,eAAsB,gBAAgB,SAAkD;CACtF,MAAM,UAAU,YAAY,QAAQ,IAAI;CACxC,MAAM,cAAc,gBAAgB,QAAQ,IAAI;CAEhD,MAAM,SAAS,cAAc,aAAa,QAAQ,IAAI;CACtD,MAAM,aAAa,kBAAkB,aAAa,QAAQ,IAAI;CAC9D,MAAM,UAAU,eAAe,aAAa,QAAQ,IAAI;CAExD,MAAM,UAA0B;EAC9B,WAAW;EACX;EACA,8BAAa,IAAI,MAAM,EAAC,aAAa;EACrC;EACA;EACA;EACD;CAGD,MAAM,SAAS,QAAQ,UAAU,KAAK,QAAQ,QAAQ,QAAQ,GAAG,KAAK,KAAK,QAAQ,KAAK,UAAU;CAClG,MAAM,UAAU,QAAQ,WAAW,KAAK,KAAK,QAAQ,eAAe;AAEpE,KAAI,CAAC,GAAG,WAAW,OAAO,CACxB,IAAG,UAAU,QAAQ,EAAE,WAAW,MAAM,CAAC;AAE3C,IAAG,cAAc,SAAS,KAAK,UAAU,SAAS,MAAM,EAAE,EAAE,QAAQ;AAGpE,iBAAgB,QAAQ,IAAI;CAE5B,MAAM,SAAS,KAAK,SAAS,QAAQ,KAAK,QAAQ;AAClD,SAAQ,IACN,iBAAiB,OAAO,IAAI,WAAW,OAAO,eAAe,OAAO,OAAO,WAAW,QAAQ,OAAO,WACtG;AAED,QAAO;;AAOT,SAAS,oBAAoB,OAAe,YAAwC;CAClF,MAAM,YAAY,WAAW,MAAM;CACnC,MAAM,SAAS,cAAc,UAAU;CAEvC,MAAM,mBAAmB,KAAK,IAAI,GAAG,WAAW,QAAQ,GAAG;CAC3D,MAAM,iBAAiB,KAAK,IAAI,MAAM,QAAQ,WAAW,QAAQ,IAAI;CACrE,MAAM,cAAc,MAAM,MAAM,kBAAkB,eAAe;CAEjE,MAAM,YAAY,aAAa,KAAK,YAAY;CAChD,MAAM,WAAW,kCAAkC,KAAK,YAAY;AAGpE,QAAO;EACL,MAAM;EACN,MAJgB,YAAY,MAAM,8BAA8B,GAI9C;EAClB;EACA;EACA;EACD;;AAGH,SAAS,uBAAuB,OAA4B;CAC1D,MAAM,SAAsB,EAAE;CAC9B,MAAM,aAAa;CACnB,IAAI;AACJ,QAAO,MAAM;AACX,eAAa,WAAW,KAAK,MAAM;AACnC,MAAI,CAAC,WAAY;AACjB,SAAO,KAAK,oBAAoB,OAAO,WAAW,CAAC;;AAErD,QAAO;;AAGT,SAAS,cAAc,OAAiB,MAA2B;CACjE,MAAM,SAAsB,EAAE;AAE9B,MAAK,MAAM,QAAQ,OAAO;EACxB,IAAI;AACJ,MAAI;AACF,UAAO,GAAG,aAAa,MAAM,QAAQ;UAC/B;AACN;;EAGF,MAAM,eACJ;EACF,IAAI;AACJ,SAAO,MAAM;AACX,WAAQ,aAAa,KAAK,KAAK;AAC/B,OAAI,CAAC,MAAO;GACZ,MAAM,QAAQ,MAAM,MAAM;AAC1B,QAAK,MAAM,SAAS,uBAAuB,MAAM,CAC/C,QAAO,KAAK,MAAM;;;AAKxB,QAAO;;AAGT,SAAS,WAAW,UAA4B;AAC9C,QAAO,SACJ,MAAM,IAAI,CACV,KAAK,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,IAAI,GAAG,CAC/D,QAAQ,MAAM,KAAK,MAAM,QAAQ;;AAGtC,SAAS,mBAAmB,MAAwB;CAClD,MAAM,cAAwB,EAAE;CAChC,MAAM,WAAW;CACjB,IAAI;AACJ,QAAO,MAAM;AACX,aAAW,SAAS,KAAK,KAAK;AAC9B,MAAI,CAAC,SAAU;AACf,MAAI,SAAS,GAAI,aAAY,KAAK,SAAS,GAAG;;AAEhD,QAAO;;AAGT,SAAS,0BAA0B,MAAc,SAAkC;CACjF,MAAM,aAA8B,EAAE;CACtC,MAAM,cACJ;CACF,IAAI;AAEJ,QAAO,MAAM;AACX,UAAQ,YAAY,KAAK,KAAK;AAC9B,MAAI,CAAC,MAAO;EACZ,MAAM,OAAO,MAAM,MAAM;EACzB,MAAM,QAAQ,WAAW,MAAM,MAAM,GAAG;EAExC,MAAM,YAAY,MAAM,QAAQ,MAAM,GAAG;EAEzC,MAAM,cAAc,mBADP,KAAK,MAAM,WAAW,KAAK,IAAI,KAAK,QAAQ,YAAY,IAAK,CAAC,CAC/B;AAE5C,aAAW,KAAK;GACd;GACA,MAAM;GACN,YAAY,YAAY,SAAS;GACjC;GACA;GACD,CAAC;;AAGJ,QAAO;;AAGT,SAAS,kBAAkB,OAAiB,MAA+B;CACzE,MAAM,aAA8B,EAAE;AAEtC,MAAK,MAAM,QAAQ,OAAO;EACxB,IAAI;AACJ,MAAI;AACF,UAAO,GAAG,aAAa,MAAM,QAAQ;UAC/B;AACN;;EAGF,MAAM,UAAU,KAAK,SAAS,MAAM,KAAK;AACzC,OAAK,MAAM,QAAQ,0BAA0B,MAAM,QAAQ,CACzD,YAAW,KAAK,KAAK;;AAIzB,QAAO;;AAGT,SAAS,eAAe,OAAiB,KAA2B;CAClE,MAAM,UAAwB,EAAE;AAEhC,MAAK,MAAM,QAAQ,OAAO;EACxB,IAAI;AACJ,MAAI;AACF,UAAO,GAAG,aAAa,MAAM,QAAQ;UAC/B;AACN;;EAGF,MAAM,WACJ;EACF,IAAI;AACJ,SAAO,MAAM;AACX,WAAQ,SAAS,KAAK,KAAK;AAC3B,OAAI,CAAC,MAAO;AACZ,OAAI,MAAM,GACR,SAAQ,KAAK;IACX,MAAM,MAAM;IACZ,MAAM,KAAK,SAAS,KAAK,KAAK;IAC9B,SAAS,MAAM,MAAM;IACtB,CAAC;;;AAKR,QAAO;;AAOT,SAAS,cAAc,WAA6B;CAClD,MAAM,SAAmB,EAAE;CAC3B,MAAM,UAAU;CAChB,IAAI;AACJ,QAAO,MAAM;AACX,UAAQ,QAAQ,KAAK,UAAU;AAC/B,MAAI,CAAC,MAAO;AACZ,MAAI,MAAM,GAAI,QAAO,KAAK,MAAM,GAAG;;AAErC,QAAO;;AAGT,SAAS,YAAY,KAAqB;AACxC,KAAI;EACF,MAAM,MAAM,KAAK,MAAM,GAAG,aAAa,KAAK,KAAK,KAAK,eAAe,EAAE,QAAQ,CAAC;EAChF,MAAM,OAAgC;GAAE,GAAG,IAAI;GAAc,GAAG,IAAI;GAAiB;AACrF,OAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,KAAK,CAChD,KAAI,KAAK,WAAW,WAAW,IAAI,OAAO,YAAY,SACpD,QAAO,QAAQ,QAAQ,UAAU,GAAG;AAGxC,SAAQ,IAAI,WAAsB;SAC5B;AACN,SAAO;;;AAIX,MAAM,gBAAgB,IAAI,IAAI;CAAC;CAAQ;CAAQ;CAAO;CAAM,CAAC;AAC7D,MAAM,gBAAgB,IAAI,IAAI;CAAC;CAAgB;CAAQ;CAAO;CAAW;CAAQ;CAAQ,CAAC;AAE1F,SAAS,gBAAgB,OAA2B;AAClD,KAAI,CAAC,MAAM,aAAa,CAAE,QAAO;AACjC,QAAO,MAAM,KAAK,WAAW,IAAI,IAAI,cAAc,IAAI,MAAM,KAAK;;AAGpE,SAAS,aAAa,KAAa,SAAyB;CAC1D,IAAI;AACJ,KAAI;AACF,YAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;SAChD;AACN;;AAGF,MAAK,MAAM,SAAS,SAAS;AAC3B,MAAI,gBAAgB,MAAM,CAAE;EAE5B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAC3C,MAAI,MAAM,aAAa,CACrB,cAAa,UAAU,QAAQ;WACtB,MAAM,QAAQ,IAAI,cAAc,IAAI,KAAK,QAAQ,MAAM,KAAK,CAAC,CACtE,SAAQ,KAAK,SAAS;;;AAK5B,SAAS,gBAAgB,KAAuB;CAC9C,MAAM,UAAoB,EAAE;AAC5B,cAAa,KAAK,QAAQ;AAC1B,QAAO;;AAGT,SAAS,gBAAgB,KAAmB;CAC1C,MAAM,gBAAgB,KAAK,KAAK,KAAK,aAAa;AAClD,KAAI;EACF,MAAM,UAAU,GAAG,WAAW,cAAc,GAAG,GAAG,aAAa,eAAe,QAAQ,GAAG;AAEzF,MAAI,CAAC,QAAQ,SAAS,WAAW,IAAI,CAAC,QAAQ,SAAS,YAAY,EAAE;GACnE,MAAM,WAAW,QAAQ,SAAS,KAAK,GAAG,eAAe;AACzD,MAAG,eAAe,eAAe,SAAS;;SAEtC;;;;;;;;;;;;;;;;;;;;ACjRV,eAAsB,OAAO,SAAyC;CACpE,MAAM,YAAY,YAAY,KAAK;CAEnC,MAAM,SAAS,UADD,mBAAmB,QAAQ,IAAI,EACb,QAAQ;CACxC,MAAM,UAAU,KAAK,MAAM,YAAY,KAAK,GAAG,UAAU;AAEzD,KAAI,QAAQ,KACV,WAAU,OAAO;KAEjB,YAAW,QAAQ,QAAQ;AAG7B,QAAO,OAAO,QAAQ;;AAOxB,MAAM,mBAAmB,IAAI,IAAI;CAAC;CAAQ;CAAQ;CAAO;CAAM,CAAC;AAChE,MAAM,mBAAmB,IAAI,IAAI;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,mBAAmB,OAA2B;AACrD,KAAI,CAAC,MAAM,aAAa,CAAE,QAAO;AACjC,QAAO,MAAM,KAAK,WAAW,IAAI,IAAI,iBAAiB,IAAI,MAAM,KAAK;;AAGvE,SAAS,gBAAgB,KAAa,SAAyB;CAC7D,IAAI;AACJ,KAAI;AACF,YAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;SAChD;AACN;;AAGF,MAAK,MAAM,SAAS,SAAS;AAC3B,MAAI,mBAAmB,MAAM,CAAE;EAE/B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAC3C,MAAI,MAAM,aAAa,CACrB,iBAAgB,UAAU,QAAQ;WACzB,MAAM,QAAQ,IAAI,iBAAiB,IAAI,KAAK,QAAQ,MAAM,KAAK,CAAC,CACzE,SAAQ,KAAK,SAAS;;;AAK5B,SAAS,mBAAmB,KAAuB;CACjD,MAAM,UAAoB,EAAE;AAC5B,iBAAgB,KAAK,QAAQ;AAC7B,QAAO;;AAOT,SAAS,iBACP,MACA,SACiD;CACjD,IAAI;AACJ,KAAI;AACF,SAAO,GAAG,aAAa,MAAM,QAAQ;SAC/B;AACN,SAAO;GAAE,QAAQ;GAAM,UAAU;GAAG;;AAGtC,KAAI,CAAC,iBAAiB,KAAK,CAAE,QAAO;EAAE,QAAQ;EAAM,UAAU;EAAG;CAEjE,MAAM,WAAW,iBAAiB,MAAM,QAAQ;AAChD,KAAI,SAAS,QAAQ,SAAS,EAC5B,IAAG,cAAc,MAAM,SAAS,MAAM,QAAQ;CAEhD,MAAM,YAAY,oBAAoB,SAAS,MAAM,QAAQ;AAC7D,KAAI,UAAU,SAAS,KAAK,SAAS,QAAQ,SAAS,EACpD,QAAO;EACL,QAAQ;GAAE,MAAM;GAAS,aAAa;GAAW,OAAO,SAAS,QAAQ,SAAS;GAAG;EACrF,UAAU,SAAS,QAAQ;EAC5B;AAEH,QAAO;EAAE,QAAQ;EAAM,UAAU;EAAG;;AAGtC,SAAS,oBAAoB,MAAc,SAAoC;CAC7E,IAAI;AACJ,KAAI;AACF,SAAO,GAAG,aAAa,MAAM,QAAQ;SAC/B;AACN,SAAO;;AAGT,KAAI,CAAC,iBAAiB,KAAK,CAAE,QAAO;CAEpC,MAAM,cAAc,oBAAoB,MAAM,QAAQ;AACtD,KAAI,YAAY,SAAS,EACvB,QAAO;EAAE,MAAM;EAAS;EAAa,OAAO;EAAO;AAErD,QAAO;;AAGT,SAAS,UAAU,OAAiB,SAAsC;CACxE,MAAM,cAA4B,EAAE;CACpC,IAAI,aAAa;AAEjB,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,UAAU,KAAK,SAAS,QAAQ,KAAK,KAAK;AAEhD,MAAI,QAAQ,KAAK;GACf,MAAM,EAAE,QAAQ,aAAa,iBAAiB,MAAM,QAAQ;AAC5D,iBAAc;AACd,OAAI,OAAQ,aAAY,KAAK,OAAO;SAC/B;GACL,MAAM,SAAS,oBAAoB,MAAM,QAAQ;AACjD,OAAI,OAAQ,aAAY,KAAK,OAAO;;;CAIxC,MAAM,cAAc,YAAY,QAAQ,KAAK,MAAM,MAAM,EAAE,YAAY,QAAQ,EAAE;CACjF,MAAM,eAAe,YAAY,QAC9B,KAAK,MAAM,MAAM,EAAE,YAAY,QAAQ,MAAM,EAAE,QAAQ,CAAC,QACzD,EACD;AAED,QAAO;EACL,QAAQ,gBAAgB;EACxB,OAAO;EACP,SAAS;GACP,cAAc,MAAM;GACpB,iBAAiB,YAAY;GAC7B;GACA;GACA;GACD;EACF;;AAOH,SAAS,UAAU,QAA4B;AAC7C,SAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;;AAG9C,SAAS,gBAAgB,YAA8B;AACrD,KAAI,WAAW,YAAY,WAAW,EAAG;AAEzC,SAAQ,IAAI,KAAK,WAAW,OAAO,WAAW,QAAQ,uBAAuB,KAAK;AAElF,MAAK,MAAM,QAAQ,WAAW,aAAa;EACzC,MAAM,SAAS,KAAK,UAAU,eAAe;AAC7C,UAAQ,IAAI,OAAO,KAAK,KAAK,GAAG,KAAK,OAAO,KAAK,KAAK,UAAU,SAAS;AACzE,UAAQ,IAAI,oBAAoB,KAAK,UAAU;AAC/C,UAAQ,IAAI,oBAAoB,KAAK,YAAY;AACjD,UAAQ,IAAI,GAAG;;;AAInB,SAAS,aAAa,SAAwC;AAC5D,SAAQ,IACN,KAAK,QAAQ,YAAY,QAAQ,QAAQ,gBAAgB,IAAI,KAAK,IAAI,MAAM,QAAQ,gBAAgB,OAAO,QAAQ,oBAAoB,IAAI,KAAK,MACjJ;AACD,KAAI,QAAQ,eAAe,EACzB,SAAQ,IAAI,KAAK,QAAQ,aAAa,oDAAoD;AAE5F,SAAQ,IAAI,GAAG;;AAGjB,SAAS,WAAW,QAAsB,SAAuB;CAC/D,MAAM,EAAE,YAAY;AAEpB,SAAQ,IAAI,GAAG;AACf,SAAQ,IAAI,6BAA6B,QAAQ,aAAa,YAAY,QAAQ,IAAI;AACtF,SAAQ,IAAI,GAAG;AAEf,KAAI,OAAO,UAAU,QAAQ,eAAe,GAAG;AAC7C,UAAQ,IAAI,mDAAmD;AAC/D,UAAQ,IAAI,GAAG;AACf;;AAGF,KAAI,QAAQ,aAAa,GAAG;AAC1B,UAAQ,IAAI,kBAAkB,QAAQ,WAAW,QAAQ,QAAQ,eAAe,IAAI,KAAK,MAAM;AAC/F,UAAQ,IAAI,GAAG;;AAGjB,MAAK,MAAM,cAAc,OAAO,MAC9B,iBAAgB,WAAW;AAG7B,cAAa,QAAQ;;;;;;;;;;;;AC5OvB,MAAM,OAAO,QAAQ,KAAK,MAAM,EAAE;AAClC,MAAM,UAAU,KAAK;AAErB,SAAS,aAAmB;AAC1B,SAAQ,IAAI;;;;;;;;;;EAUZ;;AAGF,eAAe,OAAsB;AACnC,KAAI,CAAC,WAAW,YAAY,YAAY,YAAY,MAAM;AACxD,cAAY;AACZ;;AAGF,KAAI,YAAY,eAAe,YAAY,MAAM;AAC/C,UAAQ,IAAI,QAAQ;AACpB;;AAGF,KAAI,YAAY,UAAU;EACxB,MAAM,UAAyB;GAC7B,KAAK,KAAK,SAAS,QAAQ;GAC3B,MAAM,KAAK,SAAS,SAAS;GAC7B,IAAI,KAAK,SAAS,OAAO;GACzB,KAAK,QAAQ,KAAK;GACnB;EACD,MAAM,WAAW,MAAM,OAAO,QAAQ;AACtC,MAAI,QAAQ,MAAM,WAAW,EAC3B,SAAQ,KAAK,EAAE;AAEjB;;AAGF,KAAI,YAAY,WAAW;EACzB,MAAM,SAAS,KAAK,QAAQ,QAAQ;EACpC,MAAM,UAAU,UAAU,IAAI,KAAK,SAAS,KAAK;AACjD,QAAM,gBAAgB;GAAE,KAAK,QAAQ,KAAK;GAAE;GAAS,CAAC;AACtD;;AAGF,SAAQ,MAAM,oBAAoB,UAAU;AAC5C,aAAY;AACZ,SAAQ,KAAK,EAAE;;AAGjB,MAAM,CAAC,OAAO,QAAQ;AACpB,SAAQ,MAAM,IAAI;AAClB,SAAQ,KAAK,EAAE;EACf"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["scanProject"],"sources":["../src/context.ts","../src/doctor.ts","../src/index.ts"],"sourcesContent":["/**\n * pyreon context — generates .pyreon/context.json for AI tool consumption\n *\n * Delegates scanning to @pyreon/compiler's unified project scanner,\n * then writes the result to disk and ensures .pyreon/ is gitignored.\n */\n\nimport * as fs from \"node:fs\"\nimport * as path from \"node:path\"\nimport { type ProjectContext, generateContext as scanProject } from \"@pyreon/compiler\"\n\nexport type { ComponentInfo, IslandInfo, ProjectContext, RouteInfo } from \"@pyreon/compiler\"\n\nexport interface ContextOptions {\n cwd: string\n outPath?: string | undefined\n}\n\nexport async function generateContext(options: ContextOptions): Promise<ProjectContext> {\n const context = scanProject(options.cwd)\n\n // Write to .pyreon/context.json\n const outDir = options.outPath ? path.dirname(options.outPath) : path.join(options.cwd, \".pyreon\")\n const outFile = options.outPath ?? path.join(outDir, \"context.json\")\n\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true })\n }\n fs.writeFileSync(outFile, JSON.stringify(context, null, 2), \"utf-8\")\n\n // Ensure .pyreon/ is in .gitignore\n ensureGitignore(options.cwd)\n\n const relOut = path.relative(options.cwd, outFile)\n console.log(\n ` ✓ Generated ${relOut} (${context.components.length} components, ${context.routes.length} routes, ${context.islands.length} islands)`,\n )\n\n return context\n}\n\nfunction ensureGitignore(cwd: string): void {\n const gitignorePath = path.join(cwd, \".gitignore\")\n try {\n const content = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, \"utf-8\") : \"\"\n\n if (!content.includes(\".pyreon/\") && !content.includes(\".pyreon\\n\")) {\n const addition = content.endsWith(\"\\n\") ? \".pyreon/\\n\" : \"\\n.pyreon/\\n\"\n fs.appendFileSync(gitignorePath, addition)\n }\n } catch {\n // Ignore errors with .gitignore\n }\n}\n","/**\n * pyreon doctor — project-wide health check for AI-friendly development\n *\n * Runs a pipeline of checks:\n * 1. React pattern detection (imports, hooks, JSX attributes)\n * 2. Import source validation (@pyreon/* vs react/vue)\n * 3. Common Pyreon mistakes (signal without call, key vs by, etc.)\n *\n * Output modes:\n * - Human-readable (default): colored terminal output\n * - JSON (--json): structured output for AI agent consumption\n * - CI (--ci): exits with code 1 on any error\n *\n * Fix mode (--fix): auto-applies safe transforms via migrateReactCode\n */\n\nimport * as fs from \"node:fs\"\nimport * as path from \"node:path\"\nimport {\n detectReactPatterns,\n hasReactPatterns,\n migrateReactCode,\n type ReactDiagnostic,\n} from \"@pyreon/compiler\"\n\nexport interface DoctorOptions {\n fix: boolean\n json: boolean\n ci: boolean\n cwd: string\n}\n\ninterface FileResult {\n file: string\n diagnostics: ReactDiagnostic[]\n fixed: boolean\n}\n\ninterface DoctorResult {\n passed: boolean\n files: FileResult[]\n summary: {\n filesScanned: number\n filesWithIssues: number\n totalErrors: number\n totalFixable: number\n totalFixed: number\n }\n}\n\nexport async function doctor(options: DoctorOptions): Promise<number> {\n const startTime = performance.now()\n const files = collectSourceFiles(options.cwd)\n const result = runChecks(files, options)\n const elapsed = Math.round(performance.now() - startTime)\n\n if (options.json) {\n printJson(result)\n } else {\n printHuman(result, elapsed)\n }\n\n return result.summary.totalErrors\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// File collection\n// ═══════════════════════════════════════════════════════════════════════════════\n\nconst sourceExtensions = new Set([\".tsx\", \".jsx\", \".ts\", \".js\"])\nconst sourceIgnoreDirs = new Set([\n \"node_modules\",\n \"dist\",\n \"lib\",\n \".pyreon\",\n \".git\",\n \".next\",\n \"build\",\n])\n\nfunction shouldSkipDirEntry(entry: fs.Dirent): boolean {\n if (!entry.isDirectory()) return false\n return entry.name.startsWith(\".\") || sourceIgnoreDirs.has(entry.name)\n}\n\nfunction walkSourceFiles(dir: string, results: string[]): void {\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return\n }\n\n for (const entry of entries) {\n if (shouldSkipDirEntry(entry)) continue\n\n const fullPath = path.join(dir, entry.name)\n if (entry.isDirectory()) {\n walkSourceFiles(fullPath, results)\n } else if (entry.isFile() && sourceExtensions.has(path.extname(entry.name))) {\n results.push(fullPath)\n }\n }\n}\n\nfunction collectSourceFiles(cwd: string): string[] {\n const results: string[] = []\n walkSourceFiles(cwd, results)\n return results\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Check pipeline\n// ═══════════════════════════════════════════════════════════════════════════════\n\nfunction checkFileWithFix(\n file: string,\n relPath: string,\n): { result: FileResult | null; fixCount: number } {\n let code: string\n try {\n code = fs.readFileSync(file, \"utf-8\")\n } catch {\n return { result: null, fixCount: 0 }\n }\n\n if (!hasReactPatterns(code)) return { result: null, fixCount: 0 }\n\n const migrated = migrateReactCode(code, relPath)\n if (migrated.changes.length > 0) {\n fs.writeFileSync(file, migrated.code, \"utf-8\")\n }\n const remaining = detectReactPatterns(migrated.code, relPath)\n if (remaining.length > 0 || migrated.changes.length > 0) {\n return {\n result: { file: relPath, diagnostics: remaining, fixed: migrated.changes.length > 0 },\n fixCount: migrated.changes.length,\n }\n }\n return { result: null, fixCount: 0 }\n}\n\nfunction checkFileDetectOnly(file: string, relPath: string): FileResult | null {\n let code: string\n try {\n code = fs.readFileSync(file, \"utf-8\")\n } catch {\n return null\n }\n\n if (!hasReactPatterns(code)) return null\n\n const diagnostics = detectReactPatterns(code, relPath)\n if (diagnostics.length > 0) {\n return { file: relPath, diagnostics, fixed: false }\n }\n return null\n}\n\nfunction runChecks(files: string[], options: DoctorOptions): DoctorResult {\n const fileResults: FileResult[] = []\n let totalFixed = 0\n\n for (const file of files) {\n const relPath = path.relative(options.cwd, file)\n\n if (options.fix) {\n const { result, fixCount } = checkFileWithFix(file, relPath)\n totalFixed += fixCount\n if (result) fileResults.push(result)\n } else {\n const result = checkFileDetectOnly(file, relPath)\n if (result) fileResults.push(result)\n }\n }\n\n const totalErrors = fileResults.reduce((sum, f) => sum + f.diagnostics.length, 0)\n const totalFixable = fileResults.reduce(\n (sum, f) => sum + f.diagnostics.filter((d) => d.fixable).length,\n 0,\n )\n\n return {\n passed: totalErrors === 0,\n files: fileResults,\n summary: {\n filesScanned: files.length,\n filesWithIssues: fileResults.length,\n totalErrors,\n totalFixable,\n totalFixed,\n },\n }\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// Output formatters\n// ═══════════════════════════════════════════════════════════════════════════════\n\nfunction printJson(result: DoctorResult): void {\n console.log(JSON.stringify(result, null, 2))\n}\n\nfunction printFileResult(fileResult: FileResult): void {\n if (fileResult.diagnostics.length === 0) return\n\n console.log(` ${fileResult.file}${fileResult.fixed ? \" (partially fixed)\" : \"\"}`)\n\n for (const diag of fileResult.diagnostics) {\n const fixTag = diag.fixable ? \" [fixable]\" : \"\"\n console.log(` ${diag.line}:${diag.column} — ${diag.message}${fixTag}`)\n console.log(` Current: ${diag.current}`)\n console.log(` Suggested: ${diag.suggested}`)\n console.log(\"\")\n }\n}\n\nfunction printSummary(summary: DoctorResult[\"summary\"]): void {\n console.log(\n ` ${summary.totalErrors} issue${summary.totalErrors === 1 ? \"\" : \"s\"} in ${summary.filesWithIssues} file${summary.filesWithIssues === 1 ? \"\" : \"s\"}`,\n )\n if (summary.totalFixable > 0) {\n console.log(` ${summary.totalFixable} auto-fixable — run 'pyreon doctor --fix' to apply`)\n }\n console.log(\"\")\n}\n\nfunction printHuman(result: DoctorResult, elapsed: number): void {\n const { summary } = result\n\n console.log(\"\")\n console.log(` Pyreon Doctor — scanned ${summary.filesScanned} files in ${elapsed}ms`)\n console.log(\"\")\n\n if (result.passed && summary.totalFixed === 0) {\n console.log(\" ✓ No issues found. Your code is Pyreon-native!\")\n console.log(\"\")\n return\n }\n\n if (summary.totalFixed > 0) {\n console.log(` ✓ Auto-fixed ${summary.totalFixed} issue${summary.totalFixed === 1 ? \"\" : \"s\"}`)\n console.log(\"\")\n }\n\n for (const fileResult of result.files) {\n printFileResult(fileResult)\n }\n\n printSummary(summary)\n}\n","#!/usr/bin/env node\n\n/**\n * @pyreon/cli — Developer tools for Pyreon\n *\n * Commands:\n * pyreon doctor [--fix] [--json] — Scan project for React patterns, bad imports, etc.\n * pyreon context — Generate .pyreon/context.json for AI tools\n */\n\nimport { generateContext } from \"./context\"\nimport { type DoctorOptions, doctor } from \"./doctor\"\n\nconst args = process.argv.slice(2)\nconst command = args[0]\n\nfunction printUsage(): void {\n console.log(`\n pyreon <command> [options]\n\n Commands:\n doctor [--fix] [--json] [--ci] Scan for React patterns, bad imports, and common mistakes\n context [--out <path>] Generate .pyreon/context.json for AI tools\n\n Options:\n --help Show this help message\n --version Show version\n`)\n}\n\nasync function main(): Promise<void> {\n if (!command || command === \"--help\" || command === \"-h\") {\n printUsage()\n return\n }\n\n if (command === \"--version\" || command === \"-v\") {\n console.log(\"0.4.0\")\n return\n }\n\n if (command === \"doctor\") {\n const options: DoctorOptions = {\n fix: args.includes(\"--fix\"),\n json: args.includes(\"--json\"),\n ci: args.includes(\"--ci\"),\n cwd: process.cwd(),\n }\n const exitCode = await doctor(options)\n if (options.ci && exitCode > 0) {\n process.exit(1)\n }\n return\n }\n\n if (command === \"context\") {\n const outIdx = args.indexOf(\"--out\")\n const outPath = outIdx >= 0 ? args[outIdx + 1] : undefined\n await generateContext({ cwd: process.cwd(), outPath })\n return\n }\n\n console.error(`Unknown command: ${command}`)\n printUsage()\n process.exit(1)\n}\n\nmain().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n\nexport type { ContextOptions, ProjectContext } from \"./context\"\nexport type { DoctorOptions } from \"./doctor\"\nexport { doctor, generateContext }\n"],"mappings":";;;;;;;;;;;;AAkBA,eAAsB,gBAAgB,SAAkD;CACtF,MAAM,UAAUA,kBAAY,QAAQ,IAAI;CAGxC,MAAM,SAAS,QAAQ,UAAU,KAAK,QAAQ,QAAQ,QAAQ,GAAG,KAAK,KAAK,QAAQ,KAAK,UAAU;CAClG,MAAM,UAAU,QAAQ,WAAW,KAAK,KAAK,QAAQ,eAAe;AAEpE,KAAI,CAAC,GAAG,WAAW,OAAO,CACxB,IAAG,UAAU,QAAQ,EAAE,WAAW,MAAM,CAAC;AAE3C,IAAG,cAAc,SAAS,KAAK,UAAU,SAAS,MAAM,EAAE,EAAE,QAAQ;AAGpE,iBAAgB,QAAQ,IAAI;CAE5B,MAAM,SAAS,KAAK,SAAS,QAAQ,KAAK,QAAQ;AAClD,SAAQ,IACN,iBAAiB,OAAO,IAAI,QAAQ,WAAW,OAAO,eAAe,QAAQ,OAAO,OAAO,WAAW,QAAQ,QAAQ,OAAO,WAC9H;AAED,QAAO;;AAGT,SAAS,gBAAgB,KAAmB;CAC1C,MAAM,gBAAgB,KAAK,KAAK,KAAK,aAAa;AAClD,KAAI;EACF,MAAM,UAAU,GAAG,WAAW,cAAc,GAAG,GAAG,aAAa,eAAe,QAAQ,GAAG;AAEzF,MAAI,CAAC,QAAQ,SAAS,WAAW,IAAI,CAAC,QAAQ,SAAS,YAAY,EAAE;GACnE,MAAM,WAAW,QAAQ,SAAS,KAAK,GAAG,eAAe;AACzD,MAAG,eAAe,eAAe,SAAS;;SAEtC;;;;;;;;;;;;;;;;;;;;ACAV,eAAsB,OAAO,SAAyC;CACpE,MAAM,YAAY,YAAY,KAAK;CAEnC,MAAM,SAAS,UADD,mBAAmB,QAAQ,IAAI,EACb,QAAQ;CACxC,MAAM,UAAU,KAAK,MAAM,YAAY,KAAK,GAAG,UAAU;AAEzD,KAAI,QAAQ,KACV,WAAU,OAAO;KAEjB,YAAW,QAAQ,QAAQ;AAG7B,QAAO,OAAO,QAAQ;;AAOxB,MAAM,mBAAmB,IAAI,IAAI;CAAC;CAAQ;CAAQ;CAAO;CAAM,CAAC;AAChE,MAAM,mBAAmB,IAAI,IAAI;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,mBAAmB,OAA2B;AACrD,KAAI,CAAC,MAAM,aAAa,CAAE,QAAO;AACjC,QAAO,MAAM,KAAK,WAAW,IAAI,IAAI,iBAAiB,IAAI,MAAM,KAAK;;AAGvE,SAAS,gBAAgB,KAAa,SAAyB;CAC7D,IAAI;AACJ,KAAI;AACF,YAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;SAChD;AACN;;AAGF,MAAK,MAAM,SAAS,SAAS;AAC3B,MAAI,mBAAmB,MAAM,CAAE;EAE/B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAC3C,MAAI,MAAM,aAAa,CACrB,iBAAgB,UAAU,QAAQ;WACzB,MAAM,QAAQ,IAAI,iBAAiB,IAAI,KAAK,QAAQ,MAAM,KAAK,CAAC,CACzE,SAAQ,KAAK,SAAS;;;AAK5B,SAAS,mBAAmB,KAAuB;CACjD,MAAM,UAAoB,EAAE;AAC5B,iBAAgB,KAAK,QAAQ;AAC7B,QAAO;;AAOT,SAAS,iBACP,MACA,SACiD;CACjD,IAAI;AACJ,KAAI;AACF,SAAO,GAAG,aAAa,MAAM,QAAQ;SAC/B;AACN,SAAO;GAAE,QAAQ;GAAM,UAAU;GAAG;;AAGtC,KAAI,CAAC,iBAAiB,KAAK,CAAE,QAAO;EAAE,QAAQ;EAAM,UAAU;EAAG;CAEjE,MAAM,WAAW,iBAAiB,MAAM,QAAQ;AAChD,KAAI,SAAS,QAAQ,SAAS,EAC5B,IAAG,cAAc,MAAM,SAAS,MAAM,QAAQ;CAEhD,MAAM,YAAY,oBAAoB,SAAS,MAAM,QAAQ;AAC7D,KAAI,UAAU,SAAS,KAAK,SAAS,QAAQ,SAAS,EACpD,QAAO;EACL,QAAQ;GAAE,MAAM;GAAS,aAAa;GAAW,OAAO,SAAS,QAAQ,SAAS;GAAG;EACrF,UAAU,SAAS,QAAQ;EAC5B;AAEH,QAAO;EAAE,QAAQ;EAAM,UAAU;EAAG;;AAGtC,SAAS,oBAAoB,MAAc,SAAoC;CAC7E,IAAI;AACJ,KAAI;AACF,SAAO,GAAG,aAAa,MAAM,QAAQ;SAC/B;AACN,SAAO;;AAGT,KAAI,CAAC,iBAAiB,KAAK,CAAE,QAAO;CAEpC,MAAM,cAAc,oBAAoB,MAAM,QAAQ;AACtD,KAAI,YAAY,SAAS,EACvB,QAAO;EAAE,MAAM;EAAS;EAAa,OAAO;EAAO;AAErD,QAAO;;AAGT,SAAS,UAAU,OAAiB,SAAsC;CACxE,MAAM,cAA4B,EAAE;CACpC,IAAI,aAAa;AAEjB,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,UAAU,KAAK,SAAS,QAAQ,KAAK,KAAK;AAEhD,MAAI,QAAQ,KAAK;GACf,MAAM,EAAE,QAAQ,aAAa,iBAAiB,MAAM,QAAQ;AAC5D,iBAAc;AACd,OAAI,OAAQ,aAAY,KAAK,OAAO;SAC/B;GACL,MAAM,SAAS,oBAAoB,MAAM,QAAQ;AACjD,OAAI,OAAQ,aAAY,KAAK,OAAO;;;CAIxC,MAAM,cAAc,YAAY,QAAQ,KAAK,MAAM,MAAM,EAAE,YAAY,QAAQ,EAAE;CACjF,MAAM,eAAe,YAAY,QAC9B,KAAK,MAAM,MAAM,EAAE,YAAY,QAAQ,MAAM,EAAE,QAAQ,CAAC,QACzD,EACD;AAED,QAAO;EACL,QAAQ,gBAAgB;EACxB,OAAO;EACP,SAAS;GACP,cAAc,MAAM;GACpB,iBAAiB,YAAY;GAC7B;GACA;GACA;GACD;EACF;;AAOH,SAAS,UAAU,QAA4B;AAC7C,SAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;;AAG9C,SAAS,gBAAgB,YAA8B;AACrD,KAAI,WAAW,YAAY,WAAW,EAAG;AAEzC,SAAQ,IAAI,KAAK,WAAW,OAAO,WAAW,QAAQ,uBAAuB,KAAK;AAElF,MAAK,MAAM,QAAQ,WAAW,aAAa;EACzC,MAAM,SAAS,KAAK,UAAU,eAAe;AAC7C,UAAQ,IAAI,OAAO,KAAK,KAAK,GAAG,KAAK,OAAO,KAAK,KAAK,UAAU,SAAS;AACzE,UAAQ,IAAI,oBAAoB,KAAK,UAAU;AAC/C,UAAQ,IAAI,oBAAoB,KAAK,YAAY;AACjD,UAAQ,IAAI,GAAG;;;AAInB,SAAS,aAAa,SAAwC;AAC5D,SAAQ,IACN,KAAK,QAAQ,YAAY,QAAQ,QAAQ,gBAAgB,IAAI,KAAK,IAAI,MAAM,QAAQ,gBAAgB,OAAO,QAAQ,oBAAoB,IAAI,KAAK,MACjJ;AACD,KAAI,QAAQ,eAAe,EACzB,SAAQ,IAAI,KAAK,QAAQ,aAAa,oDAAoD;AAE5F,SAAQ,IAAI,GAAG;;AAGjB,SAAS,WAAW,QAAsB,SAAuB;CAC/D,MAAM,EAAE,YAAY;AAEpB,SAAQ,IAAI,GAAG;AACf,SAAQ,IAAI,6BAA6B,QAAQ,aAAa,YAAY,QAAQ,IAAI;AACtF,SAAQ,IAAI,GAAG;AAEf,KAAI,OAAO,UAAU,QAAQ,eAAe,GAAG;AAC7C,UAAQ,IAAI,mDAAmD;AAC/D,UAAQ,IAAI,GAAG;AACf;;AAGF,KAAI,QAAQ,aAAa,GAAG;AAC1B,UAAQ,IAAI,kBAAkB,QAAQ,WAAW,QAAQ,QAAQ,eAAe,IAAI,KAAK,MAAM;AAC/F,UAAQ,IAAI,GAAG;;AAGjB,MAAK,MAAM,cAAc,OAAO,MAC9B,iBAAgB,WAAW;AAG7B,cAAa,QAAQ;;;;;;;;;;;;AC5OvB,MAAM,OAAO,QAAQ,KAAK,MAAM,EAAE;AAClC,MAAM,UAAU,KAAK;AAErB,SAAS,aAAmB;AAC1B,SAAQ,IAAI;;;;;;;;;;EAUZ;;AAGF,eAAe,OAAsB;AACnC,KAAI,CAAC,WAAW,YAAY,YAAY,YAAY,MAAM;AACxD,cAAY;AACZ;;AAGF,KAAI,YAAY,eAAe,YAAY,MAAM;AAC/C,UAAQ,IAAI,QAAQ;AACpB;;AAGF,KAAI,YAAY,UAAU;EACxB,MAAM,UAAyB;GAC7B,KAAK,KAAK,SAAS,QAAQ;GAC3B,MAAM,KAAK,SAAS,SAAS;GAC7B,IAAI,KAAK,SAAS,OAAO;GACzB,KAAK,QAAQ,KAAK;GACnB;EACD,MAAM,WAAW,MAAM,OAAO,QAAQ;AACtC,MAAI,QAAQ,MAAM,WAAW,EAC3B,SAAQ,KAAK,EAAE;AAEjB;;AAGF,KAAI,YAAY,WAAW;EACzB,MAAM,SAAS,KAAK,QAAQ,QAAQ;EACpC,MAAM,UAAU,UAAU,IAAI,KAAK,SAAS,KAAK;AACjD,QAAM,gBAAgB;GAAE,KAAK,QAAQ,KAAK;GAAE;GAAS,CAAC;AACtD;;AAGF,SAAQ,MAAM,oBAAoB,UAAU;AAC5C,aAAY;AACZ,SAAQ,KAAK,EAAE;;AAGjB,MAAM,CAAC,OAAO,QAAQ;AACpB,SAAQ,MAAM,IAAI;AAClB,SAAQ,KAAK,EAAE;EACf"}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,32 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { detectReactPatterns, hasReactPatterns, migrateReactCode } from "@pyreon/compiler";
|
|
4
|
+
import { detectReactPatterns, generateContext as generateContext$1, hasReactPatterns, migrateReactCode } from "@pyreon/compiler";
|
|
5
5
|
|
|
6
6
|
//#region src/context.ts
|
|
7
7
|
/**
|
|
8
8
|
* pyreon context — generates .pyreon/context.json for AI tool consumption
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* - Component inventory (file, props, signals)
|
|
13
|
-
* - Island declarations (name, hydration strategy)
|
|
14
|
-
* - Framework version
|
|
10
|
+
* Delegates scanning to @pyreon/compiler's unified project scanner,
|
|
11
|
+
* then writes the result to disk and ensures .pyreon/ is gitignored.
|
|
15
12
|
*/
|
|
16
13
|
async function generateContext(options) {
|
|
17
|
-
const
|
|
18
|
-
const sourceFiles = collectTsxFiles(options.cwd);
|
|
19
|
-
const routes = extractRoutes(sourceFiles, options.cwd);
|
|
20
|
-
const components = extractComponents(sourceFiles, options.cwd);
|
|
21
|
-
const islands = extractIslands(sourceFiles, options.cwd);
|
|
22
|
-
const context = {
|
|
23
|
-
framework: "pyreon",
|
|
24
|
-
version,
|
|
25
|
-
generatedAt: (/* @__PURE__ */new Date()).toISOString(),
|
|
26
|
-
routes,
|
|
27
|
-
components,
|
|
28
|
-
islands
|
|
29
|
-
};
|
|
14
|
+
const context = generateContext$1(options.cwd);
|
|
30
15
|
const outDir = options.outPath ? path.dirname(options.outPath) : path.join(options.cwd, ".pyreon");
|
|
31
16
|
const outFile = options.outPath ?? path.join(outDir, "context.json");
|
|
32
17
|
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, {
|
|
@@ -35,176 +20,9 @@ async function generateContext(options) {
|
|
|
35
20
|
fs.writeFileSync(outFile, JSON.stringify(context, null, 2), "utf-8");
|
|
36
21
|
ensureGitignore(options.cwd);
|
|
37
22
|
const relOut = path.relative(options.cwd, outFile);
|
|
38
|
-
console.log(` ✓ Generated ${relOut} (${components.length} components, ${routes.length} routes, ${islands.length} islands)`);
|
|
23
|
+
console.log(` ✓ Generated ${relOut} (${context.components.length} components, ${context.routes.length} routes, ${context.islands.length} islands)`);
|
|
39
24
|
return context;
|
|
40
25
|
}
|
|
41
|
-
function parseRouteFromBlock(block, routeMatch) {
|
|
42
|
-
const routePath = routeMatch[1] ?? "";
|
|
43
|
-
const params = extractParams(routePath);
|
|
44
|
-
const surroundingStart = Math.max(0, routeMatch.index - 50);
|
|
45
|
-
const surroundingEnd = Math.min(block.length, routeMatch.index + 200);
|
|
46
|
-
const surrounding = block.slice(surroundingStart, surroundingEnd);
|
|
47
|
-
const hasLoader = /loader\s*:/.test(surrounding);
|
|
48
|
-
const hasGuard = /beforeEnter\s*:|beforeLeave\s*:/.test(surrounding);
|
|
49
|
-
return {
|
|
50
|
-
path: routePath,
|
|
51
|
-
name: surrounding.match(/name\s*:\s*["']([^"']+)["']/)?.[1],
|
|
52
|
-
hasLoader,
|
|
53
|
-
hasGuard,
|
|
54
|
-
params
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function extractRoutesFromBlock(block) {
|
|
58
|
-
const routes = [];
|
|
59
|
-
const routeObjRe = /path\s*:\s*["']([^"']+)["']/g;
|
|
60
|
-
let routeMatch;
|
|
61
|
-
while (true) {
|
|
62
|
-
routeMatch = routeObjRe.exec(block);
|
|
63
|
-
if (!routeMatch) break;
|
|
64
|
-
routes.push(parseRouteFromBlock(block, routeMatch));
|
|
65
|
-
}
|
|
66
|
-
return routes;
|
|
67
|
-
}
|
|
68
|
-
function extractRoutes(files, _cwd) {
|
|
69
|
-
const routes = [];
|
|
70
|
-
for (const file of files) {
|
|
71
|
-
let code;
|
|
72
|
-
try {
|
|
73
|
-
code = fs.readFileSync(file, "utf-8");
|
|
74
|
-
} catch {
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
const routeArrayRe = /(?:createRouter\s*\(\s*\[|(?:const|let)\s+routes\s*(?::\s*RouteRecord\[\])?\s*=\s*\[)([\s\S]*?)\]/g;
|
|
78
|
-
let match;
|
|
79
|
-
while (true) {
|
|
80
|
-
match = routeArrayRe.exec(code);
|
|
81
|
-
if (!match) break;
|
|
82
|
-
const block = match[1] ?? "";
|
|
83
|
-
for (const route of extractRoutesFromBlock(block)) routes.push(route);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return routes;
|
|
87
|
-
}
|
|
88
|
-
function parseProps(propsStr) {
|
|
89
|
-
return propsStr.split(",").map(p => p.trim().split(":")[0]?.split("=")[0]?.trim() ?? "").filter(p => p && p !== "props");
|
|
90
|
-
}
|
|
91
|
-
function collectSignalNames(body) {
|
|
92
|
-
const signalNames = [];
|
|
93
|
-
const signalRe = /(?:const|let)\s+(\w+)\s*=\s*signal\s*[<(]/g;
|
|
94
|
-
let sigMatch;
|
|
95
|
-
while (true) {
|
|
96
|
-
sigMatch = signalRe.exec(body);
|
|
97
|
-
if (!sigMatch) break;
|
|
98
|
-
if (sigMatch[1]) signalNames.push(sigMatch[1]);
|
|
99
|
-
}
|
|
100
|
-
return signalNames;
|
|
101
|
-
}
|
|
102
|
-
function extractComponentsFromCode(code, relFile) {
|
|
103
|
-
const components = [];
|
|
104
|
-
const componentRe = /(?:export\s+)?(?:const|function)\s+([A-Z]\w*)\s*(?::\s*ComponentFn<[^>]+>\s*)?=?\s*\(?(?:\s*\{?\s*([^)]*?)\s*\}?\s*)?\)?\s*(?:=>|{)/g;
|
|
105
|
-
let match;
|
|
106
|
-
while (true) {
|
|
107
|
-
match = componentRe.exec(code);
|
|
108
|
-
if (!match) break;
|
|
109
|
-
const name = match[1] ?? "Unknown";
|
|
110
|
-
const props = parseProps(match[2] ?? "");
|
|
111
|
-
const bodyStart = match.index + match[0].length;
|
|
112
|
-
const signalNames = collectSignalNames(code.slice(bodyStart, Math.min(code.length, bodyStart + 2e3)));
|
|
113
|
-
components.push({
|
|
114
|
-
name,
|
|
115
|
-
file: relFile,
|
|
116
|
-
hasSignals: signalNames.length > 0,
|
|
117
|
-
signalNames,
|
|
118
|
-
props
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
return components;
|
|
122
|
-
}
|
|
123
|
-
function extractComponents(files, _cwd) {
|
|
124
|
-
const components = [];
|
|
125
|
-
for (const file of files) {
|
|
126
|
-
let code;
|
|
127
|
-
try {
|
|
128
|
-
code = fs.readFileSync(file, "utf-8");
|
|
129
|
-
} catch {
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
const relFile = path.relative(_cwd, file);
|
|
133
|
-
for (const comp of extractComponentsFromCode(code, relFile)) components.push(comp);
|
|
134
|
-
}
|
|
135
|
-
return components;
|
|
136
|
-
}
|
|
137
|
-
function extractIslands(files, cwd) {
|
|
138
|
-
const islands = [];
|
|
139
|
-
for (const file of files) {
|
|
140
|
-
let code;
|
|
141
|
-
try {
|
|
142
|
-
code = fs.readFileSync(file, "utf-8");
|
|
143
|
-
} catch {
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
const islandRe = /island\s*\(\s*\(\)\s*=>\s*import\(.+?\)\s*,\s*\{[^}]*name\s*:\s*["']([^"']+)["'][^}]*?(?:hydrate\s*:\s*["']([^"']+)["'])?[^}]*\}/g;
|
|
147
|
-
let match;
|
|
148
|
-
while (true) {
|
|
149
|
-
match = islandRe.exec(code);
|
|
150
|
-
if (!match) break;
|
|
151
|
-
if (match[1]) islands.push({
|
|
152
|
-
name: match[1],
|
|
153
|
-
file: path.relative(cwd, file),
|
|
154
|
-
hydrate: match[2] ?? "load"
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return islands;
|
|
159
|
-
}
|
|
160
|
-
function extractParams(routePath) {
|
|
161
|
-
const params = [];
|
|
162
|
-
const paramRe = /:(\w+)\??/g;
|
|
163
|
-
let match;
|
|
164
|
-
while (true) {
|
|
165
|
-
match = paramRe.exec(routePath);
|
|
166
|
-
if (!match) break;
|
|
167
|
-
if (match[1]) params.push(match[1]);
|
|
168
|
-
}
|
|
169
|
-
return params;
|
|
170
|
-
}
|
|
171
|
-
function readVersion(cwd) {
|
|
172
|
-
try {
|
|
173
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf-8"));
|
|
174
|
-
const deps = {
|
|
175
|
-
...pkg.dependencies,
|
|
176
|
-
...pkg.devDependencies
|
|
177
|
-
};
|
|
178
|
-
for (const [name, version] of Object.entries(deps)) if (name.startsWith("@pyreon/") && typeof version === "string") return version.replace(/^[\^~]/, "");
|
|
179
|
-
return pkg.version || "unknown";
|
|
180
|
-
} catch {
|
|
181
|
-
return "unknown";
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
function shouldSkipEntry(entry) {
|
|
185
|
-
if (!entry.isDirectory()) return false;
|
|
186
|
-
return entry.name.startsWith(".") || tsxIgnoreDirs.has(entry.name);
|
|
187
|
-
}
|
|
188
|
-
function walkTsxFiles(dir, results) {
|
|
189
|
-
let entries;
|
|
190
|
-
try {
|
|
191
|
-
entries = fs.readdirSync(dir, {
|
|
192
|
-
withFileTypes: true
|
|
193
|
-
});
|
|
194
|
-
} catch {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
for (const entry of entries) {
|
|
198
|
-
if (shouldSkipEntry(entry)) continue;
|
|
199
|
-
const fullPath = path.join(dir, entry.name);
|
|
200
|
-
if (entry.isDirectory()) walkTsxFiles(fullPath, results);else if (entry.isFile() && tsxExtensions.has(path.extname(entry.name))) results.push(fullPath);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
function collectTsxFiles(cwd) {
|
|
204
|
-
const results = [];
|
|
205
|
-
walkTsxFiles(cwd, results);
|
|
206
|
-
return results;
|
|
207
|
-
}
|
|
208
26
|
function ensureGitignore(cwd) {
|
|
209
27
|
const gitignorePath = path.join(cwd, ".gitignore");
|
|
210
28
|
try {
|
package/lib/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/context.ts","../../src/doctor.ts","../../src/index.ts"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":["scanProject"],"sources":["../../src/context.ts","../../src/doctor.ts","../../src/index.ts"],"mappings":"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"}
|
package/lib/types/index2.d.ts
CHANGED
|
@@ -1,47 +1,11 @@
|
|
|
1
|
+
import { ProjectContext, ProjectContext as ProjectContext$1 } from "@pyreon/compiler";
|
|
2
|
+
|
|
1
3
|
//#region src/context.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* pyreon context — generates .pyreon/context.json for AI tool consumption
|
|
4
|
-
*
|
|
5
|
-
* Scans the project to extract:
|
|
6
|
-
* - Route definitions (paths, params, loaders, guards)
|
|
7
|
-
* - Component inventory (file, props, signals)
|
|
8
|
-
* - Island declarations (name, hydration strategy)
|
|
9
|
-
* - Framework version
|
|
10
|
-
*/
|
|
11
4
|
interface ContextOptions {
|
|
12
5
|
cwd: string;
|
|
13
6
|
outPath?: string | undefined;
|
|
14
7
|
}
|
|
15
|
-
|
|
16
|
-
path: string;
|
|
17
|
-
name?: string | undefined;
|
|
18
|
-
component?: string | undefined;
|
|
19
|
-
hasLoader: boolean;
|
|
20
|
-
hasGuard: boolean;
|
|
21
|
-
params: string[];
|
|
22
|
-
children?: RouteInfo[] | undefined;
|
|
23
|
-
}
|
|
24
|
-
interface ComponentInfo {
|
|
25
|
-
name: string;
|
|
26
|
-
file: string;
|
|
27
|
-
hasSignals: boolean;
|
|
28
|
-
signalNames: string[];
|
|
29
|
-
props: string[];
|
|
30
|
-
}
|
|
31
|
-
interface IslandInfo {
|
|
32
|
-
name: string;
|
|
33
|
-
file: string;
|
|
34
|
-
hydrate: string;
|
|
35
|
-
}
|
|
36
|
-
interface ProjectContext {
|
|
37
|
-
framework: "pyreon";
|
|
38
|
-
version: string;
|
|
39
|
-
generatedAt: string;
|
|
40
|
-
routes: RouteInfo[];
|
|
41
|
-
components: ComponentInfo[];
|
|
42
|
-
islands: IslandInfo[];
|
|
43
|
-
}
|
|
44
|
-
declare function generateContext(options: ContextOptions): Promise<ProjectContext>;
|
|
8
|
+
declare function generateContext(options: ContextOptions): Promise<ProjectContext$1>;
|
|
45
9
|
//#endregion
|
|
46
10
|
//#region src/doctor.d.ts
|
|
47
11
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/context.ts","../../src/doctor.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/context.ts","../../src/doctor.ts"],"mappings":";;;UAaiB,cAAA;EACf,GAAA;EACA,OAAA;AAAA;AAAA,iBAGoB,eAAA,CAAgB,OAAA,EAAS,cAAA,GAAiB,OAAA,CAAQ,gBAAA;;;;;;AALxE;;;;;AAKA;;;;;;;UCOiB,aAAA;EACf,GAAA;EACA,IAAA;EACA,EAAA;EACA,GAAA;AAAA;AAAA,iBAqBoB,MAAA,CAAO,OAAA,EAAS,aAAA,GAAgB,OAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "CLI tools for Pyreon — doctor, generate, context",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"prepublishOnly": "bun run build"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@pyreon/compiler": "
|
|
45
|
+
"@pyreon/compiler": "0.5.1"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"typescript": ">=5.0.0"
|
package/src/context.ts
CHANGED
|
@@ -1,70 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* pyreon context — generates .pyreon/context.json for AI tool consumption
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Component inventory (file, props, signals)
|
|
7
|
-
* - Island declarations (name, hydration strategy)
|
|
8
|
-
* - Framework version
|
|
4
|
+
* Delegates scanning to @pyreon/compiler's unified project scanner,
|
|
5
|
+
* then writes the result to disk and ensures .pyreon/ is gitignored.
|
|
9
6
|
*/
|
|
10
7
|
|
|
11
8
|
import * as fs from "node:fs"
|
|
12
9
|
import * as path from "node:path"
|
|
10
|
+
import { type ProjectContext, generateContext as scanProject } from "@pyreon/compiler"
|
|
11
|
+
|
|
12
|
+
export type { ComponentInfo, IslandInfo, ProjectContext, RouteInfo } from "@pyreon/compiler"
|
|
13
13
|
|
|
14
14
|
export interface ContextOptions {
|
|
15
15
|
cwd: string
|
|
16
16
|
outPath?: string | undefined
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export interface RouteInfo {
|
|
20
|
-
path: string
|
|
21
|
-
name?: string | undefined
|
|
22
|
-
component?: string | undefined
|
|
23
|
-
hasLoader: boolean
|
|
24
|
-
hasGuard: boolean
|
|
25
|
-
params: string[]
|
|
26
|
-
children?: RouteInfo[] | undefined
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface ComponentInfo {
|
|
30
|
-
name: string
|
|
31
|
-
file: string
|
|
32
|
-
hasSignals: boolean
|
|
33
|
-
signalNames: string[]
|
|
34
|
-
props: string[]
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface IslandInfo {
|
|
38
|
-
name: string
|
|
39
|
-
file: string
|
|
40
|
-
hydrate: string
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface ProjectContext {
|
|
44
|
-
framework: "pyreon"
|
|
45
|
-
version: string
|
|
46
|
-
generatedAt: string
|
|
47
|
-
routes: RouteInfo[]
|
|
48
|
-
components: ComponentInfo[]
|
|
49
|
-
islands: IslandInfo[]
|
|
50
|
-
}
|
|
51
|
-
|
|
52
19
|
export async function generateContext(options: ContextOptions): Promise<ProjectContext> {
|
|
53
|
-
const
|
|
54
|
-
const sourceFiles = collectTsxFiles(options.cwd)
|
|
55
|
-
|
|
56
|
-
const routes = extractRoutes(sourceFiles, options.cwd)
|
|
57
|
-
const components = extractComponents(sourceFiles, options.cwd)
|
|
58
|
-
const islands = extractIslands(sourceFiles, options.cwd)
|
|
59
|
-
|
|
60
|
-
const context: ProjectContext = {
|
|
61
|
-
framework: "pyreon",
|
|
62
|
-
version,
|
|
63
|
-
generatedAt: new Date().toISOString(),
|
|
64
|
-
routes,
|
|
65
|
-
components,
|
|
66
|
-
islands,
|
|
67
|
-
}
|
|
20
|
+
const context = scanProject(options.cwd)
|
|
68
21
|
|
|
69
22
|
// Write to .pyreon/context.json
|
|
70
23
|
const outDir = options.outPath ? path.dirname(options.outPath) : path.join(options.cwd, ".pyreon")
|
|
@@ -80,238 +33,12 @@ export async function generateContext(options: ContextOptions): Promise<ProjectC
|
|
|
80
33
|
|
|
81
34
|
const relOut = path.relative(options.cwd, outFile)
|
|
82
35
|
console.log(
|
|
83
|
-
` ✓ Generated ${relOut} (${components.length} components, ${routes.length} routes, ${islands.length} islands)`,
|
|
36
|
+
` ✓ Generated ${relOut} (${context.components.length} components, ${context.routes.length} routes, ${context.islands.length} islands)`,
|
|
84
37
|
)
|
|
85
38
|
|
|
86
39
|
return context
|
|
87
40
|
}
|
|
88
41
|
|
|
89
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
90
|
-
// Extractors
|
|
91
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
92
|
-
|
|
93
|
-
function parseRouteFromBlock(block: string, routeMatch: RegExpExecArray): RouteInfo {
|
|
94
|
-
const routePath = routeMatch[1] ?? ""
|
|
95
|
-
const params = extractParams(routePath)
|
|
96
|
-
|
|
97
|
-
const surroundingStart = Math.max(0, routeMatch.index - 50)
|
|
98
|
-
const surroundingEnd = Math.min(block.length, routeMatch.index + 200)
|
|
99
|
-
const surrounding = block.slice(surroundingStart, surroundingEnd)
|
|
100
|
-
|
|
101
|
-
const hasLoader = /loader\s*:/.test(surrounding)
|
|
102
|
-
const hasGuard = /beforeEnter\s*:|beforeLeave\s*:/.test(surrounding)
|
|
103
|
-
const nameMatch = surrounding.match(/name\s*:\s*["']([^"']+)["']/)
|
|
104
|
-
|
|
105
|
-
return {
|
|
106
|
-
path: routePath,
|
|
107
|
-
name: nameMatch?.[1],
|
|
108
|
-
hasLoader,
|
|
109
|
-
hasGuard,
|
|
110
|
-
params,
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function extractRoutesFromBlock(block: string): RouteInfo[] {
|
|
115
|
-
const routes: RouteInfo[] = []
|
|
116
|
-
const routeObjRe = /path\s*:\s*["']([^"']+)["']/g
|
|
117
|
-
let routeMatch: RegExpExecArray | null
|
|
118
|
-
while (true) {
|
|
119
|
-
routeMatch = routeObjRe.exec(block)
|
|
120
|
-
if (!routeMatch) break
|
|
121
|
-
routes.push(parseRouteFromBlock(block, routeMatch))
|
|
122
|
-
}
|
|
123
|
-
return routes
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function extractRoutes(files: string[], _cwd: string): RouteInfo[] {
|
|
127
|
-
const routes: RouteInfo[] = []
|
|
128
|
-
|
|
129
|
-
for (const file of files) {
|
|
130
|
-
let code: string
|
|
131
|
-
try {
|
|
132
|
-
code = fs.readFileSync(file, "utf-8")
|
|
133
|
-
} catch {
|
|
134
|
-
continue
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const routeArrayRe =
|
|
138
|
-
/(?:createRouter\s*\(\s*\[|(?:const|let)\s+routes\s*(?::\s*RouteRecord\[\])?\s*=\s*\[)([\s\S]*?)\]/g
|
|
139
|
-
let match: RegExpExecArray | null
|
|
140
|
-
while (true) {
|
|
141
|
-
match = routeArrayRe.exec(code)
|
|
142
|
-
if (!match) break
|
|
143
|
-
const block = match[1] ?? ""
|
|
144
|
-
for (const route of extractRoutesFromBlock(block)) {
|
|
145
|
-
routes.push(route)
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return routes
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function parseProps(propsStr: string): string[] {
|
|
154
|
-
return propsStr
|
|
155
|
-
.split(",")
|
|
156
|
-
.map((p) => p.trim().split(":")[0]?.split("=")[0]?.trim() ?? "")
|
|
157
|
-
.filter((p) => p && p !== "props")
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function collectSignalNames(body: string): string[] {
|
|
161
|
-
const signalNames: string[] = []
|
|
162
|
-
const signalRe = /(?:const|let)\s+(\w+)\s*=\s*signal\s*[<(]/g
|
|
163
|
-
let sigMatch: RegExpExecArray | null
|
|
164
|
-
while (true) {
|
|
165
|
-
sigMatch = signalRe.exec(body)
|
|
166
|
-
if (!sigMatch) break
|
|
167
|
-
if (sigMatch[1]) signalNames.push(sigMatch[1])
|
|
168
|
-
}
|
|
169
|
-
return signalNames
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function extractComponentsFromCode(code: string, relFile: string): ComponentInfo[] {
|
|
173
|
-
const components: ComponentInfo[] = []
|
|
174
|
-
const componentRe =
|
|
175
|
-
/(?:export\s+)?(?:const|function)\s+([A-Z]\w*)\s*(?::\s*ComponentFn<[^>]+>\s*)?=?\s*\(?(?:\s*\{?\s*([^)]*?)\s*\}?\s*)?\)?\s*(?:=>|{)/g
|
|
176
|
-
let match: RegExpExecArray | null
|
|
177
|
-
|
|
178
|
-
while (true) {
|
|
179
|
-
match = componentRe.exec(code)
|
|
180
|
-
if (!match) break
|
|
181
|
-
const name = match[1] ?? "Unknown"
|
|
182
|
-
const props = parseProps(match[2] ?? "")
|
|
183
|
-
|
|
184
|
-
const bodyStart = match.index + match[0].length
|
|
185
|
-
const body = code.slice(bodyStart, Math.min(code.length, bodyStart + 2000))
|
|
186
|
-
const signalNames = collectSignalNames(body)
|
|
187
|
-
|
|
188
|
-
components.push({
|
|
189
|
-
name,
|
|
190
|
-
file: relFile,
|
|
191
|
-
hasSignals: signalNames.length > 0,
|
|
192
|
-
signalNames,
|
|
193
|
-
props,
|
|
194
|
-
})
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return components
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function extractComponents(files: string[], _cwd: string): ComponentInfo[] {
|
|
201
|
-
const components: ComponentInfo[] = []
|
|
202
|
-
|
|
203
|
-
for (const file of files) {
|
|
204
|
-
let code: string
|
|
205
|
-
try {
|
|
206
|
-
code = fs.readFileSync(file, "utf-8")
|
|
207
|
-
} catch {
|
|
208
|
-
continue
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const relFile = path.relative(_cwd, file)
|
|
212
|
-
for (const comp of extractComponentsFromCode(code, relFile)) {
|
|
213
|
-
components.push(comp)
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return components
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function extractIslands(files: string[], cwd: string): IslandInfo[] {
|
|
221
|
-
const islands: IslandInfo[] = []
|
|
222
|
-
|
|
223
|
-
for (const file of files) {
|
|
224
|
-
let code: string
|
|
225
|
-
try {
|
|
226
|
-
code = fs.readFileSync(file, "utf-8")
|
|
227
|
-
} catch {
|
|
228
|
-
continue
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const islandRe =
|
|
232
|
-
/island\s*\(\s*\(\)\s*=>\s*import\(.+?\)\s*,\s*\{[^}]*name\s*:\s*["']([^"']+)["'][^}]*?(?:hydrate\s*:\s*["']([^"']+)["'])?[^}]*\}/g
|
|
233
|
-
let match: RegExpExecArray | null
|
|
234
|
-
while (true) {
|
|
235
|
-
match = islandRe.exec(code)
|
|
236
|
-
if (!match) break
|
|
237
|
-
if (match[1]) {
|
|
238
|
-
islands.push({
|
|
239
|
-
name: match[1],
|
|
240
|
-
file: path.relative(cwd, file),
|
|
241
|
-
hydrate: match[2] ?? "load",
|
|
242
|
-
})
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return islands
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
251
|
-
// Helpers
|
|
252
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
253
|
-
|
|
254
|
-
function extractParams(routePath: string): string[] {
|
|
255
|
-
const params: string[] = []
|
|
256
|
-
const paramRe = /:(\w+)\??/g
|
|
257
|
-
let match: RegExpExecArray | null
|
|
258
|
-
while (true) {
|
|
259
|
-
match = paramRe.exec(routePath)
|
|
260
|
-
if (!match) break
|
|
261
|
-
if (match[1]) params.push(match[1])
|
|
262
|
-
}
|
|
263
|
-
return params
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function readVersion(cwd: string): string {
|
|
267
|
-
try {
|
|
268
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf-8"))
|
|
269
|
-
const deps: Record<string, unknown> = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
270
|
-
for (const [name, version] of Object.entries(deps)) {
|
|
271
|
-
if (name.startsWith("@pyreon/") && typeof version === "string") {
|
|
272
|
-
return version.replace(/^[\^~]/, "")
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return (pkg.version as string) || "unknown"
|
|
276
|
-
} catch {
|
|
277
|
-
return "unknown"
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const tsxExtensions = new Set([".tsx", ".jsx", ".ts", ".js"])
|
|
282
|
-
const tsxIgnoreDirs = new Set(["node_modules", "dist", "lib", ".pyreon", ".git", "build"])
|
|
283
|
-
|
|
284
|
-
function shouldSkipEntry(entry: fs.Dirent): boolean {
|
|
285
|
-
if (!entry.isDirectory()) return false
|
|
286
|
-
return entry.name.startsWith(".") || tsxIgnoreDirs.has(entry.name)
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
function walkTsxFiles(dir: string, results: string[]): void {
|
|
290
|
-
let entries: fs.Dirent[]
|
|
291
|
-
try {
|
|
292
|
-
entries = fs.readdirSync(dir, { withFileTypes: true })
|
|
293
|
-
} catch {
|
|
294
|
-
return
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
for (const entry of entries) {
|
|
298
|
-
if (shouldSkipEntry(entry)) continue
|
|
299
|
-
|
|
300
|
-
const fullPath = path.join(dir, entry.name)
|
|
301
|
-
if (entry.isDirectory()) {
|
|
302
|
-
walkTsxFiles(fullPath, results)
|
|
303
|
-
} else if (entry.isFile() && tsxExtensions.has(path.extname(entry.name))) {
|
|
304
|
-
results.push(fullPath)
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
function collectTsxFiles(cwd: string): string[] {
|
|
310
|
-
const results: string[] = []
|
|
311
|
-
walkTsxFiles(cwd, results)
|
|
312
|
-
return results
|
|
313
|
-
}
|
|
314
|
-
|
|
315
42
|
function ensureGitignore(cwd: string): void {
|
|
316
43
|
const gitignorePath = path.join(cwd, ".gitignore")
|
|
317
44
|
try {
|