Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor base class #191

Merged
merged 7 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/context/src/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Engine } from '@music163/tango-core';
import type { AbstractCodeWorkspace, Engine } from '@music163/tango-core';
import { IVariableTreeNode, createContext } from '@music163/tango-helpers';

export interface ITangoEngineContext {
Expand All @@ -21,8 +21,12 @@ const [TangoEngineProvider, useTangoEngine] = createContext<ITangoEngineContext>

export { TangoEngineProvider };

/**
* 获取 CodeWorkspace 实例
* @returns
*/
export const useWorkspace = () => {
return useTangoEngine()?.engine.workspace;
return useTangoEngine()?.engine.workspace as AbstractCodeWorkspace;
};

export const useDesigner = () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/factory.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { MenuDataType } from '@music163/tango-helpers';
import { Designer, DesignerViewType, Engine, SimulatorNameType } from './models';
import { IWorkspace } from './models/interfaces';
import { AbstractWorkspace } from './models/abstract-workspace';

interface ICreateEngineOptions {
/**
* 自定义工作区
*/
workspace?: IWorkspace;
workspace?: AbstractWorkspace;
/**
* 菜单信息
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/helpers/ast/traverse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { isDefineService, isDefineStore, isTangoVariable } from '../assert';
import type {
IRouteData,
IStorePropertyData,
ITangoViewNodeData,
IViewNodeData,
IImportDeclarationPayload,
InsertChildPositionType,
IImportSpecifierData,
Expand Down Expand Up @@ -1234,7 +1234,7 @@ export function cloneJSXElement(node: t.JSXElement, overrideProps?: Dict) {
export function traverseViewFile(ast: t.File, idGenerator: IdGenerator) {
const imports: Record<string, IImportSpecifierData[]> = {};
const importedModules: Dict<IImportDeclarationPayload | IImportDeclarationPayload[]> = {};
const nodes: Array<ITangoViewNodeData<t.JSXElement>> = [];
const nodes: Array<IViewNodeData<t.JSXElement>> = [];
const cloneAst = t.cloneNode(ast, true, true);
const cleanAst = clearTrackingData(cloneAst);
const variables: string[] = []; // 使用的 tango 变量
Expand Down
34 changes: 13 additions & 21 deletions packages/core/src/helpers/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,65 +8,57 @@ import { FileType } from './../types';
export function inferFileType(filename: string): FileType {
// 增加 tangoConfigJson Module
if (/\/tango\.config\.json$/.test(filename)) {
return FileType.TangoConfigJson;
return FileType.TangoConfigJsonFile;
}

if (/\/appJson\.json$/.test(filename)) {
return FileType.AppJson;
return FileType.AppJsonFile;
}

if (/\/package\.json$/.test(filename)) {
return FileType.PackageJson;
return FileType.PackageJsonFile;
}

if (/\/routes\.js$/.test(filename)) {
return FileType.RouteModule;
return FileType.JsRouteConfigFile;
}

// 所有 pages 下的 js 文件均认为是有效的 viewModule
if (/\/pages\/.+\.jsx?$/.test(filename)) {
return FileType.JsxViewModule;
return FileType.JsViewFile;
}

// 所有 pages 下的 js 文件均认为是有效的 viewModule
if (/\/pages\/.+\.schema\.json?$/.test(filename)) {
return FileType.JsonViewModule;
return FileType.JsonViewFile;
}

if (/\/(blocks|components)\/index\.js/.test(filename)) {
return FileType.ComponentsEntryModule;
return FileType.JsLocalComponentsEntryFile;
}

if (/\/services\/.+\.js$/.test(filename)) {
return FileType.ServiceModule;
return FileType.JsServiceFile;
}

if (/service\.js$/.test(filename)) {
return FileType.ServiceModule;
return FileType.JsServiceFile;
}

if (/\/stores\/index\.js$/.test(filename)) {
return FileType.StoreEntryModule;
return FileType.JsStoreEntryFile;
}

if (/\/stores\/.+\.js$/.test(filename)) {
return FileType.StoreModule;
return FileType.JsStoreFile;
}

if (/\.jsx?$/.test(filename)) {
return FileType.Module;
return FileType.JsFile;
}

if (/\.json$/.test(filename)) {
return FileType.Json;
}

if (/\.less$/.test(filename)) {
return FileType.Less;
}

if (/\.scss$/.test(filename)) {
return FileType.Scss;
return FileType.JsonFile;
}

return FileType.File;
Expand Down
264 changes: 264 additions & 0 deletions packages/core/src/models/abstract-code-workspace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
import {
Dict,
isStoreVariablePath,
parseServiceVariablePath,
parseStoreVariablePath,
} from '@music163/tango-helpers';
import { inferFileType, getFilepath } from '../helpers';
import { TangoFile } from './file';
import { FileType } from '../types';
import { JsRouteConfigFile } from './js-route-config-file';
import { JsStoreEntryFile } from './js-store-entry-file';
import { JsServiceFile } from './js-service-file';
import { JsViewFile } from './js-view-file';
import { JsLocalComponentsEntryFile } from './js-local-components-entry-file';
import { JsAppEntryFile } from './js-app-entry-file';
import { JsFile } from './js-file';
import { AbstractWorkspace, IWorkspaceInitConfig } from './abstract-workspace';
import { JsonFile } from './json-file';
import { JsStoreFile } from './js-store-file';

/**
* CodeWorkspace 抽象基类
*/
export abstract class AbstractCodeWorkspace extends AbstractWorkspace {
/**
* 模型入口配置模块
*/
storeEntryModule: JsStoreEntryFile;

/**
* 状态管理模块
*/
storeModules: Record<string, JsStoreFile>;

/**
* 数据服务模块
*/
serviceModules: Record<string, JsServiceFile>;

constructor(options: IWorkspaceInitConfig) {
super(options);
this.storeModules = {};
this.serviceModules = {};
if (options?.files) {
this.addFiles(options.files);
}
}

/**
* 添加文件到工作区
* @param filename 文件名
* @param code 代码片段
* @param fileType 模块类型
*/
addFile(filename: string, code: string, fileType?: FileType) {
if (!fileType && filename === this.entry) {
fileType = FileType.JsAppEntryFile;
}
const moduleType = fileType || inferFileType(filename);
const props = {
filename,
code,
type: moduleType,
};

let module;
switch (moduleType) {
case FileType.JsAppEntryFile:
module = new JsAppEntryFile(this, props);
this.jsAppEntryFile = module;
break;
case FileType.JsStoreEntryFile:
module = new JsStoreEntryFile(this, props);
this.storeEntryModule = module;
break;
case FileType.JsLocalComponentsEntryFile:
module = new JsLocalComponentsEntryFile(this, props);
this.componentsEntryModule = module;
break;
case FileType.JsRouteConfigFile: {
module = new JsRouteConfigFile(this, props);
this.routeModule = module;
// check if activeRoute exists
const route = module.routes.find((item) => item.path === this.activeRoute);
if (!route) {
this.setActiveRoute(module.routes[0]?.path);
}
break;
}
case FileType.JsViewFile:
module = new JsViewFile(this, props);
break;
case FileType.JsServiceFile:
module = new JsServiceFile(this, props);
this.serviceModules[module.name] = module;
break;
case FileType.JsStoreFile:
module = new JsStoreFile(this, props);
this.storeModules[module.name] = module;
break;
case FileType.JsFile:
module = new JsFile(this, props);
break;
case FileType.PackageJsonFile:
module = new JsonFile(this, props);
this.packageJson = module;
break;
case FileType.TangoConfigJsonFile:
module = new JsonFile(this, props);
this.tangoConfigJson = module;
break;
case FileType.JsonFile:
module = new JsonFile(this, props);
break;
default:
module = new TangoFile(this, props);
}

this.files.set(filename, module);
}

addServiceFile(serviceName: string, code: string) {
const filename = `/src/services/${serviceName}.js`;
this.addFile(filename, code, FileType.JsServiceFile);
const indexServiceModule = this.serviceModules.index;
indexServiceModule?.addImportDeclaration(`./${serviceName}`, []).update();
}

addStoreFile(storeName: string, code: string) {
const filename = `/src/stores/${storeName}.js`;
this.addFile(filename, code);
if (!this.storeEntryModule) {
this.addFile('/src/stores/index.js', '');
}
this.storeEntryModule.addStore(storeName).update();
}

/**
* 添加新的模型文件
* @deprecated 使用 addStoreFile 代替
*/
addStoreModule(name: string, code: string) {
this.addStoreFile(name, code);
}

/**
* 删除模型文件
* @param name
*/
removeStoreModule(name: string) {
const filename = getFilepath(name, '/src/stores', '.js');
this.storeEntryModule.removeStore(name).update();
this.removeFile(filename);
}

/**
* 添加模型属性
* @param storeName
* @param stateName
* @param initValue
*/
addStoreState(storeName: string, stateName: string, initValue: string) {
this.storeModules[storeName]?.addState(stateName, initValue).update();
}

/**
* 删除模型属性
* @param storeName
* @param stateName
*/
removeStoreState(storeName: string, stateName: string) {
this.storeModules[storeName]?.removeState(stateName).update();
}

/**
* 根据变量路径删除状态变量
* @param variablePath
*/
removeStoreVariable(variablePath: string) {
const { storeName, variableName } = parseStoreVariablePath(variablePath);
this.removeStoreState(storeName, variableName);
}

/**
* 根据变量路径更新状态变量的值
* @param variablePath 变量路径
* @param code 变量代码
*/
updateStoreVariable(variablePath: string, code: string) {
if (isStoreVariablePath(variablePath)) {
const { storeName, variableName } = parseStoreVariablePath(variablePath);
this.storeModules[storeName]?.updateState(variableName, code).update();
}
}

/**
* 获取服务函数的详情
* TODO: 不要 services 前缀
* @param serviceKey `services.list` 或 `services.sub.list`
* @returns
*/
getServiceFunction(serviceKey: string) {
const { name, moduleName } = parseServiceVariablePath(serviceKey);
if (!name) {
return;
}

return {
name,
moduleName,
config: this.serviceModules[moduleName]?.serviceFunctions[name],
};
}

/**
* 获取服务函数的列表
* @returns 返回服务函数的列表 { [serviceKey: string]: Dict }
*/
listServiceFunctions() {
const ret: Record<string, Dict> = {};
Object.keys(this.serviceModules).forEach((moduleName) => {
const module = this.serviceModules[moduleName];
Object.keys(module.serviceFunctions).forEach((name) => {
const serviceKey = moduleName === 'index' ? name : [moduleName, name].join('.');
ret[serviceKey] = module.serviceFunctions[name];
});
});
return ret;
}

/**
* 更新服务函数
*/
updateServiceFunction(serviceName: string, payload: Dict, moduleName = 'index') {
this.serviceModules[moduleName].updateServiceFunction(serviceName, payload).update();
}

/**
* 新增服务函数,支持批量添加
*/
addServiceFunction(name: string, config: Dict, moduleName = 'index') {
this.serviceModules[moduleName]?.addServiceFunction(name, config).update();
}

addServiceFunctions(configs: Dict<Dict>, modName = 'index') {
this.serviceModules[modName]?.addServiceFunctions(configs).update();
}

/**
* 删除服务函数
* @param name
*/
removeServiceFunction(serviceKey: string) {
const { moduleName, name } = parseServiceVariablePath(serviceKey);
this.serviceModules[moduleName]?.deleteServiceFunction(name).update();
}

/**
* 更新服务的基础配置
*/
updateServiceBaseConfig(config: Dict, moduleName = 'index') {
this.serviceModules[moduleName]?.updateBaseConfig(config).update();
}
}
Loading
Loading