rapydscript-ns 0.9.2 → 0.9.4

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 (88) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/PYTHON_GAPS.md +352 -0
  3. package/README.md +176 -32
  4. package/TODO.md +1 -128
  5. package/bin/rapydscript +70 -70
  6. package/language-service/index.js +242 -11
  7. package/memory/project_string_impl.md +43 -0
  8. package/package.json +1 -1
  9. package/release/baselib-plain-pretty.js +248 -38
  10. package/release/baselib-plain-ugly.js +8 -8
  11. package/release/compiler.js +778 -277
  12. package/release/signatures.json +30 -30
  13. package/src/ast.pyj +10 -1
  14. package/src/baselib-builtins.pyj +56 -2
  15. package/src/baselib-containers.pyj +25 -1
  16. package/src/baselib-errors.pyj +7 -3
  17. package/src/baselib-internal.pyj +51 -6
  18. package/src/baselib-str.pyj +18 -5
  19. package/src/lib/asyncio.pyj +534 -0
  20. package/src/lib/base64.pyj +399 -0
  21. package/src/lib/bisect.pyj +73 -0
  22. package/src/lib/collections.pyj +228 -4
  23. package/src/lib/csv.pyj +494 -0
  24. package/src/lib/heapq.pyj +98 -0
  25. package/src/lib/html.pyj +382 -0
  26. package/src/lib/http/__init__.pyj +98 -0
  27. package/src/lib/http/client.pyj +304 -0
  28. package/src/lib/http/cookies.pyj +236 -0
  29. package/src/lib/logging.pyj +672 -0
  30. package/src/lib/pprint.pyj +455 -0
  31. package/src/lib/pythonize.pyj +20 -20
  32. package/src/lib/statistics.pyj +0 -0
  33. package/src/lib/string.pyj +357 -0
  34. package/src/lib/textwrap.pyj +329 -0
  35. package/src/lib/urllib/__init__.pyj +14 -0
  36. package/src/lib/urllib/error.pyj +66 -0
  37. package/src/lib/urllib/parse.pyj +475 -0
  38. package/src/lib/urllib/request.pyj +86 -0
  39. package/src/monaco-language-service/analyzer.js +5 -2
  40. package/src/monaco-language-service/completions.js +26 -0
  41. package/src/monaco-language-service/diagnostics.js +203 -4
  42. package/src/monaco-language-service/scope.js +1 -0
  43. package/src/output/codegen.pyj +4 -1
  44. package/src/output/functions.pyj +152 -6
  45. package/src/output/loops.pyj +17 -2
  46. package/src/output/modules.pyj +1 -1
  47. package/src/output/operators.pyj +15 -0
  48. package/src/output/stream.pyj +0 -1
  49. package/src/parse.pyj +108 -24
  50. package/src/tokenizer.pyj +19 -3
  51. package/test/async_generators.pyj +144 -0
  52. package/test/asyncio.pyj +307 -0
  53. package/test/base64.pyj +202 -0
  54. package/test/baselib.pyj +23 -0
  55. package/test/bisect.pyj +178 -0
  56. package/test/chainmap.pyj +185 -0
  57. package/test/csv.pyj +405 -0
  58. package/test/float_special.pyj +64 -0
  59. package/test/heapq.pyj +174 -0
  60. package/test/html.pyj +212 -0
  61. package/test/http.pyj +259 -0
  62. package/test/imports.pyj +79 -72
  63. package/test/logging.pyj +356 -0
  64. package/test/long.pyj +130 -0
  65. package/test/parenthesized_with.pyj +141 -0
  66. package/test/pprint.pyj +232 -0
  67. package/test/python_compat.pyj +3 -5
  68. package/test/python_modulo.pyj +76 -0
  69. package/test/python_modulo_off.pyj +21 -0
  70. package/test/statistics.pyj +224 -0
  71. package/test/str.pyj +14 -0
  72. package/test/string.pyj +245 -0
  73. package/test/textwrap.pyj +172 -0
  74. package/test/type_display.pyj +48 -0
  75. package/test/type_enforcement.pyj +164 -0
  76. package/test/unit/index.js +94 -6
  77. package/test/unit/language-service-completions.js +121 -0
  78. package/test/unit/language-service-scope.js +32 -0
  79. package/test/unit/language-service.js +190 -5
  80. package/test/unit/run-language-service.js +17 -3
  81. package/test/unit/web-repl.js +2401 -13
  82. package/test/urllib.pyj +193 -0
  83. package/tools/compile.js +1 -1
  84. package/tools/embedded_compiler.js +7 -7
  85. package/tools/export.js +4 -2
  86. package/web-repl/main.js +1 -1
  87. package/web-repl/rapydscript.js +7 -5
  88. package/test/omit_function_metadata.pyj +0 -20
