build: split up into multiple projects, use kotlin DLS
All checks were successful
tagged-release / Tagged Release (push) Successful in 5m23s
All checks were successful
tagged-release / Tagged Release (push) Successful in 5m23s
This commit is contained in:
68
lib/build.gradle.kts
Normal file
68
lib/build.gradle.kts
Normal file
@@ -0,0 +1,68 @@
|
||||
import com.github.gradle.node.npm.task.NpmTask;
|
||||
|
||||
plugins {
|
||||
id("common");
|
||||
id("com.github.node-gradle.node") version "5.0.0";
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
enabled = false;
|
||||
}
|
||||
tasks.classes {
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
node {
|
||||
version = "20.0.0";
|
||||
npmVersion = "8.0.0";
|
||||
download = true;
|
||||
}
|
||||
|
||||
tasks.register<NpmTask>("compileStdlib") {
|
||||
dependsOn("npmInstall");
|
||||
|
||||
inputs.files("rollup.config.js");
|
||||
inputs.dir("src/stdlib");
|
||||
outputs.files("build/js/stdlib.js");
|
||||
|
||||
args.set(listOf("run", "build-env"));
|
||||
}
|
||||
tasks.register<NpmTask>("compileTranspiler") {
|
||||
dependsOn("npmInstall");
|
||||
|
||||
inputs.files("rollup.config.js");
|
||||
inputs.dir("src/transpiler");
|
||||
outputs.files("build/js/transpiler.js");
|
||||
// nom nom tasty ram
|
||||
environment.put("NODE_OPTIONS", "--max-old-space-size=4096");
|
||||
|
||||
args.set(listOf("run", "build-ts"));
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
manifest {
|
||||
attributes(
|
||||
"Main-Class" to properties["main_class"].toString(),
|
||||
"Build-Author" to "TopchetoEU",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
dependsOn("compileStdlib");
|
||||
dependsOn("compileTranspiler");
|
||||
|
||||
from("build/js") {
|
||||
into("lib");
|
||||
}
|
||||
from("src/lib") {
|
||||
into("lib");
|
||||
}
|
||||
|
||||
filesMatching("metadata.json", {
|
||||
expand(
|
||||
"version" to properties["project_version"].toString(),
|
||||
"name" to properties["project_name"].toString(),
|
||||
);
|
||||
})
|
||||
}
|
||||
31
lib/package.json
Normal file
31
lib/package.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"scripts": {
|
||||
"build-env": "rollup -c --environment INPUT:src/stdlib/_entry.ts,OUTPUT:build/js/stdlib.js,POLYFILLS:src/polyfills",
|
||||
"build-ts": "rollup -c --environment INPUT:src/transpiler/_entry.ts,OUTPUT:build/js/transpiler.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@babel/standalone": "^7.26.4",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@types/babel__preset-env": "^7.9.7",
|
||||
"@types/babel__standalone": "^7.1.9",
|
||||
"@types/coffeescript": "^2.5.7",
|
||||
"coffeescript": "^2.7.0",
|
||||
"typescript": "^5.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-transform-class-properties": "^7.25.9",
|
||||
"@babel/plugin-transform-runtime": "^7.25.9",
|
||||
"@babel/plugin-transform-typescript": "^7.25.9",
|
||||
"@babel/preset-env": "^7.26.0",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-commonjs": "^28.0.1",
|
||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@rollup/plugin-typescript": "^12.1.1",
|
||||
"@types/node": "^22.10.1",
|
||||
"rollup": "^4.24.0",
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
}
|
||||
131
lib/rollup.config.js
Normal file
131
lib/rollup.config.js
Normal file
@@ -0,0 +1,131 @@
|
||||
const { defineConfig } = require("rollup");
|
||||
const terser = require("@rollup/plugin-terser");
|
||||
const typescript = require("@rollup/plugin-typescript");
|
||||
const babel = require("@rollup/plugin-babel");
|
||||
const commonjs = require("@rollup/plugin-commonjs");
|
||||
const nodeResolve = require("@rollup/plugin-node-resolve");
|
||||
const json = require("@rollup/plugin-json");
|
||||
const { resolve } = require("path");
|
||||
|
||||
const shouldMinify = () => true;
|
||||
const shouldEmitSourcemaps = () => true;
|
||||
const shouldPolyfill = () => !!process.env.POLYFILLS;
|
||||
|
||||
const construct = (input, output) => defineConfig({
|
||||
input,
|
||||
plugins: [
|
||||
shouldPolyfill() && {
|
||||
name: "babel-fake-runtime",
|
||||
resolveId(source) {
|
||||
if (source.startsWith("!polyfills:/helpers")) return resolve(process.env.POLYFILLS) + source.slice(19) + ".js";
|
||||
}
|
||||
},
|
||||
commonjs(),
|
||||
nodeResolve(),
|
||||
json(),
|
||||
babel({
|
||||
extensions: [],
|
||||
exclude: ["node_modules/**"],
|
||||
|
||||
babelHelpers: "runtime",
|
||||
plugins: [
|
||||
["@babel/plugin-transform-typescript", {
|
||||
onlyRemoveTypeImports: true,
|
||||
optimizeConstEnums: true,
|
||||
allowDeclareFields: true,
|
||||
}],
|
||||
["@babel/plugin-transform-class-properties"],
|
||||
["@babel/plugin-transform-runtime", {
|
||||
moduleName: shouldPolyfill() ? "!polyfills:" : undefined,
|
||||
version: "^7.24.0",
|
||||
}],
|
||||
]
|
||||
}),
|
||||
babel({
|
||||
extensions: [],
|
||||
exclude: shouldPolyfill() ? [process.env.POLYFILLS + "/**"] : [],
|
||||
|
||||
assumptions: {
|
||||
ignoreToPrimitiveHint: true,
|
||||
noClassCalls: true,
|
||||
},
|
||||
|
||||
env: {
|
||||
development: { compact: false },
|
||||
},
|
||||
|
||||
babelHelpers: "runtime",
|
||||
plugins: [
|
||||
"@babel/plugin-transform-arrow-functions",
|
||||
"@babel/plugin-transform-block-scoping",
|
||||
"@babel/plugin-transform-classes",
|
||||
"@babel/plugin-transform-computed-properties",
|
||||
"@babel/plugin-transform-destructuring",
|
||||
"@babel/plugin-transform-for-of",
|
||||
"@babel/plugin-transform-object-super",
|
||||
"@babel/plugin-transform-parameters",
|
||||
"@babel/plugin-transform-shorthand-properties",
|
||||
"@babel/plugin-transform-spread",
|
||||
"@babel/plugin-transform-object-rest-spread",
|
||||
"@babel/plugin-transform-template-literals",
|
||||
"@babel/plugin-transform-unicode-escapes",
|
||||
"@babel/plugin-transform-unicode-regex",
|
||||
"@babel/plugin-transform-exponentiation-operator",
|
||||
"@babel/plugin-transform-async-to-generator",
|
||||
"@babel/plugin-transform-async-generator-functions",
|
||||
"@babel/plugin-transform-nullish-coalescing-operator",
|
||||
"@babel/plugin-transform-optional-chaining",
|
||||
"@babel/plugin-transform-logical-assignment-operators",
|
||||
"@babel/plugin-transform-numeric-separator",
|
||||
"@babel/plugin-transform-class-properties",
|
||||
"@babel/plugin-transform-class-static-block",
|
||||
"@babel/plugin-transform-regenerator",
|
||||
|
||||
["@babel/plugin-transform-runtime", {
|
||||
moduleName: shouldPolyfill() ? "!polyfills:" : undefined,
|
||||
version: "^7.24.0",
|
||||
}],
|
||||
],
|
||||
}),
|
||||
typescript({
|
||||
exclude: ["node_modules/**", "*.js"],
|
||||
compilerOptions: {
|
||||
allowImportingTsExtensions: true,
|
||||
noEmit: true,
|
||||
},
|
||||
noForceEmit: true,
|
||||
noEmitOnError: true,
|
||||
}),
|
||||
shouldMinify() && terser({
|
||||
sourceMap: shouldEmitSourcemaps(),
|
||||
keep_classnames: true,
|
||||
keep_fnames: true,
|
||||
}),
|
||||
],
|
||||
output: {
|
||||
file: output,
|
||||
format: "iife",
|
||||
globals: {
|
||||
fs: "null",
|
||||
path: "null",
|
||||
os: "null",
|
||||
inspector: "null",
|
||||
tty: "null",
|
||||
util: "null",
|
||||
assert: "null",
|
||||
url: "null",
|
||||
"@babel/preset-typescript/package.json": "null",
|
||||
module: "null",
|
||||
process: "null",
|
||||
v8: "null",
|
||||
},
|
||||
// plugins: [babel.getBabelOutputPlugin({
|
||||
// allowAllFormats: true,
|
||||
// })],
|
||||
|
||||
sourcemap: shouldEmitSourcemaps(),
|
||||
inlineDynamicImports: true,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = construct(process.env.INPUT, process.env.OUTPUT);
|
||||
24
lib/src/lib/async.d.ts
vendored
Normal file
24
lib/src/lib/async.d.ts
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
declare type Timer = number;
|
||||
|
||||
declare function setTimeout(func: () => void, time: number): Timer;
|
||||
declare function setTimer(func: () => void, time: number): Timer;
|
||||
declare function setImmediate(func: () => void): void;
|
||||
|
||||
declare function clearTimeout(timer: Timer): void;
|
||||
declare function clearTimer(timer: Timer): void;
|
||||
|
||||
declare type Awaited<T> = T extends { then(fn?: (val: infer Res) => void) } ? Awaited<Res> : T;
|
||||
|
||||
declare interface Thenable<T> {
|
||||
then<Res = T, Rej = never>(onFulfill?: (val: T) => Res, onReject?: (err: any) => Rej): Promise<Res | Rej>;
|
||||
}
|
||||
declare interface Promise<T> extends Thenable<T> {
|
||||
catch<Res = T>(onReject?: (err: any) => Res): Promise<Res>;
|
||||
finally(fn?: () => void): Promise<T>;
|
||||
}
|
||||
|
||||
declare interface PromiseConstructor {
|
||||
new <T>(fn: (res: (val: T) => void, rej: (err: any) => void) => void): Promise<T>;
|
||||
resolve<T>(val: T): Promise<Awaited<T>>;
|
||||
reject<T>(err: unknown): Promise<T>;
|
||||
}
|
||||
27
lib/src/lib/errors.d.ts
vendored
Normal file
27
lib/src/lib/errors.d.ts
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
interface Error {
|
||||
message: string;
|
||||
name: string;
|
||||
}
|
||||
interface ErrorConstructor {
|
||||
(msg?: string): Error;
|
||||
new (msg?: string): Error;
|
||||
}
|
||||
|
||||
interface TypeError extends Error { }
|
||||
interface TypeErrorConstructor {
|
||||
(msg?: string): TypeError;
|
||||
new (msg?: string): TypeError;
|
||||
}
|
||||
|
||||
|
||||
interface SyntaxError extends Error { }
|
||||
interface SyntaxErrorConstructor {
|
||||
(msg?: string): SyntaxError;
|
||||
new (msg?: string): SyntaxError;
|
||||
}
|
||||
|
||||
interface RangeError extends Error { }
|
||||
interface RangeErrorConstructor {
|
||||
(msg?: string): RangeError;
|
||||
new (msg?: string): RangeError;
|
||||
}
|
||||
4
lib/src/lib/globals/json.d.ts
vendored
Normal file
4
lib/src/lib/globals/json.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
interface JSON {
|
||||
stringify(val: any): string;
|
||||
parse(val: string): any;
|
||||
}
|
||||
19
lib/src/lib/globals/map.d.ts
vendored
Normal file
19
lib/src/lib/globals/map.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
interface Map<K, V> {
|
||||
readonly size: number;
|
||||
get(key: K): V;
|
||||
has(key: K): boolean;
|
||||
set(key: K, val: V): this;
|
||||
delete(key: K): boolean;
|
||||
clear(): void;
|
||||
|
||||
keys(): K[];
|
||||
values(): V[];
|
||||
entries(): [K, V][];
|
||||
|
||||
forEach(cb: (val: V, key: K, map: this) => void, self?: any): void;
|
||||
|
||||
[Symbol.iterator](): Iterator<[K, V]>;
|
||||
}
|
||||
interface MapConstructor {
|
||||
new <K, V>(iterable?: Iterable<[K, V]>): Map<K, V>;
|
||||
}
|
||||
18
lib/src/lib/globals/set.d.ts
vendored
Normal file
18
lib/src/lib/globals/set.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
interface Set<V> {
|
||||
readonly size: number;
|
||||
add(val: V): this;
|
||||
has(key: V): boolean;
|
||||
delete(key: V): boolean;
|
||||
clear(): void;
|
||||
|
||||
keys(): V[];
|
||||
values(): V[];
|
||||
entries(): [V, V][];
|
||||
|
||||
forEach(cb: (val: V, key: V, map: this) => void, self?: any): void;
|
||||
|
||||
[Symbol.iterator](): Iterator<V>;
|
||||
}
|
||||
interface SetConstructor {
|
||||
new <V>(iterable?: Iterable<V>): Set<V>;
|
||||
}
|
||||
11
lib/src/lib/globals/weak-map.d.ts
vendored
Normal file
11
lib/src/lib/globals/weak-map.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
interface WeakMap<K, V> {
|
||||
readonly size: number;
|
||||
get(key: K): V;
|
||||
set(key: K, val: V): this;
|
||||
has(key: K): boolean;
|
||||
delete(key: K): boolean;
|
||||
clear(): void;
|
||||
}
|
||||
interface WeakMapConstructor {
|
||||
new <K, V>(iterable?: Iterable<[K, V]>): WeakMap<K, V>;
|
||||
}
|
||||
22
lib/src/lib/iterator.d.ts
vendored
Normal file
22
lib/src/lib/iterator.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
declare interface NormalIterationData<T> {
|
||||
value: T;
|
||||
done: true;
|
||||
}
|
||||
declare interface DoneIterationData<T> {
|
||||
value: T;
|
||||
done?: false;
|
||||
}
|
||||
declare type IterationData<T, Return> = NormalIterationData<T> | DoneIterationData<Return>;
|
||||
|
||||
declare interface Iterator<T, Return = unknown, Next = unknown> {
|
||||
next(): IterationData<T, Return>;
|
||||
next(val: Next): IterationData<T, Return>;
|
||||
error?(err: unknown): IterationData<T, Return>;
|
||||
return?(val: Return): IterationData<T, Return>;
|
||||
}
|
||||
declare interface IterableIterator<T, Return = unknown, Next = unknown> extends Iterator<T, Return, Next> {
|
||||
[Symbol.iterator](): this;
|
||||
}
|
||||
declare interface Iterable<T> {
|
||||
[Symbol.iterator](): Iterator<T>;
|
||||
}
|
||||
44
lib/src/lib/lib.d.ts
vendored
Normal file
44
lib/src/lib/lib.d.ts
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference path="./typing.d.ts"/>
|
||||
/// <reference path="./iterator.d.ts"/>
|
||||
/// <reference path="./async.d.ts"/>
|
||||
/// <reference path="./errors.d.ts"/>
|
||||
/// <reference path="./values/function.d.ts"/>
|
||||
/// <reference path="./values/object.d.ts"/>
|
||||
/// <reference path="./values/array.d.ts"/>
|
||||
/// <reference path="./values/boolean.d.ts"/>
|
||||
/// <reference path="./values/symbol.d.ts"/>
|
||||
/// <reference path="./values/string.d.ts"/>
|
||||
/// <reference path="./values/number.d.ts"/>
|
||||
/// <reference path="./values/regexp.d.ts"/>
|
||||
/// <reference path="./globals/json.d.ts"/>
|
||||
/// <reference path="./globals/set.d.ts"/>
|
||||
/// <reference path="./globals/map.d.ts"/>
|
||||
/// <reference path="./globals/weak-map.d.ts"/>
|
||||
|
||||
declare function print(...args: any[]): void;
|
||||
declare function exit(): never;
|
||||
declare function measure(func: () => void): void;
|
||||
|
||||
declare type IArguments = Array<any>;
|
||||
|
||||
declare var Error: ErrorConstructor;
|
||||
declare var TypeError: TypeErrorConstructor;
|
||||
declare var SyntaxError: SyntaxErrorConstructor;
|
||||
declare var RangeError: RangeErrorConstructor;
|
||||
|
||||
declare var Array: ArrayConstructor;
|
||||
declare var Boolean: BooleanConstructor;
|
||||
declare var Function: FunctionConstructor;
|
||||
declare var Symbol: SymbolConstructor;
|
||||
declare var Number: NumberConstructor;
|
||||
declare var Object: ObjectConstructor;
|
||||
declare var RegExp: RegExpConstructor;
|
||||
declare var String: StringConstructor;
|
||||
declare var Promise: PromiseConstructor;
|
||||
|
||||
declare var JSON: JSON;
|
||||
|
||||
declare var Set: SetConstructor;
|
||||
declare var Map: MapConstructor;
|
||||
declare var WeakMap: WeakMapConstructor;
|
||||
7
lib/src/lib/typing.d.ts
vendored
Normal file
7
lib/src/lib/typing.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
declare type Record<Key, Val> = { [x in Key]: Val }
|
||||
declare type InstanceType<T> = T extends new (...args: any[]) => infer T ? T : never;
|
||||
declare type ReturnType<T> = T extends (...args: any[]) => infer T ? T : never;
|
||||
declare type Arguments<T> =
|
||||
T extends (...args: infer T) => any ? T :
|
||||
T extends new (...args: infer T) => any ? T :
|
||||
never;
|
||||
39
lib/src/lib/values/array.d.ts
vendored
Normal file
39
lib/src/lib/values/array.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
declare interface Array<T> {
|
||||
length: number;
|
||||
[i: number]: T;
|
||||
|
||||
forEach(this: T[], cb: (val: T, i: number, self: this) => void, self?: any): void;
|
||||
join(this: T[], delim?: string): string;
|
||||
|
||||
push(this: T[], ...elements: T[]): number;
|
||||
pop(this: T[]): T | undefined;
|
||||
|
||||
unshift(this: T[], ...elements: T[]): number;
|
||||
shift(this: T[]): T | undefined;
|
||||
|
||||
concat(this: T[], ...elements: (T | T[])[]): T[];
|
||||
slice(this: T[], start?: number, end?: number): T[];
|
||||
splice(this: T[], start?: number, count?: number): T[];
|
||||
splice(this: T[], start: number | undefined, count: number | undefined, ...elements: T[]): T[];
|
||||
|
||||
map<T2>(this: T[], cb: (val: T, i: number, self: this) => T2, self?: any): T2[];
|
||||
filter(this: T[], cb: (val: T, i: number, self: this) => boolean, self?: any): T[];
|
||||
some(this: T[], cb: (val: T, i: number, self: this) => boolean, self?: any): boolean;
|
||||
find(this: T[], cb: (val: T, i: number, self: this) => boolean, self?: any): T | undefined;
|
||||
indexOf(this: T[], el: T, start?: number): number;
|
||||
lastIndexOf(this: T[], el: T, start?: number): number;
|
||||
|
||||
sort(this: T[], cb?: (a: T, b: T) => number): T[];
|
||||
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
}
|
||||
declare interface ArrayConstructor {
|
||||
new <T>(len: number): T[];
|
||||
new <T>(...elements: T[]): T[];
|
||||
|
||||
<T>(len: number): T[];
|
||||
<T>(...elements: T[]): T[];
|
||||
|
||||
isArray(val: any): val is any[];
|
||||
// from(val: any): val is any[];
|
||||
}
|
||||
8
lib/src/lib/values/boolean.d.ts
vendored
Normal file
8
lib/src/lib/values/boolean.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
declare interface Boolean {
|
||||
valueOf(): boolean;
|
||||
toString(): string;
|
||||
}
|
||||
declare interface BooleanConstructor {
|
||||
new (val?: unknown): Boolean;
|
||||
(val?: unknown): boolean;
|
||||
}
|
||||
30
lib/src/lib/values/function.d.ts
vendored
Normal file
30
lib/src/lib/values/function.d.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
declare interface Function {
|
||||
prototype: object;
|
||||
|
||||
name: string;
|
||||
length: number;
|
||||
|
||||
valueOf(): this;
|
||||
toString(): string;
|
||||
|
||||
apply<Args extends readonly any[], Ret, Self>(this: (this: Self, ...args: Args) => Ret, self: Self, args: Args): Ret;
|
||||
apply(this: Function, self: any, args: any[]): any;
|
||||
call<Args extends readonly any[], Ret, Self>(this: (this: Self, ...args: Args) => Ret, self: Self, ...args: Args): Ret;
|
||||
call(this: Function, self: any, ...args: any): any;
|
||||
bind<T extends (...args: any[]) => any>(this: T): T;
|
||||
bind<
|
||||
Bound extends readonly any[],
|
||||
Args extends readonly any[],
|
||||
Ret, Self
|
||||
>(this: (this: Self, ...args: [...Bound, ...Args]) => Ret, self: Self, ...bound: Bound): (this: void, ...args: Args) => Ret;
|
||||
}
|
||||
declare interface CallableFunction extends Function {
|
||||
(...args: unknown[]): unknown;
|
||||
}
|
||||
declare interface NewableFunction extends Function {
|
||||
new (...args: unknown[]): unknown;
|
||||
}
|
||||
declare interface FunctionConstructor {
|
||||
new (val?: string): (this: unknown, ...args: unknown[]) => unknown;
|
||||
(val?: string): (this: unknown, ...args: unknown[]) => unknown;
|
||||
}
|
||||
24
lib/src/lib/values/number.d.ts
vendored
Normal file
24
lib/src/lib/values/number.d.ts
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
declare interface Number {
|
||||
valueOf(): number;
|
||||
toString(): string;
|
||||
}
|
||||
declare interface NumberConstructor {
|
||||
(val?: unknown): number;
|
||||
new (val?: unknown): Number;
|
||||
|
||||
isFinite(value: number): boolean;
|
||||
isInteger(value: number): boolean;
|
||||
isNaN(value: number): boolean;
|
||||
isSafeInteger(value: number): boolean;
|
||||
parseFloat(value: unknown): number;
|
||||
parseInt(value: unknown, radix?: number): number;
|
||||
|
||||
readonly EPSILON: number;
|
||||
readonly MIN_SAFE_INTEGER: number;
|
||||
readonly MAX_SAFE_INTEGER: number;
|
||||
readonly POSITIVE_INFINITY: number;
|
||||
readonly NEGATIVE_INFINITY: number;
|
||||
readonly NaN: number;
|
||||
readonly MAX_VALUE: number;
|
||||
readonly MIN_VALUE: number;
|
||||
}
|
||||
57
lib/src/lib/values/object.d.ts
vendored
Normal file
57
lib/src/lib/values/object.d.ts
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
type AssignResult<Arr extends readonly object[]> =
|
||||
Arr extends [...infer Rest extends object[], infer B extends object] ? {
|
||||
[x in keyof B | keyof AssignResult<Rest>]:
|
||||
x extends keyof B ? B[x] :
|
||||
x extends keyof AssignResult<Rest> ? AssignResult<Rest>[x] :
|
||||
never
|
||||
} : {};
|
||||
|
||||
declare interface PropertyDescriptor {
|
||||
configurable?: boolean;
|
||||
enumerable?: boolean;
|
||||
value?: any;
|
||||
writable?: boolean;
|
||||
get?(): any;
|
||||
set?(v: any): void;
|
||||
}
|
||||
declare interface PropertyDescriptorMap {
|
||||
[key: PropertyKey]: PropertyDescriptor;
|
||||
}
|
||||
|
||||
declare interface Object {
|
||||
valueOf(): number;
|
||||
toString(): string;
|
||||
}
|
||||
declare interface ObjectConstructor {
|
||||
new (val: string): String;
|
||||
(val: string): String;
|
||||
new (val: number): Number;
|
||||
new (val: number): Number;
|
||||
(val: number): Number;
|
||||
new (val: boolean): Boolean;
|
||||
(val: boolean): Boolean;
|
||||
new (val: symbol): Symbol;
|
||||
(val: symbol): Symbol;
|
||||
new <T extends object>(val: T): T;
|
||||
<T extends object>(val: T): T;
|
||||
new (): object;
|
||||
(): object;
|
||||
|
||||
getOwnPropertyDescriptor(obj: object, key: any): PropertyDescriptor;
|
||||
defineProperty<T extends object>(obj: T, key: string | symbol, desc: PropertyDescriptor): T;
|
||||
defineProperties<T extends object>(obj: T, desc: PropertyDescriptorMap): T;
|
||||
|
||||
create<T extends object>(proto: T, desc?: PropertyDescriptorMap): T;
|
||||
assign<First extends object, T extends readonly object[]>(targeT: First, ...arr: T): AssignResult<[First, ...T]>;
|
||||
|
||||
setPrototypeOf<T extends object>(obj: T, proto: object | null): T
|
||||
getPrototypeOf(obj: object): object | null;
|
||||
|
||||
keys<T extends object>(obj: T): (keyof T)[];
|
||||
values<T extends object>(obj: T): T[keyof T][];
|
||||
entries<T extends object>(obj: T): [key: keyof T, val: T[keyof T]][];
|
||||
|
||||
preventExtensions<T>(obj: T): T;
|
||||
seal<T>(obj: T): T;
|
||||
freeze<T>(obj: T): T;
|
||||
}
|
||||
36
lib/src/lib/values/regexp.d.ts
vendored
Normal file
36
lib/src/lib/values/regexp.d.ts
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
declare interface RegExpMatchArray extends Array<string> {
|
||||
0: string;
|
||||
|
||||
index?: number;
|
||||
input?: string;
|
||||
|
||||
groups?: { [key: string]: string };
|
||||
indices?: [start: number, end: number][] & {
|
||||
[key: string]: [start: number, end: number]
|
||||
}
|
||||
}
|
||||
|
||||
declare interface RegExp {
|
||||
lastIndex: number;
|
||||
|
||||
readonly source: string;
|
||||
readonly flags: string;
|
||||
|
||||
readonly indices: boolean;
|
||||
readonly global: boolean;
|
||||
readonly ignoreCase: boolean;
|
||||
readonly multiline: boolean;
|
||||
readonly dotall: boolean;
|
||||
readonly unicode: boolean;
|
||||
readonly unicodeSets: boolean;
|
||||
readonly sticky: boolean;
|
||||
|
||||
exec(target: string): RegExpMatchArray | null;
|
||||
text(target: string): boolean
|
||||
[Symbol.split](target: string, limit?: number): string[];
|
||||
[Symbol.replace](target: string, replacer: any): string;
|
||||
}
|
||||
declare interface RegExpConstructor {
|
||||
new (val: string, flags?: string): String;
|
||||
(val: string, flags?: string): String;
|
||||
}
|
||||
39
lib/src/lib/values/string.d.ts
vendored
Normal file
39
lib/src/lib/values/string.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
declare interface String {
|
||||
readonly length: number;
|
||||
[key: number]: string;
|
||||
|
||||
toString(): string;
|
||||
valueOf(): string;
|
||||
|
||||
at(index: number): string | undefined;
|
||||
charAt(i: number): string | undefined;
|
||||
charCodeAt(i: number): number;
|
||||
codePointAt(i: number): number;
|
||||
|
||||
includes(search: string, offset?: number): number;
|
||||
indexOf(search: string, offset?: number): number;
|
||||
lastIndexOf(search: string, offset?: number): number;
|
||||
|
||||
trim(): string;
|
||||
trimStart(): string;
|
||||
trimEnd(): string;
|
||||
toLowerCase(): string;
|
||||
toUpperCase(): string;
|
||||
|
||||
split(val?: any, limit?: number): string[];
|
||||
replace(val: any, replacer: any): string;
|
||||
replaceAll(val: any, replacer: any): string;
|
||||
|
||||
slice(start?: number, end?: number): string;
|
||||
substring(start?: number, end?: number): string;
|
||||
substr(start?: number, count?: number): string;
|
||||
|
||||
[Symbol.iterator](): IterableIterator<string>;
|
||||
}
|
||||
declare interface StringConstructor {
|
||||
new (val: unknown): String;
|
||||
(val: unknown): string;
|
||||
|
||||
fromCharCode(...chars: readonly number[]): string;
|
||||
fromCodePoint(...points: readonly number[]): string;
|
||||
}
|
||||
19
lib/src/lib/values/symbol.d.ts
vendored
Normal file
19
lib/src/lib/values/symbol.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
declare interface Symbol {
|
||||
readonly description: string | undefined;
|
||||
|
||||
valueOf(): symbol;
|
||||
toString(): string;
|
||||
}
|
||||
declare interface SymbolConstructor {
|
||||
(val?: string): symbol;
|
||||
for(val: string): symbol;
|
||||
|
||||
readonly asyncIterator: unique symbol;
|
||||
readonly iterator: unique symbol;
|
||||
readonly match: unique symbol;
|
||||
readonly matchAll: unique symbol;
|
||||
readonly replace: unique symbol;
|
||||
readonly search: unique symbol;
|
||||
readonly split: unique symbol;
|
||||
readonly toStringTag: unique symbol;
|
||||
}
|
||||
5
lib/src/polyfills/callSuper.js
Normal file
5
lib/src/polyfills/callSuper.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { func, object } from "../stdlib/primordials.ts";
|
||||
|
||||
export default function _callSuper(self, constr, args) {
|
||||
return func.construct(object.getPrototype(constr), func.target(1), args || []);
|
||||
}
|
||||
5
lib/src/polyfills/classCallCheck.js
Normal file
5
lib/src/polyfills/classCallCheck.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { func } from "../stdlib/primordials.ts";
|
||||
|
||||
export default function _classCallCheck() {
|
||||
if (func.invokeTypeInfer() !== "new") throw new TypeError("Cannot call a class as a function");
|
||||
}
|
||||
35
lib/src/polyfills/createClass.js
Normal file
35
lib/src/polyfills/createClass.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { object } from "../stdlib/primordials.ts";
|
||||
|
||||
function _defineProperties(target, arr) {
|
||||
if (!arr) return;
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var desc = arr[i];
|
||||
var res;
|
||||
var w, e, c;
|
||||
|
||||
c = desc.configurable;
|
||||
if (c == null) c = true;
|
||||
e = desc.enumerable;
|
||||
if (e == null) e = false;
|
||||
|
||||
if ("value" in desc) {
|
||||
w = desc.writable;
|
||||
if (w == null) w = true;
|
||||
|
||||
if (desc.writable == null)
|
||||
res = object.defineField(target, desc.key, { w: !!w, e: !!e, c: !!c, v: desc.value });
|
||||
}
|
||||
else {
|
||||
res = object.defineProperty(target, desc.key, { e: !!e, c: !!c, g: desc.get, s: desc.set });
|
||||
}
|
||||
|
||||
if (!res) throw "Couldn't set property";
|
||||
}
|
||||
}
|
||||
|
||||
export default function _createClass(clazz, instance, nonInstance) {
|
||||
_defineProperties(clazz.prototype, instance);
|
||||
_defineProperties(clazz, nonInstance);
|
||||
|
||||
return clazz;
|
||||
}
|
||||
7
lib/src/polyfills/defineProperty.js
Normal file
7
lib/src/polyfills/defineProperty.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import { object } from "../stdlib/primordials.ts";
|
||||
|
||||
export default function _defineProperty(obj, key, val) {
|
||||
if (obj == null) return;
|
||||
object.defineField(obj, key, { c: true, e: true, w: true, v: val });
|
||||
return obj;
|
||||
}
|
||||
5
lib/src/polyfills/getPrototypeOf.js
Normal file
5
lib/src/polyfills/getPrototypeOf.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { object } from "../stdlib/primordials.ts";
|
||||
|
||||
export default function _getPrototypeOf(obj) {
|
||||
return object.getPrototype(obj) || null;
|
||||
}
|
||||
11
lib/src/polyfills/inherits.js
Normal file
11
lib/src/polyfills/inherits.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { object } from "../stdlib/primordials.ts";
|
||||
|
||||
export default function _inherits(t, e) {
|
||||
if (e == null) {
|
||||
object.setPrototype(t.prototype, undefined);
|
||||
}
|
||||
else {
|
||||
object.setPrototype(t.prototype, e.prototype);
|
||||
object.setPrototype(t, e);
|
||||
}
|
||||
}
|
||||
1
lib/src/polyfills/possibleConstructorReturn.js
Normal file
1
lib/src/polyfills/possibleConstructorReturn.js
Normal file
@@ -0,0 +1 @@
|
||||
export default function _possibleConstructorReturn(_, res) { return res; }
|
||||
3
lib/src/polyfills/readOnlyError.js
Normal file
3
lib/src/polyfills/readOnlyError.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function _readOnlyError(name) {
|
||||
throw name;
|
||||
}
|
||||
5
lib/src/polyfills/setPrototypeOf.js
Normal file
5
lib/src/polyfills/setPrototypeOf.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { object } from "../stdlib/primordials";
|
||||
|
||||
export default function _setPrototypeOf(obj, proto) {
|
||||
object.setPrototype(obj, proto);
|
||||
}
|
||||
3
lib/src/polyfills/typeof.js
Normal file
3
lib/src/polyfills/typeof.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function _typeof(val) {
|
||||
return typeof val;
|
||||
}
|
||||
91
lib/src/stdlib/_entry.ts
Normal file
91
lib/src/stdlib/_entry.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { object, setGlobalPrototypes, target } from "./primordials.ts";
|
||||
import { Error, RangeError, SyntaxError, TypeError } from "./values/errors.ts";
|
||||
import { Boolean } from "./values/boolean.ts";
|
||||
import { Function } from "./values/function.ts";
|
||||
import { Number } from "./values/number.ts";
|
||||
import { Object } from "./values/object.ts";
|
||||
import { String } from "./values/string.ts";
|
||||
import { Symbol } from "./values/symbol.ts";
|
||||
import { Array } from "./values/array.ts";
|
||||
import { Map, WeakMap } from "./classes/map.ts";
|
||||
import { RegExp } from "./values/regex.ts";
|
||||
import { Date } from "./classes/date.ts";
|
||||
import { Math as _Math } from "./namespaces/math.ts";
|
||||
import { Set, WeakSet } from "./classes/set.ts";
|
||||
import { JSON } from "./namespaces/json.ts";
|
||||
import { console } from "./namespaces/console.ts";
|
||||
import { encodeURI, encodeURIComponent } from "./url.ts";
|
||||
import { Promise } from "./classes/promise.ts";
|
||||
import { ArrayBuffer } from "./arrays/ArrayBuffer.ts";
|
||||
import { Uint8Array } from "./arrays/Uint8Array.ts";
|
||||
import { Int32Array } from "./arrays/Int32Array.ts";
|
||||
import { TypedArray } from "./arrays/TypedArray.ts";
|
||||
|
||||
declare global {
|
||||
function print(...args: any[]): void;
|
||||
function measure(func: Function): void;
|
||||
}
|
||||
|
||||
function fixup<T extends Function>(clazz: T) {
|
||||
object.setPrototype(clazz, Function.prototype);
|
||||
object.setPrototype(clazz.prototype as any, Object.prototype);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
object.setPrototype(target, Object.prototype);
|
||||
|
||||
object.defineField(target, "undefined", { e: false, c: false, w: false, v: void 0 });
|
||||
|
||||
target.Symbol = fixup(Symbol);
|
||||
target.Number = fixup(Number);
|
||||
target.String = fixup(String);
|
||||
target.Boolean = fixup(Boolean);
|
||||
|
||||
target.Object = Object;
|
||||
target.Function = fixup(Function);
|
||||
target.Array = fixup(Array);
|
||||
|
||||
target.Error = fixup(Error);
|
||||
target.RangeError = RangeError;
|
||||
target.SyntaxError = SyntaxError;
|
||||
target.TypeError = TypeError;
|
||||
|
||||
fixup(TypedArray);
|
||||
target.ArrayBuffer = fixup(ArrayBuffer);
|
||||
target.Uint8Array = Uint8Array;
|
||||
target.Int32Array = Int32Array;
|
||||
|
||||
target.Map = fixup(Map);
|
||||
target.WeakMap = fixup(WeakMap);
|
||||
target.Set = fixup(Set);
|
||||
target.WeakSet = fixup(WeakSet);
|
||||
target.RegExp = fixup(RegExp);
|
||||
target.Date = fixup(Date);
|
||||
target.Promise = fixup(Promise);
|
||||
target.Math = object.setPrototype(_Math, Object.prototype);
|
||||
target.JSON = object.setPrototype(JSON, Object.prototype);
|
||||
target.console = object.setPrototype(console, 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,
|
||||
number: Number.prototype,
|
||||
boolean: Boolean.prototype,
|
||||
symbol: Symbol.prototype,
|
||||
object: Object.prototype,
|
||||
array: Array.prototype,
|
||||
function: Function.prototype,
|
||||
error: Error.prototype,
|
||||
syntax: SyntaxError.prototype,
|
||||
range: RangeError.prototype,
|
||||
type: TypeError.prototype,
|
||||
uint8: Uint8Array.prototype,
|
||||
int32: Int32Array.prototype,
|
||||
regex: RegExp,
|
||||
});
|
||||
30
lib/src/stdlib/arrays/ArrayBuffer.ts
Normal file
30
lib/src/stdlib/arrays/ArrayBuffer.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { buffer, type InternalBuffer, map, symbol } from "../primordials.ts";
|
||||
|
||||
export const abs = new map(true);
|
||||
export const abKey: unique symbol = symbol.getSymbol("ArrayBuffer.impl") as any;
|
||||
|
||||
export class ArrayBuffer {
|
||||
public [abKey]!: InternalBuffer;
|
||||
|
||||
public get byteLength() {
|
||||
return this[abKey].length;
|
||||
}
|
||||
public get byteOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public constructor(val: unknown) {
|
||||
if (buffer.isBuff(val)) this[abKey] = val;
|
||||
else this[abKey] = buffer.buff(Number(val));
|
||||
}
|
||||
}
|
||||
|
||||
export function getAB(buff: InternalBuffer): ArrayBuffer {
|
||||
let res = abs.get(buff);
|
||||
if (res == null) {
|
||||
res = new ArrayBuffer(buff);
|
||||
abs.set(buff, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
25
lib/src/stdlib/arrays/Int32Array.ts
Normal file
25
lib/src/stdlib/arrays/Int32Array.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { buffer } from "../primordials.ts";
|
||||
import { abstractIgnore, TypedArray, typedArrayFuncs } from "./TypedArray.ts";
|
||||
|
||||
const factory = buffer.int32;
|
||||
const funcs = typedArrayFuncs(4, factory);
|
||||
|
||||
export class Int32Array extends TypedArray {
|
||||
public subarray(this: number[], start?: number, end?: number) {
|
||||
return funcs.subarray(this, start, end);
|
||||
}
|
||||
public slice(this: any[], start?: number, end?: number) {
|
||||
return funcs.slice(this, start, end);
|
||||
}
|
||||
public map(this: any[], cb: (val: number, i: number, self: any) => number, self?: any) {
|
||||
return funcs.map(this, cb, self);
|
||||
}
|
||||
public filter(this: any[], cb: (val: number, i: number, self: any) => boolean, self?: any) {
|
||||
return funcs.filter(this, cb, self);
|
||||
}
|
||||
|
||||
public constructor(obj: any, start?: number, end?: number) {
|
||||
super(abstractIgnore);
|
||||
return funcs.construct(obj, start, end) as any;
|
||||
}
|
||||
}
|
||||
220
lib/src/stdlib/arrays/TypedArray.ts
Normal file
220
lib/src/stdlib/arrays/TypedArray.ts
Normal file
@@ -0,0 +1,220 @@
|
||||
import { buffer, func, type InternalBuffer, object, string, symbol } from "../primordials.ts";
|
||||
import { symbols, wrapI } from "../utils.ts";
|
||||
import { Error, TypeError } from "../values/errors.ts";
|
||||
import { abKey, ArrayBuffer, getAB } from "./ArrayBuffer.ts";
|
||||
|
||||
export const abstractIgnore = symbol.getSymbol("TypedArray.abstractIgnore");
|
||||
|
||||
export function typedArrayFuncs(perEl: number, constructor: (buff: InternalBuffer, start: number, end: number) => number[]) {
|
||||
return {
|
||||
map(self: number[], cb: (val: number, i: number, self: number[]) => number, fnSelf: any) {
|
||||
const res = constructor(buffer.buff(self.length * perEl), 0, self.length);
|
||||
|
||||
for (let i = 0; i < self.length; i++) {
|
||||
res[i] = func.invoke(cb, fnSelf, [self[i], i, self]);
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
filter(self: number[], cb: (val: number, i: number, self: number[]) => boolean, fnSelf: any) {
|
||||
const bigger = constructor(buffer.buff(self.length * perEl), 0, self.length);
|
||||
let j = 0;
|
||||
|
||||
for (let i = 0; i < self.length; i++) {
|
||||
if (func.invoke(cb, self, [self[i], i, fnSelf])) bigger[j++] = self[i];
|
||||
}
|
||||
|
||||
const res = constructor(buffer.buff(j * perEl), 0, j);
|
||||
for (let i = 0; i < j; i++) res[i] = bigger[i];
|
||||
return res;
|
||||
},
|
||||
slice(self: number[], start = 0, end = self.length) {
|
||||
start = wrapI(start, self.length);
|
||||
end = wrapI(end, self.length);
|
||||
|
||||
if (end <= start) return constructor(buffer.buff(0), 0, 0);
|
||||
|
||||
const res = constructor(buffer.buff((end - start) * perEl), 0, end - start);
|
||||
|
||||
for (let i = 0; i < end - start; i++) {
|
||||
res[i] = self[start + i];
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
subarray(self: number[], start = 0, end = self.length) {
|
||||
start = wrapI(start, self.length);
|
||||
end = wrapI(end, self.length);
|
||||
|
||||
if (end <= start) return constructor(buffer.buff(0), 0, 0);
|
||||
|
||||
const offset = buffer.start(self);
|
||||
return constructor(buffer.backer(self), offset + start, offset + end);
|
||||
},
|
||||
construct(self: ArrayBuffer | number[] | number | Iterable<number>, start?: number, end?: number) {
|
||||
if (typeof self === "number") {
|
||||
return constructor(buffer.buff(self * perEl), 0, self);
|
||||
}
|
||||
if (self instanceof ArrayBuffer) {
|
||||
const internal = self[abKey];
|
||||
if (start === undefined) start = 0;
|
||||
if (end === undefined) end = (internal.length / perEl) | 0;
|
||||
return constructor(internal, start, end);
|
||||
}
|
||||
if (symbols.iterator in self && typeof self[symbols.iterator] === "function") {
|
||||
const arr: number[] = [];
|
||||
let i = 0;
|
||||
const gen: Iterator<number> = self[symbols.iterator]();
|
||||
|
||||
for (let it = gen.next(); !it.done; it = gen.next()) {
|
||||
arr[i++] = Number(it.value);
|
||||
}
|
||||
|
||||
const res = constructor(buffer.buff(i * perEl), 0, i);
|
||||
for (let j = 0; j < i; j++) res[j] = arr[j];
|
||||
return res;
|
||||
}
|
||||
|
||||
const res = constructor(buffer.buff((self as number[]).length * perEl), 0, (self as number[]).length);
|
||||
for (let i = 0; i < (self as number[]).length; i++) res[i] = (self as number[])[i];
|
||||
return res;
|
||||
},
|
||||
byteOffset(self: number[]) {
|
||||
return buffer.start(self) * perEl;
|
||||
},
|
||||
byteLength(self: number[]) {
|
||||
return (buffer.end(self) - buffer.start(self)) * perEl;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class TypedArray {
|
||||
public get buffer() {
|
||||
return getAB(buffer.backer(this as any));
|
||||
}
|
||||
public get byteOffset(): number {
|
||||
throw new Error("abstract");
|
||||
}
|
||||
public get byteLength(): number {
|
||||
throw new Error("abstract");
|
||||
}
|
||||
|
||||
public forEach(this: number[], cb: (val: number, 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]);
|
||||
}
|
||||
}
|
||||
public join(this: number[], delim = ",") {
|
||||
delim = String(delim);
|
||||
const parts = [];
|
||||
if (delim) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (i) parts[parts.length] = delim;
|
||||
parts[parts.length] = (i in this) ? String(this[i]) : "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
parts[i] = (i in this) ? String(this[i]) : "";
|
||||
}
|
||||
}
|
||||
|
||||
return string.stringBuild(parts);
|
||||
}
|
||||
|
||||
public subarray(this: number[], start = 0, end = this.length) {
|
||||
throw new Error("'slice' is an abstract method");
|
||||
}
|
||||
|
||||
public slice(this: number[], start = 0, end = this.length) {
|
||||
throw new Error("'slice' is an abstract method");
|
||||
}
|
||||
|
||||
public map(this: number[], cb: (val: number, i: number, self: this) => number, self?: any) {
|
||||
throw new Error("'map' is an abstract method");
|
||||
}
|
||||
public filter(this: number[], cb: (val: number, i: number, self: this) => boolean, self?: any) {
|
||||
throw new Error("'filter' is an abstract method");
|
||||
}
|
||||
public reduce(this: number[], cb: (a: number, b: number, i: number, self: number[]) => number, initial?: number) {
|
||||
let i = 0;
|
||||
if (arguments.length <= 1) initial = this[i++];
|
||||
|
||||
for (; i < this.length; i++) {
|
||||
initial = cb(initial!, this[i], i, this);
|
||||
}
|
||||
|
||||
return initial;
|
||||
}
|
||||
public some(this: number[], cb: (val: number, i: number, self: number[]) => boolean, self?: any) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (func.invoke(cb, self, [this[i], i, this])) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public every(this: number[], cb: (val: number, i: number, self: number[]) => boolean, self?: any) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (!func.invoke(cb, self, [this[i], i, this])) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public find(this: number[], cb: (val: number, i: number, self: number[]) => boolean, self?: any) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (func.invoke(cb, self, [this[i], i, this])) return this[i];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
public indexOf(this: number[], val: number, start = 0) {
|
||||
start |= 0;
|
||||
if (start < 0) start = 0;
|
||||
for (let i = start; i < this.length; i++) {
|
||||
if (this[i] === val) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
public lastIndexOf(this: number[], val: number, start = 0) {
|
||||
start |= 0;
|
||||
if (start < 0) start = 0;
|
||||
|
||||
for (let i = this.length - 1; i >= start; i--) {
|
||||
if (this[i] === val) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
public includes(this: number[], val: number) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (this[i] === val) return i;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public sort(this: number[], cb?: (a: number, b: number) => number) {
|
||||
cb ||= (a, b) => a - b;
|
||||
|
||||
return object.sort(this, cb);
|
||||
}
|
||||
public reverse(this: number[]) {
|
||||
const mid = this.length >> 1;
|
||||
const end = this.length - 1;
|
||||
|
||||
for (let i = 0; i < mid; i++) {
|
||||
const tmp = this[i];
|
||||
this[i] = this[end - i];
|
||||
this[end - i] = tmp;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public constructor(token?: typeof abstractIgnore) {
|
||||
if (token !== abstractIgnore) {
|
||||
throw new TypeError("TypedArray constructor can't be called");
|
||||
}
|
||||
}
|
||||
}
|
||||
32
lib/src/stdlib/arrays/Uint8Array.ts
Normal file
32
lib/src/stdlib/arrays/Uint8Array.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { buffer } from "../primordials.ts";
|
||||
import { abstractIgnore, TypedArray, typedArrayFuncs } from "./TypedArray.ts";
|
||||
|
||||
const factory = buffer.uint8;
|
||||
const funcs = typedArrayFuncs(1, factory);
|
||||
|
||||
export class Uint8Array extends TypedArray {
|
||||
public override get byteOffset() {
|
||||
return funcs.byteOffset(this as any);
|
||||
}
|
||||
public override get byteLength() {
|
||||
return funcs.byteLength(this as any);
|
||||
}
|
||||
|
||||
public override subarray(this: number[], start?: number, end?: number) {
|
||||
return funcs.subarray(this, start, end);
|
||||
}
|
||||
public override slice(this: any[], start?: number, end?: number) {
|
||||
return funcs.slice(this, start, end);
|
||||
}
|
||||
public override map(this: any[], cb: (val: number, i: number, self: any) => number, self?: any) {
|
||||
return funcs.map(this, cb, self);
|
||||
}
|
||||
public override filter(this: any[], cb: (val: number, i: number, self: any) => boolean, self?: any) {
|
||||
return funcs.filter(this, cb, self);
|
||||
}
|
||||
|
||||
public constructor(obj: any, start?: number, end?: number) {
|
||||
super(abstractIgnore);
|
||||
return funcs.construct(obj, start, end) as any;
|
||||
}
|
||||
}
|
||||
20
lib/src/stdlib/classes/date.ts
Normal file
20
lib/src/stdlib/classes/date.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { now, symbol } from "../primordials.ts";
|
||||
|
||||
const timeKey: unique symbol = symbol.makeSymbol("") as any;
|
||||
|
||||
export const Date = (() => {
|
||||
class Date {
|
||||
[timeKey]!: number;
|
||||
|
||||
public constructor() {
|
||||
|
||||
}
|
||||
|
||||
public static now() {
|
||||
return now();
|
||||
}
|
||||
};
|
||||
|
||||
return Date as any as typeof Date & ((val?: unknown) => string);
|
||||
})();
|
||||
export type Date = InstanceType<typeof Date>;
|
||||
128
lib/src/stdlib/classes/map.ts
Normal file
128
lib/src/stdlib/classes/map.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Array } from "../values/array.ts";
|
||||
import { func, map, symbol } from "../primordials.ts";
|
||||
import { symbols } from "../utils.ts";
|
||||
|
||||
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);
|
||||
}
|
||||
public has(key: K): boolean {
|
||||
return this[mapKey].has(key);
|
||||
}
|
||||
public set(key: K, val: V) {
|
||||
this[mapKey].set(key, val);
|
||||
return this;
|
||||
}
|
||||
public delete(key: K): boolean {
|
||||
if (!this[mapKey].has(key)) return false;
|
||||
else {
|
||||
this[mapKey].delete(key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public clear() {
|
||||
this[mapKey].clear();
|
||||
}
|
||||
|
||||
public keys(): K[] {
|
||||
return this[mapKey].keys();
|
||||
}
|
||||
public values(): V[] {
|
||||
const res = this[mapKey].keys();
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
res[i] = this[mapKey].get(res[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
public entries(): [K, V][] {
|
||||
const res = this[mapKey].keys();
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
res[i] = [res[i], this[mapKey].get(res[i])];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public forEach(cb: Function, self?: any) {
|
||||
const entries = this.entries();
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
func.invoke(cb, self, [entries[i][1], entries[i][0], this]);
|
||||
}
|
||||
}
|
||||
|
||||
public [symbols.iterator](): Iterator<[K, V]> {
|
||||
return func.invoke(Array.prototype[symbols.iterator], this.entries(), []) as any;
|
||||
}
|
||||
|
||||
public constructor(iterable?: Iterable<[K, V]>) {
|
||||
const _map = this[mapKey] = new map();
|
||||
|
||||
if (iterable != null) {
|
||||
if (Array.isArray(iterable)) {
|
||||
for (let i = 0; i < iterable.length; i++) {
|
||||
if (!(i in iterable)) continue;
|
||||
_map.set(iterable[i][0], iterable[i][1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const it = (iterable as any)[symbols.iterator]();
|
||||
for (let val = it.next(); !val.done; val = it.next()) {
|
||||
_map.set(val.value[0], val.value[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export class WeakMap<K, V> {
|
||||
private [mapKey]: InstanceType<typeof map>;
|
||||
|
||||
public get(key: K): V {
|
||||
return this[mapKey].get(key);
|
||||
}
|
||||
public has(key: K): boolean {
|
||||
return this[mapKey].has(key);
|
||||
}
|
||||
public set(key: K, val: V) {
|
||||
this[mapKey].set(key, val);
|
||||
return this;
|
||||
}
|
||||
public delete(key: K): boolean {
|
||||
if (!this[mapKey].has(key)) return false;
|
||||
else {
|
||||
this[mapKey].delete(key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public clear() {
|
||||
this[mapKey].clear();
|
||||
}
|
||||
|
||||
public constructor(iterable?: Iterable<[K, V]>) {
|
||||
const _map = this[mapKey] = new map(true);
|
||||
|
||||
if (iterable != null) {
|
||||
if (Array.isArray(iterable)) {
|
||||
for (let i = 0; i < iterable.length; i++) {
|
||||
if (!(i in iterable)) continue;
|
||||
_map.set(iterable[i][0], iterable[i][1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const it = (iterable as any)[symbols.iterator]();
|
||||
for (let val = it.next(); !val.done; val = it.next()) {
|
||||
_map.set(val.value[0], val.value[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func.setCallable(Map, false);
|
||||
func.setCallable(WeakMap, false);
|
||||
154
lib/src/stdlib/classes/promise.ts
Normal file
154
lib/src/stdlib/classes/promise.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { func, next, object, symbol } from "../primordials.ts";
|
||||
|
||||
enum PromiseState {
|
||||
Pending = "pend",
|
||||
Fulfilled = "ful",
|
||||
Rejected = "rej",
|
||||
}
|
||||
|
||||
const pState: unique symbol = symbol.makeSymbol("Promise.state") as any;
|
||||
const pValue: unique symbol = symbol.makeSymbol("Promise.value") as any;
|
||||
const pFulHandles: unique symbol = symbol.makeSymbol("Promise.fulfillHandles") as any;
|
||||
const pRejHandles: unique symbol = symbol.makeSymbol("Promise.rejectHandles") as any;
|
||||
|
||||
function makePromise<T>(): Promise<T> {
|
||||
return object.setPrototype({
|
||||
[pState]: PromiseState.Pending,
|
||||
[pFulHandles]: [],
|
||||
[pRejHandles]: [],
|
||||
}, Promise.prototype) as Promise<T>;
|
||||
}
|
||||
|
||||
function fulfill(self: Promise<any>, val: any) {
|
||||
if (self[pState] !== PromiseState.Pending) return;
|
||||
if (self === val) throw new Error("A promise may not be fulfilled with itself");
|
||||
|
||||
if (val != null && typeof val.then === "function") {
|
||||
val.then(
|
||||
(val: any) => fulfill(self, val),
|
||||
(err: any) => reject(self, err),
|
||||
);
|
||||
}
|
||||
else {
|
||||
self[pValue] = val;
|
||||
self[pState] = PromiseState.Fulfilled;
|
||||
|
||||
const handles = self[pFulHandles]!;
|
||||
|
||||
for (let i = 0; i < handles.length; i++) {
|
||||
handles[i](val);
|
||||
}
|
||||
|
||||
self[pFulHandles] = undefined;
|
||||
self[pRejHandles] = undefined;
|
||||
}
|
||||
}
|
||||
function reject(self: Promise<any>, val: any) {
|
||||
if (self[pState] !== PromiseState.Pending) return;
|
||||
if (self === val) throw new Error("A promise may not be rejected with itself");
|
||||
|
||||
if (val != null && typeof val.then === "function") {
|
||||
val.then(
|
||||
(val: any) => reject(self, val),
|
||||
(err: any) => reject(self, err),
|
||||
);
|
||||
}
|
||||
else {
|
||||
self[pValue] = val;
|
||||
self[pState] = PromiseState.Rejected;
|
||||
|
||||
const handles = self[pRejHandles]!;
|
||||
|
||||
for (let i = 0; i < handles.length; i++) {
|
||||
handles[i](val);
|
||||
}
|
||||
|
||||
self[pFulHandles] = undefined;
|
||||
self[pRejHandles] = undefined;
|
||||
}
|
||||
}
|
||||
function handle<T>(self: Promise<T>, ful?: (val: T) => void, rej?: (err: any) => void) {
|
||||
if (self[pState] === PromiseState.Pending) {
|
||||
if (ful != null) {
|
||||
self[pFulHandles]![self[pFulHandles]!.length] = ful;
|
||||
}
|
||||
if (rej != null) {
|
||||
self[pRejHandles]![self[pRejHandles]!.length] = rej;
|
||||
}
|
||||
}
|
||||
else if (self[pState] === PromiseState.Fulfilled) {
|
||||
if (ful != null) ful(self[pValue] as T);
|
||||
}
|
||||
else if (self[pState] === PromiseState.Rejected) {
|
||||
if (rej != null) rej(self[pValue]);
|
||||
}
|
||||
}
|
||||
|
||||
export class Promise<T> {
|
||||
public [pState]: PromiseState;
|
||||
public [pValue]?: T | unknown;
|
||||
public [pFulHandles]?: ((val: T) => void)[] = [];
|
||||
public [pRejHandles]?: ((val: T) => void)[] = [];
|
||||
|
||||
public then<Res>(ful?: (val: T) => Res, rej?: (err: any) => Res) {
|
||||
if (typeof ful !== "function") ful = undefined;
|
||||
if (typeof rej !== "function") rej = undefined;
|
||||
|
||||
const promise = makePromise<Res>();
|
||||
|
||||
handle(this,
|
||||
val => next(() => {
|
||||
if (ful == null) fulfill(promise, val);
|
||||
else {
|
||||
try { fulfill(promise, ful(val)); }
|
||||
catch (e) { reject(promise, e); }
|
||||
}
|
||||
}),
|
||||
err => next(() => {
|
||||
if (rej == null) reject(promise, err);
|
||||
else {
|
||||
try { fulfill(promise, rej(err)); }
|
||||
catch (e) { reject(promise, e); }
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return promise;
|
||||
}
|
||||
public catch<Res>(rej?: (err: any) => Res) {
|
||||
return this.then(undefined, rej);
|
||||
}
|
||||
public finally(fn?: () => void) {
|
||||
if (typeof fn !== "function") return this["then"]();
|
||||
|
||||
return this.then(
|
||||
v => {
|
||||
fn();
|
||||
return v;
|
||||
},
|
||||
v => {
|
||||
fn();
|
||||
throw v;
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
public constructor(fn: (fulfil: (val: T) => void, reject: (err: unknown) => void) => void) {
|
||||
this[pState] = PromiseState.Pending;
|
||||
|
||||
fn(val => fulfill(this, val), err => reject(this, err));
|
||||
}
|
||||
|
||||
public static resolve(val: any) {
|
||||
const res = makePromise();
|
||||
fulfill(res, val);
|
||||
return res;
|
||||
}
|
||||
public static reject(val: any) {
|
||||
const res = makePromise();
|
||||
reject(res, val);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
func.setCallable(Promise, false);
|
||||
121
lib/src/stdlib/classes/set.ts
Normal file
121
lib/src/stdlib/classes/set.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { Array } from "../values/array.ts";
|
||||
import { func, map, symbol } from "../primordials.ts";
|
||||
import { symbols } from "../utils.ts";
|
||||
|
||||
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);
|
||||
}
|
||||
public add(val: T) {
|
||||
this[mapKey].set(val, true);
|
||||
return this;
|
||||
}
|
||||
public delete(val: T): boolean {
|
||||
if (!this[mapKey].has(val)) return false;
|
||||
else {
|
||||
this[mapKey].delete(val);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public clear() {
|
||||
this[mapKey].clear();
|
||||
}
|
||||
|
||||
public keys(): T[] {
|
||||
return this[mapKey].keys();
|
||||
}
|
||||
public values(): T[] {
|
||||
return this[mapKey].keys();
|
||||
}
|
||||
public entries(): [T, T][] {
|
||||
const res = this[mapKey].keys();
|
||||
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
res[i] = [res[i], res[i]];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public forEach(cb: Function, self?: any) {
|
||||
const vals = this.values();
|
||||
|
||||
for (let i = 0; i < vals.length; i++) {
|
||||
func.invoke(cb, self, [vals[i], vals[i], this]);
|
||||
}
|
||||
}
|
||||
|
||||
public [symbols.iterator](): Iterator<T> {
|
||||
return func.invoke(Array.prototype[symbols.iterator], this.values(), []) as any;
|
||||
}
|
||||
|
||||
public constructor(iterable?: Iterable<T>) {
|
||||
const _map = this[mapKey] = new map();
|
||||
|
||||
if (iterable != null) {
|
||||
if (Array.isArray(iterable)) {
|
||||
for (let i = 0; i < iterable.length; i++) {
|
||||
if (!(i in iterable)) continue;
|
||||
_map.set(iterable[i], true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const it = (iterable as any)[symbols.iterator]();
|
||||
for (let val = it.next(); !val.done; val = it.next()) {
|
||||
_map.set(val.value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class WeakSet<T> {
|
||||
private [mapKey]: InstanceType<typeof map>;
|
||||
|
||||
public has(key: T): boolean {
|
||||
return this[mapKey].has(key);
|
||||
}
|
||||
public add(val: T) {
|
||||
this[mapKey].set(val, true);
|
||||
return this;
|
||||
}
|
||||
public delete(val: T): boolean {
|
||||
if (!this[mapKey].has(val)) return false;
|
||||
else {
|
||||
this[mapKey].delete(val);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public clear() {
|
||||
this[mapKey].clear();
|
||||
}
|
||||
|
||||
public constructor(iterable?: Iterable<T>) {
|
||||
const _map = this[mapKey] = new map(true);
|
||||
|
||||
if (iterable != null) {
|
||||
if (Array.isArray(iterable)) {
|
||||
for (let i = 0; i < iterable.length; i++) {
|
||||
if (!(i in iterable)) continue;
|
||||
_map.set(iterable[i], true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const it = (iterable as any)[symbols.iterator]();
|
||||
for (let val = it.next(); !val.done; val = it.next()) {
|
||||
_map.set(val.value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func.setCallable(Set, false);
|
||||
func.setCallable(WeakSet, false);
|
||||
11
lib/src/stdlib/namespaces/console.ts
Normal file
11
lib/src/stdlib/namespaces/console.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { func, json, object } from "../primordials.ts";
|
||||
|
||||
export const console = {};
|
||||
|
||||
function method(name: string, func: Function) {
|
||||
object.defineField(console, name, { c: true, e: false, w: true, v: func });
|
||||
}
|
||||
|
||||
method("log", function log() {
|
||||
func.invoke(print, null, arguments as any);
|
||||
});
|
||||
15
lib/src/stdlib/namespaces/json.ts
Normal file
15
lib/src/stdlib/namespaces/json.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { json, object } from "../primordials.ts";
|
||||
|
||||
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);
|
||||
});
|
||||
60
lib/src/stdlib/namespaces/math.ts
Normal file
60
lib/src/stdlib/namespaces/math.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { number, object } from "../primordials.ts";
|
||||
|
||||
export const Math = {};
|
||||
|
||||
function method(name: string, func: Function) {
|
||||
object.defineField(Math, name, { c: true, e: false, w: true, v: func });
|
||||
}
|
||||
|
||||
method("max", function max() {
|
||||
let res = -number.Infinity;
|
||||
|
||||
for (let i = 0; i < arguments.length; i++) {
|
||||
if (res < arguments[i]) res = arguments[i];
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
let rem = val % 1;
|
||||
if (rem < 0) rem += 1;
|
||||
|
||||
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);
|
||||
});
|
||||
method("log", function log(val: number) {
|
||||
return number.log(val);
|
||||
});
|
||||
137
lib/src/stdlib/primordials.ts
Normal file
137
lib/src/stdlib/primordials.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
const buffSymbol: unique symbol = undefined as any;
|
||||
|
||||
export interface InternalBuffer {
|
||||
length: number;
|
||||
[buffSymbol]: "buffer";
|
||||
}
|
||||
|
||||
export interface SymbolPrimordials {
|
||||
makeSymbol(name: string): symbol;
|
||||
getSymbol(name: string): symbol;
|
||||
getSymbolKey(symbol: symbol): string | undefined;
|
||||
getSymbolDescription(symbol: symbol): string;
|
||||
}
|
||||
export interface NumberPrimordials {
|
||||
NaN: number;
|
||||
Infinity: number;
|
||||
PI: number;
|
||||
E: number;
|
||||
|
||||
parseInt(raw: string | number, radix?: number): number;
|
||||
parseFloat(raw: string | number): number;
|
||||
isNaN(num: number): boolean;
|
||||
|
||||
pow(a: number, b: number): number;
|
||||
log(val: number): number;
|
||||
}
|
||||
export interface StringPrimordials {
|
||||
stringBuild(parts: string[]): string;
|
||||
fromCharCode(char: number): string;
|
||||
fromCodePoint(char: number): string;
|
||||
toCharCode(char: string): number;
|
||||
toCodePoint(char: string, i: number): number;
|
||||
indexOf(str: string, search: string, start: number, reverse?: boolean): number;
|
||||
substring(str: string, start: number, end: number): string;
|
||||
lower(str: string): string;
|
||||
upper(str: string): string;
|
||||
}
|
||||
export interface ObjectPrimordials {
|
||||
defineProperty(obj: object, key: string | number | symbol, conf: { g?: Function, s?: Function, e?: boolean, c?: boolean }): boolean;
|
||||
defineField(obj: object, key: string | number | symbol, conf: { v?: any, e?: boolean, c?: boolean, w?: boolean }): boolean;
|
||||
getOwnMember(obj: object, key: any): PropertyDescriptor | undefined;
|
||||
getOwnMembers(obj: object, onlyEnumerable: boolean): string[];
|
||||
getOwnSymbolMembers(obj: object, onlyEnumerable: boolean): symbol[];
|
||||
getPrototype(obj: object): object | undefined;
|
||||
setPrototype(obj: object, proto?: object): object;
|
||||
preventExt(obj: object): void;
|
||||
seal(obj: object): void;
|
||||
freeze(obj: object): void;
|
||||
|
||||
isArray(obj: any): obj is any[];
|
||||
subarray(arr: any[], start: number, end: number): any[];
|
||||
|
||||
memcpy(src: any[], dst: any[], srcI: number, dstI: number, n: number): void;
|
||||
sort(arr: any[], cb: Function): any[];
|
||||
}
|
||||
export interface BufferPrimordials {
|
||||
buff(n: number): InternalBuffer;
|
||||
backer(arr: number[]): InternalBuffer;
|
||||
start(arr: number[]): number;
|
||||
end(arr: number[]): number;
|
||||
|
||||
uint8(buff: InternalBuffer, start: number, end: number): number[];
|
||||
int8(buff: InternalBuffer, start: number, end: number): number[];
|
||||
int32(buff: InternalBuffer, start: number, end: number): number[];
|
||||
|
||||
isUint8(val: any): val is number[];
|
||||
isInt8(val: any): val is number[];
|
||||
isInt32(val: any): val is number[];
|
||||
is(val: any): val is number[];
|
||||
isBuff(val: any): val is InternalBuffer;
|
||||
}
|
||||
export interface FunctionPrimordials {
|
||||
invokeType(args: IArguments, self: any): "new" | "call";
|
||||
invokeTypeInfer(): "new" | "call";
|
||||
target(): Function | null | undefined;
|
||||
setConstructable(func: Function, flag: boolean): void;
|
||||
setCallable(func: Function, flag: boolean): void;
|
||||
invoke(func: Function, self: any, args: any[]): any;
|
||||
construct(func: Function, self: any, args: any[]): any;
|
||||
}
|
||||
export interface JSONPrimordials {
|
||||
parse(data: string): any;
|
||||
stringify(data: any): string;
|
||||
}
|
||||
|
||||
export interface Primordials {
|
||||
symbol: SymbolPrimordials;
|
||||
number: NumberPrimordials;
|
||||
string: StringPrimordials;
|
||||
object: ObjectPrimordials;
|
||||
function: FunctionPrimordials;
|
||||
json: JSONPrimordials;
|
||||
buffer: BufferPrimordials;
|
||||
map: new (weak?: boolean) => {
|
||||
get(key: any): any;
|
||||
has(key: any): boolean;
|
||||
set(key: any, val: any): void;
|
||||
delete(key: any): void;
|
||||
keys(): any[];
|
||||
clear(): void;
|
||||
size(): number;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
compile(src: string): Function;
|
||||
setGlobalPrototypes(prototype: Record<string, any>): void;
|
||||
now(): number;
|
||||
next(func: () => void): void;
|
||||
schedule(func: () => void, delay: number): () => void;
|
||||
}
|
||||
|
||||
// prevent optimization to "undefined", which doesn't exist yet
|
||||
globalThis.undefined = ({} as any).bogus;
|
||||
export const target = (globalThis as any).target;
|
||||
export const primordials: Primordials = (globalThis as any).primordials;
|
||||
|
||||
export const {
|
||||
symbol,
|
||||
number,
|
||||
string,
|
||||
object,
|
||||
buffer,
|
||||
function: func,
|
||||
json,
|
||||
map,
|
||||
regex,
|
||||
setGlobalPrototypes,
|
||||
compile,
|
||||
now,
|
||||
next,
|
||||
schedule,
|
||||
} = primordials;
|
||||
|
||||
export type regex = InstanceType<typeof regex>;
|
||||
26
lib/src/stdlib/url.ts
Normal file
26
lib/src/stdlib/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\\-+.!~*'();/?:@&=+$,#]"));
|
||||
218
lib/src/stdlib/utils.ts
Normal file
218
lib/src/stdlib/utils.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
import { func, string, symbol } from "./primordials.ts";
|
||||
|
||||
export const valueKey: unique symbol = symbol.makeSymbol("Primitive.value") as any;
|
||||
export namespace symbols {
|
||||
export const asyncIterator: unique symbol = symbol.makeSymbol("Symbol.asyncIterator") as any;
|
||||
export const iterator: unique symbol = symbol.makeSymbol("Symbol.iterator") as any;
|
||||
export const match: unique symbol = symbol.makeSymbol("Symbol.match") as any;
|
||||
export const matchAll: unique symbol = symbol.makeSymbol("Symbol.matchAll") as any;
|
||||
export const replace: unique symbol = symbol.makeSymbol("Symbol.replace") as any;
|
||||
export const search: unique symbol = symbol.makeSymbol("Symbol.search") as any;
|
||||
export const split: unique symbol = symbol.makeSymbol("Symbol.split") as any;
|
||||
export const toStringTag: unique symbol = symbol.makeSymbol("Symbol.toStringTag") as any;
|
||||
export const isConcatSpreadable: unique symbol = symbol.makeSymbol("Symbol.isConcatSpreadable") as any;
|
||||
}
|
||||
|
||||
export interface TypeMap {
|
||||
undefined: undefined;
|
||||
boolean: boolean;
|
||||
string: string;
|
||||
number: number;
|
||||
symbol: symbol;
|
||||
object: null | object;
|
||||
function: Function;
|
||||
}
|
||||
|
||||
export function unwrapThis<T extends keyof TypeMap>(self: any, type: T, constr: Function, name: string, arg = "this", defaultVal?: TypeMap[T]): TypeMap[T] {
|
||||
if (typeof self === type) return self;
|
||||
if (self instanceof constr && valueKey in self) self = self[valueKey];
|
||||
if (typeof self === type) return self;
|
||||
if (defaultVal !== undefined) return defaultVal;
|
||||
throw new TypeError(name + " requires that '" + arg + "' be a " + constr.name);
|
||||
}
|
||||
export function wrapI(i: number, length: number) {
|
||||
if (i < 0) return (i + length) | 0;
|
||||
else return i | 0;
|
||||
}
|
||||
export function limitI(i: number, max: number) {
|
||||
i |= 0;
|
||||
if (i < 0) return 0;
|
||||
else if (i > max) return max;
|
||||
else return i;
|
||||
}
|
||||
|
||||
export type ReplaceRange = { start: number; end: number; matches: string[]; groups?: Record<string, string>; };
|
||||
type ReplaceLiteral = (string | ((_: { groups: string[]; prev: () => string; next: () => string; }) => string))[];
|
||||
|
||||
function parseReplacer(replacer: string, groupN: number) {
|
||||
const parts: ReplaceLiteral = [];
|
||||
let lastI = 0;
|
||||
let lastSlice = 0;
|
||||
|
||||
while (true) {
|
||||
const i = string.indexOf(replacer, "$", lastI);
|
||||
if (i < 0 || i + 1 >= replacer.length) break;
|
||||
lastI = i + 1;
|
||||
|
||||
switch (replacer[i + 1]) {
|
||||
case "$":
|
||||
parts[parts.length] = string.substring(replacer, lastSlice, i);
|
||||
parts[parts.length] = "$";
|
||||
lastSlice = i + 2;
|
||||
continue;
|
||||
case "&":
|
||||
parts[parts.length] = string.substring(replacer, lastSlice, i);
|
||||
parts[parts.length] = ({ groups }) => groups[0];
|
||||
lastSlice = i + 2;
|
||||
continue;
|
||||
case "`":
|
||||
parts[parts.length] = string.substring(replacer, lastSlice, i);
|
||||
parts[parts.length] = ({ prev }) => prev();
|
||||
lastSlice = i + 2;
|
||||
continue;
|
||||
case "'":
|
||||
parts[parts.length] = string.substring(replacer, lastSlice, i);
|
||||
parts[parts.length] = ({ next }) => next();
|
||||
lastSlice = i + 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
let groupI = 0;
|
||||
let hasGroup = false;
|
||||
let consumedN = 1;
|
||||
|
||||
while (i + consumedN < replacer.length) {
|
||||
const code = string.toCharCode(replacer[i + consumedN]);
|
||||
if (code >= 48 && code <= 57) {
|
||||
const newGroupI = groupI * 10 + code - 48;
|
||||
if (newGroupI < 1 || newGroupI >= groupN) break;
|
||||
|
||||
groupI = newGroupI;
|
||||
hasGroup = true;
|
||||
}
|
||||
consumedN++;
|
||||
}
|
||||
|
||||
if (hasGroup) {
|
||||
parts[parts.length] = string.substring(replacer, lastSlice, i);
|
||||
parts[parts.length] = ({ groups }) => groups[groupI];
|
||||
lastSlice = i + consumedN;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (lastSlice === 0) return [replacer];
|
||||
else parts[parts.length] = string.substring(replacer, lastSlice, replacer.length);
|
||||
|
||||
return parts;
|
||||
}
|
||||
function executeReplacer(text: string, match: ReplaceRange, literal: ReplaceLiteral, prevEnd?: number, nextStart?: number) {
|
||||
const res = [];
|
||||
|
||||
for (let i = 0; i < literal.length; i++) {
|
||||
const curr = literal[i];
|
||||
if (typeof curr === "function") res[i] = curr({
|
||||
groups: match.matches,
|
||||
next: () => string.substring(text, prevEnd ?? 0, match.start),
|
||||
prev: () => string.substring(text, match.end, nextStart ?? 0),
|
||||
});
|
||||
else res[i] = curr;
|
||||
}
|
||||
|
||||
return string.stringBuild(res);
|
||||
}
|
||||
export function applyReplaces(text: string, ranges: ReplaceRange[], replace: any, groupN?: number | false) {
|
||||
if (ranges.length === 0) return text;
|
||||
|
||||
const res: string[] = [];
|
||||
let offset = 0;
|
||||
|
||||
if (groupN !== false && typeof replace === "string") {
|
||||
if (groupN == null) {
|
||||
for (let i = 0; i < ranges.length; i++) {
|
||||
const prevEnd = i - 1 >= 0 ? ranges[i - 1].end : undefined;
|
||||
const nextStart = i + 1 < ranges.length ? ranges[i + 1].start : undefined;
|
||||
const range = ranges[i];
|
||||
res[res.length] = string.substring(text, offset, range.start);
|
||||
res[res.length] = executeReplacer(text, range, parseReplacer(replace, range.matches.length), prevEnd, nextStart);
|
||||
offset = range.end;
|
||||
}
|
||||
|
||||
res[res.length] = string.substring(text, offset, text.length);
|
||||
}
|
||||
else {
|
||||
const literal = parseReplacer(replace, groupN);
|
||||
|
||||
for (let i = 0; i < ranges.length; i++) {
|
||||
const prevEnd = i - 1 >= 0 ? ranges[i - 1].end : undefined;
|
||||
const nextStart = i + 1 < ranges.length ? ranges[i + 1].start : undefined;
|
||||
const range = ranges[i];
|
||||
res[res.length] = string.substring(text, offset, range.start);
|
||||
res[res.length] = executeReplacer(text, range, literal, prevEnd, nextStart);
|
||||
offset = range.end;
|
||||
}
|
||||
|
||||
res[res.length] = string.substring(text, offset, text.length);
|
||||
}
|
||||
return string.stringBuild(res);
|
||||
}
|
||||
|
||||
if (typeof replace === "string") {
|
||||
for (let i = 0; i < ranges.length; i++) {
|
||||
const range = ranges[i];
|
||||
res[res.length] = string.substring(text, offset, range.start);
|
||||
res[res.length] = replace;
|
||||
offset = range.end;
|
||||
}
|
||||
|
||||
res[res.length] = string.substring(text, offset, text.length);
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < ranges.length; i++) {
|
||||
const range = ranges[i];
|
||||
const args: any[] = range.matches;
|
||||
args[args.length] = range.start;
|
||||
args[args.length] = text;
|
||||
args[args.length] = range.groups;
|
||||
|
||||
res[res.length] = string.substring(text, offset, range.start);
|
||||
res[res.length] = func.invoke(replace, undefined, args);
|
||||
offset = range.end;
|
||||
}
|
||||
|
||||
res[res.length] = string.substring(text, offset, text.length);
|
||||
}
|
||||
|
||||
return string.stringBuild(res);
|
||||
}
|
||||
|
||||
export function applySplits(text: string, limit: number | undefined, next: (offset: number) => { start: number; end: number; } | undefined) {
|
||||
let lastEnd = 0;
|
||||
let lastEmpty = true;
|
||||
let offset = 0;
|
||||
|
||||
const res: string[] = [];
|
||||
|
||||
while (true) {
|
||||
if (limit != null && limit >= 0 && res.length >= limit) break;
|
||||
|
||||
const curr = next(offset);
|
||||
|
||||
if (curr == null) {
|
||||
if (!lastEmpty || !res.length) res[res.length] = string.substring(text, lastEnd, text.length);
|
||||
break;
|
||||
}
|
||||
|
||||
const { start, end } = curr;
|
||||
const empty = start === end;
|
||||
|
||||
if (offset > 0 || !empty) res[res.length] = string.substring(text, lastEnd, start);
|
||||
|
||||
lastEnd = end;
|
||||
offset = empty ? end + 1 : end;
|
||||
lastEmpty = empty;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
330
lib/src/stdlib/values/array.ts
Normal file
330
lib/src/stdlib/values/array.ts
Normal file
@@ -0,0 +1,330 @@
|
||||
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) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (i in this) func.invoke(cb, self, [this[i], i, this]);
|
||||
}
|
||||
}
|
||||
public join(this: any[], delim = ",") {
|
||||
delim = String(delim);
|
||||
const parts = [];
|
||||
if (delim) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (i) parts[parts.length] = delim;
|
||||
parts[parts.length] = (i in this) ? String(this[i]) : "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
parts[i] = (i in this) ? String(this[i]) : "";
|
||||
}
|
||||
}
|
||||
|
||||
return string.stringBuild(parts);
|
||||
}
|
||||
|
||||
public push(this: any[]) {
|
||||
const start = this.length;
|
||||
for (let i = arguments.length - 1; i >= 0; i--) {
|
||||
this[start + i] = arguments[i];
|
||||
}
|
||||
return this.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 this.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[] = [];
|
||||
|
||||
function add(arr: any) {
|
||||
if (Array.isArray(arr) || arr != null && typeof arr === "object" && symbols.isConcatSpreadable in arr) {
|
||||
const start = res.length;
|
||||
res.length += arr.length;
|
||||
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
if (i in arr) res[start + i] = arr[i];
|
||||
}
|
||||
}
|
||||
else res[res.length] = arr;
|
||||
}
|
||||
|
||||
add(this);
|
||||
|
||||
for (let i = 0; i < arguments.length; i++) {
|
||||
add(arguments[i]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
public slice(this: any[], start = 0, end = this.length) {
|
||||
start = wrapI(start, this.length);
|
||||
end = wrapI(end, this.length);
|
||||
|
||||
if (end <= start) return [];
|
||||
|
||||
const res: any[] = [];
|
||||
res.length = end - start;
|
||||
|
||||
for (let i = 0; i < end - start; i++) {
|
||||
res[i] = this[start + i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
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);
|
||||
|
||||
const res: any[] = [];
|
||||
const change = vals.length - count;
|
||||
|
||||
for (let i = start; i < start + count; i++) {
|
||||
res[i - start] = this[i];
|
||||
}
|
||||
|
||||
if (change < 0) {
|
||||
for (let i = start - change; i < this.length; i++) {
|
||||
this[i + change] = this[i];
|
||||
}
|
||||
this.length = this.length + change;
|
||||
}
|
||||
else {
|
||||
for (let i = this.length - 1; i >= start - change; i--) {
|
||||
this[i + change] = this[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < vals.length; i++) {
|
||||
this[i + start] = vals[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public map(this: any[], cb: Function, self?: any) {
|
||||
const res = [];
|
||||
res.length = this.length;
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (i in this) res[i] = func.invoke(cb, self, [this[i], i, this]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
public filter(this: any[], cb: Function, self?: any) {
|
||||
const res = [];
|
||||
|
||||
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 reduce(this: any[], cb: Function, initial: any) {
|
||||
let i = 0;
|
||||
if (arguments.length <= 1) initial = this[i++];
|
||||
|
||||
for (; i < this.length; i++) {
|
||||
initial = cb(initial, this[i], i, this);
|
||||
}
|
||||
|
||||
return initial;
|
||||
}
|
||||
public some(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 true;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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 includes(this: any[], val: any) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (i in this && this[i] === val) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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 reverse(this: any[]) {
|
||||
const mid = this.length >> 1;
|
||||
const end = this.length - 1;
|
||||
|
||||
for (let i = 0; i < mid; i++) {
|
||||
const tmp = this[i];
|
||||
this[i] = this[end - i];
|
||||
this[end - i] = tmp;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public [symbols.iterator](this: any[]) {
|
||||
let i = 0;
|
||||
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 };
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const res = arr![i];
|
||||
|
||||
if (i in arr!) {
|
||||
i++;
|
||||
return { done: false, value: res };
|
||||
}
|
||||
else i++;
|
||||
}
|
||||
},
|
||||
[symbols.iterator]() { return this; }
|
||||
};
|
||||
}
|
||||
|
||||
public constructor (len: unknown) {
|
||||
if (arguments.length === 1 && typeof len === "number") {
|
||||
const res: any[] = [];
|
||||
res.length = len;
|
||||
return res as any;
|
||||
}
|
||||
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[] {
|
||||
return object.isArray(val);
|
||||
}
|
||||
public static from(val: any, cb?: Function, self?: any): any[] {
|
||||
if (symbols.iterator in val) {
|
||||
const res = [];
|
||||
const it = val[symbols.iterator]();
|
||||
|
||||
if (cb) {
|
||||
for (let val = it.next(); !val.done; val = it.next()) {
|
||||
res[res.length] = func.invoke(cb, self, [val.value]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let val = it.next(); !val.done; val = it.next()) {
|
||||
res[res.length] = val.value;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
else if ("length" in val) {
|
||||
const res = [];
|
||||
|
||||
if (cb) {
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
if (i in val) res[i] = func.invoke(cb, self, [val[i]]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
if (i in val) res[i] = val[i];
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
else if (val == null) throw new Error("Illegal argument");
|
||||
else return [];
|
||||
}
|
||||
}
|
||||
|
||||
func.setCallable(Array, true);
|
||||
func.setConstructable(Array, true);
|
||||
|
||||
return Array as any as typeof Array & ((value?: unknown) => object);
|
||||
})();
|
||||
export type Array = InstanceType<typeof Array>;
|
||||
29
lib/src/stdlib/values/boolean.ts
Normal file
29
lib/src/stdlib/values/boolean.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { func } from "../primordials.ts";
|
||||
import { unwrapThis, valueKey } from "../utils.ts";
|
||||
|
||||
export const Boolean = (() => {
|
||||
class Boolean {
|
||||
[valueKey]!: boolean;
|
||||
|
||||
public toString() {
|
||||
return "" + unwrapThis(this, "boolean", Boolean, "Boolean.prototype.toString");
|
||||
}
|
||||
public valueOf() {
|
||||
return unwrapThis(this, "boolean", Boolean, "Boolean.prototype.valueOf");
|
||||
}
|
||||
|
||||
public constructor(value?: unknown) {
|
||||
if (func.invokeType(arguments, this) === "call") {
|
||||
if (arguments.length === 0) return false as any;
|
||||
else return !!value as any;
|
||||
}
|
||||
this[valueKey] = (Boolean as any)(value);
|
||||
}
|
||||
};
|
||||
|
||||
func.setCallable(Boolean, true);
|
||||
func.setConstructable(Boolean, true);
|
||||
|
||||
return Boolean as any as typeof Boolean & ((value?: unknown) => symbol);
|
||||
})();
|
||||
export type Boolean = InstanceType<typeof Boolean>;
|
||||
39
lib/src/stdlib/values/errors.ts
Normal file
39
lib/src/stdlib/values/errors.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { func, object } from "../primordials.ts";
|
||||
import { String } from "./string.ts";
|
||||
|
||||
export class Error {
|
||||
public declare name: string;
|
||||
public declare message: string;
|
||||
|
||||
public toString() {
|
||||
let res = this.name || "Error";
|
||||
const msg = this.message;
|
||||
|
||||
if (msg) res += ": " + msg;
|
||||
return res;
|
||||
}
|
||||
|
||||
public constructor (msg = "") {
|
||||
if (func.invokeType(arguments, this) === "call") return new Error(msg);
|
||||
this.message = String(msg);
|
||||
}
|
||||
}
|
||||
object.defineField(Error.prototype, "name", { c: true, e: false, w: true, v: "Error" });
|
||||
object.defineField(Error.prototype, "message", { c: true, e: false, w: true, v: "" });
|
||||
func.setCallable(Error, true);
|
||||
func.setConstructable(Error, true);
|
||||
|
||||
export class SyntaxError extends Error { }
|
||||
object.defineField(SyntaxError.prototype, "name", { c: true, e: false, w: true, v: "SyntaxError" });
|
||||
func.setCallable(SyntaxError, true);
|
||||
func.setConstructable(SyntaxError, true);
|
||||
|
||||
export class TypeError extends Error { }
|
||||
object.defineField(TypeError.prototype, "name", { c: true, e: false, w: true, v: "TypeError" });
|
||||
func.setCallable(TypeError, true);
|
||||
func.setConstructable(TypeError, true);
|
||||
|
||||
export class RangeError extends Error { }
|
||||
object.defineField(RangeError.prototype, "name", { c: true, e: false, w: true, v: "RangeError" });
|
||||
func.setCallable(RangeError, true);
|
||||
func.setConstructable(RangeError, true);
|
||||
82
lib/src/stdlib/values/function.ts
Normal file
82
lib/src/stdlib/values/function.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { compile, func, string } from "../primordials.ts";
|
||||
import { String } from "./string.ts";
|
||||
|
||||
export const Function = (() => {
|
||||
class Function {
|
||||
declare public readonly name: string;
|
||||
declare public readonly length: number;
|
||||
|
||||
public toString(this: Function) {
|
||||
if (this.name !== "") return "function " + this.name + "(...) { ... }";
|
||||
else return "function (...) { ... }";
|
||||
}
|
||||
public valueOf() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public apply(this: (...args: any) => any, self: any, args: any[]) {
|
||||
return func.invoke(this, self, args);
|
||||
}
|
||||
public call(this: (...args: any) => any, self: any) {
|
||||
const args: any[] = [];
|
||||
for (let i = arguments.length - 1; i >= 1; i--) args[i - 1] = arguments[i];
|
||||
return func.invoke(this, self, args);
|
||||
}
|
||||
public bind(this: (...args: any) => any, self: any) {
|
||||
const cb = this;
|
||||
if (arguments.length === 0) return function (this: any) { return func.invoke(cb, this, arguments as any) };
|
||||
if (arguments.length <= 1) return function () { return func.invoke(cb, self, arguments as any); }
|
||||
|
||||
const base: any[] = [];
|
||||
const offset = arguments.length - 1;
|
||||
base.length = offset;
|
||||
|
||||
for (let i = 0; i < offset; i++) base[i] = arguments[i + 1];
|
||||
|
||||
return function () {
|
||||
for (let i = 0; i < arguments.length; i++) {
|
||||
base[offset + i] = arguments[i];
|
||||
}
|
||||
|
||||
return func.invoke(cb, self, base);
|
||||
};
|
||||
}
|
||||
|
||||
public constructor () {
|
||||
const parts = ["(function anonymous("];
|
||||
for (let i = 0; i < arguments.length - 1; i++) {
|
||||
if (i > 0) parts[parts.length] = ",";
|
||||
parts[parts.length] = arguments[i];
|
||||
}
|
||||
parts[parts.length] = "){\n";
|
||||
parts[parts.length] = String(arguments[arguments.length - 1]);
|
||||
parts[parts.length] = "\n})";
|
||||
var res = compile(string.stringBuild(parts))();
|
||||
return res;
|
||||
}
|
||||
|
||||
public static compile(src = "", { globals = [], wrap = false }: { globals?: string[], wrap?: boolean } = {}) {
|
||||
const parts = [];
|
||||
|
||||
if (wrap) parts[parts.length] = "return (function() {\n";
|
||||
if (globals.length > 0) {
|
||||
parts[parts.length] = "let {";
|
||||
for (let i = 0; i < globals.length; i++) {
|
||||
if (i > 0) parts[parts.length] = ",";
|
||||
parts[parts.length] = globals[i];
|
||||
}
|
||||
parts[parts.length] = "} = arguments[0];";
|
||||
}
|
||||
parts[parts.length] = src;
|
||||
if (wrap) parts[parts.length] = "\n})(arguments[0])";
|
||||
|
||||
const res = compile(string.stringBuild(parts));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
func.setCallable(Function, true);
|
||||
func.setConstructable(Function, true);
|
||||
|
||||
return Function as any as typeof Function & ((value?: unknown) => (...args: any[]) => any);
|
||||
})();
|
||||
77
lib/src/stdlib/values/number.ts
Normal file
77
lib/src/stdlib/values/number.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { func, number, object } from "../primordials.ts";
|
||||
import { unwrapThis, valueKey } from "../utils.ts";
|
||||
|
||||
export const Number = (() => {
|
||||
class Number {
|
||||
[valueKey]!: number;
|
||||
|
||||
public toString() {
|
||||
return "" + unwrapThis(this, "number", Number, "Number.prototype.toString");
|
||||
}
|
||||
public valueOf() {
|
||||
return unwrapThis(this, "number", Number, "Number.prototype.toString");
|
||||
}
|
||||
|
||||
public constructor (value?: unknown) {
|
||||
if (func.invokeType(arguments, this) === "call") {
|
||||
if (arguments.length === 0) return 0 as any;
|
||||
else return +(value as any) as any;
|
||||
}
|
||||
this[valueKey] = (Number as any)(value);
|
||||
}
|
||||
|
||||
public static isFinite(value: number) {
|
||||
value = unwrapThis(value, "number", Number, "Number.isFinite", "value");
|
||||
if (value === undefined || value !== value) return false;
|
||||
if (value === number.Infinity || value === -number.Infinity) return false;
|
||||
return true;
|
||||
}
|
||||
public static isInteger(value: number) {
|
||||
value = unwrapThis(value, "number", Number, "Number.isInteger", "value");
|
||||
if (value === undefined) return false;
|
||||
return number.parseInt(value) === value;
|
||||
}
|
||||
public static isNaN(value: number) {
|
||||
return number.isNaN(value);
|
||||
}
|
||||
public static isSafeInteger(value: number) {
|
||||
value = unwrapThis(value, "number", Number, "Number.isSafeInteger", "value");
|
||||
if (value === undefined || number.parseInt(value) !== value) return false;
|
||||
return value >= -9007199254740991 && value <= 9007199254740991;
|
||||
}
|
||||
public static parseFloat(value: unknown) {
|
||||
if (typeof value === "number") return value;
|
||||
else return number.parseFloat(value + "");
|
||||
}
|
||||
public static parseInt(value: unknown, radix = 10) {
|
||||
radix = +radix;
|
||||
if (number.isNaN(radix)) radix = 10;
|
||||
|
||||
if (typeof value === "number") return number.parseInt(value, radix);
|
||||
else return number.parseInt(value + "", radix);
|
||||
}
|
||||
|
||||
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 });
|
||||
object.defineField(Number, "MIN_SAFE_INTEGER", { c: false, e: false, w: false, v: -9007199254740991 });
|
||||
object.defineField(Number, "MAX_SAFE_INTEGER", { c: false, e: false, w: false, v: 9007199254740991 });
|
||||
object.defineField(Number, "POSITIVE_INFINITY", { c: false, e: false, w: false, v: +number.Infinity });
|
||||
object.defineField(Number, "NEGATIVE_INFINITY", { c: false, e: false, w: false, v: -number.Infinity });
|
||||
object.defineField(Number, "NaN", { c: false, e: false, w: false, v: number.NaN });
|
||||
object.defineField(Number, "MAX_VALUE", { c: false, e: false, w: false, v: 1.7976931348623157e+308 });
|
||||
object.defineField(Number, "MIN_VALUE", { c: false, e: false, w: false, v: 5e-324 });
|
||||
func.setCallable(Number, true);
|
||||
func.setConstructable(Number, true);
|
||||
|
||||
return Number as any as typeof Number & ((value?: unknown) => number);
|
||||
})();
|
||||
export type Number = InstanceType<typeof Number>;
|
||||
208
lib/src/stdlib/values/object.ts
Normal file
208
lib/src/stdlib/values/object.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
import { Boolean } from "./boolean.ts";
|
||||
import { TypeError } from "./errors.ts";
|
||||
import { Number } from "./number.ts";
|
||||
import { func, object } from "../primordials.ts";
|
||||
import { String } from "./string.ts";
|
||||
import { symbols, valueKey } from "../utils.ts";
|
||||
import { Symbol } from "./symbol.ts";
|
||||
|
||||
export const Object = (() => {
|
||||
class Object {
|
||||
public toString(this: unknown) {
|
||||
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 as any)[symbols.toStringTag] + "]";
|
||||
else if (object.isArray(this)) return "[object Array]";
|
||||
else return "[object Object]";
|
||||
}
|
||||
else if (typeof this === "number" || this instanceof Number) return "[object Number]";
|
||||
else if (typeof this === "symbol" || this instanceof Symbol) return "[object Symbol]";
|
||||
else if (typeof this === "string" || this instanceof String) return "[object String]";
|
||||
else if (typeof this === "boolean" || this instanceof Boolean) return "[object Boolean]";
|
||||
else if (typeof this === "function") return "[object Function]";
|
||||
}
|
||||
public valueOf() {
|
||||
return this;
|
||||
}
|
||||
public hasOwnProperty(key: string) {
|
||||
return object.getOwnMember(this, key) != null;
|
||||
}
|
||||
|
||||
public get __proto__() {
|
||||
return object.getPrototype(this);
|
||||
}
|
||||
public set __proto__(val) {
|
||||
object.setPrototype(this, val);
|
||||
}
|
||||
|
||||
public constructor (value?: unknown) {
|
||||
if (typeof value === 'object' && value !== null) return value as any;
|
||||
if (typeof value === 'string') return new String(value) as any;
|
||||
if (typeof value === 'number') return new Number(value) as any;
|
||||
if (typeof value === 'boolean') return new Boolean(value) as any;
|
||||
if (typeof value === 'symbol') {
|
||||
const res: Symbol = {} as any;
|
||||
object.setPrototype(res, Symbol.prototype);
|
||||
res[valueKey] = value;
|
||||
return res as any;
|
||||
}
|
||||
|
||||
return {} as any;
|
||||
}
|
||||
|
||||
public static getOwnPropertyDescriptor(obj: object, key: any) {
|
||||
return object.getOwnMember(obj, key);
|
||||
}
|
||||
public static getOwnPropertyNames(obj: object): string[] {
|
||||
return object.getOwnMembers(obj, false);
|
||||
}
|
||||
public static getOwnPropertySymbols(obj: object): symbol[] {
|
||||
return object.getOwnSymbolMembers(obj, false);
|
||||
}
|
||||
|
||||
public static defineProperty(obj: object, key: string | symbol, desc: PropertyDescriptor) {
|
||||
if (obj === null || typeof obj !== "function" && typeof obj !== "object") {
|
||||
throw new TypeError("Object.defineProperty called on non-object");
|
||||
}
|
||||
if (desc === null || typeof desc !== "function" && typeof desc !== "object") {
|
||||
throw new TypeError("Property description must be an object: " + desc);
|
||||
}
|
||||
const res: any = {};
|
||||
|
||||
if ("get" in desc || "set" in desc) {
|
||||
if ("get" in desc) {
|
||||
const get = desc.get;
|
||||
if (get !== undefined && typeof get !== "function") throw new TypeError("Getter must be a function: " + get);
|
||||
res.g = get;
|
||||
}
|
||||
if ("set" in desc) {
|
||||
const set = desc.set;
|
||||
if (set !== undefined && typeof set !== "function") throw new TypeError("Setter must be a function: " + set);
|
||||
res.s = set;
|
||||
}
|
||||
if ("enumerable" in desc) res.e = !!desc.enumerable;
|
||||
if ("configurable" in desc) res.c = !!desc.configurable;
|
||||
|
||||
if (!object.defineProperty(obj, key, res)) throw new TypeError("Cannot redefine property: " + String(key));
|
||||
}
|
||||
else {
|
||||
if ("enumerable" in desc) res.e = !!desc.enumerable;
|
||||
if ("configurable" in desc) res.c = !!desc.configurable;
|
||||
if ("writable" in desc) res.w = !!desc.writable;
|
||||
if ("value" in desc) res.v = desc.value;
|
||||
|
||||
if (!object.defineField(obj, key, res)) throw new TypeError("Cannot redefine property: " + String(key));
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
public static defineProperties(obj: object, desc: PropertyDescriptorMap) {
|
||||
const keys = object.getOwnMembers(desc, true) as ((keyof typeof obj) & string)[];
|
||||
const symbols = object.getOwnSymbolMembers(desc, true) as ((keyof typeof obj) & symbol)[];
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
Object.defineProperty(obj, keys[i], desc[keys[i]]);
|
||||
}
|
||||
for (let i = 0; i < symbols.length; i++) {
|
||||
Object.defineProperty(obj, symbols[i], desc[symbols[i]]);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
public static create(proto: object, desc?: PropertyDescriptorMap) {
|
||||
let res = object.setPrototype({}, proto);
|
||||
if (desc != null) this.defineProperties(res, desc);
|
||||
|
||||
return res;
|
||||
}
|
||||
public static assign(target: any) {
|
||||
for (let i = 1; i < arguments.length; i++) {
|
||||
const obj = arguments[i];
|
||||
const keys = object.getOwnMembers(obj, false);
|
||||
const symbols = object.getOwnSymbolMembers(obj, false);
|
||||
|
||||
for (let j = 0; j < keys.length; j++) {
|
||||
target[keys[j]] = obj[keys[j]];
|
||||
}
|
||||
for (let j = 0; j < symbols.length; j++) {
|
||||
target[symbols[j]] = obj[symbols[j]];
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
public static setPrototypeOf(obj: object, proto: object | null) {
|
||||
object.setPrototype(obj, proto!);
|
||||
}
|
||||
public static getPrototypeOf(obj: object) {
|
||||
return object.getPrototype(obj) || null;
|
||||
}
|
||||
|
||||
public static keys(obj: any) {
|
||||
const res: any[] = [];
|
||||
const keys = object.getOwnMembers(obj, true);
|
||||
const symbols = object.getOwnSymbolMembers(obj, true);
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
res[res.length] = keys[i];
|
||||
}
|
||||
for (let i = 0; i < symbols.length; i++) {
|
||||
res[res.length] = symbols[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
public static values(obj: any) {
|
||||
const res: any[] = [];
|
||||
const keys = object.getOwnMembers(obj, true);
|
||||
const symbols = object.getOwnSymbolMembers(obj, true);
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
res[res.length] = obj[keys[i]];
|
||||
}
|
||||
for (let i = 0; i < symbols.length; i++) {
|
||||
res[res.length] = obj[symbols[i]];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
public static entries(obj: any) {
|
||||
const res: [any, any][] = [];
|
||||
const keys = object.getOwnMembers(obj, true);
|
||||
const symbols = object.getOwnSymbolMembers(obj, true);
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
res[res.length] = [keys[i], obj[keys[i]]];
|
||||
}
|
||||
for (let i = 0; i < symbols.length; i++) {
|
||||
res[res.length] = [symbols[i], obj[symbols[i]]];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static preventExtensions(obj: object) {
|
||||
object.preventExt(obj);
|
||||
return obj;
|
||||
}
|
||||
public static seal(obj: object) {
|
||||
object.seal(obj);
|
||||
return obj;
|
||||
}
|
||||
public static freeze(obj: object) {
|
||||
object.freeze(obj);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
object.defineProperty(Object.prototype, "__proto__", { e: false });
|
||||
object.setPrototype(Object.prototype, undefined);
|
||||
|
||||
func.setCallable(Object, true);
|
||||
func.setConstructable(Object, true);
|
||||
|
||||
return Object as any as typeof Object & ((value?: unknown) => object);
|
||||
})();
|
||||
export type Object = InstanceType<typeof Object>;
|
||||
138
lib/src/stdlib/values/regex.ts
Normal file
138
lib/src/stdlib/values/regex.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import { func, regex, symbol } from "../primordials.ts";
|
||||
import { String } from "./string.ts";
|
||||
import { type ReplaceRange } from "../utils.ts";
|
||||
import { applyReplaces } from "../utils.ts";
|
||||
import { applySplits } from "../utils.ts";
|
||||
import { symbols } from "../utils.ts";
|
||||
|
||||
const regexKey: unique symbol = symbol.makeSymbol("RegExp.impl") as any;
|
||||
|
||||
export class RegExp {
|
||||
private [regexKey]!: InstanceType<typeof regex>;
|
||||
|
||||
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 constructor(source: any, flags = "") {
|
||||
if (func.invokeType(arguments, this) === "call") return new RegExp(source, flags);
|
||||
|
||||
source = this.source = String(typeof source === "object" && "source" in source ? source.source : source);
|
||||
flags = String(flags);
|
||||
|
||||
let indices = false;
|
||||
let global = false;
|
||||
let ignoreCase = false;
|
||||
let multiline = false;
|
||||
let dotall = false;
|
||||
let unicode = false;
|
||||
let unicodeSets = false;
|
||||
let sticky = false;
|
||||
|
||||
for (let i = 0; i < flags.length; i++) {
|
||||
switch (flags[i]) {
|
||||
case "d": indices = true; break;
|
||||
case "g": global = true; break;
|
||||
case "i": ignoreCase = true; break;
|
||||
case "m": multiline = true; break;
|
||||
case "s": dotall = true; break;
|
||||
case "u": unicode = true; break;
|
||||
case "v": unicodeSets = true; break;
|
||||
case "y": sticky = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
flags = "";
|
||||
if (indices) flags += "d";
|
||||
if (global) flags += "g";
|
||||
if (ignoreCase) flags += "i";
|
||||
if (multiline) flags += "m";
|
||||
if (dotall) flags += "s";
|
||||
if (unicode) flags += "u";
|
||||
if (unicodeSets) flags += "v";
|
||||
if (sticky) flags += "y";
|
||||
this.flags = flags;
|
||||
this.indices = indices;
|
||||
this.global = global;
|
||||
this.ignoreCase = ignoreCase;
|
||||
this.multiline = multiline;
|
||||
this.dotall = dotall;
|
||||
this.unicode = unicode;
|
||||
this.unicodeSets = unicodeSets;
|
||||
this.sticky = sticky;
|
||||
|
||||
this[regexKey] = new regex(source, multiline, ignoreCase, dotall, unicode, unicodeSets);
|
||||
}
|
||||
|
||||
public exec(target: string) {
|
||||
const useLast = this.global || this.sticky;
|
||||
const start = useLast ? this.lastIndex : 0;
|
||||
|
||||
const match = this[regexKey].exec(target, start, this.indices);
|
||||
if (match != null && !(this.sticky && match.matches.index !== start)) {
|
||||
if (useLast) this.lastIndex = match.end;
|
||||
return match.matches;
|
||||
}
|
||||
|
||||
if (useLast) this.lastIndex = 0;
|
||||
return null;
|
||||
}
|
||||
public test(target: string) {
|
||||
return this.exec(target) != null;
|
||||
}
|
||||
|
||||
public [symbols.split](target: string, limit?: number) {
|
||||
return applySplits(target, limit, offset => {
|
||||
const val = this[regexKey].exec(target, offset, false);
|
||||
if (val == null) return undefined;
|
||||
|
||||
return { start: val.matches.index!, end: val.end };
|
||||
});
|
||||
}
|
||||
public [symbols.replace](target: string, replacer: any) {
|
||||
const matches: ReplaceRange[] = [];
|
||||
const regex = this[regexKey];
|
||||
|
||||
if (this.global) {
|
||||
let offset = 0;
|
||||
|
||||
while (true) {
|
||||
const match = regex.exec(target, offset, false);
|
||||
if (match == null) break;
|
||||
|
||||
const start = match.matches.index;
|
||||
const end = match.end;
|
||||
const arr: string[] = [];
|
||||
for (let i = 0; i < match.matches.length; i++) {
|
||||
arr[i] = match.matches[i];
|
||||
}
|
||||
|
||||
matches[matches.length] = { start: match.matches.index!, end: match.end, matches: arr };
|
||||
|
||||
if (start === end) offset = start + 1;
|
||||
else offset = end;
|
||||
}
|
||||
|
||||
return applyReplaces(target, matches, replacer, regex.groupCount() + 1);
|
||||
}
|
||||
else {
|
||||
const match = this.exec(target);
|
||||
if (match != null) matches[0] = {
|
||||
start: match.index!,
|
||||
end: match.index! + match[0].length,
|
||||
matches: match,
|
||||
}
|
||||
}
|
||||
|
||||
return applyReplaces(target, matches, replacer, regex.groupCount() + 1);
|
||||
}
|
||||
}
|
||||
277
lib/src/stdlib/values/string.ts
Normal file
277
lib/src/stdlib/values/string.ts
Normal file
@@ -0,0 +1,277 @@
|
||||
import { TypeError } from "./errors.ts";
|
||||
import { func, number, regex, string } from "../primordials.ts";
|
||||
import { RegExp } from "./regex.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);
|
||||
|
||||
export const String = (() => {
|
||||
class String {
|
||||
[valueKey]!: 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");
|
||||
}
|
||||
public valueOf() {
|
||||
return unwrapThis(this, "string", String, "String.prototype.valueOf");
|
||||
}
|
||||
|
||||
public includes(search: string, offset = 0) {
|
||||
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");
|
||||
offset = +offset;
|
||||
return string.indexOf(self, search, offset, false);
|
||||
}
|
||||
public lastIndexOf(search: string, offset?: number) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.lastIndexOf");
|
||||
if (offset == null) offset = self.length;
|
||||
offset = +offset;
|
||||
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 trimLeft() {
|
||||
return func.invoke(String.prototype.trimStart, this, []);
|
||||
}
|
||||
public trimRight() {
|
||||
return func.invoke(String.prototype.trimEnd, this, []);
|
||||
}
|
||||
|
||||
public charAt(i: number) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.charAt");
|
||||
return self[i];
|
||||
}
|
||||
public charCodeAt(i: number) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.charCodeAt");
|
||||
return self[i] ? string.toCharCode(self[i]) : number.NaN;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public split(val?: any, limit?: number) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.split");
|
||||
if (val === undefined) return [self];
|
||||
if (val !== null && typeof val === "object" && symbols.split in val) {
|
||||
return val[symbols.split](self, limit);
|
||||
}
|
||||
|
||||
val = (String as any)(val);
|
||||
|
||||
return applySplits(self, limit, offset => {
|
||||
const start = string.indexOf(self, val, offset, false);
|
||||
if (start < 0) return undefined;
|
||||
else return { start, end: start + val.length };
|
||||
});
|
||||
}
|
||||
public replace(val: any, replacer: any) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.replace");
|
||||
if (val !== null && typeof val === "object" && symbols.replace in val) {
|
||||
return val[symbols.replace](self, replacer);
|
||||
}
|
||||
else val = (String as any)(val);
|
||||
|
||||
const i = string.indexOf(self, val, 0);
|
||||
return applyReplaces(self, [{ start: i, end: i + val.length, matches: [val] }], replacer, false);
|
||||
}
|
||||
public replaceAll(val: any, replacer: any) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.replaceAll");
|
||||
if (val !== null && typeof val === "object" && symbols.replace in val) {
|
||||
if (val instanceof RegExp && !val.global) throw new TypeError("replaceAll must be called with a global RegExp");
|
||||
return val[symbols.replace](self, replacer);
|
||||
}
|
||||
else val = (String as any)(val);
|
||||
|
||||
let offset = 0;
|
||||
const matches: ReplaceRange[] = [];
|
||||
const add = val.length === 0 ? 1 : val.length;
|
||||
|
||||
while (true) {
|
||||
const i = string.indexOf(self, val, offset);
|
||||
if (i < 0) break;
|
||||
|
||||
matches[matches.length] = { start: i, end: i + val.length, matches: [val] };
|
||||
if (val.length === 0)
|
||||
offset = i + add;
|
||||
}
|
||||
|
||||
return applyReplaces(self, matches, replacer, false);
|
||||
}
|
||||
public repeat(n: number) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.replaceAll");
|
||||
const res: string[] = [];
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
res[i] = self;
|
||||
}
|
||||
|
||||
return string.stringBuild(res);
|
||||
}
|
||||
|
||||
public slice(start = 0, end?: number) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.slice");
|
||||
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);
|
||||
}
|
||||
public substring(start = 0, end?: number) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.substring");
|
||||
if (end === undefined) end = self.length;
|
||||
start = limitI(start, self.length);
|
||||
end = limitI(end, self.length);
|
||||
|
||||
if (end <= start) return "";
|
||||
return string.substring(self, start, end);
|
||||
}
|
||||
public substr(start = 0, count?: number) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.substr");
|
||||
count = self.length - start;
|
||||
start = limitI(start, self.length);
|
||||
count = limitI(count, self.length - start);
|
||||
|
||||
if (count <= 0) return "";
|
||||
return string.substring(self, start, count + start);
|
||||
}
|
||||
public concat() {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.concat");
|
||||
const parts = [self];
|
||||
for (let i = 0; i < arguments.length; i++) {
|
||||
parts[i + 1] = (String as any)(arguments[i]);
|
||||
}
|
||||
|
||||
return string.stringBuild(parts);
|
||||
}
|
||||
|
||||
public toLowerCase() {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.toLowerCase");
|
||||
return string.lower(self);
|
||||
}
|
||||
public toUpperCase() {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.toLowerCase");
|
||||
return string.upper(self);
|
||||
}
|
||||
|
||||
public match(regex: RegExp) {
|
||||
const self = unwrapThis(this, "string", String, "String.prototype.match");
|
||||
if (!(regex instanceof RegExp)) throw new TypeError("Regexp expected for String.prototype.match");
|
||||
|
||||
if (regex.global) {
|
||||
let matches: string[] | null = null;
|
||||
|
||||
while (true) {
|
||||
const match = regex.exec(self);
|
||||
if (match == null) break;
|
||||
|
||||
matches ||= [];
|
||||
matches[matches.length] = match[0];
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
else return regex.exec(self);
|
||||
}
|
||||
|
||||
public [symbols.iterator]() {
|
||||
var i = 0;
|
||||
var arr: string | undefined = unwrapThis(this, "string", String, "String.prototype[Symbol.iterator]");
|
||||
|
||||
return {
|
||||
next () {
|
||||
if (arr == null) return { done: true, value: undefined };
|
||||
if (i > arr.length) {
|
||||
arr = undefined;
|
||||
return { done: true, value: undefined };
|
||||
}
|
||||
else {
|
||||
var val = arr[i++];
|
||||
if (i >= arr.length) arr = undefined;
|
||||
return { done: false, value: val };
|
||||
}
|
||||
},
|
||||
[symbols.iterator]() { return this; }
|
||||
};
|
||||
}
|
||||
|
||||
public constructor (value?: unknown) {
|
||||
if (func.invokeType(arguments, this) === "call") {
|
||||
if (arguments.length === 0) return "" as any;
|
||||
else if (typeof value === "symbol") return value.toString() as any;
|
||||
else return (value as any) + "" as any;
|
||||
}
|
||||
this[valueKey] = (String as any)(value);
|
||||
}
|
||||
|
||||
public static fromCharCode() {
|
||||
const res: string[] = [];
|
||||
res[arguments.length] = "";
|
||||
|
||||
for (let i = 0; i < arguments.length; i++) {
|
||||
res[i] = string.fromCharCode(+arguments[i]);
|
||||
}
|
||||
|
||||
return string.stringBuild(res);
|
||||
}
|
||||
public static fromCodePoint() {
|
||||
const res: string[] = [];
|
||||
res[arguments.length] = "";
|
||||
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
res[i] = string.fromCodePoint(+arguments[i]);
|
||||
}
|
||||
return string.stringBuild(res);
|
||||
}
|
||||
}
|
||||
|
||||
func.setCallable(String, true);
|
||||
func.setConstructable(String, true);
|
||||
|
||||
return String as any as typeof String & ((value?: unknown) => string);
|
||||
})();
|
||||
export type String = InstanceType<typeof String>;
|
||||
53
lib/src/stdlib/values/symbol.ts
Normal file
53
lib/src/stdlib/values/symbol.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { func, object, symbol } from "../primordials.ts";
|
||||
import { symbols, unwrapThis, valueKey } from "../utils.ts";
|
||||
|
||||
export const Symbol = (() => {
|
||||
class Symbol {
|
||||
[valueKey]!: symbol;
|
||||
|
||||
get description() {
|
||||
return symbol.getSymbolDescription(unwrapThis(this, "symbol", Symbol, "Symbol.prototype.description"));
|
||||
}
|
||||
|
||||
public toString() {
|
||||
return "Symbol(" + unwrapThis(this, "symbol", Symbol, "Symbol.prototype.toString").description + ")";
|
||||
}
|
||||
public valueOf() {
|
||||
return unwrapThis(this, "symbol", Symbol, "Symbol.prototype.valueOf");
|
||||
}
|
||||
|
||||
public constructor(name = "") {
|
||||
return symbol.makeSymbol(name + "") as any;
|
||||
}
|
||||
|
||||
public static for(name: string) {
|
||||
return symbol.getSymbol(name + "");
|
||||
}
|
||||
|
||||
declare public static readonly asyncIterator: unique symbol;
|
||||
declare public static readonly iterator: unique symbol;
|
||||
declare public static readonly match: unique symbol;
|
||||
declare public static readonly matchAll: unique symbol;
|
||||
declare public static readonly replace: unique symbol;
|
||||
declare public static readonly search: unique symbol;
|
||||
declare public static readonly split: unique symbol;
|
||||
declare public static readonly toStringTag: unique symbol;
|
||||
};
|
||||
|
||||
func.setCallable(Symbol, true);
|
||||
func.setConstructable(Symbol, false);
|
||||
|
||||
object.defineField(Symbol, "asyncIterator", { c: false, e: false, w: false, v: symbols.asyncIterator });
|
||||
object.defineField(Symbol, "iterator", { c: false, e: false, w: false, v: symbols.iterator });
|
||||
object.defineField(Symbol, "match", { c: false, e: false, w: false, v: symbols.match });
|
||||
object.defineField(Symbol, "matchAll", { c: false, e: false, w: false, v: symbols.matchAll });
|
||||
object.defineField(Symbol, "replace", { c: false, e: false, w: false, v: symbols.replace });
|
||||
object.defineField(Symbol, "search", { c: false, e: false, w: false, v: symbols.search });
|
||||
object.defineField(Symbol, "split", { c: false, e: false, w: false, v: symbols.split });
|
||||
object.defineField(Symbol, "toStringTag", { c: false, e: false, w: false, v: symbols.toStringTag });
|
||||
object.defineField(Symbol, "isConcatSpreadable", { c: false, e: false, w: false, v: symbols.isConcatSpreadable });
|
||||
|
||||
return Symbol as any as typeof Symbol & ((name?: string) => ReturnType<SymbolConstructor>);
|
||||
})();
|
||||
export type Symbol = InstanceType<typeof Symbol>;
|
||||
|
||||
4
lib/src/transpiler/_entry.ts
Normal file
4
lib/src/transpiler/_entry.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import coffeescript from "./coffeescript.ts";
|
||||
import babel from "./babel.ts";
|
||||
|
||||
register(v => coffeescript(babel(v)));
|
||||
24
lib/src/transpiler/babel.ts
Normal file
24
lib/src/transpiler/babel.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { SourceMap } from "./map.ts";
|
||||
import { transform, availablePresets } from "@babel/standalone";
|
||||
|
||||
export default function babel(next: Compiler): Compiler {
|
||||
print("Loaded babel!");
|
||||
|
||||
return (filename, code, prevMap) => {
|
||||
const res = transform(code, {
|
||||
filename,
|
||||
sourceMaps: true,
|
||||
presets: [availablePresets.env],
|
||||
});
|
||||
|
||||
const map = SourceMap.parse({
|
||||
file: "babel-internal://" + filename,
|
||||
mappings: res.map!.mappings,
|
||||
sources: [filename],
|
||||
});
|
||||
|
||||
registerSource(filename, code);
|
||||
return next("babel-internal://" + filename, res.code!, SourceMap.chain(map, prevMap));
|
||||
};
|
||||
}
|
||||
|
||||
27
lib/src/transpiler/coffeescript.ts
Normal file
27
lib/src/transpiler/coffeescript.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { compile } from "coffeescript";
|
||||
import { SourceMap } from "./map.ts";
|
||||
|
||||
export default function coffee(next: Compiler): Compiler {
|
||||
print("Loaded coffeescript!");
|
||||
|
||||
return (filename, code, prevMap) => {
|
||||
const {
|
||||
js: result,
|
||||
v3SourceMap: rawMap,
|
||||
} = compile(code, {
|
||||
filename,
|
||||
sourceMap: true,
|
||||
bare: true,
|
||||
});
|
||||
|
||||
const map = SourceMap.parse({
|
||||
file: "coffee-internal://" + filename,
|
||||
mappings: JSON.parse(rawMap).mappings,
|
||||
sources: [filename],
|
||||
});
|
||||
|
||||
registerSource(filename, code);
|
||||
return next("coffee-internal://" + filename, result, SourceMap.chain(map, prevMap));
|
||||
};
|
||||
}
|
||||
|
||||
190
lib/src/transpiler/map.ts
Normal file
190
lib/src/transpiler/map.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
const map: number[] = [];
|
||||
let j = 0;
|
||||
|
||||
for (let i = 65; i <= 90; i++) map[i] = j++;
|
||||
for (let i = 97; i <= 122; i++) map[i] = j++;
|
||||
map[43] = j++;
|
||||
map[47] = j++;
|
||||
|
||||
export function decodeVLQ(val: string): number[][][] {
|
||||
const lines: number[][][] = [];
|
||||
|
||||
const fileParts = val.split(";", -1);
|
||||
|
||||
for (let i = 0; i < fileParts.length; i++) {
|
||||
const line = fileParts[i];
|
||||
if (line.length === 0) {
|
||||
lines.push([]);
|
||||
continue;
|
||||
}
|
||||
|
||||
const elements: number[][] = [];
|
||||
const lineParts = line.split(",", -1);
|
||||
|
||||
for (let i = 0; i < lineParts.length; i++) {
|
||||
const el = lineParts[i];
|
||||
|
||||
if (el.length === 0) elements.push([]);
|
||||
else {
|
||||
const list: number[] = [];
|
||||
|
||||
for (let i = 0; i < el.length;) {
|
||||
let sign = 1;
|
||||
let curr = map[el.charCodeAt(i++)];
|
||||
let cont = (curr & 0x20) === 0x20;
|
||||
if ((curr & 1) === 1) sign = -1;
|
||||
let res = (curr & 0b11110) >> 1;
|
||||
let n = 4;
|
||||
|
||||
for (; i < el.length && cont;) {
|
||||
curr = map[el.charCodeAt(i++)];
|
||||
cont = (curr & 0x20) == 0x20;
|
||||
res |= (curr & 0b11111) << n;
|
||||
n += 5;
|
||||
if (!cont) break;
|
||||
}
|
||||
|
||||
list.push(res * sign);
|
||||
}
|
||||
|
||||
elements.push(list);
|
||||
}
|
||||
}
|
||||
|
||||
lines.push(elements);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
export namespace Location {
|
||||
export function compare(a: Location, b: Location) {
|
||||
const { 0: filenameA, 1: lineA, 2: startA } = a;
|
||||
const { 0: filenameB, 1: lineB, 2: startB } = b;
|
||||
|
||||
if (filenameA < filenameB) return -1;
|
||||
if (filenameA > filenameB) return 1;
|
||||
|
||||
const lineI = lineA - lineB;
|
||||
if (lineI !== 0) return lineI;
|
||||
|
||||
return startA - startB;
|
||||
}
|
||||
export function comparePoints(a: Location, b: Location) {
|
||||
const { 1: lineA, 2: startA } = a;
|
||||
const { 1: lineB, 2: startB } = b;
|
||||
|
||||
const lineI = lineA - lineB;
|
||||
if (lineI !== 0) return lineI;
|
||||
|
||||
return startA - startB;
|
||||
}
|
||||
}
|
||||
|
||||
export class VLQSourceMap {
|
||||
public constructor(
|
||||
public readonly array: Map<string, [start: number, dst: Location][][]>,
|
||||
) { }
|
||||
|
||||
public converter() {
|
||||
return (src: Location) => {
|
||||
const file = this.array.get(src[0]);
|
||||
if (file == null) return src;
|
||||
|
||||
const line = file[src[1]];
|
||||
if (line == null || line.length === 0) return undefined;
|
||||
|
||||
let a = 0;
|
||||
let b = line.length;
|
||||
|
||||
while (true) {
|
||||
const done = b - a <= 1;
|
||||
|
||||
const mid = (a + b) >> 1;
|
||||
const el = line[mid];
|
||||
|
||||
const cmp = el[0] - src[2];
|
||||
|
||||
if (cmp < 0) {
|
||||
if (done) {
|
||||
if (b >= line.length) return undefined;
|
||||
break;
|
||||
}
|
||||
a = mid;
|
||||
}
|
||||
else if (cmp > 0) {
|
||||
if (done) {
|
||||
if (a <= 0) return undefined;
|
||||
break;
|
||||
}
|
||||
b = mid;
|
||||
}
|
||||
else return el[1];
|
||||
}
|
||||
|
||||
return line[b][1];
|
||||
};
|
||||
}
|
||||
|
||||
public static parseVLQ(compiled: string, filenames: string[], raw: string): VLQSourceMap {
|
||||
const mapping = decodeVLQ(raw);
|
||||
const file: [start: number, dst: Location][][] = [];
|
||||
const res = new Map<string, [start: number, dst: Location][][]>([[compiled, file]]);
|
||||
|
||||
let originalRow = 0;
|
||||
let originalCol = 0;
|
||||
let originalFile = 0;
|
||||
const lastCols = new Set<number>();
|
||||
|
||||
for (let compiledRow = 0; compiledRow < mapping.length; compiledRow++) {
|
||||
const line: [start: number, dst: Location][] = file[compiledRow] = [];
|
||||
let compiledCol = 0;
|
||||
|
||||
const rowData = mapping[compiledRow];
|
||||
for (let i = 0; i < rowData.length; i++) {
|
||||
const rawSeg = rowData[i];
|
||||
|
||||
compiledCol += rawSeg.length > 0 ? rawSeg[0] : 0;
|
||||
originalFile += rawSeg.length > 1 ? rawSeg[1] : 0;
|
||||
originalRow += rawSeg.length > 2 ? rawSeg[2] : 0;
|
||||
originalCol += rawSeg.length > 3 ? rawSeg[3] : 0;
|
||||
|
||||
if (!lastCols.has(compiledCol)) {
|
||||
line[line.length] = [compiledCol, [filenames[originalFile], originalRow, originalCol]];
|
||||
}
|
||||
lastCols.add(compiledCol);
|
||||
}
|
||||
|
||||
line.sort((a, b) => a[0] - b[0]);
|
||||
}
|
||||
|
||||
return new VLQSourceMap(res);
|
||||
}
|
||||
public static parse(raw: string | { file: string, mappings: string, sources: string[] }) {
|
||||
if (typeof raw === "string") raw = JSON.parse(raw) as { file: string, mappings: string, sources: string[] };
|
||||
|
||||
const compiled = raw.file;
|
||||
const mapping = raw.mappings;
|
||||
let filenames = raw.sources;
|
||||
if (filenames.length === 0 || filenames.length === 1 && filenames[0] === "") filenames = [compiled];
|
||||
|
||||
return this.parseVLQ(compiled, filenames, mapping);
|
||||
}
|
||||
}
|
||||
|
||||
export namespace SourceMap {
|
||||
export function parse(raw: string | { file: string, mappings: string, sources: string[] }) {
|
||||
return VLQSourceMap.parse(raw).converter();
|
||||
}
|
||||
export function chain(...maps: SourceMap[]): SourceMap {
|
||||
return loc => {
|
||||
for (const el of maps) {
|
||||
const tmp = el(loc);
|
||||
if (tmp == null) return undefined;
|
||||
else loc = tmp;
|
||||
}
|
||||
|
||||
return loc;
|
||||
};
|
||||
}
|
||||
}
|
||||
10
lib/src/transpiler/transpiler.d.ts
vendored
Normal file
10
lib/src/transpiler/transpiler.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
type Location = [file: string, line: number, start: number];
|
||||
type SourceMap = (loc: Location) => Location | undefined;
|
||||
|
||||
type CompilerFactory = (next: Compiler) => Compiler;
|
||||
type Compiler = (filename: string, src: string, mapper: SourceMap) => (this: any, ...args: any[]) => any;
|
||||
|
||||
declare function getResource(name: string): string | undefined;
|
||||
declare function print(...args: any[]): void;
|
||||
declare function register(factory: CompilerFactory): void;
|
||||
declare function registerSource(filename: string, src: string): void;
|
||||
118
lib/src/transpiler/typescript.ts
Normal file
118
lib/src/transpiler/typescript.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { createDocumentRegistry, createLanguageService, ModuleKind, ScriptSnapshot, ScriptTarget, type Diagnostic, type CompilerOptions, type IScriptSnapshot, flattenDiagnosticMessageText, CompilerHost, LanguageService } from "typescript";
|
||||
import { SourceMap } from "./map.ts";
|
||||
|
||||
const resources: Record<string, string | undefined> = {};
|
||||
|
||||
function resource(name: string) {
|
||||
if (name in resources) return resources[name];
|
||||
else return resources[name] = getResource(name);
|
||||
}
|
||||
|
||||
export default function typescript(next: Compiler): Compiler {
|
||||
const files: Record<string, IScriptSnapshot> = {};
|
||||
const versions: Record<string, number> = {};
|
||||
let declI = 0;
|
||||
|
||||
const settings: CompilerOptions = {
|
||||
target: ScriptTarget.ES5,
|
||||
module: ModuleKind.Preserve,
|
||||
|
||||
allowImportingTsExtensions: true,
|
||||
verbatimModuleSyntax: true,
|
||||
|
||||
strict: false,
|
||||
skipLibCheck: true,
|
||||
forceConsistentCasingInFileNames: true,
|
||||
declaration: true,
|
||||
sourceMap: true,
|
||||
downlevelIteration: true,
|
||||
};
|
||||
|
||||
let service: LanguageService;
|
||||
|
||||
measure(() => {
|
||||
service = createLanguageService({
|
||||
getCurrentDirectory: () => "/",
|
||||
getDefaultLibFileName: () => "/lib.d.ts",
|
||||
getScriptFileNames: () => {
|
||||
const res = ["/src.ts", "/lib.d.ts"];
|
||||
for (let i = 0; i < declI; i++) res.push("/src." + i + ".d.ts");
|
||||
return res;
|
||||
},
|
||||
getCompilationSettings: () => settings,
|
||||
log: print,
|
||||
fileExists: filename => filename in files || resource(filename) != null,
|
||||
|
||||
getScriptSnapshot: (filename) => {
|
||||
if (filename in files) return files[filename];
|
||||
else {
|
||||
const src = resource(filename);
|
||||
if (src == null) return undefined;
|
||||
return files[filename] = ScriptSnapshot.fromString(src);
|
||||
}
|
||||
},
|
||||
getScriptVersion: (filename) => String(versions[filename] || 0),
|
||||
|
||||
readFile: () => { throw "no"; },
|
||||
writeFile: () => { throw "no"; },
|
||||
}, createDocumentRegistry());
|
||||
});
|
||||
measure(() => {
|
||||
service.getEmitOutput("/lib.d.ts");
|
||||
});
|
||||
print("Loaded typescript!");
|
||||
|
||||
return (filename, code, prevMap) => {
|
||||
files["/src.ts"] = ScriptSnapshot.fromString(code);
|
||||
versions["/src.ts"] ??= 0;
|
||||
versions["/src.ts"]++;
|
||||
|
||||
const emit = service.getEmitOutput("/src.ts");
|
||||
|
||||
const diagnostics = new Array<Diagnostic>()
|
||||
.concat(service.getSyntacticDiagnostics("/src.ts"))
|
||||
.concat(service.getSemanticDiagnostics("/src.ts"))
|
||||
.map(diagnostic => {
|
||||
const message = flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
||||
|
||||
if (diagnostic.file != null) {
|
||||
let file = diagnostic.file.fileName.substring(1);
|
||||
if (file === "src.ts") file = filename;
|
||||
|
||||
if (diagnostic.start == null) return file;
|
||||
|
||||
const pos = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
||||
return file + ":" + (pos.line + 1) + ":" + (pos.character + 1) + ": " + message;
|
||||
}
|
||||
else return message;
|
||||
});
|
||||
|
||||
if (diagnostics.length > 0) {
|
||||
throw new SyntaxError(diagnostics.join("\n"));
|
||||
}
|
||||
|
||||
const outputs: Record<string, string> = {};
|
||||
|
||||
for (const el of emit.outputFiles) {
|
||||
outputs[el.name] = el.text;
|
||||
}
|
||||
|
||||
const rawMap = JSON.parse(outputs["/src.js.map"]);
|
||||
const map = SourceMap.parse({
|
||||
file: "ts-internal://" + filename,
|
||||
mappings: rawMap.mappings,
|
||||
sources: [filename],
|
||||
});
|
||||
const result = outputs["/src.js"];
|
||||
const declaration = outputs["/src.d.ts"];
|
||||
|
||||
registerSource(filename, code);
|
||||
const compiled = next("ts-internal://" + filename, result, SourceMap.chain(map, prevMap));
|
||||
|
||||
return function (this: any) {
|
||||
const res = compiled.apply(this, arguments);
|
||||
if (declaration !== '') files["/src." + declI++ + ".d.ts"] = ScriptSnapshot.fromString(declaration);
|
||||
return res;
|
||||
};
|
||||
};
|
||||
}
|
||||
17
lib/tsconfig.json
Normal file
17
lib/tsconfig.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"include": ["**/*.ts"],
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "Bundler",
|
||||
"module": "ESNext",
|
||||
"target": "ESNext",
|
||||
"noLib": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user