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 { Math as _Math } from "./math.ts";
|
||||
import { Set, WeakSet } from "./set.ts";
|
||||
import { JSON } from "./json.ts";
|
||||
import { encodeURI, encodeURIComponent } from "./url.ts";
|
||||
|
||||
declare global {
|
||||
function print(...args: any[]): void;
|
||||
@ -47,12 +49,14 @@ target.WeakSet = fixup(WeakSet);
|
||||
target.RegExp = fixup(RegExp);
|
||||
target.Date = fixup(Date);
|
||||
target.Math = object.setPrototype(_Math, Object.prototype);
|
||||
target.JSON = object.setPrototype(JSON, Object.prototype);
|
||||
|
||||
target.parseInt = Number.parseInt;
|
||||
target.parseFloat = Number.parseFloat;
|
||||
target.NaN = Number.NaN;
|
||||
target.Infinity = Number.POSITIVE_INFINITY;
|
||||
|
||||
target.encodeURI = encodeURI;
|
||||
target.encodeURIComponent = encodeURIComponent;
|
||||
|
||||
setGlobalPrototypes({
|
||||
string: String.prototype,
|
||||
|
@ -26,6 +26,7 @@ export const Array = (() => {
|
||||
|
||||
return string.stringBuild(parts);
|
||||
}
|
||||
|
||||
public push(this: any[]) {
|
||||
const start = this.length;
|
||||
for (let i = arguments.length - 1; i >= 0; i--) {
|
||||
@ -33,6 +34,38 @@ export const Array = (() => {
|
||||
}
|
||||
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[]) {
|
||||
const res: any[] = [];
|
||||
|
||||
@ -71,7 +104,10 @@ export const Array = (() => {
|
||||
|
||||
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);
|
||||
count = limitI(wrapI(count, this.length), this.length - start);
|
||||
|
||||
@ -105,7 +141,7 @@ export const Array = (() => {
|
||||
const res = [];
|
||||
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]);
|
||||
}
|
||||
|
||||
@ -114,35 +150,58 @@ export const Array = (() => {
|
||||
public filter(this: any[], cb: Function, self?: any) {
|
||||
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];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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[]) {
|
||||
let i = 0;
|
||||
let arr: any[] | undefined = this;
|
||||
let arr: any[] | undefined = func.invoke(Array.prototype.slice, this, []);
|
||||
|
||||
return {
|
||||
next() {
|
||||
if (arr == null) return { done: true, value: undefined };
|
||||
|
||||
if (i >= arr.length) {
|
||||
arr = undefined;
|
||||
return { done: true, value: undefined };
|
||||
}
|
||||
else {
|
||||
const val = arr[i++];
|
||||
if (i >= arr.length) arr = undefined;
|
||||
return { done: false, value: val };
|
||||
|
||||
while (true) {
|
||||
const res = arr![i];
|
||||
|
||||
if (i in arr!) {
|
||||
i++;
|
||||
return { done: false, value: res };
|
||||
}
|
||||
else i++;
|
||||
}
|
||||
},
|
||||
[symbols.iterator]() { return this; }
|
||||
@ -155,8 +214,14 @@ export const Array = (() => {
|
||||
res.length = len;
|
||||
return res as any;
|
||||
}
|
||||
// TODO: Implement spreading
|
||||
else throw new Error("Spreading not implemented");
|
||||
else {
|
||||
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[] {
|
||||
|
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> {
|
||||
private [mapKey]: InstanceType<typeof map>;
|
||||
|
||||
public get size() {
|
||||
return this[mapKey].size();
|
||||
}
|
||||
|
||||
public get(key: K): V {
|
||||
return this[mapKey].get(key);
|
||||
}
|
||||
|
@ -16,6 +16,22 @@ method("max", function max() {
|
||||
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) {
|
||||
val = val - 0;
|
||||
if (number.isNaN(val)) return number.NaN;
|
||||
@ -25,3 +41,7 @@ method("floor", function floor(val: number) {
|
||||
|
||||
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;
|
||||
NaN: number;
|
||||
Infinity: number;
|
||||
|
||||
pow(a: number, b: number): number;
|
||||
}
|
||||
export interface StringPrimordials {
|
||||
stringBuild(parts: string[]): string;
|
||||
@ -37,6 +39,7 @@ export interface ObjectPrimordials {
|
||||
freeze(obj: object): void;
|
||||
|
||||
memcpy(src: any[], dst: any[], srcI: number, dstI: number, n: number): void;
|
||||
sort(arr: any[], cb: Function): any[];
|
||||
}
|
||||
export interface FunctionPrimordials {
|
||||
invokeType(args: IArguments, self: any): "new" | "call";
|
||||
@ -66,9 +69,10 @@ export interface Primordials {
|
||||
delete(key: any): void;
|
||||
keys(): any[];
|
||||
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;
|
||||
groupCount(): number;
|
||||
};
|
||||
@ -94,3 +98,5 @@ export const {
|
||||
compile,
|
||||
now,
|
||||
} = 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> {
|
||||
private [mapKey]: InstanceType<typeof map>;
|
||||
|
||||
public get size() {
|
||||
return this[mapKey].size();
|
||||
}
|
||||
|
||||
public has(key: T): boolean {
|
||||
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 { 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 = (() => {
|
||||
class String {
|
||||
[valueKey]!: string;
|
||||
@ -33,6 +36,31 @@ export const String = (() => {
|
||||
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) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.charAt");
|
||||
return self[i];
|
||||
@ -43,7 +71,7 @@ export const String = (() => {
|
||||
}
|
||||
public codePointAt(i: number) {
|
||||
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) {
|
||||
@ -159,7 +187,7 @@ export const String = (() => {
|
||||
this[valueKey] = (String as any)(value);
|
||||
}
|
||||
|
||||
public static fromCharCode(...args: number[]) {
|
||||
public static fromCharCode() {
|
||||
const res: string[] = [];
|
||||
res[arguments.length] = "";
|
||||
|
||||
@ -169,7 +197,7 @@ export const String = (() => {
|
||||
|
||||
return string.stringBuild(res);
|
||||
}
|
||||
public static fromCodePoint(...args: number[]) {
|
||||
public static fromCodePoint() {
|
||||
const res: string[] = [];
|
||||
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