@@ -0,0 +1,357 @@
1
+ ###########################################################
2
+ # RapydScript Standard Library
3
+ # Author: RapydScript-NS Contributors
4
+ # Copyright 2024 RapydScript-NS Contributors
5
+ # License: Apache License 2.0
6
+ # This library is covered under Apache license, so that
7
+ # you can distribute it with your RapydScript applications.
8
+ ###########################################################
9
+
10
+ # Python-compatible string module.
11
+ #
12
+ # Provides:
13
+ # Character constants: ascii_letters, ascii_lowercase, ascii_uppercase,
14
+ # digits, hexdigits, octdigits, punctuation, printable, whitespace
15
+ # Template: $-substitution string templates (substitute, safe_substitute)
16
+ # Formatter: customizable str.format() foundation with subclassing support
17
+ #
18
+ # NOTE: Formatter.format() only accepts positional args via *args.
19
+ # For named-field substitution use vformat(fmt, [], {'key': val}) directly.
20
+
21
+
22
+ # ---------------------------------------------------------------------------
23
+ # Character constants
24
+ # ---------------------------------------------------------------------------
25
+
26
+ ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
27
+ ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
28
+ ascii_letters = ascii_lowercase + ascii_uppercase
29
+ digits = '0123456789'
30
+ hexdigits = digits + 'abcdef' + 'ABCDEF'
31
+ octdigits = '01234567'
32
+ # Build punctuation via chr() to avoid backslash (92) and backtick (96) escaping.
33
+ punctuation = '!"#$%&' + chr(39) + '()*+,-./:;<=>?@[' + chr(92) + ']^_' + chr(96) + '{|}~'
34
+ # chr(11) = vertical-tab (\x0b), chr(12) = form-feed (\x0c)
35
+ whitespace = ' \t\n\r' + chr(11) + chr(12)
36
+ printable = digits + ascii_letters + punctuation + whitespace
37
+
38
+
39
+ # ---------------------------------------------------------------------------
40
+ # Internal JS helpers
41
+ # ---------------------------------------------------------------------------
42
+
43
+ v"""
44
+ // ── Shared numeric-string helper ────────────────────────────────────────────
45
+
46
+ function _str_is_digits_only(s) {
47
+ if (!s.length) return false;
48
+ for (var _di = 0; _di < s.length; _di++) {
49
+ var _dc = s.charCodeAt(_di);
50
+ if (_dc < 48 || _dc > 57) return false;
51
+ }
52
+ return true;
53
+ }
54
+
55
+ // ── Template helpers ─────────────────────────────────────────────────────────
56
+
57
+ // Pattern groups:
58
+ // 1: $$ (escaped dollar → literal $)
59
+ // 2: ${identifier}
60
+ // 3: $identifier
61
+ // 4: $<anything-else> (invalid placeholder; [^]? also captures trailing $)
62
+ var _tmpl_re = /\$(?:(\$)|\{([_a-zA-Z][_a-zA-Z0-9]*)\}|([_a-zA-Z][_a-zA-Z0-9]*)|([^]?))/g;
63
+
64
+ // Convert a mapping to a plain JS object (handles ρσ_dict with .jsmap).
65
+ function _tmpl_to_plain(mapping) {
66
+ if (mapping === null || mapping === undefined) return Object.create(null);
67
+ if (mapping.jsmap !== undefined && mapping.jsmap !== null) {
68
+ var _out = Object.create(null);
69
+ mapping.jsmap.forEach(function(_v, _k) { _out[_k] = _v; });
70
+ return _out;
71
+ }
72
+ return mapping;
73
+ }
74
+
75
+ function _tmpl_substitute_impl(template_str, mapping, safe) {
76
+ var _re = _tmpl_re;
77
+ _re.lastIndex = 0;
78
+ var _res = [];
79
+ var _last = 0;
80
+ var _m;
81
+ while ((_m = _re.exec(template_str)) !== null) {
82
+ _res.push(template_str.slice(_last, _m.index));
83
+ _last = _m.index + _m[0].length;
84
+ if (_m[1] !== undefined) {
85
+ _res.push('$');
86
+ } else if (_m[2] !== undefined || _m[3] !== undefined) {
87
+ var _key = _m[2] !== undefined ? _m[2] : _m[3];
88
+ var _val = mapping[_key];
89
+ if (_val === undefined) {
90
+ if (safe) { _res.push(_m[0]); }
91
+ else { throw new KeyError(_key); }
92
+ } else {
93
+ _res.push(ρσ_str(_val));
94
+ }
95
+ } else {
96
+ // m[4]: invalid placeholder char (or empty for trailing $)
97
+ if (safe) { _res.push(_m[0]); }
98
+ else { throw new ValueError('Invalid placeholder in string: ' + JSON.stringify(_m[0])); }
99
+ }
100
+ }
101
+ _res.push(template_str.slice(_last));
102
+ return _res.join('');
103
+ }
104
+
105
+ // ── Formatter helpers ────────────────────────────────────────────────────────
106
+
107
+ function _fmt_get_kwarg(kwargs, key) {
108
+ if (!kwargs) return undefined;
109
+ if (kwargs.jsmap !== undefined && kwargs.jsmap !== null) return kwargs.jsmap.get(key);
110
+ return kwargs[key];
111
+ }
112
+
113
+ function _fmt_has_kwarg(kwargs, key) {
114
+ if (!kwargs) return false;
115
+ if (kwargs.jsmap !== undefined && kwargs.jsmap !== null) return kwargs.jsmap.has(key);
116
+ return Object.prototype.hasOwnProperty.call(kwargs, key);
117
+ }
118
+
119
+ // parse: walk format_string, return array of [literal, field_name, fmt_spec, conversion].
120
+ // A trailing literal with no field has field_name === null.
121
+ function _fmt_parse(format_string) {
122
+ var _items = [];
123
+ var _i = 0, _n = format_string.length;
124
+
125
+ while (_i <= _n) {
126
+ var _lit = '';
127
+ while (_i < _n) {
128
+ var _ch = format_string[_i];
129
+ if (_ch === '{') {
130
+ if (_i + 1 < _n && format_string[_i + 1] === '{') { _lit += '{'; _i += 2; }
131
+ else break;
132
+ } else if (_ch === '}') {
133
+ if (_i + 1 < _n && format_string[_i + 1] === '}') { _lit += '}'; _i += 2; }
134
+ else throw new ValueError("Single '}' encountered in format string");
135
+ } else { _lit += _ch; _i++; }
136
+ }
137
+
138
+ if (_i >= _n) { _items.push([_lit, null, null, null]); break; }
139
+
140
+ _i++; // skip '{'
141
+ var _j = _i, _depth = 1;
142
+ while (_j < _n && _depth > 0) {
143
+ if (format_string[_j] === '{') _depth++;
144
+ else if (format_string[_j] === '}') _depth--;
145
+ _j++;
146
+ }
147
+ if (_depth !== 0) throw new ValueError("Single '{' encountered in format string");
148
+
149
+ var _ft = format_string.slice(_i, _j - 1);
150
+ _i = _j;
151
+
152
+ // Locate ! (conversion) and : (format spec), skipping nested {}
153
+ var _bang = -1, _colon = -1;
154
+ for (var _k = 0; _k < _ft.length; _k++) {
155
+ var _fc = _ft[_k];
156
+ if (_fc === '{') { while (_k < _ft.length && _ft[_k] !== '}') _k++; }
157
+ else if (_fc === '!' && _bang === -1 && _colon === -1) _bang = _k;
158
+ else if (_fc === ':' && _colon === -1) { _colon = _k; break; }
159
+ }
160
+
161
+ var _fname, _conv, _spec;
162
+ if (_bang !== -1 && (_colon === -1 || _bang < _colon)) {
163
+ _fname = _ft.slice(0, _bang);
164
+ _conv = (_bang + 1 < _ft.length) ? _ft[_bang + 1] : null;
165
+ _spec = _colon !== -1 ? _ft.slice(_colon + 1) : '';
166
+ } else if (_colon !== -1) {
167
+ _fname = _ft.slice(0, _colon);
168
+ _conv = null;
169
+ _spec = _ft.slice(_colon + 1);
170
+ } else {
171
+ _fname = _ft;
172
+ _conv = null;
173
+ _spec = '';
174
+ }
175
+
176
+ _items.push([_lit, _fname, _spec, _conv]);
177
+ }
178
+
179
+ return _items;
180
+ }
181
+
182
+ // get_field: resolve dotted/bracket access chain. Returns [value, first_key].
183
+ function _fmt_get_field(field_name, args, kwargs, self_obj) {
184
+ // Find first '.' or '['
185
+ var _fe = -1;
186
+ for (var _ci = 0; _ci < field_name.length; _ci++) {
187
+ var _cc = field_name[_ci];
188
+ if (_cc === '.' || _cc === '[') { _fe = _ci; break; }
189
+ }
190
+ var _fk = _fe === -1 ? field_name : field_name.slice(0, _fe);
191
+ var _rest = _fe === -1 ? '' : field_name.slice(_fe);
192
+
193
+ var _lookup_key = _str_is_digits_only(_fk) ? parseInt(_fk, 10) : _fk;
194
+ var _value = self_obj.get_value(_lookup_key, args, kwargs);
195
+
196
+ while (_rest.length > 0) {
197
+ if (_rest[0] === '.') {
198
+ var _de = _rest.length;
199
+ for (var _di2 = 1; _di2 < _rest.length; _di2++) {
200
+ if (_rest[_di2] === '.' || _rest[_di2] === '[') { _de = _di2; break; }
201
+ }
202
+ _value = _value[_rest.slice(1, _de)];
203
+ _rest = _rest.slice(_de);
204
+ } else if (_rest[0] === '[') {
205
+ var _cl = _rest.indexOf(']', 1);
206
+ if (_cl === -1) break;
207
+ var _idx = _rest.slice(1, _cl);
208
+ _value = _str_is_digits_only(_idx) ? _value[parseInt(_idx, 10)] : _value[_idx];
209
+ _rest = _rest.slice(_cl + 1);
210
+ } else {
211
+ break;
212
+ }
213
+ }
214
+
215
+ return [_value, _fk];
216
+ }
217
+
218
+ // vformat: render a format string, calling self_obj's methods for each field.
219
+ function _fmt_vformat(fmt_str, args, kwargs, self_obj) {
220
+ var _items = _fmt_parse(fmt_str);
221
+ var _result = [];
222
+ var _auto_idx = 0, _auto_used = false, _manual_used = false;
223
+
224
+ for (var _ii = 0; _ii < _items.length; _ii++) {
225
+ var _item = _items[_ii];
226
+ var _lit2 = _item[0], _fname2 = _item[1], _spec2 = _item[2], _conv2 = _item[3];
227
+
228
+ if (_lit2) _result.push(_lit2);
229
+ if (_fname2 === null) continue;
230
+
231
+ // Auto-numbering vs manual
232
+ var _ename;
233
+ if (_fname2 === '') {
234
+ if (_manual_used) throw new ValueError('cannot switch from manual field specification to automatic field numbering');
235
+ _auto_used = true;
236
+ _ename = _auto_idx++;
237
+ } else if (_str_is_digits_only(_fname2)) {
238
+ if (_auto_used) throw new ValueError('cannot switch from automatic field numbering to manual field specification');
239
+ _manual_used = true;
240
+ _ename = parseInt(_fname2, 10);
241
+ } else {
242
+ // Named or complex field (e.g. "obj.attr" — let get_field handle it)
243
+ _ename = _fname2;
244
+ }
245
+
246
+ var _fr = self_obj.get_field(typeof _ename === 'number' ? String(_ename) : _ename, args, kwargs);
247
+ var _val2 = _fr[0];
248
+
249
+ if (_conv2 !== null) _val2 = self_obj.convert_field(_val2, _conv2);
250
+
251
+ // Resolve nested format specs (e.g. {:{}f})
252
+ var _rspec = _spec2;
253
+ if (_spec2 && _spec2.indexOf('{') !== -1) {
254
+ _rspec = _fmt_vformat(_spec2, args, kwargs, self_obj);
255
+ }
256
+
257
+ _result.push(self_obj.format_field(_val2, _rspec));
258
+ }
259
+
260
+ return _result.join('');
261
+ }
262
+ """
263
+
264
+
265
+ # ---------------------------------------------------------------------------
266
+ # Template
267
+ # ---------------------------------------------------------------------------
268
+
269
+ class Template:
270
+ """String template with $-based substitution."""
271
+ delimiter = '$'
272
+ idpattern = '(?-i:[_a-zA-Z][_a-zA-Z0-9]*)'
273
+ braceidpattern = None
274
+ flags = 0 # re.IGNORECASE not used; provided for API compatibility
275
+
276
+ def __init__(self, template):
277
+ self.template = template
278
+
279
+ def substitute(self, mapping=None):
280
+ """Return a copy of the template with placeholders filled from *mapping*.
281
+
282
+ Raises KeyError for missing keys and ValueError for invalid placeholders.
283
+ *mapping* may be a plain dict or any object supporting key lookup.
284
+ """
285
+ m = v'_tmpl_to_plain(mapping)'
286
+ return v'_tmpl_substitute_impl(self.template, m, false)'
287
+
288
+ def safe_substitute(self, mapping=None):
289
+ """Like substitute(), but leaves unrecognised placeholders unchanged."""
290
+ m = v'_tmpl_to_plain(mapping)'
291
+ return v'_tmpl_substitute_impl(self.template, m, true)'
292
+
293
+
294
+ # ---------------------------------------------------------------------------
295
+ # Formatter
296
+ # ---------------------------------------------------------------------------
297
+
298
+ class Formatter:
299
+ """Customisable string formatter — the foundation behind str.format().
300
+
301
+ Subclass and override format_field / convert_field / get_value / get_field
302
+ to change formatting behaviour.
303
+
304
+ Note: format() only accepts positional *args. For named-field substitution
305
+ call vformat(fmt, [], {'key': value}) directly.
306
+ """
307
+
308
+ def format(self, format_string, *args):
309
+ """Format *format_string* using positional *args*."""
310
+ return self.vformat(format_string, list(args), {})
311
+
312
+ def vformat(self, format_string, args, kwargs):
313
+ """Format *format_string* with explicit *args* list and *kwargs* dict."""
314
+ return v'_fmt_vformat(format_string, args, kwargs, self)'
315
+
316
+ def parse(self, format_string):
317
+ """Return a list of (literal_text, field_name, format_spec, conversion) tuples."""
318
+ return v'_fmt_parse(format_string)'
319
+
320
+ def get_value(self, key, args, kwargs):
321
+ """Retrieve a field value: integer key → args, string key → kwargs."""
322
+ is_int = jstype(key) is 'number'
323
+ is_int_str = not is_int and jstype(key) is 'string' and v'_str_is_digits_only(key)'
324
+ if is_int or is_int_str:
325
+ idx = key if is_int else int(key)
326
+ if idx < 0 or idx >= len(args):
327
+ raise IndexError('Replacement index ' + str(idx) + ' out of range for positional args tuple')
328
+ return args[idx]
329
+ val = v'_fmt_get_kwarg(kwargs, key)'
330
+ if val is undefined:
331
+ raise KeyError(key)
332
+ return val
333
+
334
+ def get_field(self, field_name, args, kwargs):
335
+ """Look up *field_name* (may include dotted/bracket access).
336
+
337
+ Returns (value, first_key_used).
338
+ """
339
+ return v'_fmt_get_field(field_name, args, kwargs, self)'
340
+
341
+ def convert_field(self, value, conversion):
342
+ """Apply a conversion specifier (!s, !r, !a) to *value*."""
343
+ if conversion is None or conversion is undefined:
344
+ return value
345
+ if conversion == 's':
346
+ return str(value)
347
+ if conversion == 'r':
348
+ return repr(value)
349
+ if conversion == 'a':
350
+ return repr(value)
351
+ raise ValueError('Unknown conversion specifier: ' + str(conversion))
352
+
353
+ def format_field(self, value, format_spec):
354
+ """Format a single *value* according to *format_spec*."""
355
+ if format_spec is not None and format_spec is not undefined and format_spec:
356
+ return format(value, format_spec)
357
+ return str(value)
@@ -0,0 +1,329 @@
1
+ ###########################################################
2
+ # RapydScript Standard Library
3
+ # License: Apache License 2.0
4
+ # This library is covered under Apache license, so that
5
+ # you can distribute it with your RapydScript applications.
6
+ ###########################################################
7
+
8
+ # Python-compatible textwrap module.
9
+ #
10
+ # Provides:
11
+ # TextWrapper class with .wrap(text), .fill(text)
12
+ # wrap(text[, width=70[, ...]])
13
+ # fill(text[, width=70[, ...]])
14
+ # shorten(text, width[, ...])
15
+ # dedent(text)
16
+ # indent(text, prefix[, predicate])
17
+ #
18
+ # All TextWrapper options supported:
19
+ # width, initial_indent, subsequent_indent, expand_tabs, tabsize,
20
+ # replace_whitespace, fix_sentence_endings, break_long_words,
21
+ # break_on_hyphens, drop_whitespace, max_lines, placeholder
22
+ #
23
+ # Notes:
24
+ # - break_on_hyphens=True (default) splits on em-dashes (2+ hyphens)
25
+ # between word characters, matching Python 3 behaviour.
26
+ # - shorten() normalises internal whitespace before truncating.
27
+
28
+ v"""
29
+ // ── textwrap internal helpers ────────────────────────────────────────────────
30
+
31
+ function _tw_expand_tabs(text, tabsize) {
32
+ var _res = '';
33
+ var _col = 0;
34
+ for (var _i = 0; _i < text.length; _i++) {
35
+ var _c = text[_i];
36
+ if (_c === '\t') {
37
+ var _n = tabsize - (_col % tabsize);
38
+ for (var _j = 0; _j < _n; _j++) _res += ' ';
39
+ _col += _n;
40
+ } else {
41
+ _res += _c;
42
+ if (_c === '\n' || _c === '\r') _col = 0; else _col++;
43
+ }
44
+ }
45
+ return _res;
46
+ }
47
+
48
+ // Split into alternating non-whitespace / whitespace chunks.
49
+ // break_on_hyphens: also split around em-dashes (2+ hyphens) between word chars.
50
+ function _tw_split_chunks(text, break_on_hyphens) {
51
+ var _re = break_on_hyphens
52
+ ? /(\s+|(?<=[\w!"'&.,?])-{2,}(?=\w))/g
53
+ : /(\s+)/g;
54
+ var _chunks = [];
55
+ var _last = 0;
56
+ var _m;
57
+ while ((_m = _re.exec(text)) !== null) {
58
+ if (_m.index > _last) _chunks.push(text.slice(_last, _m.index));
59
+ _chunks.push(_m[0]);
60
+ _last = _re.lastIndex;
61
+ }
62
+ if (_last < text.length) _chunks.push(text.slice(_last));
63
+ return _chunks;
64
+ }
65
+
66
+ function _tw_fix_sentence_endings(chunks) {
67
+ var _re = /[a-z][.!?]$/;
68
+ for (var _i = 0; _i < chunks.length - 1; _i++) {
69
+ if (chunks[_i + 1] === ' ' && _re.test(chunks[_i])) {
70
+ chunks[_i + 1] = ' ';
71
+ _i++;
72
+ }
73
+ }
74
+ }
75
+
76
+ function _tw_handle_long_word(chunks, cur_line, cur_len, avail, break_long_words) {
77
+ var _space = avail > 0 ? avail - cur_len : 1;
78
+ if (break_long_words) {
79
+ var _word = chunks[chunks.length - 1];
80
+ if (_space > 0) {
81
+ cur_line.push(_word.slice(0, _space));
82
+ chunks[chunks.length - 1] = _word.slice(_space);
83
+ }
84
+ if (chunks[chunks.length - 1] === '') chunks.pop();
85
+ } else if (!cur_line.length) {
86
+ cur_line.push(chunks.pop());
87
+ }
88
+ }
89
+
90
+ function _tw_wrap_chunks(chunks, width, initial_indent, subsequent_indent,
91
+ drop_whitespace, break_long_words, max_lines, placeholder) {
92
+ var _lines = [];
93
+ // Reverse so Array.pop() reads chunks left-to-right.
94
+ chunks = chunks.slice().reverse();
95
+
96
+ while (chunks.length > 0) {
97
+ var _cur_line = [];
98
+ var _cur_len = 0;
99
+ var _indent = _lines.length > 0 ? subsequent_indent : initial_indent;
100
+ var _avail = width - _indent.length;
101
+
102
+ // Drop leading whitespace on continuation lines.
103
+ if (drop_whitespace && _lines.length > 0 &&
104
+ chunks.length > 0 && chunks[chunks.length - 1].trim() === '') {
105
+ chunks.pop();
106
+ }
107
+ if (chunks.length === 0) break;
108
+
109
+ // Fill the current line.
110
+ while (chunks.length > 0) {
111
+ var _l = chunks[chunks.length - 1].length;
112
+ if (_cur_len + _l <= _avail) {
113
+ _cur_len += _l;
114
+ _cur_line.push(chunks.pop());
115
+ } else {
116
+ break;
117
+ }
118
+ }
119
+
120
+ // Handle a word longer than the available width.
121
+ if (chunks.length > 0 && chunks[chunks.length - 1].length > _avail) {
122
+ _tw_handle_long_word(chunks, _cur_line, _cur_len, _avail, break_long_words);
123
+ _cur_len = 0;
124
+ for (var _ci = 0; _ci < _cur_line.length; _ci++) _cur_len += _cur_line[_ci].length;
125
+ }
126
+
127
+ // Drop trailing whitespace.
128
+ if (drop_whitespace && _cur_line.length > 0 &&
129
+ _cur_line[_cur_line.length - 1].trim() === '') {
130
+ _cur_len -= _cur_line[_cur_line.length - 1].length;
131
+ _cur_line.pop();
132
+ }
133
+
134
+ if (_cur_line.length > 0) {
135
+ var _will_be_last = chunks.length === 0 ||
136
+ (drop_whitespace && chunks.length === 1 && chunks[0].trim() === '');
137
+
138
+ if (max_lines === null || max_lines === undefined ||
139
+ _lines.length + 1 < max_lines ||
140
+ (_will_be_last && _cur_len <= _avail)) {
141
+ _lines.push(_indent + _cur_line.join(''));
142
+ } else {
143
+ // Truncate current line to fit placeholder.
144
+ var _done = false;
145
+ while (_cur_line.length > 0) {
146
+ var _tok = _cur_line[_cur_line.length - 1];
147
+ if (_tok.trim() !== '' && _cur_len + placeholder.length <= _avail) {
148
+ _lines.push(_indent + _cur_line.join('') + placeholder);
149
+ _done = true;
150
+ break;
151
+ }
152
+ _cur_len -= _tok.length;
153
+ _cur_line.pop();
154
+ }
155
+ if (!_done) {
156
+ if (_lines.length > 0) {
157
+ var _prev = _lines[_lines.length - 1].replace(/\s+$/, '');
158
+ if (_prev.length + placeholder.length <= width) {
159
+ _lines[_lines.length - 1] = _prev + placeholder;
160
+ } else {
161
+ _lines.push(_indent + placeholder.replace(/^\s+/, ''));
162
+ }
163
+ } else {
164
+ _lines.push(_indent + placeholder.replace(/^\s+/, ''));
165
+ }
166
+ }
167
+ break;
168
+ }
169
+ }
170
+ }
171
+ return _lines;
172
+ }
173
+
174
+ function _tw_do_wrap(text, width, opts) {
175
+ var _ii = opts.initial_indent != null ? opts.initial_indent : '';
176
+ var _si = opts.subsequent_indent != null ? opts.subsequent_indent : '';
177
+ var _et = opts.expand_tabs != null ? opts.expand_tabs : true;
178
+ var _ts = opts.tabsize != null ? opts.tabsize : 8;
179
+ var _rw = opts.replace_whitespace != null ? opts.replace_whitespace : true;
180
+ var _fse = opts.fix_sentence_endings != null ? opts.fix_sentence_endings : false;
181
+ var _blw = opts.break_long_words != null ? opts.break_long_words : true;
182
+ var _boh = opts.break_on_hyphens != null ? opts.break_on_hyphens : true;
183
+ var _dw = opts.drop_whitespace != null ? opts.drop_whitespace : true;
184
+ var _ml = opts.max_lines != null ? opts.max_lines : null;
185
+ var _ph = opts.placeholder != null ? opts.placeholder : ' [...]';
186
+
187
+ if (_et) text = _tw_expand_tabs(text, _ts);
188
+ if (_rw) text = text.replace(/[\t\n\x0b\x0c\r]/g, ' ');
189
+
190
+ var _chunks = _tw_split_chunks(text, _boh);
191
+ if (_fse) _tw_fix_sentence_endings(_chunks);
192
+
193
+ return _tw_wrap_chunks(_chunks, width, _ii, _si, _dw, _blw, _ml, _ph);
194
+ }
195
+
196
+ function _tw_do_fill(text, width, opts) {
197
+ return _tw_do_wrap(text, width, opts).join('\n');
198
+ }
199
+
200
+ function _tw_shorten(text, width, opts) {
201
+ text = text.trim().split(/\s+/).join(' ');
202
+ // Build a copy of opts with max_lines forced to 1.
203
+ var _sopts = {};
204
+ for (var _k in opts) {
205
+ if (Object.prototype.hasOwnProperty.call(opts, _k)) _sopts[_k] = opts[_k];
206
+ }
207
+ _sopts.max_lines = 1;
208
+ if (_sopts.placeholder === null || _sopts.placeholder === undefined) {
209
+ _sopts.placeholder = ' [...]';
210
+ }
211
+ return _tw_do_fill(text, width, _sopts);
212
+ }
213
+
214
+ function _tw_dedent(text) {
215
+ var _lines = text.split('\n');
216
+ var _margin = null;
217
+ for (var _i = 0; _i < _lines.length; _i++) {
218
+ var _line = _lines[_i];
219
+ if (_line.trim() === '') continue;
220
+ var _m = /^(\s+)\S/.exec(_line);
221
+ if (_m) {
222
+ var _ind = _m[1];
223
+ if (_margin === null) {
224
+ _margin = _ind;
225
+ } else {
226
+ var _j = 0;
227
+ while (_j < _margin.length && _j < _ind.length && _margin[_j] === _ind[_j]) _j++;
228
+ _margin = _margin.slice(0, _j);
229
+ }
230
+ } else {
231
+ _margin = '';
232
+ }
233
+ if (_margin === '') break;
234
+ }
235
+ if (!_margin) return text;
236
+ var _result = [];
237
+ for (var _i2 = 0; _i2 < _lines.length; _i2++) {
238
+ var _l = _lines[_i2];
239
+ _result.push(_l.slice(0, _margin.length) === _margin ? _l.slice(_margin.length) : _l);
240
+ }
241
+ return _result.join('\n');
242
+ }
243
+
244
+ function _tw_indent(text, prefix, predicate) {
245
+ var _lines = text.split('\n');
246
+ var _result = [];
247
+ var _use_default = (predicate === null || predicate === undefined);
248
+ for (var _i = 0; _i < _lines.length; _i++) {
249
+ var _line = _lines[_i];
250
+ var _add = _use_default ? _line.trim() !== '' : predicate(_line);
251
+ _result.push(_add ? prefix + _line : _line);
252
+ }
253
+ return _result.join('\n');
254
+ }
255
+ """
256
+
257
+
258
+ class TextWrapper:
259
+ def __init__(self, width=70, initial_indent='', subsequent_indent='',
260
+ expand_tabs=True, tabsize=8, replace_whitespace=True,
261
+ fix_sentence_endings=False, break_long_words=True,
262
+ break_on_hyphens=True, drop_whitespace=True,
263
+ max_lines=None, placeholder=' [...]'):
264
+ self.width = width
265
+ self.initial_indent = initial_indent
266
+ self.subsequent_indent = subsequent_indent
267
+ self.expand_tabs = expand_tabs
268
+ self.tabsize = tabsize
269
+ self.replace_whitespace = replace_whitespace
270
+ self.fix_sentence_endings = fix_sentence_endings
271
+ self.break_long_words = break_long_words
272
+ self.break_on_hyphens = break_on_hyphens
273
+ self.drop_whitespace = drop_whitespace
274
+ self.max_lines = max_lines
275
+ self.placeholder = placeholder
276
+
277
+ def wrap(self, text):
278
+ return v'_tw_do_wrap(text, this.width, this)'
279
+
280
+ def fill(self, text):
281
+ return v'_tw_do_fill(text, this.width, this)'
282
+
283
+
284
+ def wrap(text, width=70, initial_indent='', subsequent_indent='',
285
+ expand_tabs=True, tabsize=8, replace_whitespace=True,
286
+ fix_sentence_endings=False, break_long_words=True,
287
+ break_on_hyphens=True, drop_whitespace=True,
288
+ max_lines=None, placeholder=' [...]'):
289
+ return TextWrapper(
290
+ width, initial_indent, subsequent_indent, expand_tabs,
291
+ tabsize, replace_whitespace, fix_sentence_endings,
292
+ break_long_words, break_on_hyphens, drop_whitespace,
293
+ max_lines, placeholder
294
+ ).wrap(text)
295
+
296
+
297
+ def fill(text, width=70, initial_indent='', subsequent_indent='',
298
+ expand_tabs=True, tabsize=8, replace_whitespace=True,
299
+ fix_sentence_endings=False, break_long_words=True,
300
+ break_on_hyphens=True, drop_whitespace=True,
301
+ max_lines=None, placeholder=' [...]'):
302
+ return TextWrapper(
303
+ width, initial_indent, subsequent_indent, expand_tabs,
304
+ tabsize, replace_whitespace, fix_sentence_endings,
305
+ break_long_words, break_on_hyphens, drop_whitespace,
306
+ max_lines, placeholder
307
+ ).fill(text)
308
+
309
+
310
+ def shorten(text, width, initial_indent='', subsequent_indent='',
311
+ expand_tabs=True, tabsize=8, replace_whitespace=True,
312
+ fix_sentence_endings=False, break_long_words=True,
313
+ break_on_hyphens=True, drop_whitespace=True,
314
+ placeholder=' [...]'):
315
+ opts = TextWrapper(
316
+ width, initial_indent, subsequent_indent, expand_tabs,
317
+ tabsize, replace_whitespace, fix_sentence_endings,
318
+ break_long_words, break_on_hyphens, drop_whitespace,
319
+ None, placeholder
320
+ )
321
+ return v'_tw_shorten(text, width, opts)'
322
+
323
+
324
+ def dedent(text):
325
+ return v'_tw_dedent(text)'
326
+
327
+
328
+ def indent(text, prefix, predicate=None):
329
+ return v'_tw_indent(text, prefix, predicate)'
@@ -0,0 +1,14 @@
1
+ ###########################################################
2
+ # RapydScript Standard Library
3
+ # urllib — URL handling utilities
4
+ ###########################################################
5
+ #
6
+ # Sub-modules:
7
+ # urllib.parse — URL parsing and encoding (urlparse, quote, urlencode, …)
8
+ # urllib.request — HTTP requests via fetch (urlopen)
9
+ # urllib.error — URLError, HTTPError exception classes
10
+ #
11
+ # Usage:
12
+ # from urllib.parse import urlparse, quote, unquote, urlencode, urljoin
13
+ # from urllib.request import urlopen
14
+ # from urllib.error import URLError, HTTPError