rapydscript-ns 0.9.2 → 0.9.3

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 (151) hide show
  1. package/.agignore +1 -1
  2. package/.github/workflows/ci.yml +38 -38
  3. package/=template.pyj +5 -5
  4. package/CHANGELOG.md +19 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/PYTHON_GAPS.md +420 -0
  8. package/README.md +153 -29
  9. package/TODO.md +16 -118
  10. package/add-toc-to-readme +2 -2
  11. package/bin/export +75 -75
  12. package/bin/rapydscript +70 -70
  13. package/bin/web-repl-export +102 -102
  14. package/build +2 -2
  15. package/language-service/index.js +237 -8
  16. package/memory/project_string_impl.md +43 -0
  17. package/package.json +1 -1
  18. package/publish.py +37 -37
  19. package/release/baselib-plain-pretty.js +248 -38
  20. package/release/baselib-plain-ugly.js +8 -8
  21. package/release/compiler.js +778 -277
  22. package/release/signatures.json +30 -30
  23. package/session.vim +4 -4
  24. package/setup.cfg +2 -2
  25. package/src/ast.pyj +4 -1
  26. package/src/baselib-builtins.pyj +56 -2
  27. package/src/baselib-containers.pyj +2 -0
  28. package/src/baselib-errors.pyj +7 -3
  29. package/src/baselib-internal.pyj +51 -6
  30. package/src/baselib-str.pyj +5 -3
  31. package/src/compiler.pyj +36 -36
  32. package/src/errors.pyj +30 -30
  33. package/src/lib/aes.pyj +646 -646
  34. package/src/lib/asyncio.pyj +534 -0
  35. package/src/lib/base64.pyj +399 -0
  36. package/src/lib/bisect.pyj +73 -0
  37. package/src/lib/collections.pyj +1 -1
  38. package/src/lib/copy.pyj +120 -120
  39. package/src/lib/csv.pyj +494 -0
  40. package/src/lib/elementmaker.pyj +83 -83
  41. package/src/lib/encodings.pyj +126 -126
  42. package/src/lib/gettext.pyj +569 -569
  43. package/src/lib/heapq.pyj +98 -0
  44. package/src/lib/html.pyj +382 -0
  45. package/src/lib/http/__init__.pyj +98 -0
  46. package/src/lib/http/client.pyj +304 -0
  47. package/src/lib/http/cookies.pyj +236 -0
  48. package/src/lib/itertools.pyj +580 -580
  49. package/src/lib/logging.pyj +672 -0
  50. package/src/lib/math.pyj +193 -193
  51. package/src/lib/operator.pyj +11 -11
  52. package/src/lib/pythonize.pyj +20 -20
  53. package/src/lib/random.pyj +118 -118
  54. package/src/lib/react.pyj +74 -74
  55. package/src/lib/string.pyj +357 -0
  56. package/src/lib/textwrap.pyj +329 -0
  57. package/src/lib/traceback.pyj +63 -63
  58. package/src/lib/urllib/__init__.pyj +14 -0
  59. package/src/lib/urllib/error.pyj +66 -0
  60. package/src/lib/urllib/parse.pyj +475 -0
  61. package/src/lib/urllib/request.pyj +86 -0
  62. package/src/lib/uuid.pyj +77 -77
  63. package/src/monaco-language-service/analyzer.js +5 -2
  64. package/src/monaco-language-service/completions.js +26 -0
  65. package/src/monaco-language-service/diagnostics.js +202 -3
  66. package/src/monaco-language-service/dts.js +550 -550
  67. package/src/monaco-language-service/scope.js +1 -0
  68. package/src/output/comments.pyj +45 -45
  69. package/src/output/exceptions.pyj +201 -201
  70. package/src/output/functions.pyj +152 -6
  71. package/src/output/jsx.pyj +164 -164
  72. package/src/output/loops.pyj +17 -2
  73. package/src/output/modules.pyj +1 -1
  74. package/src/output/operators.pyj +15 -0
  75. package/src/output/stream.pyj +0 -1
  76. package/src/output/treeshake.pyj +182 -182
  77. package/src/output/utils.pyj +72 -72
  78. package/src/parse.pyj +80 -17
  79. package/src/string_interpolation.pyj +72 -72
  80. package/src/tokenizer.pyj +1 -1
  81. package/src/unicode_aliases.pyj +576 -576
  82. package/src/utils.pyj +192 -192
  83. package/test/_import_one.pyj +37 -37
  84. package/test/_import_two/__init__.pyj +11 -11
  85. package/test/_import_two/level2/deep.pyj +4 -4
  86. package/test/_import_two/other.pyj +6 -6
  87. package/test/_import_two/sub.pyj +13 -13
  88. package/test/aes_vectors.pyj +421 -421
  89. package/test/annotations.pyj +80 -80
  90. package/test/async_generators.pyj +144 -0
  91. package/test/asyncio.pyj +307 -0
  92. package/test/base64.pyj +202 -0
  93. package/test/bisect.pyj +178 -0
  94. package/test/csv.pyj +405 -0
  95. package/test/decorators.pyj +77 -77
  96. package/test/docstrings.pyj +39 -39
  97. package/test/elementmaker_test.pyj +45 -45
  98. package/test/float_special.pyj +64 -0
  99. package/test/functions.pyj +151 -151
  100. package/test/generators.pyj +41 -41
  101. package/test/generic.pyj +370 -370
  102. package/test/heapq.pyj +174 -0
  103. package/test/html.pyj +212 -0
  104. package/test/http.pyj +259 -0
  105. package/test/imports.pyj +79 -72
  106. package/test/internationalization.pyj +73 -73
  107. package/test/lint.pyj +164 -164
  108. package/test/logging.pyj +356 -0
  109. package/test/long.pyj +130 -0
  110. package/test/loops.pyj +85 -85
  111. package/test/numpy.pyj +734 -734
  112. package/test/parenthesized_with.pyj +141 -0
  113. package/test/python_compat.pyj +3 -5
  114. package/test/python_modulo.pyj +76 -0
  115. package/test/python_modulo_off.pyj +21 -0
  116. package/test/repl.pyj +121 -121
  117. package/test/scoped_flags.pyj +76 -76
  118. package/test/str.pyj +14 -0
  119. package/test/string.pyj +245 -0
  120. package/test/textwrap.pyj +172 -0
  121. package/test/type_display.pyj +48 -0
  122. package/test/type_enforcement.pyj +164 -0
  123. package/test/unit/index.js +14 -6
  124. package/test/unit/language-service-completions.js +119 -0
  125. package/test/unit/language-service-dts.js +543 -543
  126. package/test/unit/language-service-hover.js +455 -455
  127. package/test/unit/language-service-scope.js +32 -0
  128. package/test/unit/language-service.js +127 -3
  129. package/test/unit/run-language-service.js +17 -3
  130. package/test/unit/web-repl.js +2094 -29
  131. package/test/urllib.pyj +193 -0
  132. package/tools/compile.js +1 -1
  133. package/tools/compiler.d.ts +367 -367
  134. package/tools/completer.js +131 -131
  135. package/tools/embedded_compiler.js +7 -7
  136. package/tools/gettext.js +185 -185
  137. package/tools/ini.js +65 -65
  138. package/tools/msgfmt.js +187 -187
  139. package/tools/repl.js +223 -223
  140. package/tools/test.js +118 -118
  141. package/tools/utils.js +128 -128
  142. package/tools/web_repl.js +95 -95
  143. package/try +41 -41
  144. package/web-repl/env.js +196 -196
  145. package/web-repl/index.html +163 -163
  146. package/web-repl/main.js +1 -1
  147. package/web-repl/prism.css +139 -139
  148. package/web-repl/prism.js +113 -113
  149. package/web-repl/rapydscript.js +224 -224
  150. package/web-repl/sha1.js +25 -25
  151. package/test/omit_function_metadata.pyj +0 -20
