rapydscript-ns 0.9.3 → 0.9.5

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 (111) 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 +18 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/PYTHON_GAPS.md +52 -142
  8. package/README.md +51 -21
  9. package/TODO.md +1 -26
  10. package/add-toc-to-readme +2 -2
  11. package/bin/export +75 -75
  12. package/bin/rapydscript +0 -0
  13. package/bin/web-repl-export +102 -102
  14. package/build +2 -2
  15. package/language-service/index.js +88 -36
  16. package/package.json +1 -1
  17. package/publish.py +37 -37
  18. package/release/baselib-plain-pretty.js +157 -31
  19. package/release/baselib-plain-ugly.js +5 -5
  20. package/release/compiler.js +724 -426
  21. package/release/signatures.json +29 -29
  22. package/session.vim +4 -4
  23. package/setup.cfg +2 -2
  24. package/src/ast.pyj +7 -0
  25. package/src/baselib-containers.pyj +41 -4
  26. package/src/baselib-errors.pyj +4 -3
  27. package/src/baselib-internal.pyj +47 -18
  28. package/src/baselib-str.pyj +16 -3
  29. package/src/compiler.pyj +36 -36
  30. package/src/errors.pyj +30 -30
  31. package/src/lib/aes.pyj +646 -646
  32. package/src/lib/collections.pyj +227 -3
  33. package/src/lib/copy.pyj +120 -120
  34. package/src/lib/elementmaker.pyj +83 -83
  35. package/src/lib/encodings.pyj +126 -126
  36. package/src/lib/gettext.pyj +569 -569
  37. package/src/lib/itertools.pyj +580 -580
  38. package/src/lib/math.pyj +193 -193
  39. package/src/lib/operator.pyj +11 -11
  40. package/src/lib/pprint.pyj +455 -0
  41. package/src/lib/random.pyj +118 -118
  42. package/src/lib/react.pyj +74 -74
  43. package/src/lib/statistics.pyj +0 -0
  44. package/src/lib/traceback.pyj +63 -63
  45. package/src/lib/uuid.pyj +77 -77
  46. package/src/monaco-language-service/completions.js +21 -14
  47. package/src/monaco-language-service/diagnostics.js +2 -2
  48. package/src/monaco-language-service/dts.js +58 -15
  49. package/src/monaco-language-service/package.json +3 -0
  50. package/src/output/classes.pyj +25 -2
  51. package/src/output/codegen.pyj +4 -1
  52. package/src/output/comments.pyj +45 -45
  53. package/src/output/exceptions.pyj +201 -201
  54. package/src/output/jsx.pyj +164 -164
  55. package/src/output/treeshake.pyj +182 -182
  56. package/src/output/utils.pyj +72 -72
  57. package/src/parse.pyj +42 -7
  58. package/src/string_interpolation.pyj +72 -72
  59. package/src/tokenizer.pyj +18 -2
  60. package/src/unicode_aliases.pyj +576 -576
  61. package/src/utils.pyj +192 -192
  62. package/test/_import_one.pyj +37 -37
  63. package/test/_import_two/__init__.pyj +11 -11
  64. package/test/_import_two/level2/deep.pyj +4 -4
  65. package/test/_import_two/other.pyj +6 -6
  66. package/test/_import_two/sub.pyj +13 -13
  67. package/test/aes_vectors.pyj +421 -421
  68. package/test/annotations.pyj +80 -80
  69. package/test/baselib.pyj +23 -0
  70. package/test/chainmap.pyj +185 -0
  71. package/test/dataclasses.pyj +3 -4
  72. package/test/decorators.pyj +77 -77
  73. package/test/docstrings.pyj +39 -39
  74. package/test/elementmaker_test.pyj +45 -45
  75. package/test/enum.pyj +1 -1
  76. package/test/functions.pyj +151 -151
  77. package/test/generators.pyj +41 -41
  78. package/test/generic.pyj +370 -370
  79. package/test/internationalization.pyj +73 -73
  80. package/test/lint.pyj +164 -164
  81. package/test/loops.pyj +85 -85
  82. package/test/numpy.pyj +734 -734
  83. package/test/pprint.pyj +232 -0
  84. package/test/python_features.pyj +1 -1
  85. package/test/repl.pyj +121 -121
  86. package/test/scoped_flags.pyj +76 -76
  87. package/test/statistics.pyj +224 -0
  88. package/test/str.pyj +4 -4
  89. package/test/unit/index.js +455 -0
  90. package/test/unit/language-service-completions.js +2 -0
  91. package/test/unit/language-service-dts.js +113 -0
  92. package/test/unit/language-service-hover.js +455 -455
  93. package/test/unit/language-service.js +135 -2
  94. package/test/unit/web-repl.js +349 -1
  95. package/tools/compiler.d.ts +367 -367
  96. package/tools/completer.js +131 -131
  97. package/tools/export.js +4 -2
  98. package/tools/gettext.js +185 -185
  99. package/tools/ini.js +65 -65
  100. package/tools/msgfmt.js +187 -187
  101. package/tools/repl.js +223 -223
  102. package/tools/test.js +118 -118
  103. package/tools/utils.js +141 -128
  104. package/tools/web_repl.js +95 -95
  105. package/try +41 -41
  106. package/web-repl/env.js +196 -196
  107. package/web-repl/index.html +163 -163
  108. package/web-repl/prism.css +139 -139
  109. package/web-repl/prism.js +113 -113
  110. package/web-repl/rapydscript.js +228 -226
  111. package/web-repl/sha1.js +25 -25
