From 398d88c0a57a11b598083715666eab4171ec88a5 Mon Sep 17 00:00:00 2001 From: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com> Date: Fri, 27 Dec 2024 19:10:33 +0200 Subject: [PATCH] add more functions in stdlib, fix some issues --- src/lib/libs/array.ts | 31 +++++++++++++++++++++++++++++-- src/lib/libs/function.ts | 2 +- src/lib/libs/map.ts | 2 +- src/lib/libs/math.ts | 10 ++++++++++ src/lib/libs/number.ts | 18 +++++++++--------- src/lib/libs/object.ts | 6 +++--- src/lib/libs/regex.ts | 29 +++++++++++++++-------------- src/lib/libs/string.ts | 22 +++++++++++++++++----- src/lib/libs/utils.ts | 4 ++-- 9 files changed, 87 insertions(+), 37 deletions(-) diff --git a/src/lib/libs/array.ts b/src/lib/libs/array.ts index a47c9be..ed1a11a 100644 --- a/src/lib/libs/array.ts +++ b/src/lib/libs/array.ts @@ -1,10 +1,11 @@ +import { Error } from "./errors.ts"; import { func, object, string } from "./primordials.ts"; import { String } from "./string.ts"; import { limitI, symbols, wrapI } from "./utils.ts"; export const Array = (() => { class Array { - public forEach(this: any[], cb: (val: any, i: number, self: this[]) => void, self?: any) { + public forEach(this: any[], cb: (val: any, i: number, self: this) => void, self?: any) { for (let i = 0; i < this.length; i++) { if (i in this) func.invoke(cb, self, [this[i], i, this]); } @@ -98,7 +99,7 @@ export const Array = (() => { const res: any[] = []; res.length = end - start; - for (let i = start; i < end; i++) { + for (let i = 0; i < end - start; i++) { res[i] = this[start + i]; } @@ -163,6 +164,13 @@ export const Array = (() => { return false; } + public every(this: any[], cb: Function, self?: any) { + for (let i = 0; i < this.length; i++) { + if (i in this && !func.invoke(cb, self, [this[i], i, this])) return false; + } + + return true; + } public find(this: any[], cb: Function, self?: any) { for (let i = 0; i < this.length; i++) { if (i in this && func.invoke(cb, self, [this[i], i, this])) return this[i]; @@ -170,6 +178,25 @@ export const Array = (() => { return undefined; } + public indexOf(this: any[], val: any, start = 0) { + start |= 0; + if (start < 0) start = 0; + for (let i = start; i < this.length; i++) { + if (i in this && this[i] === val) return i; + } + + return -1; + } + public lastIndexOf(this: any[], val: any, start = 0) { + start |= 0; + if (start < 0) start = 0; + + for (let i = this.length - 1; i >= start; i--) { + if (i in this && this[i] === val) return i; + } + + return -1; + } public sort(this: any[], cb?: Function) { cb ||= (a: any, b: any) => { diff --git a/src/lib/libs/function.ts b/src/lib/libs/function.ts index 6035a60..93997b5 100644 --- a/src/lib/libs/function.ts +++ b/src/lib/libs/function.ts @@ -42,7 +42,7 @@ export const Function = (() => { }; } - public constructor (...args: string[]) { + public constructor () { const parts = ["(function anonymous("]; for (let i = 0; i < arguments.length - 1; i++) { if (i > 0) parts[parts.length] = ","; diff --git a/src/lib/libs/map.ts b/src/lib/libs/map.ts index 7a6a929..82d112b 100644 --- a/src/lib/libs/map.ts +++ b/src/lib/libs/map.ts @@ -1,5 +1,5 @@ import { Array } from "./array.ts"; -import { func, map, object, symbol } from "./primordials.ts"; +import { func, map, symbol } from "./primordials.ts"; import { symbols } from "./utils.ts"; const mapKey: unique symbol = symbol.makeSymbol("Map.impl") as any; diff --git a/src/lib/libs/math.ts b/src/lib/libs/math.ts index c7b2ad5..e548c7a 100644 --- a/src/lib/libs/math.ts +++ b/src/lib/libs/math.ts @@ -41,6 +41,16 @@ method("floor", function floor(val: number) { return val - rem; }); +method("ceil", function floor(val: number) { + val = val - 0; + if (number.isNaN(val)) return number.NaN; + + let rem = val % 1; + if (rem === 0) return val; + if (rem < 0) rem += 1; + + return val + (1 - rem); +}); method("pow", function pow(a: number, b: number) { return number.pow(a, b); diff --git a/src/lib/libs/number.ts b/src/lib/libs/number.ts index 00fe148..3cbf434 100644 --- a/src/lib/libs/number.ts +++ b/src/lib/libs/number.ts @@ -23,7 +23,7 @@ export const Number = (() => { public static isFinite(value: number) { value = unwrapThis(value, "number", Number, "Number.isFinite", "value"); if (value === undefined || value !== value) return false; - if (value === Infinity || value === -Infinity) return false; + if (value === number.Infinity || value === -number.Infinity) return false; return true; } public static isInteger(value: number) { @@ -51,14 +51,14 @@ export const Number = (() => { else return number.parseInt(value + "", radix); } - public static readonly EPSILON: number; - public static readonly MIN_SAFE_INTEGER: number; - public static readonly MAX_SAFE_INTEGER: number; - public static readonly POSITIVE_INFINITY: number; - public static readonly NEGATIVE_INFINITY: number; - public static readonly NaN: number; - public static readonly MAX_VALUE: number; - public static readonly MIN_VALUE: number; + declare public static readonly EPSILON: number; + declare public static readonly MIN_SAFE_INTEGER: number; + declare public static readonly MAX_SAFE_INTEGER: number; + declare public static readonly POSITIVE_INFINITY: number; + declare public static readonly NEGATIVE_INFINITY: number; + declare public static readonly NaN: number; + declare public static readonly MAX_VALUE: number; + declare public static readonly MIN_VALUE: number; } object.defineField(Number, "EPSILON", { c: false, e: false, w: false, v: 2.220446049250313e-16 }); diff --git a/src/lib/libs/object.ts b/src/lib/libs/object.ts index eb17d94..b08bac4 100644 --- a/src/lib/libs/object.ts +++ b/src/lib/libs/object.ts @@ -12,7 +12,7 @@ export const Object = (() => { if (this === undefined) return "[object Undefined]"; else if (this === null) return "[object Null]"; else if (typeof this === "object") { - if (symbols.toStringTag in this) return "[object " + this[symbols.toStringTag] + "]"; + if (symbols.toStringTag in this) return "[object " + (this as any)[symbols.toStringTag] + "]"; else return "[object Object]"; } else if (typeof this === "number" || this instanceof Object) return "[object Object]"; @@ -84,8 +84,8 @@ export const Object = (() => { return obj; } public static defineProperties(obj: object, desc: PropertyDescriptorMap) { - const keys = object.getOwnMembers(desc, false); - const symbols = object.getOwnSymbolMembers(desc, false); + const keys = object.getOwnMembers(desc, false) as ((keyof typeof obj) & string)[]; + const symbols = object.getOwnSymbolMembers(desc, false) as ((keyof typeof obj) & symbol)[]; for (let i = 0; i < keys.length; i++) { Object.defineProperty(obj, keys[i], desc[keys[i]]); diff --git a/src/lib/libs/regex.ts b/src/lib/libs/regex.ts index 95c6a4a..96b17c7 100644 --- a/src/lib/libs/regex.ts +++ b/src/lib/libs/regex.ts @@ -1,6 +1,6 @@ import { func, regex, symbol } from "./primordials.ts"; import { String } from "./string.ts"; -import { ReplaceRange } from "./utils.ts"; +import { type ReplaceRange } from "./utils.ts"; import { applyReplaces } from "./utils.ts"; import { applySplits } from "./utils.ts"; import { symbols } from "./utils.ts"; @@ -8,22 +8,24 @@ import { symbols } from "./utils.ts"; const regexKey: unique symbol = symbol.makeSymbol("RegExp.impl") as any; export class RegExp { - private [regexKey]: InstanceType; + private [regexKey]!: InstanceType; - public readonly source: string; - public readonly flags: string; + public readonly source!: string; + public readonly flags!: string; public lastIndex = 0; - public readonly indices: boolean; - public readonly global: boolean; - public readonly ignoreCase: boolean; - public readonly multiline: boolean; - public readonly dotall: boolean; - public readonly unicode: boolean; - public readonly unicodeSets: boolean; - public readonly sticky: boolean; + public readonly indices!: boolean; + public readonly global!: boolean; + public readonly ignoreCase!: boolean; + public readonly multiline!: boolean; + public readonly dotall!: boolean; + public readonly unicode!: boolean; + public readonly unicodeSets!: boolean; + public readonly sticky!: boolean; + + public constructor(source: any, flags = "") { + if (func.invokeType(arguments, this) === "call") return new RegExp(source, flags); - public constructor(source: any, flags: string) { source = this.source = String(typeof source === "object" && "source" in source ? source.source : source); flags = String(flags); @@ -134,4 +136,3 @@ export class RegExp { return applyReplaces(target, matches, replacer, regex.groupCount() + 1); } } -func.setCallable(RegExp, false); diff --git a/src/lib/libs/string.ts b/src/lib/libs/string.ts index a2ea97b..9477401 100644 --- a/src/lib/libs/string.ts +++ b/src/lib/libs/string.ts @@ -1,6 +1,7 @@ +import { TypeError } from "./errors.ts"; import { func, number, regex, string } from "./primordials.ts"; import { RegExp } from "./regex.ts"; -import { applyReplaces, applySplits, limitI, ReplaceRange, symbols, unwrapThis, valueKey, wrapI } from "./utils.ts"; +import { applyReplaces, applySplits, limitI, type ReplaceRange, symbols, unwrapThis, valueKey, wrapI } from "./utils.ts"; const trimStartRegex = new regex("^\\s+", false, false, false, false, false); const trimEndRegex = new regex("\\s+$", false, false, false, false, false); @@ -12,7 +13,7 @@ export const String = (() => { public at(index: number) { throw "Not implemented :/"; return unwrapThis(this, "string", String, "String.prototype.at")[index]; - }; + } public toString() { return unwrapThis(this, "string", String, "String.prototype.toString"); } @@ -24,6 +25,16 @@ export const String = (() => { const self = unwrapThis(this, "string", String, "String.prototype.indexOf"); return string.indexOf(self, (String as any)(search), +offset, false) >= 0; } + public startsWith(search: string) { + const self = unwrapThis(this, "string", String, "String.prototype.indexOf"); + if (self.length < search.length) return false; + return string.substring(self, 0, search.length) === search; + } + public endsWith(search: string) { + const self = unwrapThis(this, "string", String, "String.prototype.indexOf"); + if (self.length < search.length) return false; + return string.substring(self, self.length - search.length, self.length) === search; + } public indexOf(search: string, offset = 0) { const self = unwrapThis(this, "string", String, "String.prototype.indexOf"); @@ -123,10 +134,11 @@ export const String = (() => { return applyReplaces(self, matches, replacer, false); } - public slice(this: string, start = 0, end = this.length) { + public slice(start = 0, end?: number) { const self = unwrapThis(this, "string", String, "String.prototype.slice"); - start = limitI(wrapI(start, this.length), this.length); - end = limitI(wrapI(end, this.length), this.length); + if (end === undefined) end = self.length; + start = limitI(wrapI(start, self.length), self.length); + end = limitI(wrapI(end, self.length), self.length); if (end <= start) return ""; return string.substring(self, start, end); diff --git a/src/lib/libs/utils.ts b/src/lib/libs/utils.ts index e769b75..bdd1964 100644 --- a/src/lib/libs/utils.ts +++ b/src/lib/libs/utils.ts @@ -195,12 +195,12 @@ export function applySplits(text: string, limit: number | undefined, next: (offs const res: string[] = []; while (true) { - if (limit != null && res.length >= limit) break; + if (limit != null && limit >= 0 && res.length >= limit) break; const curr = next(offset); if (curr == null) { - if (!lastEmpty) res[res.length] = string.substring(text, lastEnd, text.length); + if (!lastEmpty || !res.length) res[res.length] = string.substring(text, lastEnd, text.length); break; }