Skip to content

Commit 10c355a

Browse files
committed
Init
0 parents  commit 10c355a

File tree

7 files changed

+316
-0
lines changed

7 files changed

+316
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Deno.js
2+
test_bundle.js

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"deno.enable": true,
3+
"editor.formatOnSave": true,
4+
"editor.defaultFormatter": "denoland.vscode-deno"
5+
}

Deno.ts

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
///<reference no-default-lib="true" />
2+
///<reference lib="deno.ns" />
3+
///<reference lib="deno.console" />
4+
5+
import type {} from "./qjs.d.ts";
6+
import * as std from "std";
7+
import * as os from "os";
8+
9+
export const args: typeof Deno.args = scriptArgs.slice(1);
10+
export const mainModule: typeof Deno.mainModule = scriptArgs[0];
11+
export const noColor: typeof Deno.noColor =
12+
typeof std.getenv("NO_COLOR") !== "undefined";
13+
14+
export const exit: typeof Deno.exit = function exit(n) {
15+
return std.exit(n ?? 1);
16+
};
17+
18+
export const build: typeof Deno.build = {
19+
target: "",
20+
arch: "x86_64",
21+
os: "linux",
22+
vendor: "unknown",
23+
env: "gnu",
24+
};
25+
build.target = `${build.arch}-${build.vendor}-${build.os}-${build.env}`;
26+
27+
export const env: typeof Deno.env = {
28+
get(key) {
29+
return std.getenv(key);
30+
},
31+
set(key, value) {
32+
return std.setenv(key, value);
33+
},
34+
delete(key) {
35+
return std.unsetenv(key);
36+
},
37+
toObject() {
38+
return std.getenviron();
39+
},
40+
};
41+
42+
export const errors: typeof Deno.errors = {
43+
NotFound: class NotFound extends Error {},
44+
PermissionDenied: class PermissionDenied extends Error {},
45+
ConnectionRefused: class ConnectionRefused extends Error {},
46+
ConnectionReset: class ConnectionReset extends Error {},
47+
ConnectionAborted: class ConnectionAborted extends Error {},
48+
NotConnected: class NotConnected extends Error {},
49+
AddrInUse: class AddrInUse extends Error {},
50+
AddrNotAvailable: class AddrNotAvailable extends Error {},
51+
BrokenPipe: class BrokenPipe extends Error {},
52+
AlreadyExists: class AlreadyExists extends Error {},
53+
InvalidData: class InvalidData extends Error {},
54+
TimedOut: class TimedOut extends Error {},
55+
Interrupted: class Interrupted extends Error {},
56+
WriteZero: class WriteZero extends Error {},
57+
UnexpectedEof: class UnexpectedEof extends Error {},
58+
BadResource: class BadResource extends Error {},
59+
Http: class Http extends Error {},
60+
Busy: class Busy extends Error {},
61+
};
62+
63+
export const readTextFile: typeof Deno.readTextFile =
64+
async function readTextFile(path) {
65+
const file = std.loadFile(typeof path === "object" ? path.href : path);
66+
if (file == null) {
67+
throw new errors.NotFound(path + " not found");
68+
}
69+
return file;
70+
};
71+
72+
const files = new Map<number, { path: string; file: std.FILE }>();
73+
74+
export enum SeekMode {
75+
Start = 0,
76+
Current = 1,
77+
End = 2,
78+
}
79+
80+
export const File: typeof Deno.File = class File
81+
implements
82+
Deno.Reader,
83+
Deno.ReaderSync,
84+
Deno.Writer,
85+
Deno.WriterSync,
86+
Deno.Seeker,
87+
Deno.SeekerSync,
88+
Deno.Closer {
89+
#file: std.FILE;
90+
#closed = false;
91+
constructor(readonly rid: number) {
92+
this.#file = files.get(rid)!.file;
93+
}
94+
readSync(p: Uint8Array): number | null {
95+
if (this.#closed || this.#file.eof()) {
96+
return null;
97+
}
98+
return this.#file.read(p.buffer, p.byteOffset, p.byteLength);
99+
}
100+
async read(p: Uint8Array): Promise<number | null> {
101+
return this.readSync(p);
102+
}
103+
writeSync(p: Uint8Array): number {
104+
const nwritten = this.#file.write(p.buffer, p.byteOffset, p.byteLength);
105+
this.#file.flush();
106+
return nwritten;
107+
}
108+
async write(p: Uint8Array): Promise<number> {
109+
return this.writeSync(p);
110+
}
111+
seekSync(offset: number, whence: SeekMode): number {
112+
this.#file.seek(
113+
offset,
114+
whence === SeekMode.Start
115+
? std.SEEK_SET
116+
: whence === SeekMode.Current
117+
? std.SEEK_CUR
118+
: std.SEEK_END,
119+
);
120+
return offset;
121+
}
122+
async seek(offset: number, whence: SeekMode): Promise<number> {
123+
return this.seek(offset, whence);
124+
}
125+
close() {
126+
this.#closed = true;
127+
this.#file.close();
128+
files.delete(this.rid);
129+
}
130+
};
131+
132+
export const open: typeof Deno.open = async function open(path, options) {
133+
const file = std.open(
134+
path,
135+
`${options?.read ? "r" : ""}${
136+
options?.write ? (options?.read ? "+" : "w") : ""
137+
}`,
138+
);
139+
files.set(file.fileno(), { path, file });
140+
if (file == null) {
141+
throw new errors.NotFound(path + " not found");
142+
}
143+
return new File(file.fileno());
144+
};
145+
146+
export const stdin: typeof Deno.stdin = {
147+
rid: std.in.fileno(),
148+
close() {
149+
std.in.close();
150+
},
151+
readSync(p: Uint8Array): number | null {
152+
if (std.in.eof()) {
153+
return null;
154+
}
155+
return std.in.read(p.buffer, p.byteOffset, p.byteLength);
156+
},
157+
async read(p: Uint8Array): Promise<number | null> {
158+
return this.readSync(p);
159+
},
160+
};

