@crowdedkingdoms/crowdyjs 8.22.0 → 9.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.
Files changed (43) hide show
  1. package/MIGRATION.md +44 -0
  2. package/README.md +74 -3
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/live-coding/assets/browser-authoring-index.json +1 -0
  7. package/dist/live-coding/assets/manifest.json +19 -0
  8. package/dist/live-coding/assets/tree-sitter-rust.wasm +0 -0
  9. package/dist/live-coding/assets/web-tree-sitter.wasm +0 -0
  10. package/dist/live-coding/browser-authoring-index.generated.d.ts +2 -0
  11. package/dist/live-coding/browser-authoring-index.generated.d.ts.map +1 -0
  12. package/dist/live-coding/browser-authoring-index.generated.js +5127 -0
  13. package/dist/live-coding/ide.d.ts +14 -7
  14. package/dist/live-coding/ide.d.ts.map +1 -1
  15. package/dist/live-coding/ide.js +296 -181
  16. package/dist/live-coding/index.d.ts +8 -0
  17. package/dist/live-coding/index.d.ts.map +1 -0
  18. package/dist/live-coding/index.js +7 -0
  19. package/dist/live-coding/lsp-protocol.d.ts +98 -0
  20. package/dist/live-coding/lsp-protocol.d.ts.map +1 -0
  21. package/dist/live-coding/lsp-protocol.js +70 -0
  22. package/dist/live-coding/monaco-services.d.ts +22 -0
  23. package/dist/live-coding/monaco-services.d.ts.map +1 -0
  24. package/dist/live-coding/monaco-services.js +69 -0
  25. package/dist/live-coding/platform-index.d.ts +29 -0
  26. package/dist/live-coding/platform-index.d.ts.map +1 -0
  27. package/dist/live-coding/platform-index.js +281 -0
  28. package/dist/live-coding/rust-analysis.d.ts +24 -0
  29. package/dist/live-coding/rust-analysis.d.ts.map +1 -0
  30. package/dist/live-coding/rust-analysis.js +312 -0
  31. package/dist/live-coding/rust-lsp-server.d.ts +43 -0
  32. package/dist/live-coding/rust-lsp-server.d.ts.map +1 -0
  33. package/dist/live-coding/rust-lsp-server.js +455 -0
  34. package/dist/live-coding/rust-lsp.worker.d.ts +2 -0
  35. package/dist/live-coding/rust-lsp.worker.d.ts.map +1 -0
  36. package/dist/live-coding/rust-lsp.worker.js +26 -0
  37. package/dist/live-coding/vfs.d.ts +41 -0
  38. package/dist/live-coding/vfs.d.ts.map +1 -0
  39. package/dist/live-coding/vfs.js +174 -0
  40. package/dist/live-coding/worker-transport.d.ts +60 -0
  41. package/dist/live-coding/worker-transport.d.ts.map +1 -0
  42. package/dist/live-coding/worker-transport.js +204 -0
  43. package/package.json +18 -6
