@pooder/core 0.1.0 → 1.0.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 +6 -0
- package/dist/index.d.mts +243 -134
- package/dist/index.d.ts +243 -134
- package/dist/index.js +442 -370
- package/dist/index.mjs +434 -367
- package/package.json +2 -4
- package/src/command.ts +9 -60
- package/src/context.ts +17 -0
- package/src/contribution/index.ts +12 -0
- package/src/contribution/points.ts +63 -0
- package/src/contribution/registry.ts +118 -0
- package/src/disposable.ts +3 -0
- package/src/event.ts +9 -4
- package/src/extension.ts +108 -171
- package/src/index.ts +140 -31
- package/src/run-test-full.ts +98 -0
- package/src/service.ts +25 -0
- package/src/services/CommandService.ts +79 -0
- package/src/services/ConfigurationService.ts +107 -0
- package/src/services/index.ts +4 -0
- package/src/test-extension-full.ts +79 -0
- package/tsconfig.test.json +7 -0
- package/src/canvas.ts +0 -3
- package/src/editor.ts +0 -226
- package/src/layer.ts +0 -13
- package/src/obj.ts +0 -7
- package/src/types.ts +0 -105
package/src/index.ts
CHANGED
|
@@ -1,31 +1,140 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
import { Service, ServiceRegistry } from "./service";
|
|
2
|
+
import EventBus from "./event";
|
|
3
|
+
import { ExtensionManager } from "./extension";
|
|
4
|
+
import Disposable from "./disposable";
|
|
5
|
+
import {
|
|
6
|
+
Contribution,
|
|
7
|
+
ContributionPoint,
|
|
8
|
+
ContributionPointIds,
|
|
9
|
+
ContributionRegistry,
|
|
10
|
+
} from "./contribution";
|
|
11
|
+
import { CommandService, ConfigurationService } from "./services";
|
|
12
|
+
import { ExtensionContext } from "./context";
|
|
13
|
+
|
|
14
|
+
export * from "./extension";
|
|
15
|
+
export * from "./context";
|
|
16
|
+
export * from "./contribution";
|
|
17
|
+
export * from "./service";
|
|
18
|
+
export * from "./services";
|
|
19
|
+
|
|
20
|
+
export class Pooder {
|
|
21
|
+
readonly eventBus: EventBus = new EventBus();
|
|
22
|
+
private readonly services: ServiceRegistry = new ServiceRegistry();
|
|
23
|
+
private readonly contributions: ContributionRegistry =
|
|
24
|
+
new ContributionRegistry();
|
|
25
|
+
readonly extensionManager: ExtensionManager;
|
|
26
|
+
|
|
27
|
+
constructor() {
|
|
28
|
+
// Initialize default contribution points
|
|
29
|
+
this.initDefaultContributionPoints();
|
|
30
|
+
|
|
31
|
+
const commandService = new CommandService();
|
|
32
|
+
this.registerService(commandService);
|
|
33
|
+
|
|
34
|
+
const configurationService = new ConfigurationService();
|
|
35
|
+
this.registerService(configurationService);
|
|
36
|
+
|
|
37
|
+
// Create a restricted context for extensions
|
|
38
|
+
const context: ExtensionContext = {
|
|
39
|
+
eventBus: this.eventBus,
|
|
40
|
+
services: {
|
|
41
|
+
get: <T extends Service>(serviceName: string) =>
|
|
42
|
+
this.services.get<T>(serviceName),
|
|
43
|
+
},
|
|
44
|
+
contributions: {
|
|
45
|
+
get: <T>(pointId: string) => this.getContributions<T>(pointId),
|
|
46
|
+
register: <T>(pointId: string, contribution: Contribution<T>) =>
|
|
47
|
+
this.registerContribution(pointId, contribution),
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
this.extensionManager = new ExtensionManager(context);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private initDefaultContributionPoints() {
|
|
55
|
+
this.registerContributionPoint({
|
|
56
|
+
id: ContributionPointIds.CONTRIBUTIONS,
|
|
57
|
+
description: "Contribution point for contribution points",
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
this.registerContributionPoint({
|
|
61
|
+
id: ContributionPointIds.COMMANDS,
|
|
62
|
+
description: "Contribution point for commands",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
this.registerContributionPoint({
|
|
66
|
+
id: ContributionPointIds.TOOLS,
|
|
67
|
+
description: "Contribution point for tools",
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
this.registerContributionPoint({
|
|
71
|
+
id: ContributionPointIds.VIEWS,
|
|
72
|
+
description: "Contribution point for UI views",
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
this.registerContributionPoint({
|
|
76
|
+
id: ContributionPointIds.CONFIGURATIONS,
|
|
77
|
+
description: "Contribution point for configurations",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// --- Service Management ---
|
|
82
|
+
|
|
83
|
+
registerService(service: Service) {
|
|
84
|
+
const serviceId = service.constructor.name;
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
service?.init?.();
|
|
88
|
+
} catch (e) {
|
|
89
|
+
console.error(`Error initializing service ${serviceId}:`, e);
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.services.register(serviceId, service);
|
|
94
|
+
this.eventBus.emit("service:register", service);
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
unregisterService(service: Service) {
|
|
99
|
+
const serviceId = service.constructor.name;
|
|
100
|
+
if (!this.services.has(serviceId)) {
|
|
101
|
+
console.warn(`Service ${serviceId} is not registered.`);
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
service?.dispose?.();
|
|
107
|
+
} catch (e) {
|
|
108
|
+
console.error(`Error disposing service ${serviceId}:`, e);
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.services.delete(serviceId);
|
|
113
|
+
this.eventBus.emit("service:unregister", service);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
getService<T extends Service>(id: string): T | undefined {
|
|
118
|
+
return this.services.get<T>(id);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// --- Contribution Management ---
|
|
122
|
+
|
|
123
|
+
registerContributionPoint<T>(point: ContributionPoint<T>): void {
|
|
124
|
+
this.contributions.registerPoint(point);
|
|
125
|
+
this.eventBus.emit("contribution:point:register", point);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
registerContribution<T>(
|
|
129
|
+
pointId: string,
|
|
130
|
+
contribution: Contribution<T>,
|
|
131
|
+
): Disposable {
|
|
132
|
+
const disposable = this.contributions.register(pointId, contribution);
|
|
133
|
+
this.eventBus.emit("contribution:register", { ...contribution, pointId });
|
|
134
|
+
return disposable;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
getContributions<T>(pointId: string): Contribution<T>[] {
|
|
138
|
+
return this.contributions.get<T>(pointId);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Pooder } from "./index";
|
|
2
|
+
import { fullExtension } from "./test-extension-full";
|
|
3
|
+
import { ContributionPointIds } from "./contribution";
|
|
4
|
+
import CommandService from "./services/CommandService";
|
|
5
|
+
|
|
6
|
+
async function runTest() {
|
|
7
|
+
console.log("Starting Test...");
|
|
8
|
+
const app = new Pooder();
|
|
9
|
+
|
|
10
|
+
// Register the full extension
|
|
11
|
+
console.log("Registering extension...");
|
|
12
|
+
app.extensionManager.register(fullExtension);
|
|
13
|
+
const commandService = app.getService<CommandService>("CommandService")!;
|
|
14
|
+
|
|
15
|
+
// 1. Verify Command Contributions
|
|
16
|
+
console.log("\n--- Verifying Commands ---");
|
|
17
|
+
|
|
18
|
+
// 1.1 Imperative Command
|
|
19
|
+
try {
|
|
20
|
+
const res = await commandService.executeCommand(
|
|
21
|
+
"test.imperative.hello",
|
|
22
|
+
"User",
|
|
23
|
+
);
|
|
24
|
+
console.log(
|
|
25
|
+
`[Imperative] "test.imperative.hello" result: "${res}"` ===
|
|
26
|
+
`[Imperative] "test.imperative.hello" result: "Hello Imperative User"`
|
|
27
|
+
? "✅ PASS"
|
|
28
|
+
: "❌ FAIL",
|
|
29
|
+
);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
console.error("❌ FAIL: Imperative command failed", e);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 1.2 Declarative Auto-Registered Command
|
|
35
|
+
try {
|
|
36
|
+
const res = await commandService.executeCommand("test.declarative.auto");
|
|
37
|
+
console.log(
|
|
38
|
+
`[Declarative] "test.declarative.auto" result: "${res}"` ===
|
|
39
|
+
`[Declarative] "test.declarative.auto" result: "Auto Registered Result"`
|
|
40
|
+
? "✅ PASS"
|
|
41
|
+
: "❌ FAIL",
|
|
42
|
+
);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.error("❌ FAIL: Declarative auto-registered command failed", e);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 2. Verify Registry Entries
|
|
48
|
+
console.log("\n--- Verifying Contribution Registry ---");
|
|
49
|
+
|
|
50
|
+
const commands = app.getContributions(ContributionPointIds.COMMANDS);
|
|
51
|
+
console.log(
|
|
52
|
+
`Commands registered: ${commands.length}` === "Commands registered: 2"
|
|
53
|
+
? "✅ PASS (2 commands found)"
|
|
54
|
+
: `❌ FAIL (${commands.length} commands found)`,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const tools = app.getContributions(ContributionPointIds.TOOLS);
|
|
58
|
+
console.log(
|
|
59
|
+
`Tools registered: ${tools.length}` === "Tools registered: 1"
|
|
60
|
+
? "✅ PASS (1 tool found)"
|
|
61
|
+
: `❌ FAIL (${tools.length} tools found)`,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const views = app.getContributions(ContributionPointIds.VIEWS);
|
|
65
|
+
console.log(
|
|
66
|
+
`Views registered: ${views.length}` === "Views registered: 1"
|
|
67
|
+
? "✅ PASS (1 view found)"
|
|
68
|
+
: `❌ FAIL (${views.length} views found)`,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// 3. Unregister and Verify Cleanup
|
|
72
|
+
console.log("\n--- Verifying Unregistration/Cleanup ---");
|
|
73
|
+
// The ID is now explicit: "full-feature-test-extension"
|
|
74
|
+
const extensionId = "full-feature-test-extension";
|
|
75
|
+
app.extensionManager.unregister(extensionId);
|
|
76
|
+
|
|
77
|
+
const commandsAfter = app.getContributions(ContributionPointIds.COMMANDS);
|
|
78
|
+
console.log(
|
|
79
|
+
`Commands after unregister: ${commandsAfter.length}` ===
|
|
80
|
+
"Commands after unregister: 0"
|
|
81
|
+
? "✅ PASS"
|
|
82
|
+
: `❌ FAIL (${commandsAfter.length} left)`,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Verify command service cleanup
|
|
86
|
+
const cmdMap = commandService.getCommands();
|
|
87
|
+
const hasCmd = cmdMap.has("test.declarative.auto");
|
|
88
|
+
console.log(
|
|
89
|
+
`Command service cleaned up: ${!hasCmd}` ===
|
|
90
|
+
"Command service cleaned up: true"
|
|
91
|
+
? "✅ PASS"
|
|
92
|
+
: "❌ FAIL (Command still exists)",
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
console.log("\nTest Completed.");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
runTest().catch(console.error);
|
package/src/service.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface Service {
|
|
2
|
+
init?(): void;
|
|
3
|
+
dispose?(): void;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export class ServiceRegistry {
|
|
7
|
+
private services: Map<string, Service> = new Map();
|
|
8
|
+
|
|
9
|
+
register<T extends Service>(name: string, service: T): T {
|
|
10
|
+
this.services.set(name, service);
|
|
11
|
+
return service;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
get<T extends Service>(serviceName: string): T | undefined {
|
|
15
|
+
return this.services.get(serviceName) as T | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
has(serviceName: string): boolean {
|
|
19
|
+
return this.services.has(serviceName);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
delete(serviceName: string): void {
|
|
23
|
+
this.services.delete(serviceName);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Command } from "../command";
|
|
2
|
+
import Disposable from "../disposable";
|
|
3
|
+
import { Service } from "../service";
|
|
4
|
+
|
|
5
|
+
export default class CommandService implements Service {
|
|
6
|
+
private commands: Map<string, Command> = new Map();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Register a command
|
|
10
|
+
* @param commandId Command Name (ID)
|
|
11
|
+
* @param handler Command handler function
|
|
12
|
+
* @param thisArg The `this` context for the handler
|
|
13
|
+
* @returns Disposable to unregister the command
|
|
14
|
+
*/
|
|
15
|
+
registerCommand(
|
|
16
|
+
commandId: string,
|
|
17
|
+
handler: (...args: any[]) => any,
|
|
18
|
+
thisArg?: any,
|
|
19
|
+
): Disposable {
|
|
20
|
+
if (this.commands.has(commandId)) {
|
|
21
|
+
console.warn(
|
|
22
|
+
`Command "${commandId}" is already registered. Overwriting.`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const command: Command = {
|
|
27
|
+
id: commandId,
|
|
28
|
+
handler: thisArg ? handler.bind(thisArg) : handler,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
this.commands.set(commandId, command);
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
dispose: () => {
|
|
35
|
+
if (this.commands.get(commandId) === command) {
|
|
36
|
+
this.commands.delete(commandId);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Execute a command
|
|
44
|
+
* @param commandId Command Name (ID)
|
|
45
|
+
* @param args Arguments to pass to the handler
|
|
46
|
+
* @returns The result of the command handler
|
|
47
|
+
*/
|
|
48
|
+
async executeCommand<T = any>(commandId: string, ...args: any[]): Promise<T> {
|
|
49
|
+
const command = this.commands.get(commandId);
|
|
50
|
+
if (!command) {
|
|
51
|
+
throw new Error(`Command "${commandId}" not found.`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
return await command.handler(...args);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(`Error executing command "${commandId}":`, error);
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get all registered commands
|
|
64
|
+
*/
|
|
65
|
+
getCommands(): Map<string, Command> {
|
|
66
|
+
return this.commands;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Get a specific command
|
|
71
|
+
*/
|
|
72
|
+
getCommand(commandId: string): Command | undefined {
|
|
73
|
+
return this.commands.get(commandId);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
dispose() {
|
|
77
|
+
this.commands.clear();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Service } from "../service";
|
|
2
|
+
import EventBus from "../event";
|
|
3
|
+
import { ConfigurationContribution } from "../contribution";
|
|
4
|
+
|
|
5
|
+
export default class ConfigurationService implements Service {
|
|
6
|
+
private configValues: Map<string, any> = new Map();
|
|
7
|
+
private eventBus: EventBus = new EventBus();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Get a configuration value.
|
|
11
|
+
*/
|
|
12
|
+
get<T = any>(key: string, defaultValue?: T): T {
|
|
13
|
+
if (this.configValues.has(key)) {
|
|
14
|
+
return this.configValues.get(key);
|
|
15
|
+
}
|
|
16
|
+
return defaultValue as T;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Update a configuration value.
|
|
21
|
+
* Emits 'change' event.
|
|
22
|
+
*/
|
|
23
|
+
update(key: string, value: any) {
|
|
24
|
+
const oldValue = this.configValues.get(key);
|
|
25
|
+
if (oldValue !== value) {
|
|
26
|
+
this.configValues.set(key, value);
|
|
27
|
+
this.eventBus.emit(`change:${key}`, { key, value, oldValue });
|
|
28
|
+
this.eventBus.emit("change", { key, value, oldValue });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Listen for changes to a specific configuration key.
|
|
34
|
+
*/
|
|
35
|
+
onDidChange(
|
|
36
|
+
key: string,
|
|
37
|
+
callback: (event: { key: string; value: any; oldValue: any }) => void,
|
|
38
|
+
) {
|
|
39
|
+
this.eventBus.on(`change:${key}`, callback);
|
|
40
|
+
return {
|
|
41
|
+
dispose: () => this.eventBus.off(`change:${key}`, callback),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Listen for any configuration change.
|
|
47
|
+
*/
|
|
48
|
+
onAnyChange(
|
|
49
|
+
callback: (event: { key: string; value: any; oldValue: any }) => void,
|
|
50
|
+
) {
|
|
51
|
+
this.eventBus.on("change", callback);
|
|
52
|
+
return {
|
|
53
|
+
dispose: () => this.eventBus.off("change", callback),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Export current configuration state as a JSON-serializable object.
|
|
59
|
+
* Useful for saving configuration templates.
|
|
60
|
+
*/
|
|
61
|
+
export(): Record<string, any> {
|
|
62
|
+
const exportData: Record<string, any> = {};
|
|
63
|
+
for (const [key, value] of this.configValues) {
|
|
64
|
+
exportData[key] = value;
|
|
65
|
+
}
|
|
66
|
+
return exportData;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Import configuration from a JSON object.
|
|
71
|
+
* This will merge the provided configuration with the current state,
|
|
72
|
+
* overwriting existing keys and triggering change events.
|
|
73
|
+
*/
|
|
74
|
+
import(data: Record<string, any>): void {
|
|
75
|
+
if (!data || typeof data !== "object") {
|
|
76
|
+
console.warn("ConfigurationService: Import data must be an object.");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
80
|
+
this.update(key, value);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Initialize configuration with defaults from contributions.
|
|
86
|
+
* This should be called when a contribution is registered.
|
|
87
|
+
*/
|
|
88
|
+
initializeDefaults(contributions: ConfigurationContribution[]) {
|
|
89
|
+
contributions.forEach((contrib) => {
|
|
90
|
+
if (!contrib.id) {
|
|
91
|
+
console.warn(
|
|
92
|
+
"Configuration contribution missing 'id'. Skipping default initialization.",
|
|
93
|
+
contrib,
|
|
94
|
+
);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (!this.configValues.has(contrib.id) && contrib.default !== undefined) {
|
|
98
|
+
this.configValues.set(contrib.id, contrib.default);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
dispose() {
|
|
104
|
+
this.configValues.clear();
|
|
105
|
+
// EventBus doesn't have a clear/dispose in the snippet, but it's fine for now.
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ExtensionContext } from "./context";
|
|
2
|
+
import {
|
|
3
|
+
ContributionPointIds,
|
|
4
|
+
CommandContribution,
|
|
5
|
+
ToolContribution,
|
|
6
|
+
ViewContribution,
|
|
7
|
+
} from "./contribution";
|
|
8
|
+
import { Extension } from "./extension";
|
|
9
|
+
import CommandService from "./services/CommandService";
|
|
10
|
+
|
|
11
|
+
export const fullExtension: Extension = {
|
|
12
|
+
id: "full-feature-test-extension",
|
|
13
|
+
metadata: {
|
|
14
|
+
name: "Full Feature Test Extension",
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
activate(context: ExtensionContext) {
|
|
18
|
+
console.log("Full Feature Test Extension activated!");
|
|
19
|
+
|
|
20
|
+
// Manually register a command (imperative way)
|
|
21
|
+
const commandService =
|
|
22
|
+
context.services.get<CommandService>("CommandService");
|
|
23
|
+
commandService!.registerCommand("test.imperative.hello", (name: string) => {
|
|
24
|
+
return `Hello Imperative ${name}`;
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
deactivate(context: ExtensionContext) {
|
|
29
|
+
console.log("Full Feature Test Extension deactivated!");
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
contribute() {
|
|
33
|
+
return {
|
|
34
|
+
// 1. Command Contributions
|
|
35
|
+
[ContributionPointIds.COMMANDS]: [
|
|
36
|
+
// Declarative command with handler (auto-registered by our updated ExtensionManager)
|
|
37
|
+
{
|
|
38
|
+
id: "test.declarative.auto",
|
|
39
|
+
command: "test.declarative.auto",
|
|
40
|
+
title: "Auto Registered Command",
|
|
41
|
+
handler: () => {
|
|
42
|
+
return "Auto Registered Result";
|
|
43
|
+
},
|
|
44
|
+
} as CommandContribution,
|
|
45
|
+
|
|
46
|
+
// Declarative command without handler (just definition, maybe handled elsewhere)
|
|
47
|
+
{
|
|
48
|
+
id: "test.declarative.no-handler",
|
|
49
|
+
command: "test.declarative.no-handler",
|
|
50
|
+
title: "No Handler Command",
|
|
51
|
+
} as CommandContribution,
|
|
52
|
+
],
|
|
53
|
+
|
|
54
|
+
// 2. Tool Contributions
|
|
55
|
+
[ContributionPointIds.TOOLS]: [
|
|
56
|
+
{
|
|
57
|
+
id: "test.tool.calculator",
|
|
58
|
+
name: "Calculator",
|
|
59
|
+
description: "Simple calculator",
|
|
60
|
+
execute: async (op: string, a: number, b: number) => {
|
|
61
|
+
if (op === "add") return a + b;
|
|
62
|
+
return 0;
|
|
63
|
+
},
|
|
64
|
+
} as ToolContribution,
|
|
65
|
+
],
|
|
66
|
+
|
|
67
|
+
// 3. View Contributions
|
|
68
|
+
[ContributionPointIds.VIEWS]: [
|
|
69
|
+
{
|
|
70
|
+
id: "test.view.sidebar",
|
|
71
|
+
name: "Test Sidebar",
|
|
72
|
+
type: "sidebar",
|
|
73
|
+
component: "SidebarComponent", // Mock component string
|
|
74
|
+
location: "left",
|
|
75
|
+
} as ViewContribution,
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
};
|
package/src/canvas.ts
DELETED