Skip to content

Commit eae4500

Browse files
authored
feat!: refactor base class (#191)
* feat: refactor types * feat: rename models * fix: update types * fix: init workspace and viewNode * fix: update fileTypes * fix: update * fix: update
1 parent 1802fc0 commit eae4500

38 files changed

+1887
-2033
lines changed

packages/context/src/context.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Engine } from '@music163/tango-core';
1+
import type { AbstractCodeWorkspace, Engine } from '@music163/tango-core';
22
import { IVariableTreeNode, createContext } from '@music163/tango-helpers';
33

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

2222
export { TangoEngineProvider };
2323

24+
/**
25+
* 获取 CodeWorkspace 实例
26+
* @returns
27+
*/
2428
export const useWorkspace = () => {
25-
return useTangoEngine()?.engine.workspace;
29+
return useTangoEngine()?.engine.workspace as AbstractCodeWorkspace;
2630
};
2731

2832
export const useDesigner = () => {

packages/core/src/factory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { MenuDataType } from '@music163/tango-helpers';
22
import { Designer, DesignerViewType, Engine, SimulatorNameType } from './models';
3-
import { IWorkspace } from './models/interfaces';
3+
import { AbstractWorkspace } from './models/abstract-workspace';
44

55
interface ICreateEngineOptions {
66
/**
77
* 自定义工作区
88
*/
9-
workspace?: IWorkspace;
9+
workspace?: AbstractWorkspace;
1010
/**
1111
* 菜单信息
1212
*/

packages/core/src/helpers/ast/traverse.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { isDefineService, isDefineStore, isTangoVariable } from '../assert';
2828
import type {
2929
IRouteData,
3030
IStorePropertyData,
31-
ITangoViewNodeData,
31+
IViewNodeData,
3232
IImportDeclarationPayload,
3333
InsertChildPositionType,
3434
IImportSpecifierData,
@@ -1234,7 +1234,7 @@ export function cloneJSXElement(node: t.JSXElement, overrideProps?: Dict) {
12341234
export function traverseViewFile(ast: t.File, idGenerator: IdGenerator) {
12351235
const imports: Record<string, IImportSpecifierData[]> = {};
12361236
const importedModules: Dict<IImportDeclarationPayload | IImportDeclarationPayload[]> = {};
1237-
const nodes: Array<ITangoViewNodeData<t.JSXElement>> = [];
1237+
const nodes: Array<IViewNodeData<t.JSXElement>> = [];
12381238
const cloneAst = t.cloneNode(ast, true, true);
12391239
const cleanAst = clearTrackingData(cloneAst);
12401240
const variables: string[] = []; // 使用的 tango 变量

packages/core/src/helpers/string.ts

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,65 +8,57 @@ import { FileType } from './../types';
88
export function inferFileType(filename: string): FileType {
99
// 增加 tangoConfigJson Module
1010
if (/\/tango\.config\.json$/.test(filename)) {
11-
return FileType.TangoConfigJson;
11+
return FileType.TangoConfigJsonFile;
1212
}
1313

1414
if (/\/appJson\.json$/.test(filename)) {
15-
return FileType.AppJson;
15+
return FileType.AppJsonFile;
1616
}
1717

1818
if (/\/package\.json$/.test(filename)) {
19-
return FileType.PackageJson;
19+
return FileType.PackageJsonFile;
2020
}
2121

2222
if (/\/routes\.js$/.test(filename)) {
23-
return FileType.RouteModule;
23+
return FileType.JsRouteConfigFile;
2424
}
2525

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

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

3636
if (/\/(blocks|components)\/index\.js/.test(filename)) {
37-
return FileType.ComponentsEntryModule;
37+
return FileType.JsLocalComponentsEntryFile;
3838
}
3939

4040
if (/\/services\/.+\.js$/.test(filename)) {
41-
return FileType.ServiceModule;
41+
return FileType.JsServiceFile;
4242
}
4343

4444
if (/service\.js$/.test(filename)) {
45-
return FileType.ServiceModule;
45+
return FileType.JsServiceFile;
4646
}
4747

4848
if (/\/stores\/index\.js$/.test(filename)) {
49-
return FileType.StoreEntryModule;
49+
return FileType.JsStoreEntryFile;
5050
}
5151

5252
if (/\/stores\/.+\.js$/.test(filename)) {
53-
return FileType.StoreModule;
53+
return FileType.JsStoreFile;
5454
}
5555

5656
if (/\.jsx?$/.test(filename)) {
57-
return FileType.Module;
57+
return FileType.JsFile;
5858
}
5959

6060
if (/\.json$/.test(filename)) {
61-
return FileType.Json;
62-
}
63-
64-
if (/\.less$/.test(filename)) {
65-
return FileType.Less;
66-
}
67-
68-
if (/\.scss$/.test(filename)) {
69-
return FileType.Scss;
61+
return FileType.JsonFile;
7062
}
7163

7264
return FileType.File;
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
import {
2+
Dict,
3+
isStoreVariablePath,
4+
parseServiceVariablePath,
5+
parseStoreVariablePath,
6+
} from '@music163/tango-helpers';
7+
import { inferFileType, getFilepath } from '../helpers';
8+
import { TangoFile } from './file';
9+
import { FileType } from '../types';
10+
import { JsRouteConfigFile } from './js-route-config-file';
11+
import { JsStoreEntryFile } from './js-store-entry-file';
12+
import { JsServiceFile } from './js-service-file';
13+
import { JsViewFile } from './js-view-file';
14+
import { JsLocalComponentsEntryFile } from './js-local-components-entry-file';
15+
import { JsAppEntryFile } from './js-app-entry-file';
16+
import { JsFile } from './js-file';
17+
import { AbstractWorkspace, IWorkspaceInitConfig } from './abstract-workspace';
18+
import { JsonFile } from './json-file';
19+
import { JsStoreFile } from './js-store-file';
20+
21+
/**
22+
* CodeWorkspace 抽象基类
23+
*/
24+
export abstract class AbstractCodeWorkspace extends AbstractWorkspace {
25+
/**
26+
* 模型入口配置模块
27+
*/
28+
storeEntryModule: JsStoreEntryFile;
29+
30+
/**
31+
* 状态管理模块
32+
*/
33+
storeModules: Record<string, JsStoreFile>;
34+
35+
/**
36+
* 数据服务模块
37+
*/
38+
serviceModules: Record<string, JsServiceFile>;
39+
40+
constructor(options: IWorkspaceInitConfig) {
41+
super(options);
42+
this.storeModules = {};
43+
this.serviceModules = {};
44+
if (options?.files) {
45+
this.addFiles(options.files);
46+
}
47+
}
48+
49+
/**
50+
* 添加文件到工作区
51+
* @param filename 文件名
52+
* @param code 代码片段
53+
* @param fileType 模块类型
54+
*/
55+
addFile(filename: string, code: string, fileType?: FileType) {
56+
if (!fileType && filename === this.entry) {
57+
fileType = FileType.JsAppEntryFile;
58+
}
59+
const moduleType = fileType || inferFileType(filename);
60+
const props = {
61+
filename,
62+
code,
63+
type: moduleType,
64+
};
65+
66+
let module;
67+
switch (moduleType) {
68+
case FileType.JsAppEntryFile:
69+
module = new JsAppEntryFile(this, props);
70+
this.jsAppEntryFile = module;
71+
break;
72+
case FileType.JsStoreEntryFile:
73+
module = new JsStoreEntryFile(this, props);
74+
this.storeEntryModule = module;
75+
break;
76+
case FileType.JsLocalComponentsEntryFile:
77+
module = new JsLocalComponentsEntryFile(this, props);
78+
this.componentsEntryModule = module;
79+
break;
80+
case FileType.JsRouteConfigFile: {
81+
module = new JsRouteConfigFile(this, props);
82+
this.routeModule = module;
83+
// check if activeRoute exists
84+
const route = module.routes.find((item) => item.path === this.activeRoute);
85+
if (!route) {
86+
this.setActiveRoute(module.routes[0]?.path);
87+
}
88+
break;
89+
}
90+
case FileType.JsViewFile:
91+
module = new JsViewFile(this, props);
92+
break;
93+
case FileType.JsServiceFile:
94+
module = new JsServiceFile(this, props);
95+
this.serviceModules[module.name] = module;
96+
break;
97+
case FileType.JsStoreFile:
98+
module = new JsStoreFile(this, props);
99+
this.storeModules[module.name] = module;
100+
break;
101+
case FileType.JsFile:
102+
module = new JsFile(this, props);
103+
break;
104+
case FileType.PackageJsonFile:
105+
module = new JsonFile(this, props);
106+
this.packageJson = module;
107+
break;
108+
case FileType.TangoConfigJsonFile:
109+
module = new JsonFile(this, props);
110+
this.tangoConfigJson = module;
111+
break;
112+
case FileType.JsonFile:
113+
module = new JsonFile(this, props);
114+
break;
115+
default:
116+
module = new TangoFile(this, props);
117+
}
118+
119+
this.files.set(filename, module);
120+
}
121+
122+
addServiceFile(serviceName: string, code: string) {
123+
const filename = `/src/services/${serviceName}.js`;
124+
this.addFile(filename, code, FileType.JsServiceFile);
125+
const indexServiceModule = this.serviceModules.index;
126+
indexServiceModule?.addImportDeclaration(`./${serviceName}`, []).update();
127+
}
128+
129+
addStoreFile(storeName: string, code: string) {
130+
const filename = `/src/stores/${storeName}.js`;
131+
this.addFile(filename, code);
132+
if (!this.storeEntryModule) {
133+
this.addFile('/src/stores/index.js', '');
134+
}
135+
this.storeEntryModule.addStore(storeName).update();
136+
}
137+
138+
/**
139+
* 添加新的模型文件
140+
* @deprecated 使用 addStoreFile 代替
141+
*/
142+
addStoreModule(name: string, code: string) {
143+
this.addStoreFile(name, code);
144+
}
145+
146+
/**
147+
* 删除模型文件
148+
* @param name
149+
*/
150+
removeStoreModule(name: string) {
151+
const filename = getFilepath(name, '/src/stores', '.js');
152+
this.storeEntryModule.removeStore(name).update();
153+
this.removeFile(filename);
154+
}
155+
156+
/**
157+
* 添加模型属性
158+
* @param storeName
159+
* @param stateName
160+
* @param initValue
161+
*/
162+
addStoreState(storeName: string, stateName: string, initValue: string) {
163+
this.storeModules[storeName]?.addState(stateName, initValue).update();
164+
}
165+
166+
/**
167+
* 删除模型属性
168+
* @param storeName
169+
* @param stateName
170+
*/
171+
removeStoreState(storeName: string, stateName: string) {
172+
this.storeModules[storeName]?.removeState(stateName).update();
173+
}
174+
175+
/**
176+
* 根据变量路径删除状态变量
177+
* @param variablePath
178+
*/
179+
removeStoreVariable(variablePath: string) {
180+
const { storeName, variableName } = parseStoreVariablePath(variablePath);
181+
this.removeStoreState(storeName, variableName);
182+
}
183+
184+
/**
185+
* 根据变量路径更新状态变量的值
186+
* @param variablePath 变量路径
187+
* @param code 变量代码
188+
*/
189+
updateStoreVariable(variablePath: string, code: string) {
190+
if (isStoreVariablePath(variablePath)) {
191+
const { storeName, variableName } = parseStoreVariablePath(variablePath);
192+
this.storeModules[storeName]?.updateState(variableName, code).update();
193+
}
194+
}
195+
196+
/**
197+
* 获取服务函数的详情
198+
* TODO: 不要 services 前缀
199+
* @param serviceKey `services.list` 或 `services.sub.list`
200+
* @returns
201+
*/
202+
getServiceFunction(serviceKey: string) {
203+
const { name, moduleName } = parseServiceVariablePath(serviceKey);
204+
if (!name) {
205+
return;
206+
}
207+
208+
return {
209+
name,
210+
moduleName,
211+
config: this.serviceModules[moduleName]?.serviceFunctions[name],
212+
};
213+
}
214+
215+
/**
216+
* 获取服务函数的列表
217+
* @returns 返回服务函数的列表 { [serviceKey: string]: Dict }
218+
*/
219+
listServiceFunctions() {
220+
const ret: Record<string, Dict> = {};
221+
Object.keys(this.serviceModules).forEach((moduleName) => {
222+
const module = this.serviceModules[moduleName];
223+
Object.keys(module.serviceFunctions).forEach((name) => {
224+
const serviceKey = moduleName === 'index' ? name : [moduleName, name].join('.');
225+
ret[serviceKey] = module.serviceFunctions[name];
226+
});
227+
});
228+
return ret;
229+
}
230+
231+
/**
232+
* 更新服务函数
233+
*/
234+
updateServiceFunction(serviceName: string, payload: Dict, moduleName = 'index') {
235+
this.serviceModules[moduleName].updateServiceFunction(serviceName, payload).update();
236+
}
237+
238+
/**
239+
* 新增服务函数,支持批量添加
240+
*/
241+
addServiceFunction(name: string, config: Dict, moduleName = 'index') {
242+
this.serviceModules[moduleName]?.addServiceFunction(name, config).update();
243+
}
244+
245+
addServiceFunctions(configs: Dict<Dict>, modName = 'index') {
246+
this.serviceModules[modName]?.addServiceFunctions(configs).update();
247+
}
248+
249+
/**
250+
* 删除服务函数
251+
* @param name
252+
*/
253+
removeServiceFunction(serviceKey: string) {
254+
const { moduleName, name } = parseServiceVariablePath(serviceKey);
255+
this.serviceModules[moduleName]?.deleteServiceFunction(name).update();
256+
}
257+
258+
/**
259+
* 更新服务的基础配置
260+
*/
261+
updateServiceBaseConfig(config: Dict, moduleName = 'index') {
262+
this.serviceModules[moduleName]?.updateBaseConfig(config).update();
263+
}
264+
}

0 commit comments

Comments
 (0)