package/src/lib/react.pyj CHANGED
@@ -1,74 +1,74 @@
1
- # vim:fileencoding=utf-8
2
- # License: BSD
3
- # RapydScript bindings for React.
4
- #
5
- # Supported: all standard hooks (useState, useEffect, useContext, useReducer,
6
- # useCallback, useMemo, useRef, useImperativeHandle, useLayoutEffect,
7
- # useDebugValue, useId, useTransition, useDeferredValue), core classes
8
- # (Component, PureComponent), special elements (Fragment, StrictMode,
9
- # Suspense, Profiler), and utilities (createElement, cloneElement,
10
- # createContext, createRef, forwardRef, isValidElement, memo, lazy).
11
- #
12
- # Requires React to be available as a global variable. Load it via a CDN
13
- # <script> tag, a bundler global shim, or any other mechanism before your
14
- # compiled script runs.
15
- #
16
- # Usage:
17
- # from __python__ import jsx
18
- # from react import useState, useEffect, useRef
19
- #
20
- # def Counter():
21
- # count, setCount = useState(0)
22
- # def handleClick():
23
- # setCount(count + 1)
24
- # return <button onClick={handleClick}>{count}</button>
25
- #
26
- # For class components extend React.Component directly (no import needed):
27
- #
28
- # class MyComponent(React.Component):
29
- # def render(self):
30
- # return <div>{self.props.title}</div>
31
-
32
- # ── Hooks (React 16.8+) ───────────────────────────────────────────────────────
33
-
34
- useState = React.useState
35
- useEffect = React.useEffect
36
- useContext = React.useContext
37
- useReducer = React.useReducer
38
- useCallback = React.useCallback
39
- useMemo = React.useMemo
40
- useRef = React.useRef
41
- useImperativeHandle = React.useImperativeHandle
42
- useLayoutEffect = React.useLayoutEffect
43
- useDebugValue = React.useDebugValue
44
-
45
- # ── Hooks (React 18+) ────────────────────────────────────────────────────────
46
-
47
- useId = React.useId
48
- useTransition = React.useTransition
49
- useDeferredValue = React.useDeferredValue
50
- useSyncExternalStore = React.useSyncExternalStore
51
- useInsertionEffect = React.useInsertionEffect
52
-
53
- # ── Core classes ─────────────────────────────────────────────────────────────
54
-
55
- Component = React.Component
56
- PureComponent = React.PureComponent
57
-
58
- # ── Special elements ─────────────────────────────────────────────────────────
59
-
60
- Fragment = React.Fragment
61
- StrictMode = React.StrictMode
62
- Suspense = React.Suspense
63
- Profiler = React.Profiler
64
-
65
- # ── Utilities ────────────────────────────────────────────────────────────────
66
-
67
- createElement = React.createElement
68
- cloneElement = React.cloneElement
69
- createContext = React.createContext
70
- createRef = React.createRef
71
- forwardRef = React.forwardRef
72
- isValidElement = React.isValidElement
73
- memo = React.memo
74
- lazy = React.lazy
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD
3
+ # RapydScript bindings for React.
4
+ #
5
+ # Supported: all standard hooks (useState, useEffect, useContext, useReducer,
6
+ # useCallback, useMemo, useRef, useImperativeHandle, useLayoutEffect,
7
+ # useDebugValue, useId, useTransition, useDeferredValue), core classes
8
+ # (Component, PureComponent), special elements (Fragment, StrictMode,
9
+ # Suspense, Profiler), and utilities (createElement, cloneElement,
10
+ # createContext, createRef, forwardRef, isValidElement, memo, lazy).
11
+ #
12
+ # Requires React to be available as a global variable. Load it via a CDN
13
+ # <script> tag, a bundler global shim, or any other mechanism before your
14
+ # compiled script runs.
15
+ #
16
+ # Usage:
17
+ # from __python__ import jsx
18
+ # from react import useState, useEffect, useRef
19
+ #
20
+ # def Counter():
21
+ # count, setCount = useState(0)
22
+ # def handleClick():
23
+ # setCount(count + 1)
24
+ # return <button onClick={handleClick}>{count}</button>
25
+ #
26
+ # For class components extend React.Component directly (no import needed):
27
+ #
28
+ # class MyComponent(React.Component):
29
+ # def render(self):
30
+ # return <div>{self.props.title}</div>
31
+
32
+ # ── Hooks (React 16.8+) ───────────────────────────────────────────────────────
33
+
34
+ useState = React.useState
35
+ useEffect = React.useEffect
36
+ useContext = React.useContext
37
+ useReducer = React.useReducer
38
+ useCallback = React.useCallback
39
+ useMemo = React.useMemo
40
+ useRef = React.useRef
41
+ useImperativeHandle = React.useImperativeHandle
42
+ useLayoutEffect = React.useLayoutEffect
43
+ useDebugValue = React.useDebugValue
44
+
45
+ # ── Hooks (React 18+) ────────────────────────────────────────────────────────
46
+
47
+ useId = React.useId
48
+ useTransition = React.useTransition
49
+ useDeferredValue = React.useDeferredValue
50
+ useSyncExternalStore = React.useSyncExternalStore
51
+ useInsertionEffect = React.useInsertionEffect
52
+
53
+ # ── Core classes ─────────────────────────────────────────────────────────────
54
+
55
+ Component = React.Component
56
+ PureComponent = React.PureComponent
57
+
58
+ # ── Special elements ─────────────────────────────────────────────────────────
59
+
60
+ Fragment = React.Fragment
61
+ StrictMode = React.StrictMode
62
+ Suspense = React.Suspense
63
+ Profiler = React.Profiler
64
+
65
+ # ── Utilities ────────────────────────────────────────────────────────────────
66
+
67
+ createElement = React.createElement
68
+ cloneElement = React.cloneElement
69
+ createContext = React.createContext
70
+ createRef = React.createRef
71
+ forwardRef = React.forwardRef
72
+ isValidElement = React.isValidElement
73
+ memo = React.memo
74
+ lazy = React.lazy
Binary file
@@ -1,63 +1,63 @@
1
- # vim:fileencoding=utf-8
2
- # License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
3
- # globals: ρσ_str, ρσ_last_exception
4
-
5
-
6
- def _get_internal_traceback(err):
7
- if isinstance(err, Exception) and err.stack:
8
- lines = ρσ_str.splitlines(err.stack)
9
- final_lines = v'[]'
10
- found_sentinel = False
11
- for i, line in enumerate(lines):
12
- sline = ρσ_str.strip(line)
13
- if i is 0:
14
- final_lines.push(line)
15
- continue
16
- if found_sentinel:
17
- final_lines.push(line)
18
- continue
19
- # These two conditions work on desktop Chrome and Firefox to identify the correct
20
- # line in the traceback.
21
- if sline.startsWith('at new ' + err.name) or sline.startsWith(err.name + '@'):
22
- found_sentinel = True
23
- return final_lines.join('\n')
24
- return err and err.stack
25
-
26
- def format_exception(exc, limit):
27
- if jstype(exc) is 'undefined':
28
- exc = ρσ_last_exception
29
- if not isinstance(exc, Error):
30
- if exc and exc.toString:
31
- return [exc.toString()]
32
- return []
33
- tb = _get_internal_traceback(exc)
34
- if tb:
35
- lines = ρσ_str.splitlines(tb)
36
- e = lines[0]
37
- lines = lines[1:]
38
- if limit:
39
- lines = lines[:limit+1] if limit > 0 else lines[limit:]
40
- lines.reverse()
41
- lines.push(e)
42
- lines.insert(0, 'Traceback (most recent call last):')
43
- return [l+'\n' for l in lines]
44
- return [exc.toString()]
45
-
46
- def format_exc(limit):
47
- return format_exception(ρσ_last_exception, limit).join('')
48
-
49
- def print_exc(limit):
50
- print(format_exc(limit))
51
-
52
- def format_stack(limit):
53
- stack = Error().stack
54
- if not stack:
55
- return []
56
- lines = str.splitlines(stack)[2:]
57
- lines.reverse()
58
- if limit:
59
- lines = lines[:limit+1] if limit > 0 else lines[limit:]
60
- return [l + '\n' for l in lines]
61
-
62
- def print_stack(limit):
63
- print(format_stack(limit).join(''))
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
3
+ # globals: ρσ_str, ρσ_last_exception
4
+
5
+
6
+ def _get_internal_traceback(err):
7
+ if isinstance(err, Exception) and err.stack:
8
+ lines = ρσ_str.splitlines(err.stack)
9
+ final_lines = v'[]'
10
+ found_sentinel = False
11
+ for i, line in enumerate(lines):
12
+ sline = ρσ_str.strip(line)
13
+ if i is 0:
14
+ final_lines.push(line)
15
+ continue
16
+ if found_sentinel:
17
+ final_lines.push(line)
18
+ continue
19
+ # These two conditions work on desktop Chrome and Firefox to identify the correct
20
+ # line in the traceback.
21
+ if sline.startsWith('at new ' + err.name) or sline.startsWith(err.name + '@'):
22
+ found_sentinel = True
23
+ return final_lines.join('\n')
24
+ return err and err.stack
25
+
26
+ def format_exception(exc, limit):
27
+ if jstype(exc) is 'undefined':
28
+ exc = ρσ_last_exception
29
+ if not isinstance(exc, Error):
30
+ if exc and exc.toString:
31
+ return [exc.toString()]
32
+ return []
33
+ tb = _get_internal_traceback(exc)
34
+ if tb:
35
+ lines = ρσ_str.splitlines(tb)
36
+ e = lines[0]
37
+ lines = lines[1:]
38
+ if limit:
39
+ lines = lines[:limit+1] if limit > 0 else lines[limit:]
40
+ lines.reverse()
41
+ lines.push(e)
42
+ lines.insert(0, 'Traceback (most recent call last):')
43
+ return [l+'\n' for l in lines]
44
+ return [exc.toString()]
45
+
46
+ def format_exc(limit):
47
+ return format_exception(ρσ_last_exception, limit).join('')
48
+
49
+ def print_exc(limit):
50
+ print(format_exc(limit))
51
+
52
+ def format_stack(limit):
53
+ stack = Error().stack
54
+ if not stack:
55
+ return []
56
+ lines = str.splitlines(stack)[2:]
57
+ lines.reverse()
58
+ if limit:
59
+ lines = lines[:limit+1] if limit > 0 else lines[limit:]
60
+ return [l + '\n' for l in lines]
61
+
62
+ def print_stack(limit):
63
+ print(format_stack(limit).join(''))
package/src/lib/uuid.pyj CHANGED
@@ -1,77 +1,77 @@
1
- # vim:fileencoding=utf-8
2
- # License: BSD Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
3
- # globals: crypto
4
- from __python__ import hash_literals
5
-
6
- from encodings import hexlify, urlsafe_b64decode, urlsafe_b64encode
7
-
8
- RFC_4122 = 1
9
-
10
- if jstype(crypto) is 'object' and crypto.getRandomValues:
11
- random_bytes = def (num):
12
- ans = Uint8Array(num or 16)
13
- crypto.getRandomValues(ans)
14
- return ans
15
- else:
16
- random_bytes = def (num):
17
- ans = Uint8Array(num or 16)
18
- for i in range(ans.length):
19
- ans[i] = Math.floor(Math.random() * 256)
20
- return ans
21
-
22
-
23
- def uuid4_bytes():
24
- data = random_bytes()
25
- data[6] = 0b01000000 | (data[6] & 0b1111)
26
- data[8] = (((data[8] >> 4) & 0b11 | 0b1000) << 4) | (data[8] & 0b1111)
27
- return data
28
-
29
-
30
- def as_str():
31
- h = this.hex
32
- return h[:8] + '-' + h[8:12] + '-' + h[12:16] + '-' + h[16:20] + '-' + h[20:]
33
-
34
-
35
- def uuid4():
36
- b = uuid4_bytes()
37
- return {
38
- 'hex': hexlify(b),
39
- 'bytes': b,
40
- 'variant': RFC_4122,
41
- 'version': 4,
42
- '__str__': as_str,
43
- 'toString': as_str,
44
- }
45
-
46
-
47
- def num_to_string(numbers, alphabet, pad_to_length):
48
- ans = v'[]'
49
- alphabet_len = alphabet.length
50
- numbers = Array.prototype.slice.call(numbers)
51
- for v'var i = 0; i < numbers.length - 1; i++':
52
- x = divmod(numbers[i], alphabet_len)
53
- numbers[i] = x[0]
54
- numbers[i+1] += x[1]
55
- for v'var i = 0; i < numbers.length; i++':
56
- number = numbers[i]
57
- while number:
58
- x = divmod(number, alphabet_len)
59
- number = x[0]
60
- ans.push(alphabet[x[1]])
61
- if pad_to_length and pad_to_length > ans.length:
62
- ans.push(alphabet[0].repeat(pad_to_length - ans.length))
63
- return ans.join('')
64
-
65
-
66
- def short_uuid():
67
- # A totally random uuid encoded using only URL and filename safe characters
68
- return urlsafe_b64encode(random_bytes(), '')
69
-
70
-
71
- def short_uuid4():
72
- # A uuid4 encoded using only URL and filename safe characters
73
- return urlsafe_b64encode(uuid4_bytes(), '')
74
-
75
-
76
- def decode_short_uuid(val):
77
- return urlsafe_b64decode(val + '==')
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
3
+ # globals: crypto
4
+ from __python__ import hash_literals
5
+
6
+ from encodings import hexlify, urlsafe_b64decode, urlsafe_b64encode
7
+
8
+ RFC_4122 = 1
9
+
10
+ if jstype(crypto) is 'object' and crypto.getRandomValues:
11
+ random_bytes = def (num):
12
+ ans = Uint8Array(num or 16)
13
+ crypto.getRandomValues(ans)
14
+ return ans
15
+ else:
16
+ random_bytes = def (num):
17
+ ans = Uint8Array(num or 16)
18
+ for i in range(ans.length):
19
+ ans[i] = Math.floor(Math.random() * 256)
20
+ return ans
21
+
22
+
23
+ def uuid4_bytes():
24
+ data = random_bytes()
25
+ data[6] = 0b01000000 | (data[6] & 0b1111)
26
+ data[8] = (((data[8] >> 4) & 0b11 | 0b1000) << 4) | (data[8] & 0b1111)
27
+ return data
28
+
29
+
30
+ def as_str():
31
+ h = this.hex
32
+ return h[:8] + '-' + h[8:12] + '-' + h[12:16] + '-' + h[16:20] + '-' + h[20:]
33
+
34
+
35
+ def uuid4():
36
+ b = uuid4_bytes()
37
+ return {
38
+ 'hex': hexlify(b),
39
+ 'bytes': b,
40
+ 'variant': RFC_4122,
41
+ 'version': 4,
42
+ '__str__': as_str,
43
+ 'toString': as_str,
44
+ }
45
+
46
+
47
+ def num_to_string(numbers, alphabet, pad_to_length):
48
+ ans = v'[]'
49
+ alphabet_len = alphabet.length
50
+ numbers = Array.prototype.slice.call(numbers)
51
+ for v'var i = 0; i < numbers.length - 1; i++':
52
+ x = divmod(numbers[i], alphabet_len)
53
+ numbers[i] = x[0]
54
+ numbers[i+1] += x[1]
55
+ for v'var i = 0; i < numbers.length; i++':
56
+ number = numbers[i]
57
+ while number:
58
+ x = divmod(number, alphabet_len)
59
+ number = x[0]
60
+ ans.push(alphabet[x[1]])
61
+ if pad_to_length and pad_to_length > ans.length:
62
+ ans.push(alphabet[0].repeat(pad_to_length - ans.length))
63
+ return ans.join('')
64
+
65
+
66
+ def short_uuid():
67
+ # A totally random uuid encoded using only URL and filename safe characters
68
+ return urlsafe_b64encode(random_bytes(), '')
69
+
70
+
71
+ def short_uuid4():
72
+ # A uuid4 encoded using only URL and filename safe characters
73
+ return urlsafe_b64encode(uuid4_bytes(), '')
74
+
75
+
76
+ def decode_short_uuid(val):
77
+ return urlsafe_b64decode(val + '==')
@@ -452,7 +452,8 @@ export class CompletionEngine {
452
452
  }
