@wikex/admin-kit 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/dist/scanner.d.ts +23 -0
- package/dist/scanner.js +72 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Các thay đổi đáng chú ý của `@wikex/admin-kit` được ghi tại đây theo Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## 0.3.0 - 2026-09-13
|
|
6
|
+
|
|
7
|
+
- Thêm project scanner để phát hiện route Next.js và component React ở build-time.
|
|
8
|
+
- Component có metadata `defineWikexBlock()` hoặc hậu tố `.wikex` được đánh dấu có thể cấu hình trong CMS.
|
|
9
|
+
|
|
5
10
|
## 0.2.1 - 2026-09-12
|
|
6
11
|
|
|
7
12
|
- Publish JavaScript build và type declarations để Payload CLI chạy được trong project độc lập.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type WikexDiscoveredRoute = {
|
|
2
|
+
dynamic: boolean;
|
|
3
|
+
file: string;
|
|
4
|
+
route: string;
|
|
5
|
+
title: string;
|
|
6
|
+
};
|
|
7
|
+
type WikexDiscoveredComponent = {
|
|
8
|
+
editable: boolean;
|
|
9
|
+
file: string;
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
type WikexProjectInventory = {
|
|
13
|
+
components: WikexDiscoveredComponent[];
|
|
14
|
+
routes: WikexDiscoveredRoute[];
|
|
15
|
+
};
|
|
16
|
+
type ScanWikexProjectOptions = {
|
|
17
|
+
appDirectory?: string;
|
|
18
|
+
componentsDirectory?: string;
|
|
19
|
+
cwd?: string;
|
|
20
|
+
};
|
|
21
|
+
declare const scanWikexProject: ({ appDirectory, componentsDirectory, cwd, }?: ScanWikexProjectOptions) => Promise<WikexProjectInventory>;
|
|
22
|
+
|
|
23
|
+
export { type ScanWikexProjectOptions, type WikexDiscoveredComponent, type WikexDiscoveredRoute, type WikexProjectInventory, scanWikexProject };
|
package/dist/scanner.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// src/scanner.ts
|
|
2
|
+
import { readdir, readFile } from "fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
var walk = async (directory) => {
|
|
5
|
+
try {
|
|
6
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
7
|
+
const files = await Promise.all(
|
|
8
|
+
entries.map((entry) => {
|
|
9
|
+
const target = path.join(directory, entry.name);
|
|
10
|
+
return entry.isDirectory() ? walk(target) : Promise.resolve([target]);
|
|
11
|
+
})
|
|
12
|
+
);
|
|
13
|
+
return files.flat();
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (error.code === "ENOENT") return [];
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var routeTitle = (route) => {
|
|
20
|
+
if (route === "/") return "Trang ch\u1EE7";
|
|
21
|
+
return route.split("/").filter(Boolean).at(-1).replace(/\[(?:\.\.\.)?([^\]]+)\]/g, "$1").replace(/[-_]/g, " ").replace(/\b\p{L}/gu, (letter) => letter.toUpperCase());
|
|
22
|
+
};
|
|
23
|
+
var exportedComponentNames = (source, fallback) => {
|
|
24
|
+
const names = /* @__PURE__ */ new Set();
|
|
25
|
+
for (const match of source.matchAll(/export\s+(?:default\s+)?(?:async\s+)?function\s+([A-Z]\w*)/g)) {
|
|
26
|
+
names.add(match[1]);
|
|
27
|
+
}
|
|
28
|
+
for (const match of source.matchAll(/export\s+const\s+([A-Z]\w*)\s*=/g)) {
|
|
29
|
+
names.add(match[1]);
|
|
30
|
+
}
|
|
31
|
+
const defaultMatch = source.match(/export\s+default\s+([A-Z]\w*)/);
|
|
32
|
+
if (defaultMatch) names.add(defaultMatch[1] || fallback);
|
|
33
|
+
return [...names];
|
|
34
|
+
};
|
|
35
|
+
var scanWikexProject = async ({
|
|
36
|
+
appDirectory = "src/app",
|
|
37
|
+
componentsDirectory = "src/components",
|
|
38
|
+
cwd = process.cwd()
|
|
39
|
+
} = {}) => {
|
|
40
|
+
const appRoot = path.resolve(cwd, appDirectory);
|
|
41
|
+
const componentRoot = path.resolve(cwd, componentsDirectory);
|
|
42
|
+
const [appFiles, componentFiles] = await Promise.all([walk(appRoot), walk(componentRoot)]);
|
|
43
|
+
const routes = appFiles.filter((file) => /[/\\]page\.(?:tsx?|jsx?)$/.test(file)).map((file) => {
|
|
44
|
+
const relative = path.relative(appRoot, file).replace(/\\/g, "/");
|
|
45
|
+
const directory = relative.replace(/(?:^|\/)page\.(?:tsx?|jsx?)$/, "");
|
|
46
|
+
const segments = directory.split("/").filter((segment) => segment && !/^\(.+\)$/.test(segment) && !segment.startsWith("@"));
|
|
47
|
+
const route = `/${segments.join("/")}`.replace(/\/$/, "") || "/";
|
|
48
|
+
return {
|
|
49
|
+
dynamic: route.includes("["),
|
|
50
|
+
file: relative,
|
|
51
|
+
route,
|
|
52
|
+
title: routeTitle(route)
|
|
53
|
+
};
|
|
54
|
+
}).filter(({ route }) => !route.startsWith("/admin")).sort((left, right) => left.route.localeCompare(right.route));
|
|
55
|
+
const components = (await Promise.all(
|
|
56
|
+
componentFiles.filter((file) => /\.(?:tsx|jsx)$/.test(file)).map(async (file) => {
|
|
57
|
+
const relative = path.relative(componentRoot, file).replace(/\\/g, "/");
|
|
58
|
+
const source = await readFile(file, "utf8");
|
|
59
|
+
const fallback = path.basename(file).replace(/\.wikex\.(?:tsx|jsx)$|\.(?:tsx|jsx)$/g, "");
|
|
60
|
+
const editable = /\.wikex\.(?:tsx|jsx)$/.test(file) || /\bdefineWikexBlock\s*\(/.test(source);
|
|
61
|
+
return exportedComponentNames(source, fallback).map((name) => ({
|
|
62
|
+
editable,
|
|
63
|
+
file: relative,
|
|
64
|
+
name
|
|
65
|
+
}));
|
|
66
|
+
})
|
|
67
|
+
)).flat().sort((left, right) => left.name.localeCompare(right.name) || left.file.localeCompare(right.file));
|
|
68
|
+
return { components, routes };
|
|
69
|
+
};
|
|
70
|
+
export {
|
|
71
|
+
scanWikexProject
|
|
72
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wikex/admin-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Reusable Payload CMS admin shell, visual editor and typography tools for Wikex projects",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"./project": "./dist/project.js",
|
|
37
37
|
"./rich-text": "./dist/rich-text.js",
|
|
38
38
|
"./rich-text/client": "./dist/rich-text-client.js",
|
|
39
|
+
"./scanner": "./dist/scanner.js",
|
|
39
40
|
"./starter": "./dist/starter.js",
|
|
40
41
|
"./starter/client": "./dist/starter-client.js",
|
|
41
42
|
"./styles": "./src/styles/admin.scss",
|