lwazi 1.3.0 → 1.3.2
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/bin/lwazi.js +5 -0
- package/bin/update.js +73 -0
- package/package.json +1 -1
- package/src/Console/AnalyzeProjectCommand.php +78 -0
- package/src/Console/SetupCommand.php +79 -0
package/bin/lwazi.js
CHANGED
|
@@ -10,6 +10,10 @@ switch (command) {
|
|
|
10
10
|
require("./install");
|
|
11
11
|
break;
|
|
12
12
|
|
|
13
|
+
case "update":
|
|
14
|
+
require("./update");
|
|
15
|
+
break;
|
|
16
|
+
|
|
13
17
|
case "uninstall":
|
|
14
18
|
require("./uninstall");
|
|
15
19
|
break;
|
|
@@ -22,6 +26,7 @@ Commands:
|
|
|
22
26
|
|
|
23
27
|
lwazi install Install Lwazi into this Laravel project
|
|
24
28
|
lwazi install --url <url> Install and crawl website for navigation
|
|
29
|
+
lwazi update Update Lwazi to latest version
|
|
25
30
|
lwazi uninstall Remove Lwazi from this project
|
|
26
31
|
`);
|
|
27
32
|
}
|
package/bin/update.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { execSync } = require("child_process");
|
|
6
|
+
|
|
7
|
+
const projectRoot = process.cwd();
|
|
8
|
+
const targetDir = path.join(projectRoot, "lwazi");
|
|
9
|
+
const packageDir = path.resolve(__dirname, "..");
|
|
10
|
+
|
|
11
|
+
console.log("Updating Lwazi...");
|
|
12
|
+
|
|
13
|
+
if (!fs.existsSync(path.join(projectRoot, "artisan"))) {
|
|
14
|
+
console.error("This is not a Laravel project.");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!fs.existsSync(targetDir)) {
|
|
19
|
+
console.log("Lwazi not installed. Running install instead...");
|
|
20
|
+
require("./install");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.log("Updating Lwazi files...");
|
|
25
|
+
|
|
26
|
+
const ignore = new Set([
|
|
27
|
+
"node_modules",
|
|
28
|
+
".git",
|
|
29
|
+
"package-lock.json"
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
function copyDirectory(src, dest) {
|
|
33
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
34
|
+
|
|
35
|
+
for (const item of fs.readdirSync(src)) {
|
|
36
|
+
if (ignore.has(item)) continue;
|
|
37
|
+
|
|
38
|
+
const s = path.join(src, item);
|
|
39
|
+
const d = path.join(dest, item);
|
|
40
|
+
|
|
41
|
+
if (fs.statSync(s).isDirectory()) {
|
|
42
|
+
copyDirectory(s, d);
|
|
43
|
+
} else {
|
|
44
|
+
fs.copyFileSync(s, d);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
copyDirectory(packageDir, targetDir);
|
|
50
|
+
|
|
51
|
+
console.log("Running composer update...");
|
|
52
|
+
try {
|
|
53
|
+
execSync("composer update lwazi/core --no-interaction", {
|
|
54
|
+
stdio: "inherit",
|
|
55
|
+
cwd: projectRoot,
|
|
56
|
+
shell: true,
|
|
57
|
+
});
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.log("Composer update skipped or failed.");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log("Clearing caches...");
|
|
63
|
+
try {
|
|
64
|
+
execSync("php artisan config:clear && php artisan cache:clear", {
|
|
65
|
+
stdio: "ignore",
|
|
66
|
+
cwd: projectRoot,
|
|
67
|
+
shell: true,
|
|
68
|
+
});
|
|
69
|
+
} catch (e) {
|
|
70
|
+
// Ignore cache errors
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log("\nLwazi updated successfully!");
|
package/package.json
CHANGED
|
@@ -25,6 +25,8 @@ class AnalyzeProjectCommand extends Command
|
|
|
25
25
|
|
|
26
26
|
$crawler = new NavigationCrawler($rootUrl);
|
|
27
27
|
$manifest = $crawler->crawl();
|
|
28
|
+
|
|
29
|
+
$manifest = $this->mergeWithRoutes($manifest, $rootUrl);
|
|
28
30
|
|
|
29
31
|
$storagePath = storage_path('lwazi');
|
|
30
32
|
if (!is_dir($storagePath)) {
|
|
@@ -50,4 +52,80 @@ class AnalyzeProjectCommand extends Command
|
|
|
50
52
|
|
|
51
53
|
return 0;
|
|
52
54
|
}
|
|
55
|
+
|
|
56
|
+
protected function mergeWithRoutes(array $manifest, string $rootUrl): array
|
|
57
|
+
{
|
|
58
|
+
$knowledgePath = storage_path('lwazi/project_knowledge.json');
|
|
59
|
+
if (!file_exists($knowledgePath)) {
|
|
60
|
+
return $manifest;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
$knowledge = json_decode(file_get_contents($knowledgePath), true);
|
|
64
|
+
$routes = $knowledge['routes'] ?? [];
|
|
65
|
+
|
|
66
|
+
if (empty($routes)) {
|
|
67
|
+
return $manifest;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
$root = $this->extractRoot($rootUrl);
|
|
71
|
+
|
|
72
|
+
foreach ($routes as $route) {
|
|
73
|
+
$path = '/' . ltrim($route['uri'], '/');
|
|
74
|
+
|
|
75
|
+
if (in_array($path, ['/storage/{path}', '/sanctum/csrf-cookie'])) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (isset($manifest['flat'][$root . $path])) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
$label = $this->humanizeRoutePath($path);
|
|
84
|
+
|
|
85
|
+
$manifest['nodes'][$root . $path] = [
|
|
86
|
+
'url' => $root . $path,
|
|
87
|
+
'title' => $label,
|
|
88
|
+
'headings' => [$label],
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
$manifest['flat'][$root . $path] = [
|
|
92
|
+
'label' => $label,
|
|
93
|
+
'segments' => array_filter(explode('/', trim($path, '/'))),
|
|
94
|
+
'_path' => $root . $path,
|
|
95
|
+
'_weight' => 2,
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
$manifest['adjacency'][$root . $path] = [];
|
|
99
|
+
|
|
100
|
+
if (!isset($manifest['adjacency'][$root . '/'])) {
|
|
101
|
+
$manifest['adjacency'][$root . '/'] = [];
|
|
102
|
+
}
|
|
103
|
+
$manifest['adjacency'][$root . '/'][] = $root . $path;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return $manifest;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
protected function extractRoot(string $url): string
|
|
110
|
+
{
|
|
111
|
+
$parts = parse_url($url);
|
|
112
|
+
$scheme = $parts['scheme'] ?? 'http';
|
|
113
|
+
$host = $parts['host'] ?? 'localhost';
|
|
114
|
+
$port = $parts['port'] ?? ($scheme === 'https' ? 443 : 80);
|
|
115
|
+
|
|
116
|
+
$root = $scheme . '://' . $host;
|
|
117
|
+
if (($scheme === 'http' && $port !== 80) || ($scheme === 'https' && $port !== 443)) {
|
|
118
|
+
$root .= ':' . $port;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return $root;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
protected function humanizeRoutePath(string $path): string
|
|
125
|
+
{
|
|
126
|
+
$path = preg_replace('/\{[^}]+\}/', '', $path);
|
|
127
|
+
$path = str_replace(['/', '-', '_'], ' ', $path);
|
|
128
|
+
$path = preg_replace('/\s+/', ' ', $path);
|
|
129
|
+
return ucwords(trim($path));
|
|
130
|
+
}
|
|
53
131
|
}
|
|
@@ -111,6 +111,9 @@ class SetupCommand extends Command
|
|
|
111
111
|
try {
|
|
112
112
|
$crawler = new NavigationCrawler($url, true);
|
|
113
113
|
$manifest = $crawler->crawl();
|
|
114
|
+
|
|
115
|
+
$manifest = $this->mergeWithRoutes($manifest, $url);
|
|
116
|
+
|
|
114
117
|
$crawler->saveManifest();
|
|
115
118
|
|
|
116
119
|
$this->info("Crawled " . count($manifest['nodes']) . " pages.");
|
|
@@ -129,4 +132,80 @@ class SetupCommand extends Command
|
|
|
129
132
|
$this->warn('Website crawling failed: ' . $e->getMessage());
|
|
130
133
|
}
|
|
131
134
|
}
|
|
135
|
+
|
|
136
|
+
protected function mergeWithRoutes(array $manifest, string $rootUrl): array
|
|
137
|
+
{
|
|
138
|
+
$knowledgePath = storage_path('lwazi/project_knowledge.json');
|
|
139
|
+
if (!file_exists($knowledgePath)) {
|
|
140
|
+
return $manifest;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
$knowledge = json_decode(file_get_contents($knowledgePath), true);
|
|
144
|
+
$routes = $knowledge['routes'] ?? [];
|
|
145
|
+
|
|
146
|
+
if (empty($routes)) {
|
|
147
|
+
return $manifest;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
$root = $this->extractRoot($rootUrl);
|
|
151
|
+
|
|
152
|
+
foreach ($routes as $route) {
|
|
153
|
+
$path = '/' . ltrim($route['uri'], '/');
|
|
154
|
+
|
|
155
|
+
if (in_array($path, ['/storage/{path}', '/sanctum/csrf-cookie'])) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (isset($manifest['flat'][$root . $path])) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
$label = $this->humanizeRoutePath($path);
|
|
164
|
+
|
|
165
|
+
$manifest['nodes'][$root . $path] = [
|
|
166
|
+
'url' => $root . $path,
|
|
167
|
+
'title' => $label,
|
|
168
|
+
'headings' => [$label],
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
$manifest['flat'][$root . $path] = [
|
|
172
|
+
'label' => $label,
|
|
173
|
+
'segments' => array_filter(explode('/', trim($path, '/'))),
|
|
174
|
+
'_path' => $root . $path,
|
|
175
|
+
'_weight' => 2,
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
$manifest['adjacency'][$root . $path] = [];
|
|
179
|
+
|
|
180
|
+
if (!isset($manifest['adjacency'][$root . '/'])) {
|
|
181
|
+
$manifest['adjacency'][$root . '/'] = [];
|
|
182
|
+
}
|
|
183
|
+
$manifest['adjacency'][$root . '/'][] = $root . $path;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return $manifest;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
protected function extractRoot(string $url): string
|
|
190
|
+
{
|
|
191
|
+
$parts = parse_url($url);
|
|
192
|
+
$scheme = $parts['scheme'] ?? 'http';
|
|
193
|
+
$host = $parts['host'] ?? 'localhost';
|
|
194
|
+
$port = $parts['port'] ?? ($scheme === 'https' ? 443 : 80);
|
|
195
|
+
|
|
196
|
+
$root = $scheme . '://' . $host;
|
|
197
|
+
if (($scheme === 'http' && $port !== 80) || ($scheme === 'https' && $port !== 443)) {
|
|
198
|
+
$root .= ':' . $port;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return $root;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
protected function humanizeRoutePath(string $path): string
|
|
205
|
+
{
|
|
206
|
+
$path = preg_replace('/\{[^}]+\}/', '', $path);
|
|
207
|
+
$path = str_replace(['/', '-', '_'], ' ', $path);
|
|
208
|
+
$path = preg_replace('/\s+/', ' ', $path);
|
|
209
|
+
return ucwords(trim($path));
|
|
210
|
+
}
|
|
132
211
|
}
|