解析entity定义和创建oak组件功能初始化
This commit is contained in:
parent
dab1e738b1
commit
8fab2de5dc
75
esbuild.js
75
esbuild.js
|
|
@ -1,45 +1,90 @@
|
|||
const esbuild = require("esbuild");
|
||||
|
||||
const production = process.argv.includes('--production');
|
||||
const watch = process.argv.includes('--watch');
|
||||
const production = process.argv.includes("--production");
|
||||
const watch = process.argv.includes("--watch");
|
||||
const path = require("path");
|
||||
const fs = require("fs").promises;
|
||||
|
||||
/**
|
||||
* 递归复制目录
|
||||
* @param {string} src 源目录
|
||||
* @param {string} dest 目标目录
|
||||
*/
|
||||
async function copyDir(src, dest) {
|
||||
await fs.mkdir(dest, { recursive: true });
|
||||
let entries = await fs.readdir(src, { withFileTypes: true });
|
||||
|
||||
for (let entry of entries) {
|
||||
let srcPath = path.join(src, entry.name);
|
||||
let destPath = path.join(dest, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
await copyDir(srcPath, destPath);
|
||||
} else {
|
||||
await fs.copyFile(srcPath, destPath);
|
||||
console.log(`Copied ${srcPath} to ${destPath}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {import('esbuild').Plugin}
|
||||
*/
|
||||
const copyTemplatesPlugin = {
|
||||
name: "copy-templates",
|
||||
setup(build) {
|
||||
build.onEnd(async () => {
|
||||
const srcDir = path.join(__dirname, "src", "templates");
|
||||
const destDir = path.join(__dirname, "dist", "templates");
|
||||
|
||||
try {
|
||||
await copyDir(srcDir, destDir);
|
||||
console.log("Templates copied successfully");
|
||||
} catch (err) {
|
||||
console.error("Error copying templates:", err);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {import('esbuild').Plugin}
|
||||
*/
|
||||
const esbuildProblemMatcherPlugin = {
|
||||
name: 'esbuild-problem-matcher',
|
||||
name: "esbuild-problem-matcher",
|
||||
|
||||
setup(build) {
|
||||
build.onStart(() => {
|
||||
console.log('[watch] build started');
|
||||
console.log("[watch] build started");
|
||||
});
|
||||
build.onEnd((result) => {
|
||||
result.errors.forEach(({ text, location }) => {
|
||||
console.error(`✘ [ERROR] ${text}`);
|
||||
console.error(` ${location.file}:${location.line}:${location.column}:`);
|
||||
console.error(
|
||||
` ${location.file}:${location.line}:${location.column}:`
|
||||
);
|
||||
});
|
||||
console.log('[watch] build finished');
|
||||
console.log("[watch] build finished");
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
async function main() {
|
||||
const ctx = await esbuild.context({
|
||||
entryPoints: [
|
||||
'src/extension.ts'
|
||||
],
|
||||
entryPoints: ["src/extension.ts"],
|
||||
bundle: true,
|
||||
format: 'cjs',
|
||||
format: "cjs",
|
||||
minify: production,
|
||||
sourcemap: !production,
|
||||
sourcesContent: false,
|
||||
platform: 'node',
|
||||
outfile: 'dist/extension.js',
|
||||
external: ['vscode'],
|
||||
logLevel: 'silent',
|
||||
platform: "node",
|
||||
outfile: "dist/extension.js",
|
||||
external: ["vscode"],
|
||||
logLevel: "silent",
|
||||
plugins: [
|
||||
/* add to the end of plugins array */
|
||||
esbuildProblemMatcherPlugin,
|
||||
copyTemplatesPlugin,
|
||||
],
|
||||
});
|
||||
if (watch) {
|
||||
|
|
@ -50,7 +95,7 @@ async function main() {
|
|||
}
|
||||
}
|
||||
|
||||
main().catch(e => {
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
|
|||
35
package.json
35
package.json
|
|
@ -22,8 +22,21 @@
|
|||
{
|
||||
"command": "oak-assistant.check-pages-and-namespace",
|
||||
"title": "检查page和namespace对应关系"
|
||||
},
|
||||
{
|
||||
"command": "oak-assistant.create-oak-component",
|
||||
"title": "创建OAK组件"
|
||||
}
|
||||
]
|
||||
],
|
||||
"menus": {
|
||||
"explorer/context": [
|
||||
{
|
||||
"when": "explorerResourceIsFolder",
|
||||
"command": "oak-assistant.create-oak-component",
|
||||
"group": "navigation"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "pnpm run package",
|
||||
|
|
@ -40,16 +53,22 @@
|
|||
"test": "vscode-test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "^1.94.0",
|
||||
"@types/lodash": "^4.17.12",
|
||||
"@types/mocha": "^10.0.8",
|
||||
"@types/node": "20.x",
|
||||
"@types/node-schedule": "^2.1.7",
|
||||
"@types/vscode": "^1.94.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.7.0",
|
||||
"@typescript-eslint/parser": "^8.7.0",
|
||||
"eslint": "^9.11.1",
|
||||
"esbuild": "^0.24.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"typescript": "^5.6.2",
|
||||
"@vscode/test-cli": "^0.0.10",
|
||||
"@vscode/test-electron": "^2.4.1"
|
||||
"@vscode/test-electron": "^2.4.1",
|
||||
"esbuild": "^0.24.0",
|
||||
"eslint": "^9.11.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"oak-domain": "^5.1.6",
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.21"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,13 +4,24 @@ settings:
|
|||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
lodash:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
|
||||
devDependencies:
|
||||
'@types/lodash':
|
||||
specifier: ^4.17.12
|
||||
version: 4.17.12
|
||||
'@types/mocha':
|
||||
specifier: ^10.0.8
|
||||
version: 10.0.9
|
||||
'@types/node':
|
||||
specifier: 20.x
|
||||
version: 20.16.12
|
||||
'@types/node-schedule':
|
||||
specifier: ^2.1.7
|
||||
version: 2.1.7
|
||||
'@types/vscode':
|
||||
specifier: ^1.94.0
|
||||
version: 1.94.0
|
||||
|
|
@ -35,6 +46,9 @@ devDependencies:
|
|||
npm-run-all:
|
||||
specifier: ^4.1.5
|
||||
version: 4.1.5
|
||||
oak-domain:
|
||||
specifier: ^5.1.6
|
||||
version: 5.1.6
|
||||
typescript:
|
||||
specifier: ^5.6.2
|
||||
version: 5.6.3
|
||||
|
|
@ -422,10 +436,20 @@ packages:
|
|||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
dev: true
|
||||
|
||||
/@types/lodash@4.17.12:
|
||||
resolution: {integrity: sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==}
|
||||
dev: true
|
||||
|
||||
/@types/mocha@10.0.9:
|
||||
resolution: {integrity: sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==}
|
||||
dev: true
|
||||
|
||||
/@types/node-schedule@2.1.7:
|
||||
resolution: {integrity: sha512-G7Z3R9H7r3TowoH6D2pkzUHPhcJrDF4Jz1JOQ80AX0K2DWTHoN9VC94XzFAPNMdbW9TBzMZ3LjpFi7RYdbxtXA==}
|
||||
dependencies:
|
||||
'@types/node': 20.16.12
|
||||
dev: true
|
||||
|
||||
/@types/node@20.16.12:
|
||||
resolution: {integrity: sha512-LfPFB0zOeCeCNQV3i+67rcoVvoN5n0NVuR2vLG0O5ySQMgchuZlC4lgz546ZOJyDtj5KIgOxy+lacOimfqZAIA==}
|
||||
dependencies:
|
||||
|
|
@ -888,6 +912,13 @@ packages:
|
|||
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||
dev: true
|
||||
|
||||
/cron-parser@4.9.0:
|
||||
resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
dependencies:
|
||||
luxon: 3.5.0
|
||||
dev: true
|
||||
|
||||
/cross-spawn@6.0.5:
|
||||
resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
|
||||
engines: {node: '>=4.8'}
|
||||
|
|
@ -935,6 +966,10 @@ packages:
|
|||
is-data-view: 1.0.1
|
||||
dev: true
|
||||
|
||||
/dayjs@1.11.13:
|
||||
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||
dev: true
|
||||
|
||||
/debug@4.3.7(supports-color@8.1.1):
|
||||
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
|
|
@ -1854,6 +1889,10 @@ packages:
|
|||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
dev: true
|
||||
|
||||
/lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
dev: false
|
||||
|
||||
/log-symbols@4.1.0:
|
||||
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -1870,10 +1909,19 @@ packages:
|
|||
is-unicode-supported: 1.3.0
|
||||
dev: true
|
||||
|
||||
/long-timeout@0.1.1:
|
||||
resolution: {integrity: sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==}
|
||||
dev: true
|
||||
|
||||
/lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
dev: true
|
||||
|
||||
/luxon@3.5.0:
|
||||
resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==}
|
||||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/make-dir@4.0.0:
|
||||
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -1968,6 +2016,15 @@ packages:
|
|||
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
|
||||
dev: true
|
||||
|
||||
/node-schedule@2.1.1:
|
||||
resolution: {integrity: sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
cron-parser: 4.9.0
|
||||
long-timeout: 0.1.1
|
||||
sorted-array-functions: 1.3.0
|
||||
dev: true
|
||||
|
||||
/normalize-package-data@2.5.0:
|
||||
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
|
||||
dependencies:
|
||||
|
|
@ -1998,6 +2055,15 @@ packages:
|
|||
string.prototype.padend: 3.1.6
|
||||
dev: true
|
||||
|
||||
/oak-domain@5.1.6:
|
||||
resolution: {integrity: sha512-rxWWaC22WpV67h92c6c9nUHgvGA2T61yml4/oFEpVqd7HejV6NlAVJKloZa1oVdW1TUeCrf8XhHe2AYZIB0nYg==}
|
||||
dependencies:
|
||||
dayjs: 1.11.13
|
||||
node-schedule: 2.1.1
|
||||
uuid: 9.0.1
|
||||
webidl-conversions: 5.0.0
|
||||
dev: true
|
||||
|
||||
/object-inspect@1.13.2:
|
||||
resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -2381,6 +2447,10 @@ packages:
|
|||
engines: {node: '>=14'}
|
||||
dev: true
|
||||
|
||||
/sorted-array-functions@1.3.0:
|
||||
resolution: {integrity: sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==}
|
||||
dev: true
|
||||
|
||||
/spdx-correct@3.2.0:
|
||||
resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
|
||||
dependencies:
|
||||
|
|
@ -2655,6 +2725,11 @@ packages:
|
|||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
dev: true
|
||||
|
||||
/uuid@9.0.1:
|
||||
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/v8-to-istanbul@9.3.0:
|
||||
resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
|
||||
engines: {node: '>=10.12.0'}
|
||||
|
|
@ -2671,6 +2746,11 @@ packages:
|
|||
spdx-expression-parse: 3.0.1
|
||||
dev: true
|
||||
|
||||
/webidl-conversions@5.0.0:
|
||||
resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/which-boxed-primitive@1.0.2:
|
||||
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
||||
dependencies:
|
||||
|
|
|
|||
192
src/extension.ts
192
src/extension.ts
|
|
@ -1,93 +1,123 @@
|
|||
import * as vscode from "vscode";
|
||||
import { setProjectHome, pathConfig } from "./paths";
|
||||
import { setProjectHome, pathConfig } from "./utils/paths";
|
||||
import { join } from "path";
|
||||
import { Uri } from "vscode";
|
||||
|
||||
let projectHome: string | undefined;
|
||||
import checkPagesAndNamespace from "./plugins/checkPagesAndNamespace";
|
||||
import { OakConfiog } from "./types/OakConfig";
|
||||
import createOakComponent from "./plugins/createOakComponent";
|
||||
import { analyzeOakAppDomain } from "./utils/entities";
|
||||
|
||||
// 初始化配置
|
||||
// 查找工作区的根目录中的oak.config.json文件
|
||||
vscode.workspace.findFiles("oak.config.json").then((uris) => {
|
||||
if (uris.length === 0) {
|
||||
vscode.window.showErrorMessage("未找到oak.config.json文件");
|
||||
return;
|
||||
}
|
||||
const uri = uris[0];
|
||||
const fs = vscode.workspace.fs;
|
||||
fs.readFile(uri).then((content) => {
|
||||
const config = JSON.parse(content.toString());
|
||||
projectHome = join(uri.path, "../", config.projectHome);
|
||||
console.log("projectHome:", projectHome);
|
||||
// 设置projectHome
|
||||
setProjectHome(projectHome);
|
||||
});
|
||||
// 查找工作区的根目录中的oak.config.json文件,排除src和node_modules目录
|
||||
const exclude: vscode.GlobPattern = new vscode.RelativePattern(
|
||||
"**",
|
||||
"{src,node_modules,lib,configuration}"
|
||||
);
|
||||
|
||||
vscode.workspace.findFiles("oak.config.json", exclude).then((uris) => {
|
||||
if (uris.length === 0) {
|
||||
// 获取当前工作区
|
||||
const workspaceFolders = vscode.workspace.workspaceFolders;
|
||||
|
||||
if (!workspaceFolders || workspaceFolders.length === 0) {
|
||||
vscode.window.showErrorMessage(
|
||||
"未找到工作区,请打开一个文件夹后再试。"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// 弹出提示消息,询问是否以根目录为工作区
|
||||
vscode.window
|
||||
.showInformationMessage(
|
||||
"未找到oak.config.json文件,是否以当前工作区根目录为项目主目录?",
|
||||
"是",
|
||||
"否"
|
||||
)
|
||||
.then((value) => {
|
||||
if (value === "是") {
|
||||
const rootPath = workspaceFolders[0].uri.fsPath;
|
||||
const projectPath = join(rootPath, "./");
|
||||
setProjectHome(projectPath);
|
||||
vscode.window.showInformationMessage(
|
||||
`已将项目主目录设置为: ${projectPath}`
|
||||
);
|
||||
afterPathSet();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
const uri = uris[0];
|
||||
const fs = vscode.workspace.fs;
|
||||
fs.readFile(uri).then((content) => {
|
||||
const config = JSON.parse(content.toString()) as OakConfiog;
|
||||
const projectHome = join(uri.fsPath, "..", config.projectHome);
|
||||
console.log("projectHome:", projectHome);
|
||||
// 设置projectHome
|
||||
setProjectHome(projectHome);
|
||||
// 通知已经启用
|
||||
vscode.window.showInformationMessage("已启用oak-assistant!");
|
||||
afterPathSet();
|
||||
});
|
||||
});
|
||||
|
||||
const afterPathSet = async () => {
|
||||
const stepList: {
|
||||
name: string;
|
||||
description: string;
|
||||
function: () => Promise<void>;
|
||||
}[] = [
|
||||
{
|
||||
name: "解析 Entity",
|
||||
description: "解析项目中的 Entity 结构",
|
||||
function: async () => {
|
||||
await analyzeOakAppDomain(pathConfig.oakAppDomainHome);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: "解析oak项目结构",
|
||||
cancellable: false,
|
||||
},
|
||||
async (progress) => {
|
||||
progress.report({ message: "开始分析..." });
|
||||
try {
|
||||
for (let i = 0; i < stepList.length; i++) {
|
||||
const step = stepList[i];
|
||||
progress.report({
|
||||
message: step.description,
|
||||
increment: 100 / stepList.length,
|
||||
});
|
||||
await step.function();
|
||||
}
|
||||
vscode.window.showInformationMessage("分析完成");
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(`分析过程中出错: ${error}`);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
console.log(
|
||||
'Congratulations, your extension "oak-assistant" is now active!'
|
||||
);
|
||||
console.log(
|
||||
'Congratulations, your extension "oak-assistant" is now active!'
|
||||
);
|
||||
|
||||
const helloOak = vscode.commands.registerCommand(
|
||||
"oak-assistant.hello-oak",
|
||||
() => {
|
||||
vscode.window.showInformationMessage(
|
||||
"Hello OAK from oak-assistant!"
|
||||
);
|
||||
}
|
||||
);
|
||||
const helloOak = vscode.commands.registerCommand(
|
||||
"oak-assistant.hello-oak",
|
||||
() => {
|
||||
vscode.window.showInformationMessage(
|
||||
"Hello OAK from oak-assistant!"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const checkPagesAndNamespace = vscode.commands.registerCommand(
|
||||
"oak-assistant.check-pages-and-namespace",
|
||||
async () => {
|
||||
if (!projectHome) {
|
||||
vscode.window.showErrorMessage(
|
||||
"配置未初始化,请检查oak.config.json文件"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let errorNums: number = 0;
|
||||
const fs = vscode.workspace.fs;
|
||||
const pagesHome = pathConfig.pagesHome;
|
||||
const namespacesHome = pathConfig.namespacesHome;
|
||||
console.log("checking:", pagesHome, namespacesHome);
|
||||
|
||||
try {
|
||||
const namespaces = await fs.readDirectory(
|
||||
Uri.file(namespacesHome)
|
||||
);
|
||||
for (const [namespaceName, namespaceType] of namespaces) {
|
||||
if (namespaceType === vscode.FileType.Directory) {
|
||||
// 只检查 namespacesHome 下的第一层目录
|
||||
const pagePath = join(pagesHome, namespaceName);
|
||||
try {
|
||||
const stat = await fs.stat(Uri.file(pagePath));
|
||||
if (stat.type !== vscode.FileType.Directory) {
|
||||
vscode.window.showErrorMessage(
|
||||
`页面${namespaceName}不存在或不是目录`
|
||||
);
|
||||
errorNums++;
|
||||
}
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(
|
||||
`页面${namespaceName}不存在`
|
||||
);
|
||||
errorNums++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errorNums === 0) {
|
||||
vscode.window.showInformationMessage("检查通过");
|
||||
}
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(`检查过程中发生错误: ${error}`);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
context.subscriptions.push(helloOak, checkPagesAndNamespace);
|
||||
context.subscriptions.push(
|
||||
helloOak,
|
||||
checkPagesAndNamespace(),
|
||||
createOakComponent()
|
||||
);
|
||||
}
|
||||
|
||||
export function deactivate() {}
|
||||
|
|
|
|||
29
src/paths.ts
29
src/paths.ts
|
|
@ -1,29 +0,0 @@
|
|||
export const pathConfig: {
|
||||
projectHome: string;
|
||||
get entityHome(): string;
|
||||
get triggerHome(): string;
|
||||
get checkerHome(): string;
|
||||
get pagesHome(): string;
|
||||
get namespacesHome(): string;
|
||||
} = {
|
||||
projectHome: __dirname,
|
||||
get entityHome() {
|
||||
return `${this.projectHome}\\src\\entities`;
|
||||
},
|
||||
get triggerHome() {
|
||||
return `${this.projectHome}\\src\\triggers`;
|
||||
},
|
||||
get checkerHome() {
|
||||
return `${this.projectHome}\\src\\checkers`;
|
||||
},
|
||||
get pagesHome() {
|
||||
return `${this.projectHome}\\src\\pages`;
|
||||
},
|
||||
get namespacesHome() {
|
||||
return `${this.projectHome}\\web\\src\\app\\namespaces`;
|
||||
}
|
||||
};
|
||||
|
||||
export const setProjectHome = (projectHome: string) => {
|
||||
pathConfig.projectHome = projectHome.substring(1, projectHome.length - 1);
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import * as vscode from "vscode";
|
||||
import { isConfigReady, pathConfig } from "../utils/paths";
|
||||
import { Uri } from "vscode";
|
||||
import { join } from "path";
|
||||
|
||||
const checkPageAndNamespacePlugin = () => {
|
||||
const checkPagesAndNamespace = vscode.commands.registerCommand(
|
||||
"oak-assistant.check-pages-and-namespace",
|
||||
async () => {
|
||||
if (!isConfigReady()) {
|
||||
vscode.window.showErrorMessage(
|
||||
"配置未初始化,请检查oak.config.json文件"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let errorNums: number = 0;
|
||||
const fs = vscode.workspace.fs;
|
||||
const pagesHome = pathConfig.pagesHome;
|
||||
const namespacesHome = pathConfig.namespacesHome;
|
||||
console.log("checking:", pagesHome, namespacesHome);
|
||||
const namespacesList: string[] = [];
|
||||
|
||||
try {
|
||||
const namespaces = await fs.readDirectory(
|
||||
Uri.file(namespacesHome)
|
||||
);
|
||||
for (const [namespaceName, namespaceType] of namespaces) {
|
||||
namespacesList.push(namespaceName);
|
||||
|
||||
if (namespaceType === vscode.FileType.Directory) {
|
||||
// 只检查 namespacesHome 下的第一层目录
|
||||
const pagePath = join(pagesHome, namespaceName);
|
||||
try {
|
||||
const stat = await fs.stat(Uri.file(pagePath));
|
||||
if (stat.type !== vscode.FileType.Directory) {
|
||||
vscode.window.showErrorMessage(
|
||||
`页面${namespaceName}不存在或不是目录`
|
||||
);
|
||||
errorNums++;
|
||||
}
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(
|
||||
`页面${namespaceName}不存在`
|
||||
);
|
||||
errorNums++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errorNums === 0) {
|
||||
vscode.window
|
||||
.showInformationMessage(
|
||||
"检查通过",
|
||||
...namespacesList,
|
||||
"关闭"
|
||||
)
|
||||
.then((value) => {
|
||||
if (value) {
|
||||
if (value === "取消") {
|
||||
return;
|
||||
}
|
||||
// 根据选择的namespace,左侧目录结构定位到对应的页面目录
|
||||
const pagePath = join(pagesHome, value);
|
||||
vscode.commands.executeCommand(
|
||||
"revealInExplorer",
|
||||
Uri.file(pagePath)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(`检查过程中发生错误: ${error}`);
|
||||
}
|
||||
}
|
||||
);
|
||||
return checkPagesAndNamespace;
|
||||
};
|
||||
|
||||
export default checkPageAndNamespacePlugin;
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
import * as vscode from "vscode";
|
||||
import { isFileInDirectory } from "../utils/paths";
|
||||
import { entityConfig } from "../utils/entities";
|
||||
|
||||
type CreateComponentConfig = {
|
||||
entityName: string;
|
||||
isList: boolean;
|
||||
autoProjection: boolean;
|
||||
};
|
||||
|
||||
type ConfigStep = {
|
||||
name: keyof CreateComponentConfig;
|
||||
description: string;
|
||||
inputType: "input" | "select" | "confirm";
|
||||
options?: string[] | (() => string[] | Promise<string[]>);
|
||||
result?: string;
|
||||
};
|
||||
|
||||
const createComponentSteps: ConfigStep[] = [
|
||||
{
|
||||
name: "entityName",
|
||||
description: "请选择实体名称",
|
||||
inputType: "select",
|
||||
options: () => entityConfig.entityNameList,
|
||||
},
|
||||
{
|
||||
name: "isList",
|
||||
description: "是否为列表",
|
||||
inputType: "confirm",
|
||||
},
|
||||
{
|
||||
name: "autoProjection",
|
||||
description: "是否注入Projection",
|
||||
inputType: "confirm",
|
||||
},
|
||||
];
|
||||
|
||||
const createOakComponent = () => {
|
||||
const plugin = vscode.commands.registerCommand(
|
||||
"oak-assistant.create-oak-component",
|
||||
async (uri: vscode.Uri) => {
|
||||
if (!uri) {
|
||||
vscode.window.showErrorMessage("请在文件夹上右键选择此命令。");
|
||||
return;
|
||||
}
|
||||
|
||||
const folderPath = uri.fsPath;
|
||||
const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri);
|
||||
|
||||
if (!workspaceFolder) {
|
||||
vscode.window.showErrorMessage("无法确定工作区文件夹。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isFileInDirectory(folderPath, "pagesHome", "componentsHome")) {
|
||||
vscode.window.showWarningMessage(
|
||||
"选择的文件夹不在 pages或components 目录下,无法创建 OAK 组件。"
|
||||
);
|
||||
}
|
||||
|
||||
const createComponentConfig: CreateComponentConfig = {
|
||||
entityName: "",
|
||||
isList: false,
|
||||
autoProjection: false,
|
||||
};
|
||||
for (const step of createComponentSteps) {
|
||||
if (step.inputType === "input") {
|
||||
const result = await vscode.window.showInputBox({
|
||||
prompt: step.description,
|
||||
});
|
||||
if (result) {
|
||||
(createComponentConfig as any)[step.name] = result;
|
||||
} else {
|
||||
vscode.window.showErrorMessage(
|
||||
"未输入有效值,退出创建。"
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else if (step.inputType === "select") {
|
||||
const options = step.options
|
||||
? step.options instanceof Function
|
||||
? await step.options()
|
||||
: step.options
|
||||
: [];
|
||||
const result = await vscode.window.showQuickPick(options, {
|
||||
placeHolder: step.description,
|
||||
});
|
||||
if (result) {
|
||||
(createComponentConfig as any)[step.name] = result;
|
||||
} else {
|
||||
vscode.window.showErrorMessage(
|
||||
"未选择有效值,退出创建。"
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else if (step.inputType === "confirm") {
|
||||
const result = await vscode.window.showInformationMessage(
|
||||
step.description,
|
||||
"是",
|
||||
"否"
|
||||
);
|
||||
if (result === "是") {
|
||||
(createComponentConfig as any)[step.name] = true;
|
||||
} else {
|
||||
(createComponentConfig as any)[step.name] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vscode.window.showInformationMessage(
|
||||
`创建组件: ${createComponentConfig.entityName}`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return plugin;
|
||||
};
|
||||
|
||||
export default createOakComponent;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export type OakConfiog = {
|
||||
projectHome: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,337 @@
|
|||
import * as vscode from "vscode";
|
||||
import { EntityShape } from "oak-domain/lib/types";
|
||||
import { StorageDesc } from "oak-domain/lib/types/Storage";
|
||||
import { join, dirname } from "path";
|
||||
import fs from "fs";
|
||||
import * as ts from "typescript";
|
||||
|
||||
export type EntityDict = {
|
||||
[key: string]: StorageDesc<EntityShape>;
|
||||
};
|
||||
|
||||
const entityDict: EntityDict = {};
|
||||
|
||||
const genEntityNameList = (): string[] => {
|
||||
return Object.keys(entityDict);
|
||||
};
|
||||
|
||||
export const entityConfig = {
|
||||
get entityNameList() {
|
||||
return genEntityNameList();
|
||||
},
|
||||
};
|
||||
|
||||
function resolveImportPath(importPath: string, currentDir: string): string {
|
||||
if (importPath.startsWith(".")) {
|
||||
return join(currentDir, `${importPath}.ts`);
|
||||
}
|
||||
// 处理非相对路径的导入(如 node_modules)
|
||||
return importPath;
|
||||
}
|
||||
|
||||
function getEvaluateNodeForShorthandProperty(
|
||||
program: ts.Program,
|
||||
node: ts.ShorthandPropertyAssignment,
|
||||
typeChecker: ts.TypeChecker
|
||||
): any {
|
||||
const symbol = typeChecker.getSymbolAtLocation(node.name);
|
||||
if (!symbol) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 获取符号的声明
|
||||
const declarations = symbol.declarations;
|
||||
if (!declarations || declarations.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const declaration = declarations[0];
|
||||
// 从当前文件的所有导入中找到对应的导入
|
||||
const sourceFile = declaration.getSourceFile();
|
||||
let propertyName = "";
|
||||
const importDeclaration = sourceFile.statements.find((statement) => {
|
||||
// 在这里找到import { actions } from "./Actions" 这样的形式
|
||||
if (ts.isImportDeclaration(statement)) {
|
||||
const moduleSpecifier = statement.moduleSpecifier;
|
||||
if (ts.isStringLiteral(moduleSpecifier)) {
|
||||
const imports = statement.importClause?.namedBindings;
|
||||
// 如果导入了node.name
|
||||
if (imports && ts.isNamedImports(imports)) {
|
||||
// 这里需要注意,如果是import { generalActions as actions } from "./Actions" 这样的形式,要拿到as的内容和node.name进行比较
|
||||
return imports.elements.some((element) => {
|
||||
if (ts.isImportSpecifier(element)) {
|
||||
if (element.propertyName) {
|
||||
propertyName = element.propertyName.getText();
|
||||
// 这里要确保是as actions里的actions和node.name进行比较
|
||||
return element
|
||||
.getText()
|
||||
.endsWith(` as ${node.getText()}`);
|
||||
}
|
||||
// 这里是import { actions } from "./Actions" 这样的形式
|
||||
propertyName = element.name.getText();
|
||||
return element.name.getText() === node.getText();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}) as ts.ImportDeclaration | undefined;
|
||||
|
||||
// 这里对包内的genericActions做特殊处理
|
||||
if (propertyName === "genericActions") {
|
||||
return [
|
||||
"count",
|
||||
"stat",
|
||||
"download",
|
||||
"select",
|
||||
"aggregate",
|
||||
"create",
|
||||
"remove",
|
||||
"update",
|
||||
];
|
||||
}
|
||||
|
||||
if (importDeclaration) {
|
||||
// 得到导入的路径
|
||||
const importPath = (
|
||||
importDeclaration.moduleSpecifier as ts.StringLiteral
|
||||
).text;
|
||||
const currentSourceFile = node.getSourceFile();
|
||||
const resolvedPath = resolveImportPath(
|
||||
importPath,
|
||||
dirname(currentSourceFile.fileName)
|
||||
);
|
||||
|
||||
// 创建新的程序来解析导入的文件
|
||||
const importProgram = ts.createProgram(
|
||||
[resolvedPath],
|
||||
program.getCompilerOptions()
|
||||
);
|
||||
const importSourceFile = importProgram.getSourceFile(resolvedPath);
|
||||
|
||||
if (importSourceFile) {
|
||||
let foundDeclaration: ts.Node | undefined;
|
||||
ts.forEachChild(importSourceFile, (child) => {
|
||||
if (ts.isVariableStatement(child)) {
|
||||
const declaration = child.declarationList.declarations[0];
|
||||
if (
|
||||
ts.isIdentifier(declaration.name) &&
|
||||
declaration.name.text === propertyName
|
||||
) {
|
||||
foundDeclaration = declaration;
|
||||
}
|
||||
} else if (
|
||||
ts.isFunctionDeclaration(child) &&
|
||||
child.name &&
|
||||
child.name.text === propertyName
|
||||
) {
|
||||
foundDeclaration = child;
|
||||
} else if (
|
||||
ts.isExportAssignment(child) &&
|
||||
ts.isIdentifier(child.expression) &&
|
||||
child.expression.text === propertyName
|
||||
) {
|
||||
foundDeclaration = child;
|
||||
}
|
||||
});
|
||||
|
||||
if (foundDeclaration) {
|
||||
return evaluateNode(
|
||||
importProgram,
|
||||
foundDeclaration,
|
||||
importProgram.getTypeChecker()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果没有找到导入声明,则假设它是当前文件中的定义
|
||||
return evaluateNode(program, declaration, typeChecker);
|
||||
}
|
||||
|
||||
function evaluateNode(
|
||||
program: ts.Program,
|
||||
node: ts.Node,
|
||||
typeChecker: ts.TypeChecker
|
||||
): any {
|
||||
if (ts.isObjectLiteralExpression(node)) {
|
||||
return node.properties.reduce((obj: any, prop) => {
|
||||
if (ts.isShorthandPropertyAssignment(prop)) {
|
||||
// 得到标识符的名称
|
||||
const name = prop.name.getText();
|
||||
const evaluated = getEvaluateNodeForShorthandProperty(
|
||||
program,
|
||||
prop,
|
||||
typeChecker
|
||||
);
|
||||
obj[name] = evaluated;
|
||||
} else if (ts.isPropertyAssignment(prop)) {
|
||||
const name = prop.name.getText();
|
||||
obj[name] = evaluateNode(
|
||||
program,
|
||||
prop.initializer,
|
||||
typeChecker
|
||||
);
|
||||
}
|
||||
return obj;
|
||||
}, {});
|
||||
} else if (ts.isArrayLiteralExpression(node)) {
|
||||
return node.elements.map((element) =>
|
||||
evaluateNode(program, element, typeChecker)
|
||||
);
|
||||
} else if (ts.isStringLiteral(node)) {
|
||||
return node.text;
|
||||
} else if (ts.isNumericLiteral(node)) {
|
||||
return Number(node.text);
|
||||
} else if (node.kind === ts.SyntaxKind.TrueKeyword) {
|
||||
return true;
|
||||
} else if (node.kind === ts.SyntaxKind.FalseKeyword) {
|
||||
return false;
|
||||
} else if (ts.isIdentifier(node)) {
|
||||
// 处理导入的标识符
|
||||
const symbol = typeChecker.getSymbolAtLocation(node);
|
||||
if (symbol && symbol.valueDeclaration) {
|
||||
return evaluateNode(program, symbol.valueDeclaration, typeChecker);
|
||||
}
|
||||
} else if (ts.isVariableDeclaration(node) && node.initializer) {
|
||||
// 处理变量声明
|
||||
return evaluateNode(program, node.initializer, typeChecker);
|
||||
}
|
||||
// 对于其他类型的节点,可能需要进一步处理
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseDescFile(
|
||||
filePath: string,
|
||||
program: ts.Program
|
||||
): StorageDesc<EntityShape> | null {
|
||||
const sourceFile = program.getSourceFile(filePath);
|
||||
if (!sourceFile) {
|
||||
vscode.window.showWarningMessage(`无法解析文件: ${filePath}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const typeChecker = program.getTypeChecker();
|
||||
let descObject: StorageDesc<EntityShape> | null = null;
|
||||
|
||||
ts.forEachChild(sourceFile, (node) => {
|
||||
if (ts.isVariableStatement(node)) {
|
||||
const declaration = node.declarationList.declarations[0];
|
||||
if (
|
||||
ts.isIdentifier(declaration.name) &&
|
||||
declaration.name.text === "desc"
|
||||
) {
|
||||
if (
|
||||
declaration.initializer &&
|
||||
ts.isObjectLiteralExpression(declaration.initializer)
|
||||
) {
|
||||
descObject = evaluateNode(
|
||||
program,
|
||||
declaration.initializer,
|
||||
typeChecker
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return descObject;
|
||||
}
|
||||
|
||||
export const analyzeOakAppDomain = (path: string) => {
|
||||
const storageFile = join(path, "Storage.ts");
|
||||
|
||||
if (!fs.existsSync(storageFile)) {
|
||||
vscode.window.showErrorMessage(
|
||||
"Storage.ts文件不存在,请先尝试make:domain"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const program = ts.createProgram([storageFile], {});
|
||||
const sourceFile = program.getSourceFile(storageFile);
|
||||
|
||||
if (!sourceFile) {
|
||||
vscode.window.showErrorMessage("无法解析Storage.ts文件");
|
||||
return;
|
||||
}
|
||||
|
||||
let storageSchemaNode: ts.Node | undefined;
|
||||
|
||||
ts.forEachChild(sourceFile, (node) => {
|
||||
if (ts.isVariableStatement(node)) {
|
||||
const declaration = node.declarationList.declarations[0];
|
||||
if (
|
||||
ts.isIdentifier(declaration.name) &&
|
||||
declaration.name.text === "storageSchema"
|
||||
) {
|
||||
storageSchemaNode = declaration.initializer;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (
|
||||
!storageSchemaNode ||
|
||||
!ts.isObjectLiteralExpression(storageSchemaNode)
|
||||
) {
|
||||
vscode.window.showErrorMessage("无法找到storageSchema或格式不正确");
|
||||
return;
|
||||
}
|
||||
|
||||
const importMap: { [key: string]: string } = {};
|
||||
|
||||
ts.forEachChild(sourceFile, (node) => {
|
||||
if (ts.isImportDeclaration(node)) {
|
||||
const moduleSpecifier = node.moduleSpecifier;
|
||||
if (ts.isStringLiteral(moduleSpecifier)) {
|
||||
const importPath = moduleSpecifier.text;
|
||||
const importClause = node.importClause;
|
||||
if (
|
||||
importClause &&
|
||||
importClause.namedBindings &&
|
||||
ts.isNamedImports(importClause.namedBindings)
|
||||
) {
|
||||
importClause.namedBindings.elements.forEach((element) => {
|
||||
if (
|
||||
element.propertyName &&
|
||||
element.propertyName.text === "desc"
|
||||
) {
|
||||
importMap[element.name.text] = importPath;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
storageSchemaNode.properties.forEach((prop) => {
|
||||
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
||||
const entityName = prop.name.text;
|
||||
if (ts.isIdentifier(prop.initializer)) {
|
||||
const descName = prop.initializer.text;
|
||||
const importPath = importMap[descName];
|
||||
if (importPath) {
|
||||
const resolvedPath = resolveImportPath(
|
||||
importPath,
|
||||
dirname(storageFile)
|
||||
);
|
||||
const descObject = parseDescFile(resolvedPath, program);
|
||||
if (descObject) {
|
||||
entityDict[entityName] = descObject;
|
||||
}
|
||||
} else {
|
||||
vscode.window.showWarningMessage(
|
||||
`未找到 ${descName} 的导入路径`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
vscode.window.showWarningMessage(
|
||||
`${entityName} 的值不是预期的标识符`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log("entityDict:", entityDict);
|
||||
};
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
export const pluginPaths: {
|
||||
root: string;
|
||||
get templates(): string;
|
||||
} = {
|
||||
root: __dirname,
|
||||
get templates() {
|
||||
return `${this.root}\\templates`;
|
||||
},
|
||||
};
|
||||
|
||||
console.log("plugin inited:", pluginPaths);
|
||||
|
||||
export const internalPath = {
|
||||
entities: "src\\entities",
|
||||
triggers: "src\\triggers",
|
||||
checkers: "src\\checkers",
|
||||
pages: "src\\pages",
|
||||
namespaces: "web\\src\\app\\namespaces",
|
||||
oakAppDomain: "src\\oak-app-domain",
|
||||
components: "src\\components",
|
||||
};
|
||||
|
||||
export const pathConfig: {
|
||||
projectHome: string;
|
||||
get entityHome(): string;
|
||||
get triggerHome(): string;
|
||||
get checkerHome(): string;
|
||||
get pagesHome(): string;
|
||||
get namespacesHome(): string;
|
||||
get oakAppDomainHome(): string;
|
||||
get componentsHome(): string;
|
||||
} = {
|
||||
projectHome: "",
|
||||
get entityHome() {
|
||||
return `${this.projectHome}\\${internalPath.entities}`;
|
||||
},
|
||||
get triggerHome() {
|
||||
return `${this.projectHome}\\${internalPath.triggers}`;
|
||||
},
|
||||
get checkerHome() {
|
||||
return `${this.projectHome}\\${internalPath.checkers}`;
|
||||
},
|
||||
get pagesHome() {
|
||||
return `${this.projectHome}\\${internalPath.pages}`;
|
||||
},
|
||||
get namespacesHome() {
|
||||
return `${this.projectHome}\\${internalPath.namespaces}`;
|
||||
},
|
||||
get oakAppDomainHome() {
|
||||
return `${this.projectHome}\\${internalPath.oakAppDomain}`;
|
||||
},
|
||||
get componentsHome() {
|
||||
return `${this.projectHome}\\${internalPath.components}`;
|
||||
},
|
||||
};
|
||||
|
||||
export const isConfigReady = (): boolean => {
|
||||
return pathConfig.projectHome !== "";
|
||||
};
|
||||
|
||||
export const setProjectHome = (projectHome: string) => {
|
||||
pathConfig.projectHome = projectHome.endsWith("\\")
|
||||
? projectHome.slice(0, -1)
|
||||
: projectHome;
|
||||
};
|
||||
|
||||
export const isFileInDirectory = (
|
||||
file: string,
|
||||
...directory: (keyof typeof pathConfig)[]
|
||||
): boolean => {
|
||||
return directory.some((dir) => {
|
||||
const pathGetter = pathConfig[dir];
|
||||
return file.startsWith(pathGetter);
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import { join } from "path";
|
||||
import { pluginPaths } from "./paths";
|
||||
import fs from "fs";
|
||||
|
||||
export const templateNames = {
|
||||
index: "index.ts",
|
||||
webPcTsx: "web.pc.tsx",
|
||||
webTsx: "web.tsx",
|
||||
localeZhCN: "locale\\zh_CN.json",
|
||||
styleLess: "style.module.less",
|
||||
} as const;
|
||||
|
||||
export type TemplateName = keyof typeof templateNames;
|
||||
|
||||
export function getTemplateContext(name: TemplateName): string {
|
||||
const templateFolder = pluginPaths.templates;
|
||||
if (!fs.existsSync(templateFolder)) {
|
||||
throw new Error(`Template folder not found: ${templateFolder}`);
|
||||
}
|
||||
const templatePath = join(templateFolder, templateNames[name] + ".template");
|
||||
if (!fs.existsSync(templatePath)) {
|
||||
throw new Error(`Template not found: ${templatePath}`);
|
||||
}
|
||||
const template = fs.readFileSync(templatePath, "utf-8");
|
||||
return template;
|
||||
}
|
||||
|
||||
export function fillTemplate(
|
||||
template: string,
|
||||
data: Record<string, any>
|
||||
): string {
|
||||
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => {
|
||||
return data[key] !== undefined ? data[key] : `{{${key}}}`;
|
||||
});
|
||||
}
|
||||
|
||||
export const getFilledTemplate = (name: TemplateName, data: Record<string, any>) => {
|
||||
const template = getTemplateContext(name);
|
||||
return fillTemplate(template, data);
|
||||
};
|
||||
Loading…
Reference in New Issue