@@ -1,543 +1,543 @@
1
- /*
2
- * test/unit/language-service-dts.js
3
- *
4
- * Unit tests for src/monaco-language-service/dts.js (Phase 6).
5
- *
6
- * Usage:
7
- * node test/unit/language-service-dts.js # run all tests
8
- * node test/unit/language-service-dts.js <test-name> # run single test
9
- */
10
- "use strict";
11
-
12
- var assert = require("assert");
13
- var path = require("path");
14
- var url = require("url");
15
- var utils = require("../../tools/utils");
16
- var colored = utils.safe_colored;
17
-
18
- // ---------------------------------------------------------------------------
19
- // Helpers
20
- // ---------------------------------------------------------------------------
21
-
22
- /** Return labels from a TypeInfo members Map. */
23
- function member_names(ti) {
24
- return ti.members ? Array.from(ti.members.keys()) : [];
25
- }
26
-
27
- // ---------------------------------------------------------------------------
28
- // Tests
29
- // ---------------------------------------------------------------------------
30
-
31
- function make_tests(parse_dts, DtsRegistry, TypeInfo) {
32
-
33
- var TESTS = [
34
-
35
- // ── parse_dts: var / let / const ─────────────────────────────────
36
-
37
- {
38
- name: "parse_var",
39
- description: "declare var name: Type; produces a 'var' TypeInfo",
40
- run: function () {
41
- var types = parse_dts("declare var NaN: number;");
42
- assert.strictEqual(types.length, 1);
43
- assert.strictEqual(types[0].name, "NaN");
44
- assert.strictEqual(types[0].kind, "var");
45
- assert.strictEqual(types[0].return_type, "number");
46
- },
47
- },
48
-
49
- {
50
- name: "parse_const",
51
- description: "declare const name: Type; is treated as 'var'",
52
- run: function () {
53
- var types = parse_dts("declare const PI: number;");
54
- assert.strictEqual(types.length, 1);
55
- assert.strictEqual(types[0].name, "PI");
56
- assert.strictEqual(types[0].kind, "var");
57
- },
58
- },
59
-
60
- // ── parse_dts: function ───────────────────────────────────────────
61
-
62
- {
63
- name: "parse_function_no_params",
64
- description: "declare function with no params",
65
- run: function () {
66
- var types = parse_dts("declare function now(): number;");
67
- assert.strictEqual(types.length, 1);
68
- var ti = types[0];
69
- assert.strictEqual(ti.name, "now");
70
- assert.strictEqual(ti.kind, "function");
71
- assert.ok(Array.isArray(ti.params));
72
- assert.strictEqual(ti.params.length, 0);
73
- assert.strictEqual(ti.return_type, "number");
74
- },
75
- },
76
-
77
- {
78
- name: "parse_function_with_params",
79
- description: "declare function with regular params",
80
- run: function () {
81
- var types = parse_dts("declare function parseInt(string: string, radix?: number): number;");
82
- assert.strictEqual(types.length, 1);
83
- var ti = types[0];
84
- assert.strictEqual(ti.name, "parseInt");
85
- assert.strictEqual(ti.params.length, 2);
86
- assert.strictEqual(ti.params[0].name, "string");
87
- assert.strictEqual(ti.params[0].type, "string");
88
- assert.strictEqual(ti.params[0].optional, false);
89
- assert.strictEqual(ti.params[1].name, "radix");
90
- assert.strictEqual(ti.params[1].optional, true);
91
- assert.strictEqual(ti.return_type, "number");
92
- },
93
- },
94
-
95
- {
96
- name: "parse_function_rest_param",
97
- description: "declare function with ...rest param",
98
- run: function () {
99
- var types = parse_dts("declare function log(...data: any[]): void;");
100
- assert.strictEqual(types.length, 1);
101
- var ti = types[0];
102
- assert.strictEqual(ti.params.length, 1);
103
- assert.strictEqual(ti.params[0].name, "data");
104
- assert.strictEqual(ti.params[0].rest, true);
105
- },
106
- },
107
-
108
- // ── parse_dts: interface ──────────────────────────────────────────
109
-
110
- {
111
- name: "parse_interface_members",
112
- description: "interface with methods and properties",
113
- run: function () {
114
- var src = [
115
- "interface Console {",
116
- " log(...data: any[]): void;",
117
- " error(message?: any): void;",
118
- " warn(message?: any): void;",
119
- "}",
120
- ].join("\n");
121
- var types = parse_dts(src);
122
- assert.strictEqual(types.length, 1);
123
- var ti = types[0];
124
- assert.strictEqual(ti.name, "Console");
125
- assert.strictEqual(ti.kind, "interface");
126
- assert.ok(ti.members instanceof Map);
127
- assert.ok(ti.members.has("log"), "should have log");
128
- assert.ok(ti.members.has("error"), "should have error");
129
- assert.ok(ti.members.has("warn"), "should have warn");
130
- var log = ti.members.get("log");
131
- assert.strictEqual(log.kind, "method");
132
- assert.strictEqual(log.params[0].rest, true);
133
- },
134
- },
135
-
136
- {
137
- name: "parse_interface_property",
138
- description: "interface property produces a 'property' member",
139
- run: function () {
140
- var src = [
141
- "interface Location {",
142
- " href: string;",
143
- " pathname: string;",
144
- "}",
145
- ].join("\n");
146
- var types = parse_dts(src);
147
- var ti = types[0];
148
- assert.ok(ti.members.has("href"), "should have href");
149
- assert.strictEqual(ti.members.get("href").kind, "property");
150
- assert.strictEqual(ti.members.get("href").return_type, "string");
151
- },
152
- },
153
-
154
- // ── parse_dts: class ──────────────────────────────────────────────
155
-
156
- {
157
- name: "parse_class",
158
- description: "declare class with methods",
159
- run: function () {
160
- var src = [
161
- "declare class Map<K, V> {",
162
- " get(key: K): V | undefined;",
163
- " set(key: K, value: V): this;",
164
- " has(key: K): boolean;",
165
- " size: number;",
166
- "}",
167
- ].join("\n");
168
- var types = parse_dts(src);
169
- assert.strictEqual(types.length, 1);
170
- var ti = types[0];
171
- assert.strictEqual(ti.name, "Map");
172
- assert.strictEqual(ti.kind, "class");
173
- assert.ok(ti.members.has("get"), "should have get");
174
- assert.ok(ti.members.has("set"), "should have set");
175
- assert.ok(ti.members.has("has"), "should have has");
176
- assert.ok(ti.members.has("size"), "should have size");
177
- },
178
- },
179
-
180
- // ── parse_dts: namespace ──────────────────────────────────────────
181
-
182
- {
183
- name: "parse_namespace",
184
- description: "declare namespace with function members",
185
- run: function () {
186
- var src = [
187
- "declare namespace Math {",
188
- " function abs(x: number): number;",
189
- " function sqrt(x: number): number;",
190
- " const PI: number;",
191
- "}",
192
- ].join("\n");
193
- var types = parse_dts(src);
194
- assert.strictEqual(types.length, 1);
195
- var ti = types[0];
196
- assert.strictEqual(ti.name, "Math");
197
- assert.strictEqual(ti.kind, "namespace");
198
- // namespace members parsed as methods/properties in inner scope
199
- assert.ok(ti.members instanceof Map);
200
- },
201
- },
202
-
203
- // ── parse_dts: JSDoc ─────────────────────────────────────────────
204
-
205
- {
206
- name: "parse_jsdoc",
207
- description: "JSDoc comment above a declaration is captured as doc",
208
- run: function () {
209
- var src = [
210
- "/** Converts a string to a number. */",
211
- "declare function parseFloat(string: string): number;",
212
- ].join("\n");
213
- var types = parse_dts(src);
214
- assert.ok(types[0].doc, "should have doc");
215
- assert.ok(types[0].doc.indexOf("Converts") !== -1,
216
- "doc should contain 'Converts'");
217
- },
218
- },
219
-
220
- {
221
- name: "parse_multiline_jsdoc",
222
- description: "Multi-line JSDoc is joined into one string",
223
- run: function () {
224
- var src = [
225
- "/**",
226
- " * Encodes a URI component.",
227
- " * @param uriComponent The string to encode.",
228
- " */",
229
- "declare function encodeURIComponent(uriComponent: string): string;",
230
- ].join("\n");
231
- var types = parse_dts(src);
232
- assert.ok(types[0].doc, "should have doc");
233
- assert.ok(types[0].doc.indexOf("Encodes") !== -1);
234
- },
235
- },
236
-
237
- // ── parse_dts: multiple declarations ────────────────────────────
238
-
239
- {
240
- name: "parse_multiple",
241
- description: "Multiple declarations in one file are all returned",
242
- run: function () {
243
- var src = [
244
- "declare var undefined: undefined;",
245
- "declare function isNaN(number: number): boolean;",
246
- "declare function isFinite(number: number): boolean;",
247
- "interface Error {",
248
- " message: string;",
249
- "}",
250
- ].join("\n");
251
- var types = parse_dts(src);
252
- assert.strictEqual(types.length, 4);
253
- var names = types.map(function (t) { return t.name; });
254
- assert.ok(names.indexOf("undefined") !== -1);
255
- assert.ok(names.indexOf("isNaN") !== -1);
256
- assert.ok(names.indexOf("isFinite") !== -1);
257
- assert.ok(names.indexOf("Error") !== -1);
258
- },
259
- },
260
-
261
- // ── DtsRegistry ───────────────────────────────────────────────────
262
-
263
- {
264
- name: "registry_addDts_getGlobal",
265
- description: "addDts registers globals retrievable by getGlobal",
266
- run: function () {
267
- var reg = new DtsRegistry();
268
- reg.addDts("lib", "declare function alert(message?: any): void;");
269
- var ti = reg.getGlobal("alert");
270
- assert.ok(ti, "alert should be registered");
271
- assert.strictEqual(ti.kind, "function");
272
- },
273
- },
274
-
275
- {
276
- name: "registry_getGlobalNames",
277
- description: "getGlobalNames returns all registered names",
278
- run: function () {
279
- var reg = new DtsRegistry();
280
- reg.addDts("lib", [
281
- "declare var document: Document;",
282
- "declare function alert(msg: string): void;",
283
- ].join("\n"));
284
- var names = reg.getGlobalNames();
285
- assert.ok(names.indexOf("document") !== -1);
286
- assert.ok(names.indexOf("alert") !== -1);
287
- },
288
- },
289
-
290
- {
291
- name: "registry_getGlobal_unknown",
292
- description: "getGlobal returns null for an unknown name",
293
- run: function () {
294
- var reg = new DtsRegistry();
295
- assert.strictEqual(reg.getGlobal("doesNotExist"), null);
296
- },
297
- },
298
-
299
- {
300
- name: "registry_merge",
301
- description: "Calling addDts multiple times merges all globals",
302
- run: function () {
303
- var reg = new DtsRegistry();
304
- reg.addDts("a", "declare var x: number;");
305
- reg.addDts("b", "declare var y: string;");
306
- assert.ok(reg.getGlobal("x"), "x should be registered");
307
- assert.ok(reg.getGlobal("y"), "y should be registered");
308
- assert.strictEqual(reg.getGlobalNames().length, 2);
309
- },
310
- },
311
-
312
- {
313
- name: "registry_getHoverMarkdown_function",
314
- description: "getHoverMarkdown returns markdown for a function",
315
- run: function () {
316
- var reg = new DtsRegistry();
317
- reg.addDts("lib", "declare function parseInt(s: string, radix?: number): number;");
318
- var md = reg.getHoverMarkdown("parseInt");
319
- assert.ok(md, "should return markdown");
320
- assert.ok(md.indexOf("parseInt") !== -1, "should include name");
321
- assert.ok(md.indexOf("function") !== -1, "should include kind");
322
- assert.ok(md.indexOf("```") !== -1, "should be in code block");
323
- },
324
- },
325
-
326
- {
327
- name: "registry_getHoverMarkdown_var",
328
- description: "getHoverMarkdown returns markdown for a var with type",
329
- run: function () {
330
- var reg = new DtsRegistry();
331
- reg.addDts("lib", "declare var NaN: number;");
332
- var md = reg.getHoverMarkdown("NaN");
333
- assert.ok(md, "should return markdown");
334
- assert.ok(md.indexOf("NaN") !== -1);
335
- assert.ok(md.indexOf("number") !== -1, "should show type");
336
- },
337
- },
338
-
339
- {
340
- name: "registry_getHoverMarkdown_with_doc",
341
- description: "getHoverMarkdown includes the JSDoc comment",
342
- run: function () {
343
- var reg = new DtsRegistry();
344
- reg.addDts("lib", [
345
- "/** Parses a float. */",
346
- "declare function parseFloat(s: string): number;",
347
- ].join("\n"));
348
- var md = reg.getHoverMarkdown("parseFloat");
349
- assert.ok(md.indexOf("Parses a float") !== -1,
350
- "should include docstring");
351
- },
352
- },
353
-
354
- {
355
- name: "registry_getHoverMarkdown_unknown",
356
- description: "getHoverMarkdown returns null for unknown name",
357
- run: function () {
358
- var reg = new DtsRegistry();
359
- assert.strictEqual(reg.getHoverMarkdown("nope"), null);
360
- },
361
- },
362
-
363
- {
364
- name: "registry_getMemberNames",
365
- description: "getMemberNames returns method/property names for a class/interface",
366
- run: function () {
367
- var reg = new DtsRegistry();
368
- reg.addDts("lib", [
369
- "interface Console {",
370
- " log(...data: any[]): void;",
371
- " error(message?: any): void;",
372
- "}",
373
- ].join("\n"));
374
- var names = reg.getMemberNames("Console");
375
- assert.ok(names.indexOf("log") !== -1, "should have log");
376
- assert.ok(names.indexOf("error") !== -1, "should have error");
377
- },
378
- },
379
-
380
- // ── Hover integration ─────────────────────────────────────────────
381
-
382
- {
383
- name: "hover_dts_fallback",
384
- description: "HoverEngine falls back to DTS registry when word not in ScopeMap",
385
- run: function () {
386
- var reg = new DtsRegistry();
387
- reg.addDts("lib", "declare function alert(msg: string): void;");
388
- var md = reg.getHoverMarkdown("alert");
389
- assert.ok(md, "registry should provide hover for alert");
390
- assert.ok(md.indexOf("alert") !== -1);
391
- },
392
- },
393
-
394
- // ── loadDts (async lazy loader) ───────────────────────────────────
395
-
396
- {
397
- name: "loadDts_calls_callback_and_registers",
398
- description: "loadDts calls the provided callback and registers the result",
399
- run: function (done) {
400
- var reg = new DtsRegistry();
401
- var called_with = null;
402
-
403
- function loader(name) {
404
- called_with = name;
405
- return Promise.resolve("declare function fetch(url: string): any;");
406
- }
407
-
408
- // Simulate what index.js does: call loader, then addDts
409
- var promise = Promise.resolve(loader("lib.fetch")).then(function (text) {
410
- reg.addDts("lib.fetch", text);
411
- });
412
-
413
- return promise.then(function () {
414
- assert.strictEqual(called_with, "lib.fetch", "loader called with correct name");
415
- assert.ok(reg.getGlobal("fetch"), "fetch should be registered");
416
- assert.strictEqual(reg.getGlobal("fetch").kind, "function");
417
- });
418
- },
419
- },
420
-
421
- {
422
- name: "loadDts_promise_resolves_after_registration",
423
- description: "The Promise from loadDts resolves only after addDts completes",
424
- run: function () {
425
- var reg = new DtsRegistry();
426
- var resolved = false;
427
-
428
- var p = Promise.resolve("declare var myGlobal: string;").then(function (text) {
429
- reg.addDts("test", text);
430
- resolved = true;
431
- });
432
-
433
- return p.then(function () {
434
- assert.ok(resolved, "promise should have resolved");
435
- assert.ok(reg.getGlobal("myGlobal"), "myGlobal should be registered");
436
- });
437
- },
438
- },
439
-
440
- {
441
- name: "loadDts_no_callback_rejects",
442
- description: "loadDts without a callback returns a rejected Promise",
443
- run: function () {
444
- // Simulate the index.js guard: no _loadDts stored
445
- var loadDts = function (name) {
446
- return Promise.reject(
447
- new Error("registerRapydScript: options.loadDts was not provided")
448
- );
449
- };
450
-
451
- return loadDts("anything").then(
452
- function () { assert.fail("should have rejected"); },
453
- function (err) {
454
- assert.ok(err.message.indexOf("loadDts") !== -1,
455
- "error should mention loadDts");
456
- }
457
- );
458
- },
459
- },
460
-
461
- ];
462
-
463
- return TESTS;
464
- }
465
-
466
- // ---------------------------------------------------------------------------
467
- // Runner
468
- // ---------------------------------------------------------------------------
469
-
470
- function run_tests(TESTS, filter) {
471
- var tests = filter
472
- ? TESTS.filter(function (t) { return t.name === filter; })
473
- : TESTS;
474
-
475
- if (tests.length === 0) {
476
- console.error(colored("No test found: " + filter, "red"));
477
- process.exit(1);
478
- }
479
-
480
- var failures = [];
481
-
482
- // Run tests sequentially, supporting tests that return a Promise.
483
- function run_next(i) {
484
- if (i >= tests.length) {
485
- console.log("");
486
- if (failures.length) {
487
- console.log(colored(failures.length + " test(s) failed.", "red"));
488
- } else {
489
- console.log(colored("All " + tests.length + " language-service-dts tests passed!", "green"));
490
- }
491
- process.exit(failures.length ? 1 : 0);
492
- return;
493
- }
494
- var test = tests[i];
495
- var result;
496
- try {
497
- result = test.run();
498
- } catch (e) {
499
- failures.push(test.name);
500
- console.log(colored("FAIL " + test.name, "red") +
501
- "\n " + (e.message || String(e)) + "\n");
502
- run_next(i + 1);
503
- return;
504
- }
505
- // If the test returned a Promise, wait for it.
506
- if (result && typeof result.then === 'function') {
507
- result.then(function () {
508
- console.log(colored("PASS " + test.name, "green") +
509
- " – " + test.description);
510
- run_next(i + 1);
511
- }, function (e) {
512
- failures.push(test.name);
513
- console.log(colored("FAIL " + test.name, "red") +
514
- "\n " + (e.message || String(e)) + "\n");
515
- run_next(i + 1);
516
- });
517
- } else {
518
- console.log(colored("PASS " + test.name, "green") +
519
- " – " + test.description);
520
- run_next(i + 1);
521
- }
522
- }
523
-
524
- run_next(0);
525
- }
526
-
527
- // ---------------------------------------------------------------------------
528
- // Entry point
529
- // ---------------------------------------------------------------------------
530
-
531
- var dts_path = url.pathToFileURL(
532
- path.join(__dirname, "../../src/monaco-language-service/dts.js")
533
- ).href;
534
-
535
- var filter = process.argv[2] || null;
536
-
537
- import(dts_path).then(function (mod) {
538
- var TESTS = make_tests(mod.parse_dts, mod.DtsRegistry, mod.TypeInfo);
539
- run_tests(TESTS, filter);
540
- }).catch(function (e) {
541
- console.error(colored("Failed to load dts module:", "red"), e);
542
- process.exit(1);
543
- });
1
+ /*
2
+ * test/unit/language-service-dts.js
3
+ *
4
+ * Unit tests for src/monaco-language-service/dts.js (Phase 6).
5
+ *
6
+ * Usage:
7
+ * node test/unit/language-service-dts.js # run all tests
8
+ * node test/unit/language-service-dts.js <test-name> # run single test
9
+ */
10
+ "use strict";
11
+
12
+ var assert = require("assert");
13
+ var path = require("path");
14
+ var url = require("url");
15
+ var utils = require("../../tools/utils");
16
+ var colored = utils.safe_colored;
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Helpers
20
+ // ---------------------------------------------------------------------------
21
+
22
+ /** Return labels from a TypeInfo members Map. */
23
+ function member_names(ti) {
24
+ return ti.members ? Array.from(ti.members.keys()) : [];
25
+ }
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // Tests
29
+ // ---------------------------------------------------------------------------
30
+
31
+ function make_tests(parse_dts, DtsRegistry, TypeInfo) {
32
+
33
+ var TESTS = [
34
+
35
+ // ── parse_dts: var / let / const ─────────────────────────────────
36
+
37
+ {
38
+ name: "parse_var",
39
+ description: "declare var name: Type; produces a 'var' TypeInfo",
40
+ run: function () {
41
+ var types = parse_dts("declare var NaN: number;");
42
+ assert.strictEqual(types.length, 1);
43
+ assert.strictEqual(types[0].name, "NaN");
44
+ assert.strictEqual(types[0].kind, "var");
45
+ assert.strictEqual(types[0].return_type, "number");
46
+ },
47
+ },
48
+
49
+ {
50
+ name: "parse_const",
51
+ description: "declare const name: Type; is treated as 'var'",
52
+ run: function () {
53
+ var types = parse_dts("declare const PI: number;");
54
+ assert.strictEqual(types.length, 1);
55
+ assert.strictEqual(types[0].name, "PI");
56
+ assert.strictEqual(types[0].kind, "var");
57
+ },
58
+ },
59
+
60
+ // ── parse_dts: function ───────────────────────────────────────────
61
+
62
+ {
63
+ name: "parse_function_no_params",
64
+ description: "declare function with no params",
65
+ run: function () {
66
+ var types = parse_dts("declare function now(): number;");
67
+ assert.strictEqual(types.length, 1);
68
+ var ti = types[0];
69
+ assert.strictEqual(ti.name, "now");
70
+ assert.strictEqual(ti.kind, "function");
71
+ assert.ok(Array.isArray(ti.params));
72
+ assert.strictEqual(ti.params.length, 0);
73
+ assert.strictEqual(ti.return_type, "number");
74
+ },
75
+ },
76
+
77
+ {
78
+ name: "parse_function_with_params",
79
+ description: "declare function with regular params",
80
+ run: function () {
81
+ var types = parse_dts("declare function parseInt(string: string, radix?: number): number;");
82
+ assert.strictEqual(types.length, 1);
83
+ var ti = types[0];
84
+ assert.strictEqual(ti.name, "parseInt");
85
+ assert.strictEqual(ti.params.length, 2);
86
+ assert.strictEqual(ti.params[0].name, "string");
87
+ assert.strictEqual(ti.params[0].type, "string");
88
+ assert.strictEqual(ti.params[0].optional, false);
89
+ assert.strictEqual(ti.params[1].name, "radix");
90
+ assert.strictEqual(ti.params[1].optional, true);
91
+ assert.strictEqual(ti.return_type, "number");
92
+ },
93
+ },
94
+
95
+ {
96
+ name: "parse_function_rest_param",
97
+ description: "declare function with ...rest param",
98
+ run: function () {
99
+ var types = parse_dts("declare function log(...data: any[]): void;");
100
+ assert.strictEqual(types.length, 1);
101
+ var ti = types[0];
102
+ assert.strictEqual(ti.params.length, 1);
103
+ assert.strictEqual(ti.params[0].name, "data");
104
+ assert.strictEqual(ti.params[0].rest, true);
105
+ },
106
+ },
107
+
108
+ // ── parse_dts: interface ──────────────────────────────────────────
109
+
110
+ {
111
+ name: "parse_interface_members",
112
+ description: "interface with methods and properties",
113
+ run: function () {
114
+ var src = [
115
+ "interface Console {",
116
+ " log(...data: any[]): void;",
117
+ " error(message?: any): void;",
118
+ " warn(message?: any): void;",
119
+ "}",
120
+ ].join("\n");
121
+ var types = parse_dts(src);
122
+ assert.strictEqual(types.length, 1);
123
+ var ti = types[0];
124
+ assert.strictEqual(ti.name, "Console");
125
+ assert.strictEqual(ti.kind, "interface");
126
+ assert.ok(ti.members instanceof Map);
127
+ assert.ok(ti.members.has("log"), "should have log");
128
+ assert.ok(ti.members.has("error"), "should have error");
129
+ assert.ok(ti.members.has("warn"), "should have warn");
130
+ var log = ti.members.get("log");
131
+ assert.strictEqual(log.kind, "method");
132
+ assert.strictEqual(log.params[0].rest, true);
133
+ },
134
+ },
135
+
136
+ {
137
+ name: "parse_interface_property",
138
+ description: "interface property produces a 'property' member",
139
+ run: function () {
140
+ var src = [
141
+ "interface Location {",
142
+ " href: string;",
143
+ " pathname: string;",
144
+ "}",
145
+ ].join("\n");
146
+ var types = parse_dts(src);
147
+ var ti = types[0];
148
+ assert.ok(ti.members.has("href"), "should have href");
149
+ assert.strictEqual(ti.members.get("href").kind, "property");
150
+ assert.strictEqual(ti.members.get("href").return_type, "string");
151
+ },
152
+ },
153
+
154
+ // ── parse_dts: class ──────────────────────────────────────────────
155
+
156
+ {
157
+ name: "parse_class",
158
+ description: "declare class with methods",
159
+ run: function () {
160
+ var src = [
161
+ "declare class Map<K, V> {",
162
+ " get(key: K): V | undefined;",
163
+ " set(key: K, value: V): this;",
164
+ " has(key: K): boolean;",
165
+ " size: number;",
166
+ "}",
167
+ ].join("\n");
168
+ var types = parse_dts(src);
169
+ assert.strictEqual(types.length, 1);
170
+ var ti = types[0];
171
+ assert.strictEqual(ti.name, "Map");
172
+ assert.strictEqual(ti.kind, "class");
173
+ assert.ok(ti.members.has("get"), "should have get");
174
+ assert.ok(ti.members.has("set"), "should have set");
175
+ assert.ok(ti.members.has("has"), "should have has");
176
+ assert.ok(ti.members.has("size"), "should have size");
177
+ },
178
+ },
179
+
180
+ // ── parse_dts: namespace ──────────────────────────────────────────
181
+
182
+ {
183
+ name: "parse_namespace",
184
+ description: "declare namespace with function members",
185
+ run: function () {
186
+ var src = [
187
+ "declare namespace Math {",
188
+ " function abs(x: number): number;",
189
+ " function sqrt(x: number): number;",
190
+ " const PI: number;",
191
+ "}",
192
+ ].join("\n");
193
+ var types = parse_dts(src);
194
+ assert.strictEqual(types.length, 1);
195
+ var ti = types[0];
196
+ assert.strictEqual(ti.name, "Math");
197
+ assert.strictEqual(ti.kind, "namespace");
198
+ // namespace members parsed as methods/properties in inner scope
199
+ assert.ok(ti.members instanceof Map);
200
+ },
201
+ },
202
+
203
+ // ── parse_dts: JSDoc ─────────────────────────────────────────────
204
+
205
+ {
206
+ name: "parse_jsdoc",
207
+ description: "JSDoc comment above a declaration is captured as doc",
208
+ run: function () {
209
+ var src = [
210
+ "/** Converts a string to a number. */",
211
+ "declare function parseFloat(string: string): number;",
212
+ ].join("\n");
213
+ var types = parse_dts(src);
214
+ assert.ok(types[0].doc, "should have doc");
215
+ assert.ok(types[0].doc.indexOf("Converts") !== -1,
216
+ "doc should contain 'Converts'");
217
+ },
218
+ },
219
+
220
+ {
221
+ name: "parse_multiline_jsdoc",
222
+ description: "Multi-line JSDoc is joined into one string",
223
+ run: function () {
224
+ var src = [
225
+ "/**",
226
+ " * Encodes a URI component.",
227
+ " * @param uriComponent The string to encode.",
228
+ " */",
229
+ "declare function encodeURIComponent(uriComponent: string): string;",
230
+ ].join("\n");
231
+ var types = parse_dts(src);
232
+ assert.ok(types[0].doc, "should have doc");
233
+ assert.ok(types[0].doc.indexOf("Encodes") !== -1);
234
+ },
235
+ },
236
+
237
+ // ── parse_dts: multiple declarations ────────────────────────────
238
+
239
+ {
240
+ name: "parse_multiple",
241
+ description: "Multiple declarations in one file are all returned",
242
+ run: function () {
243
+ var src = [
244
+ "declare var undefined: undefined;",
245
+ "declare function isNaN(number: number): boolean;",
246
+ "declare function isFinite(number: number): boolean;",
247
+ "interface Error {",
248
+ " message: string;",
249
+ "}",
250
+ ].join("\n");
251
+ var types = parse_dts(src);
252
+ assert.strictEqual(types.length, 4);
253
+ var names = types.map(function (t) { return t.name; });
254
+ assert.ok(names.indexOf("undefined") !== -1);
255
+ assert.ok(names.indexOf("isNaN") !== -1);
256
+ assert.ok(names.indexOf("isFinite") !== -1);
257
+ assert.ok(names.indexOf("Error") !== -1);
258
+ },
259
+ },
260
+
261
+ // ── DtsRegistry ───────────────────────────────────────────────────
262
+
263
+ {
264
+ name: "registry_addDts_getGlobal",
265
+ description: "addDts registers globals retrievable by getGlobal",
266
+ run: function () {
267
+ var reg = new DtsRegistry();
268
+ reg.addDts("lib", "declare function alert(message?: any): void;");
269
+ var ti = reg.getGlobal("alert");
270
+ assert.ok(ti, "alert should be registered");
271
+ assert.strictEqual(ti.kind, "function");
272
+ },
273
+ },
274
+
275
+ {
276
+ name: "registry_getGlobalNames",
277
+ description: "getGlobalNames returns all registered names",
278
+ run: function () {
279
+ var reg = new DtsRegistry();
280
+ reg.addDts("lib", [
281
+ "declare var document: Document;",
282
+ "declare function alert(msg: string): void;",
283
+ ].join("\n"));
284
+ var names = reg.getGlobalNames();
285
+ assert.ok(names.indexOf("document") !== -1);
286
+ assert.ok(names.indexOf("alert") !== -1);
287
+ },
288
+ },
289
+
290
+ {
291
+ name: "registry_getGlobal_unknown",
292
+ description: "getGlobal returns null for an unknown name",
293
+ run: function () {
294
+ var reg = new DtsRegistry();
295
+ assert.strictEqual(reg.getGlobal("doesNotExist"), null);
296
+ },
297
+ },
298
+
299
+ {
300
+ name: "registry_merge",
301
+ description: "Calling addDts multiple times merges all globals",
302
+ run: function () {
303
+ var reg = new DtsRegistry();
304
+ reg.addDts("a", "declare var x: number;");
305
+ reg.addDts("b", "declare var y: string;");
306
+ assert.ok(reg.getGlobal("x"), "x should be registered");
307
+ assert.ok(reg.getGlobal("y"), "y should be registered");
308
+ assert.strictEqual(reg.getGlobalNames().length, 2);
309
+ },
310
+ },
311
+
312
+ {
313
+ name: "registry_getHoverMarkdown_function",
314
+ description: "getHoverMarkdown returns markdown for a function",
315
+ run: function () {
316
+ var reg = new DtsRegistry();
317
+ reg.addDts("lib", "declare function parseInt(s: string, radix?: number): number;");
318
+ var md = reg.getHoverMarkdown("parseInt");
319
+ assert.ok(md, "should return markdown");
320
+ assert.ok(md.indexOf("parseInt") !== -1, "should include name");
321
+ assert.ok(md.indexOf("function") !== -1, "should include kind");
322
+ assert.ok(md.indexOf("```") !== -1, "should be in code block");
323
+ },
324
+ },
325
+
326
+ {
327
+ name: "registry_getHoverMarkdown_var",
328
+ description: "getHoverMarkdown returns markdown for a var with type",
329
+ run: function () {
330
+ var reg = new DtsRegistry();
331
+ reg.addDts("lib", "declare var NaN: number;");
332
+ var md = reg.getHoverMarkdown("NaN");
333
+ assert.ok(md, "should return markdown");
334
+ assert.ok(md.indexOf("NaN") !== -1);
335
+ assert.ok(md.indexOf("number") !== -1, "should show type");
336
+ },
337
+ },
338
+
339
+ {
340
+ name: "registry_getHoverMarkdown_with_doc",
341
+ description: "getHoverMarkdown includes the JSDoc comment",
342
+ run: function () {
343
+ var reg = new DtsRegistry();
344
+ reg.addDts("lib", [
345
+ "/** Parses a float. */",
346
+ "declare function parseFloat(s: string): number;",
347
+ ].join("\n"));
348
+ var md = reg.getHoverMarkdown("parseFloat");
349
+ assert.ok(md.indexOf("Parses a float") !== -1,
350
+ "should include docstring");
351
+ },
352
+ },
353
+
354
+ {
355
+ name: "registry_getHoverMarkdown_unknown",
356
+ description: "getHoverMarkdown returns null for unknown name",
357
+ run: function () {
358
+ var reg = new DtsRegistry();
359
+ assert.strictEqual(reg.getHoverMarkdown("nope"), null);
360
+ },
361
+ },
362
+
363
+ {
364
+ name: "registry_getMemberNames",
365
+ description: "getMemberNames returns method/property names for a class/interface",
366
+ run: function () {
367
+ var reg = new DtsRegistry();
368
+ reg.addDts("lib", [
369
+ "interface Console {",
370
+ " log(...data: any[]): void;",
371
+ " error(message?: any): void;",
372
+ "}",
373
+ ].join("\n"));
374
+ var names = reg.getMemberNames("Console");
375
+ assert.ok(names.indexOf("log") !== -1, "should have log");
376
+ assert.ok(names.indexOf("error") !== -1, "should have error");
377
+ },
378
+ },
379
+
380
+ // ── Hover integration ─────────────────────────────────────────────
381
+
382
+ {
383
+ name: "hover_dts_fallback",
384
+ description: "HoverEngine falls back to DTS registry when word not in ScopeMap",
385
+ run: function () {
386
+ var reg = new DtsRegistry();
387
+ reg.addDts("lib", "declare function alert(msg: string): void;");
388
+ var md = reg.getHoverMarkdown("alert");
389
+ assert.ok(md, "registry should provide hover for alert");
390
+ assert.ok(md.indexOf("alert") !== -1);
391
+ },
392
+ },
393
+
394
+ // ── loadDts (async lazy loader) ───────────────────────────────────
395
+
396
+ {
397
+ name: "loadDts_calls_callback_and_registers",
398
+ description: "loadDts calls the provided callback and registers the result",
399
+ run: function (done) {
400
+ var reg = new DtsRegistry();
401
+ var called_with = null;
402
+
403
+ function loader(name) {
404
+ called_with = name;
405
+ return Promise.resolve("declare function fetch(url: string): any;");
406
+ }
407
+
408
+ // Simulate what index.js does: call loader, then addDts
409
+ var promise = Promise.resolve(loader("lib.fetch")).then(function (text) {
410
+ reg.addDts("lib.fetch", text);
411
+ });
412
+
413
+ return promise.then(function () {
414
+ assert.strictEqual(called_with, "lib.fetch", "loader called with correct name");
415
+ assert.ok(reg.getGlobal("fetch"), "fetch should be registered");
416
+ assert.strictEqual(reg.getGlobal("fetch").kind, "function");
417
+ });
418
+ },
419
+ },
420
+
421
+ {
422
+ name: "loadDts_promise_resolves_after_registration",
423
+ description: "The Promise from loadDts resolves only after addDts completes",
424
+ run: function () {
425
+ var reg = new DtsRegistry();
426
+ var resolved = false;
427
+
428
+ var p = Promise.resolve("declare var myGlobal: string;").then(function (text) {
429
+ reg.addDts("test", text);
430
+ resolved = true;
431
+ });
432
+
433
+ return p.then(function () {
434
+ assert.ok(resolved, "promise should have resolved");
435
+ assert.ok(reg.getGlobal("myGlobal"), "myGlobal should be registered");
436
+ });
437
+ },
438
+ },
439
+
440
+ {
441
+ name: "loadDts_no_callback_rejects",
442
+ description: "loadDts without a callback returns a rejected Promise",
443
+ run: function () {
444
+ // Simulate the index.js guard: no _loadDts stored
445
+ var loadDts = function (name) {
446
+ return Promise.reject(
447
+ new Error("registerRapydScript: options.loadDts was not provided")
448
+ );
449
+ };
450
+
451
+ return loadDts("anything").then(
452
+ function () { assert.fail("should have rejected"); },
453
+ function (err) {
454
+ assert.ok(err.message.indexOf("loadDts") !== -1,
455
+ "error should mention loadDts");
456
+ }
457
+ );
458
+ },
459
+ },
460
+
461
+ ];
462
+
463
+ return TESTS;
464
+ }
465
+
466
+ // ---------------------------------------------------------------------------
467
+ // Runner
468
+ // ---------------------------------------------------------------------------
469
+
470
+ function run_tests(TESTS, filter) {
471
+ var tests = filter
472
+ ? TESTS.filter(function (t) { return t.name === filter; })
473
+ : TESTS;
474
+
475
+ if (tests.length === 0) {
476
+ console.error(colored("No test found: " + filter, "red"));
477
+ process.exit(1);
478
+ }
479
+
480
+ var failures = [];
481
+
482
+ // Run tests sequentially, supporting tests that return a Promise.
483
+ function run_next(i) {
484
+ if (i >= tests.length) {
485
+ console.log("");
486
+ if (failures.length) {
487
+ console.log(colored(failures.length + " test(s) failed.", "red"));
488
+ } else {
489
+ console.log(colored("All " + tests.length + " language-service-dts tests passed!", "green"));
490
+ }
491
+ process.exit(failures.length ? 1 : 0);
492
+ return;
493
+ }
494
+ var test = tests[i];
495
+ var result;
496
+ try {
497
+ result = test.run();
498
+ } catch (e) {
499
+ failures.push(test.name);
500
+ console.log(colored("FAIL " + test.name, "red") +
501
+ "\n " + (e.message || String(e)) + "\n");
502
+ run_next(i + 1);
503
+ return;
504
+ }
505
+ // If the test returned a Promise, wait for it.
506
+ if (result && typeof result.then === 'function') {
507
+ result.then(function () {
508
+ console.log(colored("PASS " + test.name, "green") +
509
+ " – " + test.description);
510
+ run_next(i + 1);
511
+ }, function (e) {
512
+ failures.push(test.name);
513
+ console.log(colored("FAIL " + test.name, "red") +
514
+ "\n " + (e.message || String(e)) + "\n");
515
+ run_next(i + 1);
516
+ });
517
+ } else {
518
+ console.log(colored("PASS " + test.name, "green") +
519
+ " – " + test.description);
520
+ run_next(i + 1);
521
+ }
522
+ }
523
+
524
+ run_next(0);
525
+ }
526
+
527
+ // ---------------------------------------------------------------------------
528
+ // Entry point
529
+ // ---------------------------------------------------------------------------
530
+
531
+ var dts_path = url.pathToFileURL(
532
+ path.join(__dirname, "../../src/monaco-language-service/dts.js")
533
+ ).href;
534
+
535
+ var filter = process.argv[2] || null;
536
+
537
+ import(dts_path).then(function (mod) {
538
+ var TESTS = make_tests(mod.parse_dts, mod.DtsRegistry, mod.TypeInfo);
539
+ run_tests(TESTS, filter);
540
+ }).catch(function (e) {
541
+ console.error(colored("Failed to load dts module:", "red"), e);
542
+ process.exit(1);
543
+ });