453
453
  // Walk remaining path segments through member types
454
454
  for (let i = 1; i < parts.length && ti; i++) {
455
- const member = ti.members ? ti.members.get(parts[i]) : null;
455
+ const all = this._dts.getAllMembers(ti);
456
+ const member = all.get(parts[i]) || null;
456
457
  if (!member) { ti = null; break; }
457
458
  if (member.members) {
458
459
  ti = member;
@@ -462,8 +463,9 @@ export class CompletionEngine {
462
463
  ti = null;
463
464
  }
464
465
  }
465
- if (ti && ti.members) {
466
- for (const [name, member] of ti.members) {
466
+ if (ti) {
467
+ const all_members = this._dts.getAllMembers(ti);
468
+ for (const [name, member] of all_members) {
467
469
  if (!ctx.prefix || name.startsWith(ctx.prefix)) {
468
470
  items.push(_dts_member_to_item(member, range, monacoKind));
469
471
  }
@@ -583,13 +585,16 @@ export class CompletionEngine {
583
585
  const member_ti = this._dts.getMemberInfo(object_path, method_name);
584
586
  if (member_ti && member_ti.return_type) {
585
587
  const return_ti = this._dts.getGlobal(resolve_first_type(member_ti.return_type));
586
- if (return_ti && return_ti.members) {
587
- scope_matched = true;
588
- for (const [name, member] of return_ti.members) {
589
- if (!ctx.prefix || name.startsWith(ctx.prefix)) {
590
- if (!seen.has(name)) {
591
- seen.add(name);
592
- items.push(_dts_member_to_item(member, range, monacoKind));
588
+ if (return_ti) {
589
+ const rt_members = this._dts.getAllMembers(return_ti);
590
+ if (rt_members.size > 0) {
591
+ scope_matched = true;
592
+ for (const [name, member] of rt_members) {
593
+ if (!ctx.prefix || name.startsWith(ctx.prefix)) {
594
+ if (!seen.has(name)) {
595
+ seen.add(name);
596
+ items.push(_dts_member_to_item(member, range, monacoKind));
597
+ }
593
598
  }
594
599
  }
595
600
  }
@@ -606,8 +611,9 @@ export class CompletionEngine {
606
611
  if (ti && !ti.members && ti.return_type) {
607
612
  ti = this._dts.getGlobal(resolve_first_type(ti.return_type));
608
613
  }
609
- if (ti && ti.members) {
610
- for (const [name, member] of ti.members) {
614
+ if (ti) {
615
+ const all_members = this._dts.getAllMembers(ti);
616
+ for (const [name, member] of all_members) {
611
617
  if (!ctx.prefix || name.startsWith(ctx.prefix)) {
612
618
  if (!seen.has(name)) {
613
619
  seen.add(name);
@@ -642,8 +648,9 @@ export class CompletionEngine {
642
648
  }
643
649
  if (member_ti && member_ti.return_type) {
644
650
  const return_ti = this._dts.getGlobal(resolve_first_type(member_ti.return_type));
645
- if (return_ti && return_ti.members) {
646
- for (const [name, member] of return_ti.members) {
651
+ if (return_ti) {
652
+ const all_members = this._dts.getAllMembers(return_ti);
653
+ for (const [name, member] of all_members) {
647
654
  if (!ctx.prefix || name.startsWith(ctx.prefix)) {
648
655
  seen.add(name);
649
656
  items.push(_dts_member_to_item(member, range, monacoKind));
@@ -33,7 +33,7 @@ const MESSAGES = {
33
33
  export const STDLIB_MODULES = [
34
34
  'abc', 'aes', 'asyncio', 'base64', 'bisect', 'collections', 'contextlib', 'copy', 'csv', 'dataclasses', 'datetime', 'elementmaker', 'encodings', 'enum',
35
35
  'functools', 'gettext', 'heapq', 'html', 'http', 'io', 'itertools', 'json', 'logging', 'math', 'numpy', 'operator',
36
- 'pythonize', 'random', 're', 'react', 'string', 'textwrap', 'traceback', 'typing', 'urllib', 'uuid',
36
+ 'pprint', 'pythonize', 'random', 're', 'react', 'statistics', 'string', 'textwrap', 'traceback', 'typing', 'urllib', 'uuid',
37
37
  // Pseudo-modules for language feature flags (from __python__ import ...)
38
38
  '__python__', '__builtins__',
39
39
  ];
@@ -53,7 +53,7 @@ export const BASE_BUILTINS = (
53
53
  ' NodeList alert console Node Symbol NamedNodeMap ρσ_eslice ρσ_delslice Number' +
54
54
  ' Boolean encodeURIComponent decodeURIComponent setTimeout setInterval' +
55
55
  ' setImmediate clearTimeout clearInterval clearImmediate requestAnimationFrame' +
56
- ' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN super Ellipsis slice all any next __import__ ρσ_new ρσ_object_new hash ρσ_object_setattr ρσ_object_getattr ρσ_object_delattr ExceptionGroup BaseExceptionGroup tuple bytes bytearray format object vars locals globals'
56
+ ' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN super Ellipsis slice all any next __import__ ρσ_new ρσ_object_new hash ρσ_object_setattr ρσ_object_getattr ρσ_object_delattr ExceptionGroup BaseExceptionGroup tuple bytes bytearray format object vars locals globals type'
57
57
  ).split(' ');
58
58
 
59
59
  // ---------------------------------------------------------------------------
@@ -32,13 +32,14 @@ export class TypeInfo {
32
32
  * @param {string} [opts.source] 'dts'
33
33
  */
34
34
  constructor(opts) {
35
- this.name = opts.name;
36
- this.kind = opts.kind;
37
- this.params = opts.params || null;
38
- this.return_type = opts.return_type || null;
39
- this.members = opts.members || null;
40
- this.doc = opts.doc || null;
41
- this.source = opts.source || 'dts';
35
+ this.name = opts.name;
36
+ this.kind = opts.kind;
37
+ this.params = opts.params || null;
38
+ this.return_type = opts.return_type || null;
39
+ this.members = opts.members || null;
40
+ this.doc = opts.doc || null;
41
+ this.source = opts.source || 'dts';
42
+ this.extends_names = opts.extends_names || null;
42
43
  }
43
44
  }
44
45
 
@@ -351,21 +352,28 @@ export function parse_dts(text) {
351
352
  }
352
353
 
353
354
  // ── class / interface / abstract class / namespace / module ────────
354
- const block_m = l.match(/^(abstract\s+class|class|interface|namespace|module)\s+(\w+)/);
355
+ const block_m = l.match(/^(abstract\s+class|class|interface|namespace|module)\s+(\w+)(?:<[^>]*>)?(?:\s+extends\s+(.+?))?(?:\s*\{|\s*$)/);
355
356
  if (block_m) {
356
357
  const kind_raw = block_m[1].replace('abstract ', '').trim();
357
358
  const kind = (kind_raw === 'module') ? 'namespace' : kind_raw;
358
359
  const name = block_m[2];
360
+ let extends_names = null;
361
+ if (block_m[3]) {
362
+ extends_names = block_m[3].split(',').map(function (s) {
363
+ return s.trim().replace(/<.*>$/, '');
364
+ }).filter(function (s) { return s.length > 0; });
365
+ if (extends_names.length === 0) extends_names = null;
366
+ }
359
367
 
360
368
  if (l.includes('{')) {
361
369
  // Block opens on this line — collect to matching '}'
362
370
  const { inner, next_i } = collect_block(lines, i);
363
371
  const members = parse_members(inner);
364
- results.push(new TypeInfo({ name, kind, members, doc }));
372
+ results.push(new TypeInfo({ name, kind, members, extends_names, doc }));
365
373
  i = next_i;
366
374
  } else {
367
375
  // Declaration without body (e.g. `declare class Foo;`)
368
- results.push(new TypeInfo({ name, kind, doc }));
376
+ results.push(new TypeInfo({ name, kind, extends_names, doc }));
369
377
  i++;
370
378
  }
371
379
  continue;
@@ -462,10 +470,43 @@ export class DtsRegistry {
462
470
  * @param {string} name
463
471
  * @returns {string[]}
464
472
  */
473
+ /**
474
+ * Return a merged Map of all members for a type, including inherited ones.
475
+ * Child members override parent members. Uses a visited set to avoid cycles.
476
+ * @param {TypeInfo} ti
477
+ * @returns {Map<string, TypeInfo>}
478
+ */
479
+ getAllMembers(ti) {
480
+ const result = new Map();
481
+ const visited = new Set();
482
+ this._collectMembers(ti, result, visited);
483
+ return result;
484
+ }
485
+
486
+ /** @private */
487
+ _collectMembers(ti, result, visited) {
488
+ if (!ti || visited.has(ti.name)) return;
489
+ visited.add(ti.name);
490
+ // Recurse into parents first so child members override
491
+ if (ti.extends_names) {
492
+ for (const parent_name of ti.extends_names) {
493
+ const parent_ti = this._globals.get(parent_name);
494
+ if (parent_ti) this._collectMembers(parent_ti, result, visited);
495
+ }
496
+ }
497
+ // Own members override inherited ones
498
+ if (ti.members) {
499
+ for (const [name, member] of ti.members) {
500
+ result.set(name, member);
501
+ }
502
+ }
503
+ }
504
+
465
505
  getMemberNames(name) {
466
506
  const ti = this.getGlobal(name);
467
- if (!ti || !ti.members) return [];
468
- return Array.from(ti.members.keys());
507
+ if (!ti) return [];
508
+ const all = this.getAllMembers(ti);
509
+ return Array.from(all.keys());
469
510
  }
470
511
 
471
512
  /**
@@ -489,7 +530,8 @@ export class DtsRegistry {
489
530
  }
490
531
  // Walk remaining path segments
491
532
  for (let i = 1; i < parts.length && ti; i++) {
492
- const member = ti.members ? ti.members.get(parts[i]) : null;
533
+ const all = this.getAllMembers(ti);
534
+ const member = all.get(parts[i]) || null;
493
535
  if (!member) { ti = null; break; }
494
536
  if (member.members) {
495
537
  ti = member;
@@ -499,8 +541,9 @@ export class DtsRegistry {
499
541
  ti = null;
500
542
  }
501
543
  }
502
- if (!ti || !ti.members) return null;
503
- return ti.members.get(memberName) || null;
544
+ if (!ti) return null;
545
+ const all_members = this.getAllMembers(ti);
546
+ return all_members.get(memberName) || null;
504
547
  }
505
548
 
506
549
  /**
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }