@mindcraft-lang/bridge-app 0.1.1
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/README.md +44 -0
- package/dist/app-bridge.d.ts +56 -0
- package/dist/app-bridge.d.ts.map +1 -0
- package/dist/app-bridge.js +197 -0
- package/dist/app-project.d.ts +27 -0
- package/dist/app-project.d.ts.map +1 -0
- package/dist/app-project.js +65 -0
- package/dist/compilation.d.ts +47 -0
- package/dist/compilation.d.ts.map +1 -0
- package/dist/compilation.js +195 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/package.json +84 -0
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# @mindcraft-lang/bridge-app
|
|
2
|
+
|
|
3
|
+
App-side client for the Mindcraft bridge.
|
|
4
|
+
|
|
5
|
+
Wraps `@mindcraft-lang/bridge-client` with app-role-specific behavior: automatic join code
|
|
6
|
+
management and the `"app"` WebSocket path. Apps that connect to the bridge should depend on
|
|
7
|
+
this package rather than using `bridge-client` directly.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { createAppBridge } from "@mindcraft-lang/bridge-app";
|
|
13
|
+
import { createCompilationFeature } from "@mindcraft-lang/bridge-app/compilation";
|
|
14
|
+
|
|
15
|
+
const bridge = createAppBridge({
|
|
16
|
+
app: { id: "my-app", name: "My App", projectId: "p1", projectName: "Project" },
|
|
17
|
+
bridgeUrl: "ws://localhost:6464",
|
|
18
|
+
workspace: myWorkspaceAdapter,
|
|
19
|
+
features: [createCompilationFeature({ compiler })],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
bridge.start();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The bridge facade supports:
|
|
26
|
+
|
|
27
|
+
- `start()` / `stop()` -- lifecycle management
|
|
28
|
+
- `requestSync()` -- request a full workspace sync from the VS Code extension
|
|
29
|
+
- `snapshot()` -- current connection status and join code
|
|
30
|
+
- `onStateChange(...)` / `onRemoteChange(...)` -- event subscriptions
|
|
31
|
+
|
|
32
|
+
Optional features (like compilation) attach through the `features` array and receive
|
|
33
|
+
a `AppBridgeFeatureContext` with workspace access, sync hooks, and diagnostic/status
|
|
34
|
+
publication helpers.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
npm install @mindcraft-lang/bridge-app
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ConnectionStatus, ExportedFileSystem, FileSystemNotification } from "@mindcraft-lang/bridge-client";
|
|
2
|
+
import type { CompileDiagnosticEntry } from "@mindcraft-lang/bridge-protocol";
|
|
3
|
+
export type WorkspaceSnapshot = ExportedFileSystem;
|
|
4
|
+
export type WorkspaceChange = FileSystemNotification;
|
|
5
|
+
export type AppBridgeState = ConnectionStatus;
|
|
6
|
+
export type DiagnosticEntry = CompileDiagnosticEntry;
|
|
7
|
+
export interface AppBridge {
|
|
8
|
+
start(): void;
|
|
9
|
+
stop(): void;
|
|
10
|
+
requestSync(): Promise<void>;
|
|
11
|
+
snapshot(): AppBridgeSnapshot;
|
|
12
|
+
onStateChange(listener: (state: AppBridgeState) => void): () => void;
|
|
13
|
+
onRemoteChange(listener: (change: WorkspaceChange) => void): () => void;
|
|
14
|
+
}
|
|
15
|
+
export interface AppBridgeSnapshot {
|
|
16
|
+
status: AppBridgeState;
|
|
17
|
+
joinCode?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface AppBridgeOptions {
|
|
20
|
+
app: {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
projectId: string;
|
|
24
|
+
projectName: string;
|
|
25
|
+
};
|
|
26
|
+
bridgeUrl: string;
|
|
27
|
+
workspace: WorkspaceAdapter;
|
|
28
|
+
features?: readonly AppBridgeFeature[];
|
|
29
|
+
}
|
|
30
|
+
export interface WorkspaceAdapter {
|
|
31
|
+
exportSnapshot(): WorkspaceSnapshot;
|
|
32
|
+
applyRemoteChange(change: WorkspaceChange): void;
|
|
33
|
+
onLocalChange(listener: (change: WorkspaceChange) => void): () => void;
|
|
34
|
+
}
|
|
35
|
+
export interface AppBridgeFeature {
|
|
36
|
+
attach(context: AppBridgeFeatureContext): () => void;
|
|
37
|
+
}
|
|
38
|
+
export interface AppBridgeFeatureContext {
|
|
39
|
+
snapshot(): AppBridgeSnapshot;
|
|
40
|
+
workspaceSnapshot(): WorkspaceSnapshot;
|
|
41
|
+
onStateChange(listener: (state: AppBridgeState) => void): () => void;
|
|
42
|
+
onRemoteChange(listener: (change: WorkspaceChange) => void): () => void;
|
|
43
|
+
onDidSync(listener: () => void): () => void;
|
|
44
|
+
publishDiagnostics(file: string, diagnostics: readonly DiagnosticEntry[]): void;
|
|
45
|
+
publishStatus(update: AppBridgeFeatureStatus): void;
|
|
46
|
+
}
|
|
47
|
+
export interface AppBridgeFeatureStatus {
|
|
48
|
+
file: string;
|
|
49
|
+
success: boolean;
|
|
50
|
+
diagnosticCount: {
|
|
51
|
+
error: number;
|
|
52
|
+
warning: number;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export declare function createAppBridge(options: AppBridgeOptions): AppBridge;
|
|
56
|
+
//# sourceMappingURL=app-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-bridge.d.ts","sourceRoot":"","sources":["../src/app-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAClH,OAAO,KAAK,EAAoB,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAGhG,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AACnD,MAAM,MAAM,eAAe,GAAG,sBAAsB,CAAC;AACrD,MAAM,MAAM,cAAc,GAAG,gBAAgB,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,sBAAsB,CAAC;AAErD,MAAM,WAAW,SAAS;IACxB,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;IACb,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,QAAQ,IAAI,iBAAiB,CAAC;IAC9B,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACrE,cAAc,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACzE;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE;QACH,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,IAAI,iBAAiB,CAAC;IACpC,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IACjD,aAAa,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACxE;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,IAAI,iBAAiB,CAAC;IAC9B,iBAAiB,IAAI,iBAAiB,CAAC;IACvC,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACrE,cAAc,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACxE,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAC5C,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI,CAAC;IAChF,aAAa,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAEpE"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { AppProject } from "./app-project.js";
|
|
2
|
+
export function createAppBridge(options) {
|
|
3
|
+
return new AppBridgeController(options);
|
|
4
|
+
}
|
|
5
|
+
class AppBridgeController {
|
|
6
|
+
_options;
|
|
7
|
+
_stateListeners = new Set();
|
|
8
|
+
_remoteChangeListeners = new Set();
|
|
9
|
+
_syncListeners = new Set();
|
|
10
|
+
_diagnosticVersions = new Map();
|
|
11
|
+
_featureDisposers = [];
|
|
12
|
+
_project;
|
|
13
|
+
_workspaceUnsub;
|
|
14
|
+
_projectUnsubs = [];
|
|
15
|
+
_status = "disconnected";
|
|
16
|
+
_joinCode;
|
|
17
|
+
constructor(options) {
|
|
18
|
+
this._options = options;
|
|
19
|
+
}
|
|
20
|
+
start() {
|
|
21
|
+
if (this._project) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
this.attachFeatures();
|
|
25
|
+
const project = new AppProject({
|
|
26
|
+
appName: this._options.app.name,
|
|
27
|
+
projectId: this._options.app.projectId,
|
|
28
|
+
projectName: this._options.app.projectName,
|
|
29
|
+
bridgeUrl: this._options.bridgeUrl,
|
|
30
|
+
filesystem: this._options.workspace.exportSnapshot(),
|
|
31
|
+
});
|
|
32
|
+
this._project = project;
|
|
33
|
+
this._workspaceUnsub = this._options.workspace.onLocalChange((change) => {
|
|
34
|
+
project.files.toRemote.applyNotification(change);
|
|
35
|
+
});
|
|
36
|
+
this._projectUnsubs = [
|
|
37
|
+
project.session.addEventListener("status", (status) => {
|
|
38
|
+
this.setStatus(status);
|
|
39
|
+
}),
|
|
40
|
+
project.onJoinCodeChange((joinCode) => {
|
|
41
|
+
this.setJoinCode(joinCode);
|
|
42
|
+
}),
|
|
43
|
+
project.onRemoteFileChange((change) => {
|
|
44
|
+
this._options.workspace.applyRemoteChange(change);
|
|
45
|
+
this.emitRemoteChange(change);
|
|
46
|
+
}),
|
|
47
|
+
project.onDidSync(() => {
|
|
48
|
+
this.emitDidSync();
|
|
49
|
+
}),
|
|
50
|
+
];
|
|
51
|
+
project.session.start();
|
|
52
|
+
}
|
|
53
|
+
stop() {
|
|
54
|
+
const project = this._project;
|
|
55
|
+
if (!project) {
|
|
56
|
+
this.setJoinCode(undefined);
|
|
57
|
+
this.setStatus("disconnected");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
project.session.stop();
|
|
61
|
+
this.disposeProjectBindings();
|
|
62
|
+
this._project = undefined;
|
|
63
|
+
this.setJoinCode(undefined);
|
|
64
|
+
this.disposeFeatures();
|
|
65
|
+
}
|
|
66
|
+
async requestSync() {
|
|
67
|
+
const project = this.requireProject();
|
|
68
|
+
await project.requestSync();
|
|
69
|
+
}
|
|
70
|
+
snapshot() {
|
|
71
|
+
return {
|
|
72
|
+
status: this._status,
|
|
73
|
+
joinCode: this._joinCode,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
onStateChange(listener) {
|
|
77
|
+
this._stateListeners.add(listener);
|
|
78
|
+
return () => {
|
|
79
|
+
this._stateListeners.delete(listener);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
onRemoteChange(listener) {
|
|
83
|
+
this._remoteChangeListeners.add(listener);
|
|
84
|
+
return () => {
|
|
85
|
+
this._remoteChangeListeners.delete(listener);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
attachFeatures() {
|
|
89
|
+
if (this._featureDisposers.length > 0) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const features = this._options.features ?? [];
|
|
93
|
+
const context = {
|
|
94
|
+
snapshot: () => this.snapshot(),
|
|
95
|
+
workspaceSnapshot: () => this._options.workspace.exportSnapshot(),
|
|
96
|
+
onStateChange: (listener) => this.onStateChange(listener),
|
|
97
|
+
onRemoteChange: (listener) => this.onRemoteChange(listener),
|
|
98
|
+
onDidSync: (listener) => this.onDidSync(listener),
|
|
99
|
+
publishDiagnostics: (file, diagnostics) => {
|
|
100
|
+
this.publishDiagnostics(file, diagnostics);
|
|
101
|
+
},
|
|
102
|
+
publishStatus: (update) => {
|
|
103
|
+
this.publishStatus(update);
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
for (const feature of features) {
|
|
107
|
+
this._featureDisposers.push(feature.attach(context));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
disposeFeatures() {
|
|
111
|
+
for (const dispose of this._featureDisposers.splice(0)) {
|
|
112
|
+
dispose();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
onDidSync(listener) {
|
|
116
|
+
this._syncListeners.add(listener);
|
|
117
|
+
return () => {
|
|
118
|
+
this._syncListeners.delete(listener);
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
emitDidSync() {
|
|
122
|
+
for (const listener of this._syncListeners) {
|
|
123
|
+
listener();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
emitRemoteChange(change) {
|
|
127
|
+
for (const listener of this._remoteChangeListeners) {
|
|
128
|
+
listener(change);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
publishDiagnostics(file, diagnostics) {
|
|
132
|
+
const project = this._project;
|
|
133
|
+
if (!project || this._status !== "connected") {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const version = (this._diagnosticVersions.get(file) ?? 0) + 1;
|
|
137
|
+
this._diagnosticVersions.set(file, version);
|
|
138
|
+
const message = {
|
|
139
|
+
type: "compile:diagnostics",
|
|
140
|
+
payload: {
|
|
141
|
+
file,
|
|
142
|
+
version,
|
|
143
|
+
diagnostics: [...diagnostics],
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
project.session.send(message);
|
|
147
|
+
}
|
|
148
|
+
publishStatus(update) {
|
|
149
|
+
const project = this._project;
|
|
150
|
+
if (!project || this._status !== "connected") {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const message = {
|
|
154
|
+
type: "compile:status",
|
|
155
|
+
payload: {
|
|
156
|
+
file: update.file,
|
|
157
|
+
success: update.success,
|
|
158
|
+
diagnosticCount: {
|
|
159
|
+
error: update.diagnosticCount.error,
|
|
160
|
+
warning: update.diagnosticCount.warning,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
project.session.send(message);
|
|
165
|
+
}
|
|
166
|
+
setStatus(status) {
|
|
167
|
+
if (this._status === status) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this._status = status;
|
|
171
|
+
for (const listener of this._stateListeners) {
|
|
172
|
+
listener(status);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
setJoinCode(joinCode) {
|
|
176
|
+
if (this._joinCode === joinCode) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
this._joinCode = joinCode;
|
|
180
|
+
for (const listener of this._stateListeners) {
|
|
181
|
+
listener(this._status);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
disposeProjectBindings() {
|
|
185
|
+
this._workspaceUnsub?.();
|
|
186
|
+
this._workspaceUnsub = undefined;
|
|
187
|
+
for (const unsub of this._projectUnsubs.splice(0)) {
|
|
188
|
+
unsub();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
requireProject() {
|
|
192
|
+
if (!this._project) {
|
|
193
|
+
throw new Error("Bridge not started");
|
|
194
|
+
}
|
|
195
|
+
return this._project;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ExportedFileSystem } from "@mindcraft-lang/bridge-client";
|
|
2
|
+
import { Project } from "@mindcraft-lang/bridge-client";
|
|
3
|
+
import type { AppClientMessage, AppServerMessage, FileSystemNotification } from "@mindcraft-lang/bridge-protocol";
|
|
4
|
+
import { CompilationManager, type CompilationProvider } from "./compilation.js";
|
|
5
|
+
export interface AppProjectOptions {
|
|
6
|
+
appName: string;
|
|
7
|
+
projectId: string;
|
|
8
|
+
projectName: string;
|
|
9
|
+
bridgeUrl: string;
|
|
10
|
+
filesystem: ExportedFileSystem;
|
|
11
|
+
compilationProvider?: CompilationProvider;
|
|
12
|
+
}
|
|
13
|
+
export declare class AppProject extends Project<AppClientMessage, AppServerMessage> {
|
|
14
|
+
private _joinCode;
|
|
15
|
+
private readonly _joinCodeListeners;
|
|
16
|
+
private readonly _sessionUnsubs;
|
|
17
|
+
private readonly _compilation;
|
|
18
|
+
private readonly _remoteFileChangeListeners;
|
|
19
|
+
constructor(options: AppProjectOptions);
|
|
20
|
+
get compilation(): CompilationManager | undefined;
|
|
21
|
+
get joinCode(): string | undefined;
|
|
22
|
+
onJoinCodeChange(fn: (joinCode: string | undefined) => void): () => void;
|
|
23
|
+
onRemoteFileChange(fn: (ev: FileSystemNotification) => void): () => void;
|
|
24
|
+
private wireJoinCode;
|
|
25
|
+
private setJoinCode;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=app-project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-project.d.ts","sourceRoot":"","sources":["../src/app-project.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,OAAO,EAAuB,MAAM,+BAA+B,CAAC;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAClH,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEhF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CAC3C;AAED,qBAAa,UAAW,SAAQ,OAAO,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IACzE,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqD;IACxF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAsB;IACrD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiC;IAC9D,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAmD;gBAElF,OAAO,EAAE,iBAAiB;IAgCtC,IAAI,WAAW,IAAI,kBAAkB,GAAG,SAAS,CAEhD;IAED,IAAI,QAAQ,IAAI,MAAM,GAAG,SAAS,CAEjC;IAED,gBAAgB,CAAC,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI;IAOxE,kBAAkB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,sBAAsB,KAAK,IAAI,GAAG,MAAM,IAAI;IAOxE,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,WAAW;CAOpB"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Project } from "@mindcraft-lang/bridge-client";
|
|
2
|
+
import { CompilationManager } from "./compilation.js";
|
|
3
|
+
export class AppProject extends Project {
|
|
4
|
+
_joinCode;
|
|
5
|
+
_joinCodeListeners = new Set();
|
|
6
|
+
_sessionUnsubs = [];
|
|
7
|
+
_compilation;
|
|
8
|
+
_remoteFileChangeListeners = new Set();
|
|
9
|
+
constructor(options) {
|
|
10
|
+
const projectOptions = {
|
|
11
|
+
...options,
|
|
12
|
+
wsPath: "app",
|
|
13
|
+
};
|
|
14
|
+
super(projectOptions);
|
|
15
|
+
this.wireJoinCode();
|
|
16
|
+
if (options.compilationProvider) {
|
|
17
|
+
this._compilation = new CompilationManager(options.compilationProvider, (msg) => this.session.send(msg), () => this.session.status === "connected");
|
|
18
|
+
this._sessionUnsubs.push(this.onDidSync(() => {
|
|
19
|
+
this._compilation?.sendDiagnostics();
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
this.fromRemoteFileChange = (ev) => {
|
|
23
|
+
if (this._compilation) {
|
|
24
|
+
this._compilation.handleFileChange(ev);
|
|
25
|
+
}
|
|
26
|
+
for (const fn of this._remoteFileChangeListeners) {
|
|
27
|
+
fn(ev);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
get compilation() {
|
|
32
|
+
return this._compilation;
|
|
33
|
+
}
|
|
34
|
+
get joinCode() {
|
|
35
|
+
return this._joinCode;
|
|
36
|
+
}
|
|
37
|
+
onJoinCodeChange(fn) {
|
|
38
|
+
this._joinCodeListeners.add(fn);
|
|
39
|
+
return () => {
|
|
40
|
+
this._joinCodeListeners.delete(fn);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
onRemoteFileChange(fn) {
|
|
44
|
+
this._remoteFileChangeListeners.add(fn);
|
|
45
|
+
return () => {
|
|
46
|
+
this._remoteFileChangeListeners.delete(fn);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
wireJoinCode() {
|
|
50
|
+
this._sessionUnsubs.push(this.session.on("session:welcome", (msg) => {
|
|
51
|
+
this.setJoinCode(msg.payload.joinCode);
|
|
52
|
+
}));
|
|
53
|
+
this._sessionUnsubs.push(this.session.on("session:joinCode", (msg) => {
|
|
54
|
+
this.setJoinCode(msg.payload.joinCode);
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
setJoinCode(joinCode) {
|
|
58
|
+
if (this._joinCode === joinCode)
|
|
59
|
+
return;
|
|
60
|
+
this._joinCode = joinCode;
|
|
61
|
+
for (const fn of this._joinCodeListeners) {
|
|
62
|
+
fn(joinCode);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { AppClientMessage, CompileDiagnosticEntry, FileSystemNotification } from "@mindcraft-lang/bridge-protocol";
|
|
2
|
+
import type { AppBridgeFeature, DiagnosticEntry, WorkspaceChange, WorkspaceSnapshot } from "./app-bridge.js";
|
|
3
|
+
export interface DiagnosticSnapshot {
|
|
4
|
+
files: ReadonlyMap<string, readonly DiagnosticEntry[]>;
|
|
5
|
+
}
|
|
6
|
+
export interface WorkspaceCompiler {
|
|
7
|
+
replaceWorkspace(snapshot: WorkspaceSnapshot): void;
|
|
8
|
+
applyWorkspaceChange(change: WorkspaceChange): void;
|
|
9
|
+
compile(): DiagnosticSnapshot;
|
|
10
|
+
onDidCompile(listener: (snapshot: DiagnosticSnapshot) => void): () => void;
|
|
11
|
+
}
|
|
12
|
+
export interface CompilationFeatureOptions {
|
|
13
|
+
compiler: WorkspaceCompiler;
|
|
14
|
+
publishStatus?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface CompilationResult {
|
|
17
|
+
files: Map<string, CompileDiagnosticEntry[]>;
|
|
18
|
+
}
|
|
19
|
+
export interface CompilationProvider {
|
|
20
|
+
fileWritten(path: string, content: string): void;
|
|
21
|
+
fileDeleted(path: string): void;
|
|
22
|
+
fileRenamed(oldPath: string, newPath: string): void;
|
|
23
|
+
fullSync(files: Iterable<[string, {
|
|
24
|
+
kind: string;
|
|
25
|
+
content?: string;
|
|
26
|
+
}]>): void;
|
|
27
|
+
compileAll(): CompilationResult;
|
|
28
|
+
}
|
|
29
|
+
export declare function createCompilationFeature(options: CompilationFeatureOptions): AppBridgeFeature;
|
|
30
|
+
export declare class CompilationManager {
|
|
31
|
+
private readonly _provider;
|
|
32
|
+
private readonly _send;
|
|
33
|
+
private readonly _isConnected;
|
|
34
|
+
private readonly _versions;
|
|
35
|
+
private readonly _previousFiles;
|
|
36
|
+
private readonly _compilationListeners;
|
|
37
|
+
private _lastResult;
|
|
38
|
+
private readonly _removalListeners;
|
|
39
|
+
constructor(provider: CompilationProvider, send: (msg: AppClientMessage) => void, isConnected: () => boolean);
|
|
40
|
+
handleFileChange(ev: FileSystemNotification): void;
|
|
41
|
+
onCompilation(fn: (result: CompilationResult) => void): () => void;
|
|
42
|
+
onRemoval(fn: (path: string) => void): () => void;
|
|
43
|
+
sendDiagnostics(): void;
|
|
44
|
+
private compileAndEmit;
|
|
45
|
+
private emitDiagnostics;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=compilation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compilation.d.ts","sourceRoot":"","sources":["../src/compilation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACxH,OAAO,KAAK,EACV,gBAAgB,EAGhB,eAAe,EACf,eAAe,EACf,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpD,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IACpD,OAAO,IAAI,kBAAkB,CAAC;IAC9B,YAAY,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC5E;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACpD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,GAAG,IAAI,CAAC;IAC9E,UAAU,IAAI,iBAAiB,CAAC;CACjC;AAwBD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,gBAAgB,CA8E7F;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;IAChD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;IACvD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAkD;IACxF,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqC;gBAE3D,QAAQ,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,EAAE,WAAW,EAAE,MAAM,OAAO;IAM5G,gBAAgB,CAAC,EAAE,EAAE,sBAAsB,GAAG,IAAI;IAsBlD,aAAa,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI;IAOlE,SAAS,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAOjD,eAAe,IAAI,IAAI;IAUvB,OAAO,CAAC,cAAc;IAoCtB,OAAO,CAAC,eAAe;CAyBxB"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
function buildFeatureStatus(file, diagnostics) {
|
|
2
|
+
let errorCount = 0;
|
|
3
|
+
let warningCount = 0;
|
|
4
|
+
for (const diagnostic of diagnostics) {
|
|
5
|
+
if (diagnostic.severity === "error") {
|
|
6
|
+
errorCount++;
|
|
7
|
+
}
|
|
8
|
+
else if (diagnostic.severity === "warning") {
|
|
9
|
+
warningCount++;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
file,
|
|
14
|
+
success: errorCount === 0,
|
|
15
|
+
diagnosticCount: {
|
|
16
|
+
error: errorCount,
|
|
17
|
+
warning: warningCount,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function createCompilationFeature(options) {
|
|
22
|
+
return {
|
|
23
|
+
attach(context) {
|
|
24
|
+
let lastSnapshot;
|
|
25
|
+
const previousDiagnosticFiles = new Set();
|
|
26
|
+
const publishStatus = options.publishStatus ?? true;
|
|
27
|
+
const publishSnapshot = (snapshot) => {
|
|
28
|
+
if (context.snapshot().status !== "connected") {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const currentFiles = new Set();
|
|
32
|
+
for (const [file, diagnostics] of snapshot.files) {
|
|
33
|
+
currentFiles.add(file);
|
|
34
|
+
if (diagnostics.length > 0 || previousDiagnosticFiles.has(file)) {
|
|
35
|
+
context.publishDiagnostics(file, diagnostics);
|
|
36
|
+
if (publishStatus) {
|
|
37
|
+
context.publishStatus(buildFeatureStatus(file, diagnostics));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const file of previousDiagnosticFiles) {
|
|
42
|
+
if (!currentFiles.has(file)) {
|
|
43
|
+
context.publishDiagnostics(file, []);
|
|
44
|
+
if (publishStatus) {
|
|
45
|
+
context.publishStatus(buildFeatureStatus(file, []));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
previousDiagnosticFiles.clear();
|
|
50
|
+
for (const [file, diagnostics] of snapshot.files) {
|
|
51
|
+
if (diagnostics.length > 0) {
|
|
52
|
+
previousDiagnosticFiles.add(file);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const compileAndPublish = () => {
|
|
57
|
+
const snapshot = options.compiler.compile();
|
|
58
|
+
if (lastSnapshot !== snapshot) {
|
|
59
|
+
lastSnapshot = snapshot;
|
|
60
|
+
publishSnapshot(snapshot);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const compileUnsub = options.compiler.onDidCompile((snapshot) => {
|
|
64
|
+
lastSnapshot = snapshot;
|
|
65
|
+
publishSnapshot(snapshot);
|
|
66
|
+
});
|
|
67
|
+
options.compiler.replaceWorkspace(context.workspaceSnapshot());
|
|
68
|
+
compileAndPublish();
|
|
69
|
+
const remoteChangeUnsub = context.onRemoteChange((change) => {
|
|
70
|
+
options.compiler.applyWorkspaceChange(change);
|
|
71
|
+
compileAndPublish();
|
|
72
|
+
});
|
|
73
|
+
const syncUnsub = context.onDidSync(() => {
|
|
74
|
+
if (lastSnapshot) {
|
|
75
|
+
publishSnapshot(lastSnapshot);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return () => {
|
|
79
|
+
syncUnsub();
|
|
80
|
+
remoteChangeUnsub();
|
|
81
|
+
compileUnsub();
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export class CompilationManager {
|
|
87
|
+
_provider;
|
|
88
|
+
_send;
|
|
89
|
+
_isConnected;
|
|
90
|
+
_versions = new Map();
|
|
91
|
+
_previousFiles = new Set();
|
|
92
|
+
_compilationListeners = new Set();
|
|
93
|
+
_lastResult;
|
|
94
|
+
_removalListeners = new Set();
|
|
95
|
+
constructor(provider, send, isConnected) {
|
|
96
|
+
this._provider = provider;
|
|
97
|
+
this._send = send;
|
|
98
|
+
this._isConnected = isConnected;
|
|
99
|
+
}
|
|
100
|
+
handleFileChange(ev) {
|
|
101
|
+
switch (ev.action) {
|
|
102
|
+
case "write":
|
|
103
|
+
this._provider.fileWritten(ev.path, ev.content);
|
|
104
|
+
break;
|
|
105
|
+
case "delete":
|
|
106
|
+
this._provider.fileDeleted(ev.path);
|
|
107
|
+
break;
|
|
108
|
+
case "rename":
|
|
109
|
+
this._provider.fileRenamed(ev.oldPath, ev.newPath);
|
|
110
|
+
break;
|
|
111
|
+
case "import":
|
|
112
|
+
this._provider.fullSync(ev.entries);
|
|
113
|
+
break;
|
|
114
|
+
case "mkdir":
|
|
115
|
+
case "rmdir":
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
this.compileAndEmit();
|
|
119
|
+
}
|
|
120
|
+
onCompilation(fn) {
|
|
121
|
+
this._compilationListeners.add(fn);
|
|
122
|
+
return () => {
|
|
123
|
+
this._compilationListeners.delete(fn);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
onRemoval(fn) {
|
|
127
|
+
this._removalListeners.add(fn);
|
|
128
|
+
return () => {
|
|
129
|
+
this._removalListeners.delete(fn);
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
sendDiagnostics() {
|
|
133
|
+
if (!this._lastResult || !this._isConnected())
|
|
134
|
+
return;
|
|
135
|
+
for (const [file, diagnostics] of this._lastResult.files) {
|
|
136
|
+
if (diagnostics.length > 0) {
|
|
137
|
+
this.emitDiagnostics(file, diagnostics);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
compileAndEmit() {
|
|
142
|
+
const result = this._provider.compileAll();
|
|
143
|
+
this._lastResult = result;
|
|
144
|
+
for (const fn of this._compilationListeners) {
|
|
145
|
+
fn(result);
|
|
146
|
+
}
|
|
147
|
+
if (!this._isConnected())
|
|
148
|
+
return;
|
|
149
|
+
const currentFiles = new Set();
|
|
150
|
+
for (const [file, diagnostics] of result.files) {
|
|
151
|
+
currentFiles.add(file);
|
|
152
|
+
if (diagnostics.length > 0 || this._previousFiles.has(file)) {
|
|
153
|
+
this.emitDiagnostics(file, diagnostics);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const file of this._previousFiles) {
|
|
157
|
+
if (!currentFiles.has(file)) {
|
|
158
|
+
this.emitDiagnostics(file, []);
|
|
159
|
+
for (const fn of this._removalListeners) {
|
|
160
|
+
fn(file);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
this._previousFiles.clear();
|
|
165
|
+
for (const [file, diagnostics] of result.files) {
|
|
166
|
+
if (diagnostics.length > 0) {
|
|
167
|
+
this._previousFiles.add(file);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
emitDiagnostics(file, diagnostics) {
|
|
172
|
+
const version = (this._versions.get(file) ?? 0) + 1;
|
|
173
|
+
this._versions.set(file, version);
|
|
174
|
+
this._send({
|
|
175
|
+
type: "compile:diagnostics",
|
|
176
|
+
payload: { file, version, diagnostics },
|
|
177
|
+
});
|
|
178
|
+
let errorCount = 0;
|
|
179
|
+
let warningCount = 0;
|
|
180
|
+
for (const d of diagnostics) {
|
|
181
|
+
if (d.severity === "error")
|
|
182
|
+
errorCount++;
|
|
183
|
+
else if (d.severity === "warning")
|
|
184
|
+
warningCount++;
|
|
185
|
+
}
|
|
186
|
+
this._send({
|
|
187
|
+
type: "compile:status",
|
|
188
|
+
payload: {
|
|
189
|
+
file,
|
|
190
|
+
success: errorCount === 0,
|
|
191
|
+
diagnosticCount: { error: errorCount, warning: warningCount },
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { AppBridge, AppBridgeFeature, AppBridgeFeatureContext, AppBridgeFeatureStatus, AppBridgeOptions, AppBridgeSnapshot, AppBridgeState, DiagnosticEntry, WorkspaceAdapter, WorkspaceChange, WorkspaceSnapshot, } from "./app-bridge.js";
|
|
2
|
+
export { createAppBridge } from "./app-bridge.js";
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createAppBridge } from "./app-bridge.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mindcraft-lang/bridge-app",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "App-side client for the Mindcraft bridge",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"author": "humanapp",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/humanapp/mindcraft-lang.git",
|
|
11
|
+
"directory": "packages/bridge-app"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/humanapp/mindcraft-lang/issues"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/humanapp/mindcraft-lang/tree/main/packages/bridge-app#readme",
|
|
17
|
+
"keywords": [
|
|
18
|
+
"mindcraft",
|
|
19
|
+
"visual-programming",
|
|
20
|
+
"tile-based",
|
|
21
|
+
"typescript",
|
|
22
|
+
"vscode",
|
|
23
|
+
"language",
|
|
24
|
+
"education",
|
|
25
|
+
"stem",
|
|
26
|
+
"coding",
|
|
27
|
+
"game-development",
|
|
28
|
+
"creative-coding",
|
|
29
|
+
"kodu",
|
|
30
|
+
"project-spark"
|
|
31
|
+
],
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
},
|
|
42
|
+
"main": "dist/index.js",
|
|
43
|
+
"types": "dist/index.d.ts",
|
|
44
|
+
"exports": {
|
|
45
|
+
".": {
|
|
46
|
+
"types": "./dist/index.d.ts",
|
|
47
|
+
"browser": "./dist/index.js",
|
|
48
|
+
"import": "./dist/index.js"
|
|
49
|
+
},
|
|
50
|
+
"./compilation": {
|
|
51
|
+
"types": "./dist/compilation.d.ts",
|
|
52
|
+
"browser": "./dist/compilation.js",
|
|
53
|
+
"import": "./dist/compilation.js"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsc --build",
|
|
58
|
+
"build:prod": "tsc --build",
|
|
59
|
+
"clean": "tsc --build --clean",
|
|
60
|
+
"watch": "tsc --build --watch",
|
|
61
|
+
"lint:only": "biome lint ./src",
|
|
62
|
+
"check:only": "biome check ./src",
|
|
63
|
+
"format:only": "biome format ./src",
|
|
64
|
+
"lint": "biome lint ./src --write",
|
|
65
|
+
"check": "biome check ./src --write",
|
|
66
|
+
"pretest": "npm run build",
|
|
67
|
+
"test": "tsx --tsconfig tsconfig.spec.json --test $(find test -name '*.spec.ts')",
|
|
68
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.spec.json",
|
|
69
|
+
"format": "biome format ./src --write",
|
|
70
|
+
"release:patch": "node ../../scripts/release.js patch",
|
|
71
|
+
"release:minor": "node ../../scripts/release.js minor",
|
|
72
|
+
"release:major": "node ../../scripts/release.js major"
|
|
73
|
+
},
|
|
74
|
+
"dependencies": {
|
|
75
|
+
"@mindcraft-lang/bridge-client": "^0.1.1",
|
|
76
|
+
"@mindcraft-lang/bridge-protocol": "^0.1.5"
|
|
77
|
+
},
|
|
78
|
+
"devDependencies": {
|
|
79
|
+
"@biomejs/biome": "2.3.15",
|
|
80
|
+
"@types/node": "^25.3.0",
|
|
81
|
+
"tsx": "^4.21.0",
|
|
82
|
+
"typescript": "~5.9.3"
|
|
83
|
+
}
|
|
84
|
+
}
|