feat: implement a lot of built-ins
This commit is contained in:
parent
c18015b9a0
commit
c7c31c3859
@ -12,6 +12,8 @@ import { RegExp } from "./regex.ts";
|
|||||||
import { Date } from "./date.ts";
|
import { Date } from "./date.ts";
|
||||||
import { Math as _Math } from "./math.ts";
|
import { Math as _Math } from "./math.ts";
|
||||||
import { Set, WeakSet } from "./set.ts";
|
import { Set, WeakSet } from "./set.ts";
|
||||||
|
import { JSON } from "./json.ts";
|
||||||
|
import { encodeURI, encodeURIComponent } from "./url.ts";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
function print(...args: any[]): void;
|
function print(...args: any[]): void;
|
||||||
@ -47,12 +49,14 @@ target.WeakSet = fixup(WeakSet);
|
|||||||
target.RegExp = fixup(RegExp);
|
target.RegExp = fixup(RegExp);
|
||||||
target.Date = fixup(Date);
|
target.Date = fixup(Date);
|
||||||
target.Math = object.setPrototype(_Math, Object.prototype);
|
target.Math = object.setPrototype(_Math, Object.prototype);
|
||||||
|
target.JSON = object.setPrototype(JSON, Object.prototype);
|
||||||
|
|
||||||
target.parseInt = Number.parseInt;
|
target.parseInt = Number.parseInt;
|
||||||
target.parseFloat = Number.parseFloat;
|
target.parseFloat = Number.parseFloat;
|
||||||
target.NaN = Number.NaN;
|
target.NaN = Number.NaN;
|
||||||
target.Infinity = Number.POSITIVE_INFINITY;
|
target.Infinity = Number.POSITIVE_INFINITY;
|
||||||
|
target.encodeURI = encodeURI;
|
||||||
|
target.encodeURIComponent = encodeURIComponent;
|
||||||
|
|
||||||
setGlobalPrototypes({
|
setGlobalPrototypes({
|
||||||
string: String.prototype,
|
string: String.prototype,
|
||||||
|
@ -26,6 +26,7 @@ export const Array = (() => {
|
|||||||
|
|
||||||
return string.stringBuild(parts);
|
return string.stringBuild(parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public push(this: any[]) {
|
public push(this: any[]) {
|
||||||
const start = this.length;
|
const start = this.length;
|
||||||
for (let i = arguments.length - 1; i >= 0; i--) {
|
for (let i = arguments.length - 1; i >= 0; i--) {
|
||||||
@ -33,6 +34,38 @@ export const Array = (() => {
|
|||||||
}
|
}
|
||||||
return arguments.length;
|
return arguments.length;
|
||||||
}
|
}
|
||||||
|
public pop(this: any[]) {
|
||||||
|
if (this.length === 0) return undefined;
|
||||||
|
else {
|
||||||
|
const res = this[this.length - 1];
|
||||||
|
this.length--;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public unshift(this: any[]) {
|
||||||
|
for (let i = this.length + arguments.length - 1; i >= arguments.length; i--) {
|
||||||
|
this[i] = this[i - arguments.length];
|
||||||
|
}
|
||||||
|
for (let i = 0; i < arguments.length; i++) {
|
||||||
|
this[i] = arguments[i];
|
||||||
|
}
|
||||||
|
return arguments.length;
|
||||||
|
}
|
||||||
|
public shift(this: any[]) {
|
||||||
|
if (this.length === 0) return undefined;
|
||||||
|
|
||||||
|
const tmp = this[0];
|
||||||
|
|
||||||
|
for (let i = 1; i < this.length; i++) {
|
||||||
|
this[i - 1] = this[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.length--;
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
public concat(this: any[]) {
|
public concat(this: any[]) {
|
||||||
const res: any[] = [];
|
const res: any[] = [];
|
||||||
|
|
||||||
@ -71,7 +104,10 @@ export const Array = (() => {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public splice(this: any[], start = 0, count = this.length - start, ...vals: any[]) {
|
public splice(this: any[], start = 0, count = this.length - start) {
|
||||||
|
const vals: any[] = []
|
||||||
|
for (let i = 0; i < arguments.length - 2; i++) vals[i] = arguments[i + 2];
|
||||||
|
|
||||||
start = limitI(wrapI(start, this.length), this.length);
|
start = limitI(wrapI(start, this.length), this.length);
|
||||||
count = limitI(wrapI(count, this.length), this.length - start);
|
count = limitI(wrapI(count, this.length), this.length - start);
|
||||||
|
|
||||||
@ -105,7 +141,7 @@ export const Array = (() => {
|
|||||||
const res = [];
|
const res = [];
|
||||||
res.length = this.length;
|
res.length = this.length;
|
||||||
|
|
||||||
for (let i = 0; i < arguments.length; i++) {
|
for (let i = 0; i < this.length; i++) {
|
||||||
if (i in this) res[i] = func.invoke(cb, self, [this[i], i, this]);
|
if (i in this) res[i] = func.invoke(cb, self, [this[i], i, this]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,35 +150,58 @@ export const Array = (() => {
|
|||||||
public filter(this: any[], cb: Function, self?: any) {
|
public filter(this: any[], cb: Function, self?: any) {
|
||||||
const res = [];
|
const res = [];
|
||||||
|
|
||||||
for (let i = 0; i < arguments.length; i++) {
|
for (let i = 0; i < this.length; i++) {
|
||||||
if (i in this && func.invoke(cb, self, [this[i], i, this])) res[res.length] = this[i];
|
if (i in this && func.invoke(cb, self, [this[i], i, this])) res[res.length] = this[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public some(this: any[], cb: Function, self?: any) {
|
public some(this: any[], cb: Function, self?: any) {
|
||||||
for (let i = 0; i < arguments.length; i++) {
|
for (let i = 0; i < this.length; i++) {
|
||||||
if (i in this && func.invoke(cb, self, [this[i], i, this])) return true;
|
if (i in this && func.invoke(cb, self, [this[i], i, this])) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sort(this: any[], cb?: Function) {
|
||||||
|
cb ||= (a: any, b: any) => {
|
||||||
|
if (String(a) < String(b)) return -1;
|
||||||
|
if (String(a) === String(b)) return 0;
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
return object.sort(this, cb);
|
||||||
|
}
|
||||||
|
|
||||||
public [symbols.iterator](this: any[]) {
|
public [symbols.iterator](this: any[]) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let arr: any[] | undefined = this;
|
let arr: any[] | undefined = func.invoke(Array.prototype.slice, this, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
next() {
|
next() {
|
||||||
if (arr == null) return { done: true, value: undefined };
|
if (arr == null) return { done: true, value: undefined };
|
||||||
|
|
||||||
if (i >= arr.length) {
|
if (i >= arr.length) {
|
||||||
arr = undefined;
|
arr = undefined;
|
||||||
return { done: true, value: undefined };
|
return { done: true, value: undefined };
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
const val = arr[i++];
|
while (true) {
|
||||||
if (i >= arr.length) arr = undefined;
|
const res = arr![i];
|
||||||
return { done: false, value: val };
|
|
||||||
|
if (i in arr!) {
|
||||||
|
i++;
|
||||||
|
return { done: false, value: res };
|
||||||
|
}
|
||||||
|
else i++;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[symbols.iterator]() { return this; }
|
[symbols.iterator]() { return this; }
|
||||||
@ -155,8 +214,14 @@ export const Array = (() => {
|
|||||||
res.length = len;
|
res.length = len;
|
||||||
return res as any;
|
return res as any;
|
||||||
}
|
}
|
||||||
// TODO: Implement spreading
|
else {
|
||||||
else throw new Error("Spreading not implemented");
|
const res: any[] = [];
|
||||||
|
res.length = arguments.length;
|
||||||
|
for (let i = 0; i < arguments.length; i++) {
|
||||||
|
res[i] = arguments[i];
|
||||||
|
}
|
||||||
|
return res as any;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static isArray(val: any): val is any[] {
|
public static isArray(val: any): val is any[] {
|
||||||
|
15
src/lib/libs/json.ts
Normal file
15
src/lib/libs/json.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { json, object } from "./primordials";
|
||||||
|
|
||||||
|
export const JSON = {};
|
||||||
|
|
||||||
|
function method(name: string, func: Function) {
|
||||||
|
object.defineField(JSON, name, { c: true, e: false, w: true, v: func });
|
||||||
|
}
|
||||||
|
|
||||||
|
method("parse", function parse(val: string) {
|
||||||
|
return json.parse(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
method("stringify", function stringify(val: string) {
|
||||||
|
return json.stringify(val);
|
||||||
|
});
|
@ -7,6 +7,10 @@ const mapKey: unique symbol = symbol.makeSymbol("Map.impl") as any;
|
|||||||
export class Map<K, V> {
|
export class Map<K, V> {
|
||||||
private [mapKey]: InstanceType<typeof map>;
|
private [mapKey]: InstanceType<typeof map>;
|
||||||
|
|
||||||
|
public get size() {
|
||||||
|
return this[mapKey].size();
|
||||||
|
}
|
||||||
|
|
||||||
public get(key: K): V {
|
public get(key: K): V {
|
||||||
return this[mapKey].get(key);
|
return this[mapKey].get(key);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,22 @@ method("max", function max() {
|
|||||||
return res;
|
return res;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
method("min", function min() {
|
||||||
|
let res = +number.Infinity;
|
||||||
|
|
||||||
|
for (let i = 0; i < arguments.length; i++) {
|
||||||
|
if (res > arguments[i]) res = arguments[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
|
||||||
|
method("abs", function abs(val: number) {
|
||||||
|
val = +val;
|
||||||
|
if (val < 0) return -val;
|
||||||
|
else return val;
|
||||||
|
});
|
||||||
|
|
||||||
method("floor", function floor(val: number) {
|
method("floor", function floor(val: number) {
|
||||||
val = val - 0;
|
val = val - 0;
|
||||||
if (number.isNaN(val)) return number.NaN;
|
if (number.isNaN(val)) return number.NaN;
|
||||||
@ -25,3 +41,7 @@ method("floor", function floor(val: number) {
|
|||||||
|
|
||||||
return val - rem;
|
return val - rem;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
method("pow", function pow(a: number, b: number) {
|
||||||
|
return number.pow(a, b);
|
||||||
|
});
|
||||||
|
@ -10,6 +10,8 @@ export interface NumberPrimordials {
|
|||||||
isNaN(num: number): boolean;
|
isNaN(num: number): boolean;
|
||||||
NaN: number;
|
NaN: number;
|
||||||
Infinity: number;
|
Infinity: number;
|
||||||
|
|
||||||
|
pow(a: number, b: number): number;
|
||||||
}
|
}
|
||||||
export interface StringPrimordials {
|
export interface StringPrimordials {
|
||||||
stringBuild(parts: string[]): string;
|
stringBuild(parts: string[]): string;
|
||||||
@ -37,6 +39,7 @@ export interface ObjectPrimordials {
|
|||||||
freeze(obj: object): void;
|
freeze(obj: object): void;
|
||||||
|
|
||||||
memcpy(src: any[], dst: any[], srcI: number, dstI: number, n: number): void;
|
memcpy(src: any[], dst: any[], srcI: number, dstI: number, n: number): void;
|
||||||
|
sort(arr: any[], cb: Function): any[];
|
||||||
}
|
}
|
||||||
export interface FunctionPrimordials {
|
export interface FunctionPrimordials {
|
||||||
invokeType(args: IArguments, self: any): "new" | "call";
|
invokeType(args: IArguments, self: any): "new" | "call";
|
||||||
@ -66,9 +69,10 @@ export interface Primordials {
|
|||||||
delete(key: any): void;
|
delete(key: any): void;
|
||||||
keys(): any[];
|
keys(): any[];
|
||||||
clear(): void;
|
clear(): void;
|
||||||
|
size(): number;
|
||||||
};
|
};
|
||||||
|
|
||||||
regex: new (source: string, multiline: boolean, noCase: boolean, dotall: boolean, unicode: boolean, unicodeClass: boolean) => {
|
regex: new (source: string, multiline?: boolean, noCase?: boolean, dotall?: boolean, unicode?: boolean, unicodeClass?: boolean) => {
|
||||||
exec(target: string, offset: number, indices: boolean): { matches: RegExpMatchArray, end: number } | null;
|
exec(target: string, offset: number, indices: boolean): { matches: RegExpMatchArray, end: number } | null;
|
||||||
groupCount(): number;
|
groupCount(): number;
|
||||||
};
|
};
|
||||||
@ -94,3 +98,5 @@ export const {
|
|||||||
compile,
|
compile,
|
||||||
now,
|
now,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
|
||||||
|
export type regex = InstanceType<typeof regex>;
|
@ -7,6 +7,10 @@ const mapKey: unique symbol = symbol.makeSymbol("Set.impl") as any;
|
|||||||
export class Set<T> {
|
export class Set<T> {
|
||||||
private [mapKey]: InstanceType<typeof map>;
|
private [mapKey]: InstanceType<typeof map>;
|
||||||
|
|
||||||
|
public get size() {
|
||||||
|
return this[mapKey].size();
|
||||||
|
}
|
||||||
|
|
||||||
public has(key: T): boolean {
|
public has(key: T): boolean {
|
||||||
return this[mapKey].has(key);
|
return this[mapKey].has(key);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import { func, number, string } from "./primordials.ts";
|
import { func, number, regex, string } from "./primordials.ts";
|
||||||
import { RegExp } from "./regex.ts";
|
import { RegExp } from "./regex.ts";
|
||||||
import { applyReplaces, applySplits, limitI, ReplaceRange, symbols, unwrapThis, valueKey, wrapI } from "./utils.ts";
|
import { applyReplaces, applySplits, limitI, 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);
|
||||||
|
|
||||||
export const String = (() => {
|
export const String = (() => {
|
||||||
class String {
|
class String {
|
||||||
[valueKey]!: string;
|
[valueKey]!: string;
|
||||||
@ -33,6 +36,31 @@ export const String = (() => {
|
|||||||
return string.indexOf(self, search, offset, true);
|
return string.indexOf(self, search, offset, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public trim() {
|
||||||
|
const self = unwrapThis(this, "string", String, "String.prototype.trim");
|
||||||
|
const start = trimStartRegex.exec(self, 0, false);
|
||||||
|
const end = trimEndRegex.exec(self, 0, false);
|
||||||
|
|
||||||
|
const startI = start == null ? 0 : start.end;
|
||||||
|
const endI = end == null ? self.length : end.matches.index!;
|
||||||
|
|
||||||
|
return string.substring(self, startI, endI);
|
||||||
|
}
|
||||||
|
public trimStart() {
|
||||||
|
const self = unwrapThis(this, "string", String, "String.prototype.trim");
|
||||||
|
const start = trimStartRegex.exec(self, 0, false);
|
||||||
|
const startI = start == null ? 0 : start.end;
|
||||||
|
|
||||||
|
return string.substring(self, startI, self.length);
|
||||||
|
}
|
||||||
|
public trimEnd() {
|
||||||
|
const self = unwrapThis(this, "string", String, "String.prototype.trim");
|
||||||
|
const end = trimEndRegex.exec(self, 0, false);
|
||||||
|
const endI = end == null ? self.length : end.matches.index!;
|
||||||
|
|
||||||
|
return string.substring(self, 0, endI);
|
||||||
|
}
|
||||||
|
|
||||||
public charAt(i: number) {
|
public charAt(i: number) {
|
||||||
const self = unwrapThis(this, "string", String, "String.prototype.charAt");
|
const self = unwrapThis(this, "string", String, "String.prototype.charAt");
|
||||||
return self[i];
|
return self[i];
|
||||||
@ -43,7 +71,7 @@ export const String = (() => {
|
|||||||
}
|
}
|
||||||
public codePointAt(i: number) {
|
public codePointAt(i: number) {
|
||||||
const self = unwrapThis(this, "string", String, "String.prototype.charCodeAt");
|
const self = unwrapThis(this, "string", String, "String.prototype.charCodeAt");
|
||||||
return i > 0 && i <= self.length ? string.toCodePoint(self, i) : number.NaN;
|
return i >= 0 && i < self.length ? string.toCodePoint(self, i) : number.NaN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public split(val?: any, limit?: number) {
|
public split(val?: any, limit?: number) {
|
||||||
@ -159,7 +187,7 @@ export const String = (() => {
|
|||||||
this[valueKey] = (String as any)(value);
|
this[valueKey] = (String as any)(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromCharCode(...args: number[]) {
|
public static fromCharCode() {
|
||||||
const res: string[] = [];
|
const res: string[] = [];
|
||||||
res[arguments.length] = "";
|
res[arguments.length] = "";
|
||||||
|
|
||||||
@ -169,7 +197,7 @@ export const String = (() => {
|
|||||||
|
|
||||||
return string.stringBuild(res);
|
return string.stringBuild(res);
|
||||||
}
|
}
|
||||||
public static fromCodePoint(...args: number[]) {
|
public static fromCodePoint() {
|
||||||
const res: string[] = [];
|
const res: string[] = [];
|
||||||
res[arguments.length] = "";
|
res[arguments.length] = "";
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
function split(val, limit) {
|
|
||||||
var self = unwrapThis(this, "string", String, "String.prototype.split");
|
|
||||||
if (val === undefined) return [self];
|
|
||||||
if (val !== null && typeof val === "object" && Symbol.split in val) {
|
|
||||||
return val[Symbol.split](self, limit);
|
|
||||||
}
|
|
||||||
val = String(val);
|
|
||||||
var offset = 0;
|
|
||||||
var res = [];
|
|
||||||
while (true) {
|
|
||||||
var start = string.indexOf(self, val, offset, false);
|
|
||||||
if (start < 0) {
|
|
||||||
res[res.length] = string.substring(self, offset, self.length);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var end = start + val.length;
|
|
||||||
res[res.length] = string.substring(self, offset, start);
|
|
||||||
offset = end;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
split(print(), print());
|
|
26
src/lib/libs/url.ts
Normal file
26
src/lib/libs/url.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { regex, string } from "./primordials";
|
||||||
|
|
||||||
|
function escaper(matcher: regex) {
|
||||||
|
return (text: string) => {
|
||||||
|
const parts: string[] = [];
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const match = matcher.exec(text, i, false);
|
||||||
|
if (match == null) break;
|
||||||
|
|
||||||
|
const char = match.matches[0];
|
||||||
|
const code = string.toCharCode(char);
|
||||||
|
parts[parts.length] = string.substring(text, i, match.matches.index!);
|
||||||
|
parts[parts.length] = "%" + code;
|
||||||
|
i = match.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
parts[parts.length] = string.substring(text, i, text.length);
|
||||||
|
|
||||||
|
return string.stringBuild(parts);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const encodeURI = escaper(new regex("[^A-Za-z0-9\\-+.!~*'()]"));
|
||||||
|
export const encodeURIComponent = escaper(new regex("[^A-Za-z0-9\\-+.!~*'();/?:@&=+$,#]"));
|
Loading…
Reference in New Issue
Block a user