@@ -0,0 +1,312 @@
1
+ import { Language, Parser, } from 'web-tree-sitter';
2
+ import { offsetAt } from './vfs.js';
3
+ const DECLARATION_KINDS = new Map([
4
+ ['function_item', 12],
5
+ ['function_signature_item', 12],
6
+ ['struct_item', 23],
7
+ ['enum_item', 10],
8
+ ['trait_item', 11],
9
+ ['type_item', 5],
10
+ ['const_item', 14],
11
+ ['static_item', 13],
12
+ ['mod_item', 2],
13
+ ['macro_definition', 12],
14
+ ]);
15
+ const RUST_KEYWORDS = [
16
+ 'as',
17
+ 'async',
18
+ 'await',
19
+ 'break',
20
+ 'const',
21
+ 'continue',
22
+ 'crate',
23
+ 'dyn',
24
+ 'else',
25
+ 'enum',
26
+ 'extern',
27
+ 'false',
28
+ 'fn',
29
+ 'for',
30
+ 'if',
31
+ 'impl',
32
+ 'in',
33
+ 'let',
34
+ 'loop',
35
+ 'match',
36
+ 'mod',
37
+ 'move',
38
+ 'mut',
39
+ 'pub',
40
+ 'ref',
41
+ 'return',
42
+ 'self',
43
+ 'static',
44
+ 'struct',
45
+ 'super',
46
+ 'trait',
47
+ 'true',
48
+ 'type',
49
+ 'unsafe',
50
+ 'use',
51
+ 'where',
52
+ 'while',
53
+ ];
54
+ let parserInitialization = null;
55
+ export class RustAnalysis {
56
+ constructor(parser, platformIndex) {
57
+ this.parser = parser;
58
+ this.platformIndex = platformIndex;
59
+ this.cache = new Map();
60
+ }
61
+ static async create(options) {
62
+ parserInitialization ?? (parserInitialization = Parser.init({
63
+ locateFile: () => options.parserWasmUrl,
64
+ }));
65
+ await parserInitialization;
66
+ const language = await Language.load(options.grammarWasmUrl);
67
+ const parser = new Parser();
68
+ parser.setLanguage(language);
69
+ return new RustAnalysis(parser, options.platformIndex);
70
+ }
71
+ diagnostics(document) {
72
+ return this.analyze(document).diagnostics;
73
+ }
74
+ completions(document, position, workspace) {
75
+ const prefix = wordPrefixAt(document.text, position);
76
+ const local = this.workspaceSymbols(workspace);
77
+ const items = [];
78
+ const seen = new Set();
79
+ const add = (item) => {
80
+ if (seen.has(item.label) ||
81
+ (prefix && !item.label.toLowerCase().startsWith(prefix.toLowerCase()))) {
82
+ return;
83
+ }
84
+ seen.add(item.label);
85
+ items.push(item);
86
+ };
87
+ for (const symbol of local) {
88
+ add({
89
+ label: symbol.name,
90
+ kind: symbol.kind,
91
+ detail: symbol.detail,
92
+ sortText: `0-${symbol.name}`,
93
+ });
94
+ }
95
+ for (const symbol of this.platformIndex.symbols) {
96
+ add(platformCompletion(symbol, this.platformIndex));
97
+ }
98
+ for (const keyword of RUST_KEYWORDS) {
99
+ add({ label: keyword, kind: 14, detail: 'Rust keyword', sortText: `2-${keyword}` });
100
+ }
101
+ return items.slice(0, 200);
102
+ }
103
+ hover(document, position, workspace) {
104
+ const word = wordAt(document.text, position);
105
+ if (!word)
106
+ return null;
107
+ const local = this.workspaceSymbols(workspace).find((symbol) => symbol.name === word);
108
+ if (local) {
109
+ return {
110
+ contents: {
111
+ kind: 'markdown',
112
+ value: `\`\`\`rust\n${local.detail}\n\`\`\`\n\nDefined in \`${local.uri}\`.`,
113
+ },
114
+ range: wordRange(document.text, position),
115
+ };
116
+ }
117
+ const platform = this.platformIndex.symbols.find((symbol) => symbol.name.replace(/!$/u, '').split('::').at(-1) === word);
118
+ if (!platform)
119
+ return null;
120
+ const crate = platformCrateForSymbol(this.platformIndex, platform);
121
+ const provenance = crate
122
+ ? `Crate ${crate.name} ${crate.version} · source ${crate.sourceHash.slice(0, 12)}…\n\n`
123
+ : '';
124
+ return {
125
+ contents: {
126
+ kind: 'markdown',
127
+ value: `\`\`\`rust\n${platform.signature}\n\`\`\`\n\n` +
128
+ `${platform.docs || `Defined in \`${platform.module}\`.`}\n\n` +
129
+ provenance +
130
+ `SDK ${this.platformIndex.sdkVersion} · ABI ${this.platformIndex.abiVersion}`,
131
+ },
132
+ range: wordRange(document.text, position),
133
+ };
134
+ }
135
+ documentSymbols(document) {
136
+ return this.analyze(document).symbols.map((symbol) => ({
137
+ name: symbol.name,
138
+ detail: symbol.detail,
139
+ kind: symbol.kind,
140
+ range: symbol.range,
141
+ selectionRange: symbol.selectionRange,
142
+ }));
143
+ }
144
+ definition(document, position, workspace) {
145
+ const word = wordAt(document.text, position);
146
+ if (!word)
147
+ return null;
148
+ const symbol = this.workspaceSymbols(workspace).find((candidate) => candidate.name === word);
149
+ return symbol
150
+ ? { uri: symbol.uri, range: symbol.selectionRange }
151
+ : null;
152
+ }
153
+ invalidate(uri) {
154
+ this.cache.delete(uri);
155
+ }
156
+ dispose() {
157
+ this.cache.clear();
158
+ this.parser.delete();
159
+ }
160
+ workspaceSymbols(documents) {
161
+ return documents.flatMap((document) => this.analyze(document).symbols);
162
+ }
163
+ analyze(document) {
164
+ const cached = this.cache.get(document.uri);
165
+ if (cached?.version === document.version)
166
+ return cached;
167
+ const tree = this.parser.parse(document.text);
168
+ if (!tree)
169
+ throw new Error(`Rust parser did not produce a tree for ${document.path}`);
170
+ try {
171
+ const diagnostics = [];
172
+ const symbols = [];
173
+ visit(tree.rootNode, (node) => {
174
+ if ((node.isError || node.isMissing) && diagnostics.length < 100) {
175
+ diagnostics.push({
176
+ range: nodeRange(document.text, node),
177
+ severity: 1,
178
+ source: 'crowdy-rust',
179
+ code: node.isMissing ? 'missing-syntax' : 'syntax-error',
180
+ message: node.isMissing
181
+ ? `Expected ${node.type}`
182
+ : `Unexpected Rust syntax: ${bounded(node.text, 80) || node.type}`,
183
+ });
184
+ }
185
+ const kind = DECLARATION_KINDS.get(node.type);
186
+ if (kind === undefined)
187
+ return;
188
+ const nameNode = node.childForFieldName('name') ??
189
+ node.namedChildren.find((child) => child.type === 'identifier');
190
+ if (!nameNode)
191
+ return;
192
+ const name = nameNode.text.replace(/!$/u, '');
193
+ symbols.push({
194
+ name,
195
+ detail: declarationDetail(node),
196
+ kind: node.type === 'function_item' && node.parent?.type === 'declaration_list'
197
+ ? 6
198
+ : kind,
199
+ uri: document.uri,
200
+ range: nodeRange(document.text, node),
201
+ selectionRange: nodeRange(document.text, nameNode),
202
+ });
203
+ });
204
+ const result = { version: document.version, diagnostics, symbols };
205
+ this.cache.set(document.uri, result);
206
+ return result;
207
+ }
208
+ finally {
209
+ tree.delete();
210
+ }
211
+ }
212
+ }
213
+ function visit(node, callback) {
214
+ callback(node);
215
+ for (const child of node.namedChildren)
216
+ visit(child, callback);
217
+ }
218
+ function declarationDetail(node) {
219
+ const firstBody = node.text.search(/[;{]/u);
220
+ return bounded((firstBody < 0 ? node.text : node.text.slice(0, firstBody)).trim(), 500);
221
+ }
222
+ function nodeRange(text, node) {
223
+ return {
224
+ start: pointToPosition(text, node.startPosition),
225
+ end: pointToPosition(text, node.endPosition),
226
+ };
227
+ }
228
+ function pointToPosition(text, point) {
229
+ const lines = text.split('\n');
230
+ const line = lines[point.row] ?? '';
231
+ let bytes = 0;
232
+ let character = 0;
233
+ for (const value of line) {
234
+ const width = new TextEncoder().encode(value).byteLength;
235
+ if (bytes + width > point.column)
236
+ break;
237
+ bytes += width;
238
+ character += value.length;
239
+ }
240
+ return { line: point.row, character };
241
+ }
242
+ function wordAt(text, position) {
243
+ const offset = offsetAt(text, position);
244
+ const left = text.slice(0, offset).match(/[A-Za-z_][A-Za-z0-9_]*$/u)?.[0] ?? '';
245
+ const right = text.slice(offset).match(/^[A-Za-z0-9_]*/u)?.[0] ?? '';
246
+ const word = left + right;
247
+ return /^[A-Za-z_][A-Za-z0-9_]*$/u.test(word) ? word : null;
248
+ }
249
+ function wordPrefixAt(text, position) {
250
+ const offset = offsetAt(text, position);
251
+ return text.slice(0, offset).match(/[A-Za-z_][A-Za-z0-9_]*$/u)?.[0] ?? '';
252
+ }
253
+ function wordRange(text, position) {
254
+ const offset = offsetAt(text, position);
255
+ const left = text.slice(0, offset).match(/[A-Za-z_][A-Za-z0-9_]*$/u)?.[0] ?? '';
256
+ const right = text.slice(offset).match(/^[A-Za-z0-9_]*/u)?.[0] ?? '';
257
+ return {
258
+ start: { line: position.line, character: position.character - left.length },
259
+ end: { line: position.line, character: position.character + right.length },
260
+ };
261
+ }
262
+ function platformCompletion(symbol, index) {
263
+ const crate = platformCrateForSymbol(index, symbol);
264
+ const label = symbol.kind === 'field'
265
+ ? symbol.name.split('::').at(-1)
266
+ : symbol.kind === 'macro' && !symbol.name.endsWith('!')
267
+ ? `${symbol.name}!`
268
+ : symbol.name;
269
+ return {
270
+ label,
271
+ kind: platformCompletionKind(symbol.kind),
272
+ detail: `${symbol.module} · ${symbol.signature}` +
273
+ (crate ? ` · ${crate.name}@${crate.version}` : ''),
274
+ documentation: symbol.docs,
275
+ insertText: label,
276
+ sortText: `1-${label}`,
277
+ };
278
+ }
279
+ function platformCompletionKind(kind) {
280
+ switch (kind) {
281
+ case 'function':
282
+ case 'method':
283
+ return 3;
284
+ case 'macro':
285
+ return 15;
286
+ case 'module':
287
+ return 9;
288
+ case 'const':
289
+ return 21;
290
+ case 'static':
291
+ return 6;
292
+ case 'field':
293
+ return 5;
294
+ case 'enum':
295
+ return 13;
296
+ case 'variant':
297
+ return 20;
298
+ case 'reexport':
299
+ return 9;
300
+ case 'struct':
301
+ case 'trait':
302
+ case 'type':
303
+ return 7;
304
+ }
305
+ }
306
+ function platformCrateForSymbol(index, symbol) {
307
+ const moduleRoot = symbol.module.split('::', 1)[0];
308
+ return index.crates.find((crate) => crate.name.replace(/-/gu, '_') === moduleRoot);
309
+ }
310
+ function bounded(value, length) {
311
+ return value.length <= length ? value : `${value.slice(0, length - 1)}…`;
312
+ }
@@ -0,0 +1,43 @@
1
+ import { type PlatformIndex } from './platform-index.js';
2
+ import { RustAnalysis } from './rust-analysis.js';
3
+ export interface RustLspServerOptions {
4
+ postMessage: (message: unknown) => void;
5
+ createAnalysis: (index: PlatformIndex) => Promise<RustAnalysis>;
6
+ diagnosticDebounceMs?: number;
7
+ requestTimeoutMs?: number;
8
+ }
9
+ export declare const MAX_PENDING_LSP_REQUESTS = 256;
10
+ export declare class RustLspServer {
11
+ private readonly options;
12
+ private vfs;
13
+ private analysis;
14
+ private initialized;
15
+ private shuttingDown;
16
+ private disposed;
17
+ private readonly requestStates;
18
+ private readonly diagnosticTimers;
19
+ private readonly diagnosticGenerations;
20
+ constructor(options: RustLspServerOptions);
21
+ handle(raw: unknown): Promise<void>;
22
+ /**
23
+ * Observes a worker message before it enters the serialized dispatch queue.
24
+ * Request state is bounded, and unknown cancellation ids are never retained.
25
+ */
26
+ observeIncoming(raw: unknown): boolean;
27
+ /** Backwards-compatible immediate cancellation hook for direct transports. */
28
+ handleImmediate(raw: unknown): boolean;
29
+ private cancelRequest;
30
+ dispose(): void;
31
+ private handleRequest;
32
+ private initialize;
33
+ private dispatchAnalysisRequest;
34
+ private handleNotification;
35
+ private scheduleDiagnostics;
36
+ private cancelDiagnostics;
37
+ private publishDiagnostics;
38
+ private requireVfs;
39
+ private requireAnalysis;
40
+ private sendResult;
41
+ private sendError;
42
+ }
43
+ //# sourceMappingURL=rust-lsp-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rust-lsp-server.d.ts","sourceRoot":"","sources":["../../src/live-coding/rust-lsp-server.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAQlD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,cAAc,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAChE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAiBD,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,qBAAa,aAAa;IAaZ,OAAO,CAAC,QAAQ,CAAC,OAAO;IAZpC,OAAO,CAAC,GAAG,CAAkC;IAC7C,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAG1B;IACJ,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoD;IACrF,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA6B;gBAEtC,OAAO,EAAE,oBAAoB;IAEpD,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBzC;;;OAGG;IACH,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IA8BtC,8EAA8E;IAC9E,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAItC,OAAO,CAAC,aAAa;IAQrB,OAAO,IAAI,IAAI;YAgBD,aAAa;YA8Eb,UAAU;YAwCV,uBAAuB;YAgEvB,kBAAkB;IAwFhC,OAAO,CAAC,mBAAmB;IAyB3B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,SAAS;CAYlB"}