Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/codegen/builtins/host/globals.builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ export default b.declarations(
main: mainModulePath,
// What process.argv answers at the first read: the list that it keeps, which this read makes if nobody has asked for it,
// or what the program has stored there, or what a getter of the program answers.
argv: b.property(b.any, {
argv: b.property(b.anyMadeOf("Array"), {
createdOnFirstRead: {
capability: "js",
throws: true,
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/api/html_rewriter.bind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export const HTMLRewriter = b.class({
onDocument: { ...chainable(b.self), args: { handlers: b.any }, capability: "js", throws: true },
transform: {
args: { input: b.any },
returns: b.any.returning("string", "object"),
returns: b.any.returning("string", "Response", "ArrayBuffer"),
Comment thread
robobun marked this conversation as resolved.
Resolved
capability: "js",
throws: true,
passThis: true,
Expand Down
9 changes: 8 additions & 1 deletion src/runtime/node/util/parse_args.bind.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import * as b from "../../../codegen/bindgen-lib.ts";
import * as table from "../../../codegen/builtins/lib.ts";

export default b.module({ rustPath: "crate::node::util::parse_args" });

export const parseArgs = b.fn({ args: { config: b.any }, returns: b.any, capability: "js", throws: true });
/** New objects and lists, `values` without a prototype. A `default` comes back as the program handed it in: it may be a list of a class of its own. */
export const parseArgs = b.fn({
args: { config: b.any },
returns: b.any.returning(table.anyMadeOf("Object", "Array").spec),
capability: "js",
throws: true,
});
3 changes: 2 additions & 1 deletion test/aot/builtins/differential/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export type WorkerNote = [entry: string, mode: CallMode] | { notStarted: string
// `failure`: the test itself threw, which says nothing about the built-in.
export type WorkerReport = CallReport & { entry: string; failure?: string };

const [requestPath, reportsPath] = process.env.AOT_BUILTINS_WORKER_FILES?.split("\n") ?? process.argv.slice(2);
// The two paths are taken out of process.argv: a built-in that reads it would be handed them, and util.parseArgs refuses them as positionals before it answers.
const [requestPath, reportsPath] = process.env.AOT_BUILTINS_WORKER_FILES?.split("\n") ?? process.argv.splice(2);
const { tablePath, calls }: WorkerRequest = JSON.parse(readFileSync(requestPath, "utf8"));

process.on("unhandledRejection", () => {});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { EventEmitter, getEventListeners } from "node:events";
import { closeSync, openSync } from "node:fs";
import { join, posix, win32 } from "node:path";
import { domainToASCII, domainToUnicode } from "node:url";
import { MIMEParams, MIMEType, parseEnv } from "node:util";
import { MIMEParams, MIMEType, parseArgs, parseEnv } from "node:util";
import { describe, test } from "../supported";
import { never } from "./differential/fixtures";
import { Log } from "./differential/log";
Expand Down Expand Up @@ -644,6 +644,80 @@ const cases: Case[] = [
typesIn: result,
see: () => [{ value: parseEnv("FIRST=1\nSECOND=two\n7=seven") }, { value: parseEnv("") }],
},
// parse_args.rs: an object that holds `values` without a prototype, the list `positionals` and, where they are asked for, the list `tokens` of objects.
// A `default` comes back as the operand held it, so a list of a class of the program may lie in `values`.
{
row: "native:Bindgen:parse_args.bind.ts:parseArgs",
mode: "Call",
place: "the result",
typesIn: result,
see: () => [
{
value: parseArgs({
args: ["--name", "made-for-this-test", "-v", "first", "--no-color", "--", "last"],
options: {
name: { type: "string" },
verbose: { type: "boolean", short: "v" },
color: { type: "boolean" },
listed: { type: "string", multiple: true, default: new (class Words extends Array<string> {})("p", "q") },
plain: { type: "string", default: "kept" },
},
allowPositionals: true,
allowNegative: true,
tokens: true,
}),
},
{
value: parseArgs({
args: ["--many", "1", "--many", "2"],
options: { many: { type: "string", multiple: true } },
}),
},
{ value: parseArgs({ args: [] }) },
],
},
// BunProcess.cpp Process::getArgv(): what process.argv answers when Bun.argv is first read. Native code makes the list of strings there.
// Another value that a program has stored in process.argv comes back as it is.
{
row: "Bun.argv",
mode: "Get",
place: "the result",
typesIn: result,
see: () => [{ value: Bun.argv }],
},
// html_rewriter.rs transform(): a string for a string, a new ArrayBuffer for a buffer or a view of any kind, a new Response for a Response.
{
row: "HTMLRewriter.prototype.transform",
mode: "Call",
place: "the result",
typesIn: result,
see: () => {
const rewriter = new HTMLRewriter().on("p", {
element(element) {
element.setAttribute("seen", "yes");
},
});
const text = "<p>made for this test</p>";
const bytes = () => new TextEncoder().encode(text);
const shared = new SharedArrayBuffer(text.length);
new Uint8Array(shared).set(bytes());
return [
text,
"",
bytes().buffer,
new ArrayBuffer(0),
shared,
new Uint8Array(shared),
bytes(),
new DataView(bytes().buffer),
new Float64Array(8),
Buffer.from(text),
new Response(text),
new (class Answer extends Response {})(text),
new Response(new Blob([text])),
].map(input => ({ value: rewriter.transform(input as Response) }));
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
},
},
{
row: "native:NewCppFunction:JSEventTargetNode.cpp:jsFunctionNodeEventsGetEventListeners",
mode: "Call",
Expand Down
118 changes: 118 additions & 0 deletions test/aot/trimmed-is-whole/cases/classes-that-a-call-may-return.js.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,121 @@ import { createHistogram } from "node:perf_hooks";
const histogram = createHistogram();
histogram.record(5);
console.log(histogram.count, histogram.max);
//// the-text-that-a-rewriter-of-HTML-answers
//@ removes Bun.build
//@ removes bun:test
//@ removes Bun.Cookie
//@ removes SubtleCrypto
const rewriter = new HTMLRewriter().on("p", {
element(element) {
element.setAttribute("seen", "yes");
},
});
console.log(rewriter.transform("<p>text</p>"), rewriter.transform("") === "");
//// the-bytes-that-a-rewriter-of-HTML-answers
//@ removes Bun.build
//@ removes bun:test
//@ removes Bun.Cookie
//@ removes SubtleCrypto
const rewriter = new HTMLRewriter().on("p", {
element(element) {
element.setAttribute("seen", "yes");
},
});
const bytes = () => new TextEncoder().encode("<p>bytes</p>");
const shared = new SharedArrayBuffer(12);
new Uint8Array(shared).set(bytes());
const decoder = new TextDecoder();
for (const input of [bytes().buffer, bytes(), new DataView(bytes().buffer), shared, new Uint8Array(shared)]) {
const answer = rewriter.transform(input);
console.log(answer.byteLength, decoder.decode(answer));
}
//// the-response-that-a-rewriter-of-HTML-answers
//@ removes Bun.build
//@ removes bun:test
//@ removes Bun.Cookie
//@ removes SubtleCrypto
const rewriter = new HTMLRewriter().on("p", {
element(element) {
element.setAttribute("seen", "yes");
},
});
const response = rewriter.transform(new Response("<p>response</p>", { status: 201 }));
console.log(typeof response, response.status, await response.text());
//// what-a-rewriter-of-HTML-refuses
//@ removes Bun.build
//@ removes bun:test
//@ removes Bun.Cookie
//@ removes SubtleCrypto
const rewriter = new HTMLRewriter();
for (const refused of [new Blob(["<p>blob</p>"]), 5, undefined]) {
try {
rewriter.transform(refused);
} catch (error) {
console.log(error.name, error.message);
}
}
//// the-arguments-that-node-util-parses
//@ removes Bun.build
//@ removes Bun.serve
//@ removes bun:test
//@ removes Bun.Cookie
//@ removes SubtleCrypto
import { parseArgs } from "node:util";
class Words extends Array {}
const words = Words.of("p", "q");
const { values, positionals, tokens } = parseArgs({
args: ["--name", "x", "-v", "first", "--no-color", "--", "last"],
options: {
name: { type: "string" },
verbose: { type: "boolean", short: "v" },
color: { type: "boolean" },
listed: { type: "string", multiple: true, default: words },
plain: { type: "string", default: "kept" },
},
allowPositionals: true,
allowNegative: true,
tokens: true,
});
console.log(Object.getPrototypeOf(values), Object.keys(values).join(), "toString" in values);
console.log(values.name.toUpperCase(), values.verbose, values.color, values.plain, values.listed === words, values.listed instanceof Words);
console.log(positionals.join(), tokens.map(token => `${token.kind}:${token.name ?? token.value}:${token.index}`).join(" "));
const repeated = parseArgs({ args: ["--many", "1", "--many", "2"], options: { many: { type: "string", multiple: true } } });
console.log(repeated.values.many.map(Number).join(), repeated.tokens);
try {
parseArgs({ args: ["--nope"], options: {} });
} catch (error) {
console.log(error.code);
}
//// the-arguments-that-Bun-keeps
//@ args first --second
//@ removes Bun.build
//@ removes Bun.serve
//@ removes bun:test
//@ removes Bun.Cookie
//@ removes SubtleCrypto
const { argv } = Bun;
console.log(Array.isArray(argv), argv === process.argv, argv.length, argv.slice(2).join(), argv.every(each => typeof each === "string"));
//// what-node-util-prints-of-an-object
//@ removes Bun.build
//@ removes Bun.serve
//@ removes bun:test
//@ removes Bun.Cookie
//@ removes SubtleCrypto
import { inspect, promisify } from "node:util";
console.log(inspect({ a: 1, list: [1, "two"] }), typeof promisify);
//// the-arguments-as-the-guide-of-the-documentation-parses-them
//@ args --flag1 --flag2 value
//@ removes Bun.build
//@ removes Bun.serve
//@ removes bun:test
//@ removes Bun.Cookie
//@ removes SubtleCrypto
import { parseArgs } from "util";
const { values, positionals } = parseArgs({
args: Bun.argv,
options: { flag1: { type: "boolean" }, flag2: { type: "string" } },
strict: true,
allowPositionals: true,
});
console.log(values, positionals.length);
Loading