build.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
console.log(
2+
Object.entries(
3+
(await Deno.emit(Deno.args[0], {
4+
check: false,
5+
})).files,
6+
).find(([k, v]) => k.endsWith(".js"))![1],
7+
);

dev.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
deno run --unstable --allow-read=Deno.ts,qjs.d.ts build.ts Deno.ts > Deno.js
2+
deno bundle test.js > test_bundle.js
3+
deno run -A test_bundle.js "$@"
4+
./qjs --unhandled-rejection test_bundle.js "$@"

qjs.d.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
declare var console: Console;
2+
declare var print: typeof console["log"];
3+
declare var scriptArgs: string[];
4+
5+
declare module "std" {
6+
export const SEEK_SET: number;
7+
export const SEEK_CUR: number;
8+
export const SEEK_END: number;
9+
10+
export interface FILE {
11+
/** Close the file. Return 0 if OK or `-errno` in case of I/O error. */
12+
close(): number;
13+
/** Outputs the string with the UTF-8 encoding. */
14+
puts(str: string): void;
15+
/** Formatted printf. The same formats as the standard C library `printf` are supported. Integer format types (e.g. `%d`) truncate the Numbers or BigInts to 32 bits. Use the `l` modifier (e.g. `%ld`) to truncate to 64 bits. */
16+
printf(fmt: string, ...args: any[]): void;
17+
18+
/** Flush the buffered file. */
19+
flush(): void;
20+
/** Seek to a give file position (whence is `std.SEEK_*`). `offset` can be a number or a bigint. Return 0 if OK or `-errno` in case of I/O error. */
21+
seek(
22+
offset: number | bigint,
23+
whence: typeof SEEK_SET | typeof SEEK_CUR | typeof SEEK_END,
24+
): void;
25+
26+
/** Return the current file position. */
27+
tell(): number;
28+
29+
/** Return the current file position as a bigint. */
30+
tello(): bigint;
31+
32+
/** Return true if end of file. */
33+
eof(): boolean;
34+
35+
/** Return the associated OS handle. */
36+
fileno(): number;
37+
38+
/** Return true if there was an error. */
39+
error(): boolean;
40+
41+
/** Clear the error indication. */
42+
clearerr(): void;
43+
44+
/** Read `length` bytes from the file to the ArrayBuffer `buffer` at byte position `position` (wrapper to the libc `fread`). */
45+
read(buffer: ArrayBuffer, position: number, length: number): number;
46+
47+
/** Write `length` bytes to the file from the ArrayBuffer `buffer` at byte position `position` (wrapper to the libc `fwrite`). */
48+
write(buffer: ArrayBuffer, position: number, length: number): number;
49+
50+
/** Return the next line from the file, assuming UTF-8 encoding, excluding the trailing line feed. */
51+
getline(): string;
52+
53+
/** Read `max_size` bytes from the file and return them as a string assuming UTF-8 encoding. If `max_size` is not present, the file is read up its end. */
54+
readAsString(max_size?: number): string;
55+
56+
/** Return the next byte from the file. Return -1 if the end of file is reached. */
57+
getByte(): number;
58+
59+
/** Write one byte to the file. */
60+
putByte(c: number): void;
61+
}
62+
63+
/** Exit the process. */
64+
export function exit(n: number): never;
65+
66+
/** Load the file `filename` and return it as a string assuming UTF-8 encoding. Return `null` in case of I/O error. */
67+
export function loadFile(filename: string): string | null;
68+
69+
/** Open a file (wrapper to the libc `fopen()`). Return the FILE object or `null` in case of I/O error. If `errorObj` is not undefined, set its `errno` property to the error code or to 0 if no error occured. */
70+
export function open(
71+
filename: string,
72+
flags: string,
73+
errorObj?: { errno?: number },
74+
): FILE;
75+
76+
/** Open a file from a file handle (wrapper to the libc `fdopen()`). Return the FILE object or `null` in case of I/O error. If `errorObj` is not undefined, set its `errno` property to the error code or to 0 if no error occured. */
77+
export function fdopen(
78+
fd: number,
79+
flags: string,
80+
errorObj?: { errno?: number },
81+
): FILE;
82+
83+
const In: FILE;
84+
export { In as in };
85+
export const out: FILE;
86+
export const err: FILE;
87+
88+
/** Return the value of the environment variable `name` or `undefined` if it is not defined. */
89+
export function getenv(name: string): string | undefined;
90+
/** Set the value of the environment variable `name` to the string `value`. */
91+
export function setenv(name: string, value: string): void;
92+
/** Delete the environment variable `name`. */
93+
export function unsetenv(name: string): void;
94+
/** Return an object containing the environment variables as key-value pairs. */
95+
export function getenviron(): Record<string, string>;
96+
/** Download url using the curl command line utility. */
97+
export function urlGet<Full extends boolean = false>(
98+
url: string,
99+
options?: {
100+
/** Boolean (default = false). If true, the response is an ArrayBuffer instead of a string. When a string is returned, the data is assumed to be UTF-8 encoded. */
101+
binary?: boolean;
102+
/** Boolean (default = false). If true, return the an object contains the properties `response` (response content), `responseHeaders` (headers separated by CRLF), `status` (status code). `response` is `null` is case of protocol or network error. If `full` is false, only the response is returned if the status is between 200 and 299. Otherwise `null` is returned. */
103+
full?: Full;
104+
},
105+
): Full extends true ? {
106+
/** response content */
107+
response: string;
108+
/** headers separated by CRLF */
109+
responseHeaders: Record<string, string>;
110+
/** status code */
111+
status: number;
112+
}
113+
: string | null;
114+
}
115+
116+
declare module "os" {
117+
export function chdir(path: string): number;
118+
}

test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {
2+
iterateReader,
3+
writeAll,
4+
} from "https://deno.land/[email protected]/streams/conversion.ts";
5+
6+
(async () => {
7+
// code to conditionally import deno.qjs
8+
// #region
9+
/** @type {typeof globalThis.Deno} */
10+
const Deno = "Deno" in globalThis
11+
? globalThis.Deno
12+
: await import("./Deno.js");
13+
"Deno" in globalThis || (globalThis.Deno = Deno);
14+
// #endregion
15+
16+
const file = await Deno.open("test.txt", { write: true });
17+
for await (const buf of iterateReader(Deno.stdin, { bufSize: 10 })) {
18+
await writeAll(file, buf);
19+
}
20+
})();

0 commit comments

Comments
 (0)