]> Lady’s Gitweb - Pisces/blob - string.js
Minor refactors to numeric.js
[Pisces] / string.js
1 // SPDX-FileCopyrightText: 2022, 2023, 2025 Lady <https://www.ladys.computer/about/#lady>
2 // SPDX-License-Identifier: MPL-2.0
3 /**
4 * ⁌ ♓🧩 Piscēs ∷ string.js
5 *
6 * Copyright © 2022–2023, 2025 Lady [@ Ladys Computer].
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
11 */
12
13 import {
14 bind,
15 call,
16 completesNormally,
17 createArrowFunction,
18 createCallableFunction,
19 identity,
20 } from "./function.js";
21 import {
22 arrayIteratorFunction,
23 stringIteratorFunction,
24 } from "./iterable.js";
25 import {
26 defineOwnDataProperty,
27 defineOwnProperties,
28 getOwnPropertyDescriptors,
29 objectCreate,
30 setPropertyValues,
31 setPrototype,
32 } from "./object.js";
33 import { sameValue, toLength, UNDEFINED } from "./value.js";
34
35 const PISCĒS = "♓🧩 Piscēs";
36
37 const RE = RegExp;
38 const { prototype: rePrototype } = RE;
39 const { prototype: arrayPrototype } = Array;
40 const { prototype: stringPrototype } = String;
41
42 const { exec: reExec } = rePrototype;
43
44 export const {
45 /**
46 * A `RegExp´‐like object which only matches entire strings, and may
47 * have additional constraints specified.
48 *
49 * Matchers are callable objects and will return true if they are
50 * called with a string that they match, and false otherwise.
51 * Matchers will always return false if called with nonstrings, altho
52 * other methods like `::exec´ coerce their arguments and may still
53 * return true.
54 */
55 Matcher,
56 } = (() => {
57 const { toString: reToString } = rePrototype;
58 const getDotAll =
59 Object.getOwnPropertyDescriptor(rePrototype, "dotAll").get;
60 const getFlags =
61 Object.getOwnPropertyDescriptor(rePrototype, "flags").get;
62 const getGlobal =
63 Object.getOwnPropertyDescriptor(rePrototype, "global").get;
64 const getHasIndices =
65 Object.getOwnPropertyDescriptor(rePrototype, "hasIndices").get;
66 const getIgnoreCase =
67 Object.getOwnPropertyDescriptor(rePrototype, "ignoreCase").get;
68 const getMultiline =
69 Object.getOwnPropertyDescriptor(rePrototype, "multiline").get;
70 const getSource =
71 Object.getOwnPropertyDescriptor(rePrototype, "source").get;
72 const getSticky =
73 Object.getOwnPropertyDescriptor(rePrototype, "sticky").get;
74 const getUnicode =
75 Object.getOwnPropertyDescriptor(rePrototype, "unicode").get;
76 const getUnicodeSets =
77 Object.getOwnPropertyDescriptor(rePrototype, "unicodeSets").get;
78
79 /**
80 * The internal implementation of `Matcher´.
81 *
82 * ※ This class extends the identity function to enable the addition
83 * of private fields to the callable matcher function it constructs.
84 *
85 * ※ This class is not exposed.
86 */
87 const Matcher = class extends identity {
88 #constraint;
89 #regExp;
90
91 /**
92 * Constructs a new `Matcher´ from the provided source.
93 *
94 * If the provided source is a regular expression, then it must
95 * have either the unicode flag set or the unicode sets flag set.
96 * Otherwise, it is interpreted as the string source of a regular
97 * expression with the unicode flag set.
98 *
99 * Other flags are taken from the provided regular expression
100 * object, if any are present.
101 *
102 * A name for the matcher may be provided as the second argument.
103 *
104 * A callable constraint on acceptable inputs may be provided as a
105 * third argument. If provided, it will be called with three
106 * arguments whenever a match appears successful: first, the string
107 * being matched, second, the match result, and third, the
108 * `Matcher´ object itself. If the return value of this call is
109 * falsey, then the match will be considered a failure.
110 *
111 * ☡ If the provided source regular expression uses nongreedy
112 * quantifiers, it may not match the whole string even if a match
113 * with the whole string is possible. Surround the regular
114 * expression with `^(?:´ and `)$´ if you don¦t want nongreedy
115 * regular expressions to fail when shorter matches are possible.
116 */
117 constructor(source, name = UNDEFINED, constraint = null) {
118 super(
119 ($) => {
120 if (typeof $ !== "string") {
121 // The provided value is not a string.
122 return false;
123 } else {
124 // The provided value is a string.
125 //
126 // Set the `.lastIndex´ of the regular expression to 0, and
127 // see if the first attempt at a match successfully matches
128 // the whole string and passes the provided constraint (if
129 // present).
130 regExp.lastIndex = 0;
131 const result = call(reExec, regExp, [$]);
132 return result?.[0] === $
133 && (constraint === null || constraint($, result, this));
134 }
135 },
136 );
137 const regExp = this.#regExp = (() => {
138 if (completesNormally(() => call(reExec, source, [""]))) {
139 // The provided source is a `RegExp´.
140 if (
141 !call(getUnicode, source, [])
142 && !call(getUnicodeSets, source, [])
143 ) {
144 // The provided regular expression does not have a unicode
145 // flag or unicode sets flag.
146 throw new TypeError(
147 `${PISCĒS}: Cannot create Matcher from non‐Unicode RegExp: ${source}`,
148 );
149 } else {
150 // The provided regular expression has a unicode flag or
151 // unicode sets flag.
152 return new RE(source);
153 }
154 } else {
155 // The provided source is not a `RegExp´.
156 //
157 // Create one using it as the source string.
158 return new RE(`${source}`, "u");
159 }
160 })();
161 if (constraint !== null && typeof constraint !== "function") {
162 throw new TypeError(
163 `${PISCĒS}: Cannot construct Matcher: Constraint is not callable.`,
164 );
165 } else {
166 this.#constraint = constraint;
167 return defineOwnProperties(
168 setPrototype(this, matcherPrototype),
169 {
170 lastIndex: setPropertyValues(objectCreate(null), {
171 configurable: false,
172 enumerable: false,
173 value: 0,
174 writable: false,
175 }),
176 name: defineOwnDataProperty(
177 objectCreate(null),
178 "value",
179 name != null
180 ? `${name}`
181 : `Matcher(${call(reToString, regExp, [])})`,
182 ),
183 },
184 );
185 }
186 }
187
188 /** Gets whether the dot‐all flag is present on this `Matcher´. */
189 get dotAll() {
190 return call(getDotAll, this.#regExp, []);
191 }
192
193 /**
194 * Executes this `Matcher´ on the provided value and returns the
195 * result if there is a match, or null otherwise.
196 *
197 * Matchers only match if they can match the entire value on the
198 * first attempt.
199 *
200 * ☡ The match result returned by this method will be the same as
201 * that passed to the constraint function—and may have been
202 * modified by said function prior to being returned.
203 */
204 exec($) {
205 const regExp = this.#regExp;
206 const constraint = this.#constraint;
207 const string = `${$}`;
208 regExp.lastIndex = 0;
209 const result = call(reExec, regExp, [string]);
210 if (
211 result?.[0] === string
212 && (constraint === null || constraint(string, result, this))
213 ) {
214 // The entire string was matched and the constraint, if
215 // present, returned a truthy value.
216 return result;
217 } else {
218 // The entire string was not matched or the constraint returned
219 // a falsey value.
220 return null;
221 }
222 }
223
224 /**
225 * Gets the flags present on this `Matcher´.
226 *
227 * ※ This needs to be defined because the internal `RegExp´ object
228 * may have flags which are not yet recognized by ♓🧩 Piscēs.
229 */
230 get flags() {
231 return call(getFlags, this.#regExp, []);
232 }
233
234 /** Gets whether the global flag is present on this `Matcher´. */
235 get global() {
236 return call(getGlobal, this.#regExp, []);
237 }
238
239 /**
240 * Gets whether the has‐indices flag is present on this `Matcher´.
241 */
242 get hasIndices() {
243 return call(getHasIndices, this.#regExp, []);
244 }
245
246 /**
247 * Gets whether the ignore‐case flag is present on this `Matcher´.
248 */
249 get ignoreCase() {
250 return call(getIgnoreCase, this.#regExp, []);
251 }
252
253 /**
254 * Gets whether the multiline flag is present on this `Matcher´.
255 */
256 get multiline() {
257 return call(getMultiline, this.#regExp, []);
258 }
259
260 /** Gets the regular expression source for this `Matcher´. */
261 get source() {
262 return call(getSource, this.#regExp, []);
263 }
264
265 /** Gets whether the sticky flag is present on this `Matcher´. */
266 get sticky() {
267 return call(getSticky, this.#regExp, []);
268 }
269
270 /**
271 * Gets whether the unicode flag is present on this `Matcher´.
272 */
273 get unicode() {
274 return call(getUnicode, this.#regExp, []);
275 }
276
277 /**
278 * Gets whether the unicode sets flag is present on this `Matcher´.
279 */
280 get unicodeSets() {
281 return call(getUnicodeSets, this.#regExp, []);
282 }
283 };
284
285 const matcherConstructor = Object.defineProperties(
286 class extends RegExp {
287 constructor(...args) {
288 return new Matcher(...args);
289 }
290 },
291 {
292 name: defineOwnDataProperty(
293 Object.create(null),
294 "value",
295 "Matcher",
296 ),
297 length: defineOwnDataProperty(Object.create(null), "value", 1),
298 },
299 );
300 const matcherPrototype = defineOwnProperties(
301 matcherConstructor.prototype,
302 getOwnPropertyDescriptors(Matcher.prototype),
303 {
304 constructor: defineOwnDataProperty(
305 Object.create(null),
306 "value",
307 matcherConstructor,
308 ),
309 },
310 );
311
312 return { Matcher: matcherConstructor };
313 })();
314
315 export const {
316 /**
317 * Returns the result of converting the provided value to A·S·C·I·I
318 * lowercase.
319 */
320 asciiLowercase,
321
322 /**
323 * Returns the result of converting the provided value to A·S·C·I·I
324 * uppercase.
325 */
326 asciiUppercase,
327 } = (() => {
328 const {
329 toLowerCase: stringToLowercase,
330 toUpperCase: stringToUppercase,
331 } = stringPrototype;
332 return {
333 asciiLowercase: ($) =>
334 stringReplaceAll(
335 `${$}`,
336 /[A-Z]/gu,
337 createCallableFunction(stringToLowercase),
338 ),
339 asciiUppercase: ($) =>
340 stringReplaceAll(
341 `${$}`,
342 /[a-z]/gu,
343 createCallableFunction(stringToUppercase),
344 ),
345 };
346 })();
347
348 /**
349 * Returns −0 if the provided argument is `"-0"´; returns a number
350 * representing the index if the provided argument is a canonical
351 * numeric index string; otherwise, returns undefined.
352 *
353 * There is no clamping of the numeric index, but note that numbers
354 * above 2^53 − 1 are not safe nor valid integer indices.
355 */
356 export const canonicalNumericIndexString = ($) => {
357 if (typeof $ !== "string") {
358 return UNDEFINED;
359 } else if ($ === "-0") {
360 return -0;
361 } else {
362 const n = +$;
363 return $ === `${n}` ? n : UNDEFINED;
364 }
365 };
366
367 export const {
368 /**
369 * Returns an iterator over the codepoints in the string representation
370 * of the provided value according to the algorithm of
371 * `String::[Symbol.iterator]´.
372 */
373 characters,
374
375 /**
376 * Returns an iterator over the code units in the string
377 * representation of the provided value.
378 */
379 codeUnits,
380
381 /**
382 * Returns an iterator over the codepoints in the string
383 * representation of the provided value.
384 */
385 codepoints,
386
387 /**
388 * Returns an iterator over the scalar values in the string
389 * representation of the provided value.
390 *
391 * Codepoints which are not valid Unicode scalar values are replaced
392 * with U+FFFD.
393 */
394 scalarValues,
395 } = (() => {
396 const generateCharacters = function* (character) {
397 yield character;
398 };
399 const generateCodeUnits = function* (ucsCharacter) {
400 yield getCodeUnit(ucsCharacter, 0);
401 };
402 const generateCodepoints = function* (character) {
403 const { allowSurrogates } = this;
404 const codepoint = getCodepoint(character, 0);
405 yield allowSurrogates || codepoint <= 0xD7FF || codepoint >= 0xE000
406 ? codepoint
407 : 0xFFFD;
408 };
409
410 const charactersIterator = stringIteratorFunction(
411 generateCharacters,
412 "String Character Iterator",
413 );
414 const codeUnitsIterator = arrayIteratorFunction(
415 generateCodeUnits,
416 "String Code Unit Iterator",
417 );
418 const codepointsIterator = stringIteratorFunction(
419 bind(generateCodepoints, { allowSurrogates: true }, []),
420 "String Codepoint Iterator",
421 );
422 const scalarValuesIterator = stringIteratorFunction(
423 bind(generateCodepoints, { allowSurrogates: false }, []),
424 "String Scalar Value Iterator",
425 );
426
427 return {
428 characters: ($) => charactersIterator(`${$}`),
429 codeUnits: ($) => codeUnitsIterator(`${$}`),
430 codepoints: ($) => codepointsIterator(`${$}`),
431 scalarValues: ($) => scalarValuesIterator(`${$}`),
432 };
433 })();
434
435 /**
436 * Returns the character at the provided position in the string
437 * representation of the provided value according to the algorithm of
438 * `String::codePointAt´.
439 */
440 export const getCharacter = ($, pos) => {
441 const codepoint = getCodepoint($, pos);
442 return codepoint == null
443 ? UNDEFINED
444 : stringFromCodepoints(codepoint);
445 };
446
447 export const {
448 /**
449 * Returns the code unit at the provided position in the string
450 * representation of the provided value according to the algorithm of
451 * `String::charAt´, except that out‐of‐bounds values return
452 * undefined in place of nan.
453 */
454 getCodeUnit,
455
456 /**
457 * Returns a string created from the provided code units.
458 *
459 * ※ This is effectively an alias for `String.fromCharCode´, but
460 * with the same error behaviour as `String.fromCodePoint´.
461 *
462 * ☡ This function throws an error if provided with an argument which
463 * is not an integral number from 0 to FFFF₁₆ inclusive.
464 */
465 stringFromCodeUnits,
466
467 /**
468 * Returns the result of catenating the string representations of the
469 * provided values, returning a new string according to the algorithm
470 * of `String::concat´.
471 *
472 * ※ If no arguments are given, this function returns the empty
473 * string. This is different behaviour than if an explicit undefined
474 * first argument is given, in which case the resulting string will
475 * begin with `"undefined"´.
476 */
477 stringCatenate,
478 } = (() => {
479 const { fromCharCode } = String;
480 const { charCodeAt, concat } = String.prototype;
481 const {
482 isInteger: isIntegralNumber,
483 isNaN: isNan,
484 } = Number;
485
486 return {
487 getCodeUnit: ($, n) => {
488 const codeUnit = call(charCodeAt, $, [n]);
489 return isNan(codeUnit) ? UNDEFINED : codeUnit;
490 },
491 stringCatenate: Object.defineProperties(
492 (...args) => call(concat, "", args),
493 { name: { value: "stringCatenate" }, length: { value: 2 } },
494 ),
495 stringFromCodeUnits: Object.defineProperties(
496 (...codeUnits) => {
497 for (let index = 0; index < codeUnits.length; ++index) {
498 // Iterate over each provided code unit and throw if it is
499 // out of range.
500 const nextCU = +codeUnits[index];
501 if (
502 !isIntegralNumber(nextCU) || nextCU < 0 || nextCU > 0xFFFF
503 ) {
504 // The code unit is not an integral number between 0 and
505 // 0xFFFF; this is an error.
506 throw new RangeError(
507 `${PISCĒS}: Code unit out of range: ${nextCU}.`,
508 );
509 } else {
510 // The code unit is acceptable.
511 /* do nothing */
512 }
513 }
514 return call(fromCharCode, UNDEFINED, codeUnits);
515 },
516 { name: { value: "stringFromCodeUnits" }, length: { value: 1 } },
517 ),
518 };
519 })();
520
521 /**
522 * Returns the codepoint at the provided position in the string
523 * representation of the provided value according to the algorithm of
524 * `String::codePointAt´.
525 */
526 export const getCodepoint = createCallableFunction(
527 stringPrototype.codePointAt,
528 { name: "getCodepoint" },
529 );
530
531 /**
532 * Returns the index of the first occurrence of the search string in
533 * the string representation of the provided value according to the
534 * algorithm of `String::indexOf´.
535 */
536 export const getFirstSubstringIndex = createCallableFunction(
537 stringPrototype.indexOf,
538 { name: "getFirstSubstringIndex" },
539 );
540
541 /**
542 * Returns the index of the last occurrence of the search string in the
543 * string representation of the provided value according to the
544 * algorithm of `String::lastIndexOf´.
545 */
546 export const getLastSubstringIndex = createCallableFunction(
547 stringPrototype.lastIndexOf,
548 { name: "getLastSubstringIndex" },
549 );
550
551 /** Returns whether the provided value is an array index. */
552 export const isArrayIndexString = ($) => {
553 const value = canonicalNumericIndexString($);
554 if (value !== UNDEFINED) {
555 // The provided value is a canonical numeric index string.
556 //
557 // Return whether it is in range for array indices.
558 return sameValue(value, 0)
559 || value === toLength(value) && value > 0 && value < -1 >>> 0;
560 } else {
561 // The provided value is not a canonical numeric index string.
562 return false;
563 }
564 };
565
566 /** Returns whether the provided value is an integer index string. */
567 export const isIntegerIndexString = ($) => {
568 const value = canonicalNumericIndexString($);
569 if (value !== UNDEFINED) {
570 // The provided value is a canonical numeric index string.
571 //
572 // Return whether it is in range for integer indices.
573 return sameValue(value, 0)
574 || value === toLength(value) && value > 0;
575 } else {
576 // The provided value is not a canonical numeric index string.
577 return false;
578 }
579 };
580
581 /**
582 * Returns the result of joining the provided iterable.
583 *
584 * If no separator is provided, it defaults to `","´.
585 *
586 * If a value is nullish, it will be stringified as the empty string.
587 */
588 export const join = (() => {
589 const { join: arrayJoin } = arrayPrototype;
590 const join = ($, separator) =>
591 call(
592 arrayJoin,
593 [...$],
594 [separator === UNDEFINED ? "," : `${separator}`],
595 );
596 return join;
597 })();
598
599 /**
600 * Returns a string created from the raw value of the tagged template
601 * literal.
602 *
603 * ※ This is effectively an alias for `String.raw´.
604 */
605 export const rawString = createArrowFunction(String.raw, {
606 name: "rawString",
607 });
608
609 /**
610 * Returns a string created from the provided codepoints.
611 *
612 * ※ This is effectively an alias for `String.fromCodePoint´.
613 *
614 * ☡ This function throws an error if provided with an argument which
615 * is not an integral number from 0 to 10FFFF₁₆ inclusive.
616 */
617 export const stringFromCodepoints = createArrowFunction(
618 String.fromCodePoint,
619 { name: "stringFromCodepoints" },
620 );
621
622 /**
623 * Returns the result of splitting the provided value on Ascii
624 * whitespace.
625 */
626 export const splitOnAsciiWhitespace = ($) =>
627 stringSplit(stripAndCollapseAsciiWhitespace($), " ");
628
629 /**
630 * Returns the result of splitting the provided value on commas,
631 * trimming Ascii whitespace from the resulting tokens.
632 */
633 export const splitOnCommas = ($) =>
634 stringSplit(
635 stripLeadingAndTrailingAsciiWhitespace(
636 stringReplaceAll(
637 `${$}`,
638 /[\n\r\t\f ]*,[\n\r\t\f ]*/gu,
639 ",",
640 ),
641 ),
642 ",",
643 );
644
645 /**
646 * Returns whether the string representation of the provided value ends
647 * with the provided search string according to the algorithm of
648 * `String::endsWith´.
649 */
650 export const stringEndsWith = createCallableFunction(
651 stringPrototype.endsWith,
652 { name: "stringEndsWith" },
653 );
654
655 /**
656 * Returns whether the string representation of the provided value
657 * contains the provided search string according to the algorithm of
658 * `String::includes´.
659 */
660 export const stringIncludes = createCallableFunction(
661 stringPrototype.includes,
662 { name: "stringIncludes" },
663 );
664
665 /**
666 * Returns the result of matching the string representation of the
667 * provided value with the provided matcher according to the algorithm
668 * of `String::match´.
669 */
670 export const stringMatch = createCallableFunction(
671 stringPrototype.match,
672 { name: "stringMatch" },
673 );
674
675 /**
676 * Returns the result of matching the string representation of the
677 * provided value with the provided matcher according to the algorithm
678 * of `String::matchAll´.
679 */
680 export const stringMatchAll = createCallableFunction(
681 stringPrototype.matchAll,
682 { name: "stringMatchAll" },
683 );
684
685 /**
686 * Returns the normalized form of the string representation of the
687 * provided value according to the algorithm of `String::normalize´.
688 */
689 export const stringNormalize = createCallableFunction(
690 stringPrototype.normalize,
691 { name: "stringNormalize" },
692 );
693
694 /**
695 * Returns the result of padding the end of the string representation
696 * of the provided value padded until it is the desired length
697 * according to the algorithm of `String::padEnd´.
698 */
699 export const stringPadEnd = createCallableFunction(
700 stringPrototype.padEnd,
701 { name: "stringPadEnd" },
702 );
703
704 /**
705 * Returns the result of padding the start of the string representation
706 * of the provided value padded until it is the desired length
707 * according to the algorithm of `String::padStart´.
708 */
709 export const stringPadStart = createCallableFunction(
710 stringPrototype.padStart,
711 { name: "stringPadStart" },
712 );
713
714 /**
715 * Returns the result of repeating the string representation of the
716 * provided value the provided number of times according to the
717 * algorithm of `String::repeat´.
718 */
719 export const stringRepeat = createCallableFunction(
720 stringPrototype.repeat,
721 { name: "stringRepeat" },
722 );
723
724 /**
725 * Returns the result of replacing the string representation of the
726 * provided value with the provided replacement, using the provided
727 * matcher and according to the algorithm of `String::replace´.
728 */
729 export const stringReplace = createCallableFunction(
730 stringPrototype.replace,
731 { name: "stringReplace" },
732 );
733
734 /**
735 * Returns the result of replacing the string representation of the
736 * provided value with the provided replacement, using the provided
737 * matcher and according to the algorithm of `String::replaceAll´.
738 */
739 export const stringReplaceAll = createCallableFunction(
740 stringPrototype.replaceAll,
741 { name: "stringReplaceAll" },
742 );
743
744 /**
745 * Returns the result of searching the string representation of the
746 * provided value using the provided matcher and according to the
747 * algorithm of `String::search´.
748 */
749 export const stringSearch = createCallableFunction(
750 stringPrototype.search,
751 { name: "stringSearch" },
752 );
753
754 /**
755 * Returns a slice of the string representation of the provided value
756 * according to the algorithm of `String::slice´.
757 */
758 export const stringSlice = createCallableFunction(
759 stringPrototype.slice,
760 { name: "stringSlice" },
761 );
762
763 /**
764 * Returns the result of splitting of the string representation of the
765 * provided value on the provided separator according to the algorithm
766 * of `String::split´.
767 */
768 export const stringSplit = createCallableFunction(
769 stringPrototype.split,
770 { name: "stringSplit" },
771 );
772
773 /**
774 * Returns whether the string representation of the provided value
775 * starts with the provided search string according to the algorithm of
776 * `String::startsWith´.
777 */
778 export const stringStartsWith = createCallableFunction(
779 stringPrototype.startsWith,
780 { name: "stringStartsWith" },
781 );
782
783 /**
784 * Returns the value of the provided string.
785 *
786 * ※ This is effectively an alias for the `String::valueOf´.
787 *
788 * ☡ This function throws if the provided argument is not a string and
789 * does not have a `[[StringData]]´ slot.
790 */
791 export const stringValue = createCallableFunction(
792 stringPrototype.valueOf,
793 { name: "stringValue" },
794 );
795
796 /**
797 * Returns the result of stripping leading and trailing Ascii
798 * whitespace from the provided value and collapsing other Ascii
799 * whitespace in the string representation of the provided value.
800 */
801 export const stripAndCollapseAsciiWhitespace = ($) =>
802 stripLeadingAndTrailingAsciiWhitespace(
803 stringReplaceAll(
804 `${$}`,
805 /[\n\r\t\f ]+/gu,
806 " ",
807 ),
808 );
809
810 /**
811 * Returns the result of stripping leading and trailing Ascii
812 * whitespace from the string representation of the provided value.
813 */
814 export const stripLeadingAndTrailingAsciiWhitespace = ($) =>
815 call(reExec, /^[\n\r\t\f ]*([^]*?)[\n\r\t\f ]*$/u, [$])[1];
816
817 /**
818 * Returns a substring of the string representation of the provided
819 * value according to the algorithm of `String::substring´.
820 */
821 export const substring = createCallableFunction(
822 stringPrototype.substring,
823 );
824
825 /**
826 * Returns the result of converting the provided value to a string of
827 * scalar values by replacing (unpaired) surrogate values with
828 * U+FFFD.
829 */
830 export const toScalarValueString = createCallableFunction(
831 String.prototype.toWellFormed,
832 { name: "toScalarValueString" },
833 );
834
835 /**
836 * Returns the result of converting the provided value to a string.
837 *
838 * ☡ This method throws for symbols and other objects without a string
839 * representation.
840 */
841 export const toString = ($) => `${$}`;
This page took 0.710888 seconds and 5 git commands to generate.