mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-22 05:59:31 +08:00
Compile the deprecated punycode and constants builtin modules
- node:punycode: encode, decode, toASCII, toUnicode, ucs2.decode, ucs2.encode and version, ported from the punycode.js 2.1.0 Node bundles (scr_url.c), with its RangeErrors. DEP0040 follows Node: a static ES import reports before any module evaluates and before the program can register a 'warning' listener; require() reports on the next tick, once for both spellings, not when a dependency under node_modules loads the module first, and not under process.noDeprecation. - node:constants: the frozen object Node builds from os.constants' dlopen, errno, priority and signals groups, fs.constants (node_constants.cc order and guards) and crypto.constants (scr_os.c); its bindings read it as a checked-dynamic value. These unblock tr46 (whatwg-url, node-fetch@2) and graceful-fs (fs-extra). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b4e25cdba0
commit
1c19d6613d
@@ -74,6 +74,8 @@ title: "Limitations"
|
||||
|
||||
<include>../limitations/builtin-apis/legacy-url-api.mdx</include>
|
||||
|
||||
<include>../limitations/builtin-apis/deprecated-modules.mdx</include>
|
||||
|
||||
<include>../limitations/builtin-apis/filesystem-flags.mdx</include>
|
||||
|
||||
<include>../limitations/builtin-apis/copy.mdx</include>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
- **Deprecated `punycode` and `constants` modules:** `punycode.encode()`, `decode()`, `toASCII()`, `toUnicode()`, `ucs2.decode()`, `ucs2.encode()`, and `version` compile, with the `DEP0040` warning Node.js reports when the module loads. A `require("punycode")` made from inside `node_modules` doesn't warn; a `require()` used inside a larger expression, such as `require("punycode").toASCII(name)`, doesn't warn either. The `punycode.ucs2` object itself is unsupported as a value. The `constants` module is the frozen object Node.js builds from `os.constants` and `fs.constants`, plus the `crypto.constants` of Node.js 24.22.0.
|
||||
@@ -2,6 +2,6 @@
|
||||
"schemaVersion": 3,
|
||||
"nodeVersion": "24.22.0",
|
||||
"nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93",
|
||||
"artifactVersion": "a1ff929d49885bd8c92e",
|
||||
"artifactVersion": "7b345b86e2e5f616a7a0",
|
||||
"rowCount": 3880
|
||||
}
|
||||
|
||||
@@ -584,9 +584,9 @@
|
||||
"apiEntries": 9,
|
||||
"static": {
|
||||
"supported": 0,
|
||||
"partial": 0,
|
||||
"partial": 8,
|
||||
"refused": 0,
|
||||
"not-implemented": 9,
|
||||
"not-implemented": 1,
|
||||
"by-design": 0,
|
||||
"unreviewed": 0,
|
||||
"not-applicable": 0
|
||||
@@ -58489,7 +58489,7 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"status": "partial",
|
||||
"detail": "Derived from the exact API rows in this chapter.",
|
||||
"verification": "derived"
|
||||
}
|
||||
@@ -58512,9 +58512,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the call shapes accepted by the compiler lowering.",
|
||||
"verification": "test-backed"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -58535,9 +58535,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the call shapes accepted by the compiler lowering.",
|
||||
"verification": "test-backed"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -58558,9 +58558,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the call shapes accepted by the compiler lowering.",
|
||||
"verification": "test-backed"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -58581,9 +58581,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the call shapes accepted by the compiler lowering.",
|
||||
"verification": "test-backed"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -58627,9 +58627,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the call shapes accepted by the compiler lowering.",
|
||||
"verification": "test-backed"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -58650,9 +58650,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the call shapes accepted by the compiler lowering.",
|
||||
"verification": "test-backed"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -58673,9 +58673,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the call shapes accepted by the compiler lowering.",
|
||||
"verification": "test-backed"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
"tierItemCount": 3456,
|
||||
"tiers": {
|
||||
"static": {
|
||||
"audit-partial": 1091,
|
||||
"verify-gap": 2238,
|
||||
"audit-partial": 1098,
|
||||
"verify-gap": 2231,
|
||||
"replace-refusal": 40,
|
||||
"classify": 2,
|
||||
"implement": 85
|
||||
@@ -58534,12 +58534,16 @@
|
||||
"priority": "low",
|
||||
"tiers": {
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"action": "verify-gap",
|
||||
"verification": "registry-gap",
|
||||
"confidence": "low",
|
||||
"source": "compiler-unmatched:punycode",
|
||||
"tests": []
|
||||
"status": "partial",
|
||||
"action": "audit-partial",
|
||||
"verification": "test-backed",
|
||||
"confidence": "high",
|
||||
"source": "surface-manifest:node-builtin.punycode.decode",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -58559,12 +58563,16 @@
|
||||
"priority": "low",
|
||||
"tiers": {
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"action": "verify-gap",
|
||||
"verification": "registry-gap",
|
||||
"confidence": "low",
|
||||
"source": "compiler-unmatched:punycode",
|
||||
"tests": []
|
||||
"status": "partial",
|
||||
"action": "audit-partial",
|
||||
"verification": "test-backed",
|
||||
"confidence": "high",
|
||||
"source": "surface-manifest:node-builtin.punycode.encode",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -58584,12 +58592,16 @@
|
||||
"priority": "low",
|
||||
"tiers": {
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"action": "verify-gap",
|
||||
"verification": "registry-gap",
|
||||
"confidence": "low",
|
||||
"source": "compiler-unmatched:punycode",
|
||||
"tests": []
|
||||
"status": "partial",
|
||||
"action": "audit-partial",
|
||||
"verification": "test-backed",
|
||||
"confidence": "high",
|
||||
"source": "surface-manifest:node-builtin.punycode.toASCII",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -58609,12 +58621,16 @@
|
||||
"priority": "low",
|
||||
"tiers": {
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"action": "verify-gap",
|
||||
"verification": "registry-gap",
|
||||
"confidence": "low",
|
||||
"source": "compiler-unmatched:punycode",
|
||||
"tests": []
|
||||
"status": "partial",
|
||||
"action": "audit-partial",
|
||||
"verification": "test-backed",
|
||||
"confidence": "high",
|
||||
"source": "surface-manifest:node-builtin.punycode.toUnicode",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -58659,12 +58675,16 @@
|
||||
"priority": "low",
|
||||
"tiers": {
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"action": "verify-gap",
|
||||
"verification": "registry-gap",
|
||||
"confidence": "low",
|
||||
"source": "compiler-unmatched:punycode",
|
||||
"tests": []
|
||||
"status": "partial",
|
||||
"action": "audit-partial",
|
||||
"verification": "test-backed",
|
||||
"confidence": "high",
|
||||
"source": "surface-manifest:node-builtin.punycode.ucs2.decode",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -58684,12 +58704,16 @@
|
||||
"priority": "low",
|
||||
"tiers": {
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"action": "verify-gap",
|
||||
"verification": "registry-gap",
|
||||
"confidence": "low",
|
||||
"source": "compiler-unmatched:punycode",
|
||||
"tests": []
|
||||
"status": "partial",
|
||||
"action": "audit-partial",
|
||||
"verification": "test-backed",
|
||||
"confidence": "high",
|
||||
"source": "surface-manifest:node-builtin.punycode.ucs2.encode",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -58709,12 +58733,16 @@
|
||||
"priority": "low",
|
||||
"tiers": {
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"action": "verify-gap",
|
||||
"verification": "registry-gap",
|
||||
"confidence": "low",
|
||||
"source": "compiler-unmatched:punycode",
|
||||
"tests": []
|
||||
"status": "partial",
|
||||
"action": "audit-partial",
|
||||
"verification": "test-backed",
|
||||
"confidence": "high",
|
||||
"source": "surface-manifest:node-builtin.punycode.version",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -611,9 +611,9 @@
|
||||
"apiEntries": 9,
|
||||
"static": {
|
||||
"supported": 0,
|
||||
"partial": 0,
|
||||
"partial": 8,
|
||||
"refused": 0,
|
||||
"not-implemented": 9,
|
||||
"not-implemented": 1,
|
||||
"by-design": 0,
|
||||
"unreviewed": 0,
|
||||
"not-applicable": 0
|
||||
@@ -81908,8 +81908,13 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "derived:descendants"
|
||||
"status": "partial",
|
||||
"evidence": "derived:descendants",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
},
|
||||
"anchorSource": "chapter"
|
||||
},
|
||||
@@ -81931,8 +81936,13 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:punycode"
|
||||
"status": "partial",
|
||||
"evidence": "surface-manifest:node-builtin.punycode.decode",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
},
|
||||
"anchorSource": "exact"
|
||||
},
|
||||
@@ -81954,8 +81964,13 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:punycode"
|
||||
"status": "partial",
|
||||
"evidence": "surface-manifest:node-builtin.punycode.encode",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
},
|
||||
"anchorSource": "exact"
|
||||
},
|
||||
@@ -81977,8 +81992,13 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:punycode"
|
||||
"status": "partial",
|
||||
"evidence": "surface-manifest:node-builtin.punycode.toASCII",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
},
|
||||
"anchorSource": "exact"
|
||||
},
|
||||
@@ -82000,8 +82020,13 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:punycode"
|
||||
"status": "partial",
|
||||
"evidence": "surface-manifest:node-builtin.punycode.toUnicode",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
},
|
||||
"anchorSource": "exact"
|
||||
},
|
||||
@@ -82046,8 +82071,13 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:punycode"
|
||||
"status": "partial",
|
||||
"evidence": "surface-manifest:node-builtin.punycode.ucs2.decode",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
},
|
||||
"anchorSource": "exact"
|
||||
},
|
||||
@@ -82069,8 +82099,13 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:punycode"
|
||||
"status": "partial",
|
||||
"evidence": "surface-manifest:node-builtin.punycode.ucs2.encode",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
},
|
||||
"anchorSource": "exact"
|
||||
},
|
||||
@@ -82092,8 +82127,13 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:punycode"
|
||||
"status": "partial",
|
||||
"evidence": "surface-manifest:node-builtin.punycode.version",
|
||||
"tests": [
|
||||
"tests/corpus/6122-punycode-conversions.ts",
|
||||
"tests/corpus/6124-punycode-require-warnings.cjs",
|
||||
"tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
]
|
||||
},
|
||||
"anchorSource": "chapter"
|
||||
},
|
||||
|
||||
@@ -146,6 +146,7 @@
|
||||
"node-builtin.process.rows": ["tests/corpus/2992-stream-rows.ts", "tests/harness/terminal-geometry.test.ts"],
|
||||
"node-builtin.process.columns": ["tests/corpus/1448-stream-columns.ts", "tests/harness/terminal-geometry.test.ts"],
|
||||
"node-builtin.process.exitCode": ["tests/corpus/2941-process-exit-code.ts", "tests/corpus/2942-process-exit-code-override.ts", "tests/corpus/2943-process-exit-code-invalid.ts", "tests/corpus/2944-process-exit-code-wrap.ts"],
|
||||
"node-builtin.punycode": ["tests/corpus/6122-punycode-conversions.ts", "tests/corpus/6124-punycode-require-warnings.cjs", "tests/corpus/6126-punycode-dependency/main.cjs"],
|
||||
"node-builtin.querystring": ["tests/corpus/957-builtins-namespace.ts", "tests/corpus/2917-builtin-callable-widths.ts"],
|
||||
"node-builtin.readline": ["tests/corpus/1475-readline-closed-stdin.ts"],
|
||||
"node-builtin.stream": ["tests/corpus/1685-stream-readable-basics.ts", "tests/corpus/1746-stream-for-await.ts", "tests/corpus/1814-stream-pipeline.cjs", "tests/corpus/2629-stream-consumers.ts", "tests/corpus/2861-readable-iterator-close.ts"],
|
||||
|
||||
@@ -3643,6 +3643,39 @@ declare module "node:querystring" {
|
||||
export * from "querystring";
|
||||
}
|
||||
|
||||
/* node:punycode (deprecated, DEP0040) — punycode.js 2.1.0: decode and
|
||||
* toUnicode throw its RangeErrors on malformed input; ucs2 converts
|
||||
* between strings and UTF-16 code point arrays. */
|
||||
declare module "punycode" {
|
||||
export function decode(string: string): string;
|
||||
export function encode(string: string): string;
|
||||
export function toUnicode(domain: string): string;
|
||||
export function toASCII(domain: string): string;
|
||||
export namespace ucs2 {
|
||||
function decode(string: string): number[];
|
||||
function encode(codePoints: readonly number[]): string;
|
||||
}
|
||||
export const version: string;
|
||||
}
|
||||
declare module "node:punycode" {
|
||||
export * from "punycode";
|
||||
}
|
||||
|
||||
/* node:constants (deprecated, DEP0008) — one frozen object: os.constants'
|
||||
* dlopen, errno, priority and signals groups, fs.constants, and
|
||||
* crypto.constants. A platform's missing constant reads as undefined. */
|
||||
declare module "constants" {
|
||||
const constants: { readonly [name: string]: number } & {
|
||||
readonly defaultCoreCipherList: string;
|
||||
readonly defaultCipherList: string;
|
||||
};
|
||||
export = constants;
|
||||
}
|
||||
declare module "node:constants" {
|
||||
import constants = require("constants");
|
||||
export = constants;
|
||||
}
|
||||
|
||||
/* node:readline — the question/close slice: createInterface over exactly
|
||||
* { input: process.stdin, output: process.stdout }, question(query, cb)
|
||||
* (the query writes to stdout, the callback gets the next line's text),
|
||||
|
||||
@@ -680,6 +680,8 @@ export function emitLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue {
|
||||
case "events":
|
||||
case "blob":
|
||||
case "record":
|
||||
case "punycode":
|
||||
case "constants":
|
||||
return host.emitGenericLibCall(e);
|
||||
case "test":
|
||||
return emitTestLibCall(host, e);
|
||||
|
||||
@@ -192,6 +192,7 @@ export const LIB_FN_SYMS: Record<string, string> = {
|
||||
"os.cpusModel": "scr_os_cpus_model",
|
||||
"os.cpusField": "scr_os_cpus_field",
|
||||
"os.constants": "scr_os_constants",
|
||||
"constants.object": "scr_node_constants",
|
||||
"os.release": "scr_os_release",
|
||||
"os.userName": "scr_os_user_name",
|
||||
"os.userShell": "scr_os_user_shell",
|
||||
@@ -631,6 +632,13 @@ export const LIB_FN_SYMS: Record<string, string> = {
|
||||
"url.legacyFormat": "scr_url_legacy_format",
|
||||
"url.legacyResolve": "scr_url_legacy_resolve",
|
||||
"url.domainToASCII": "scr_url_domain_to_ascii",
|
||||
"punycode.decode": "scr_punycode_decode",
|
||||
"punycode.encode": "scr_punycode_encode",
|
||||
"punycode.toASCII": "scr_punycode_to_ascii",
|
||||
"punycode.toUnicode": "scr_punycode_to_unicode",
|
||||
"punycode.ucs2Decode": "scr_punycode_ucs2_decode",
|
||||
"punycode.ucs2Encode": "scr_str_from_code_point",
|
||||
"punycode.warn": "scr_punycode_warn",
|
||||
"url.domainToUnicode": "scr_url_domain_to_unicode",
|
||||
"url.pathToFileURL": "scr_url_from_path",
|
||||
"url.pathToFileURLPlatform": "scr_url_from_path_platform",
|
||||
|
||||
@@ -42,6 +42,8 @@ export const SUPPORTED_BUILTIN_MODULES = [
|
||||
"module",
|
||||
"console",
|
||||
"process",
|
||||
"punycode",
|
||||
"constants",
|
||||
] as const;
|
||||
|
||||
/** Builtins Node itself serves ONLY under the node: prefix —
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
builtinModulesArrayLit,
|
||||
stdlibGlobalNameOf,
|
||||
} from "./surfaces.js";
|
||||
import { CRYPTO_CONSTANTS } from "./crypto-tables.js";
|
||||
|
||||
const PROTOTYPE_METHODS: Record<string, readonly string[]> = {
|
||||
Date: ["getTime", "valueOf", "toISOString", "toJSON"],
|
||||
@@ -680,3 +681,34 @@ export function lowerBuiltinLoaderValue(lowerer: Lowerer, loc: SrcLoc): IrExpr {
|
||||
loc,
|
||||
};
|
||||
}
|
||||
|
||||
/** The deprecated node:constants module object: the runtime merges
|
||||
* os.constants' groups and fs.constants with crypto.constants, which a
|
||||
* lifted function answers from the baked table the first time the object
|
||||
* is built. */
|
||||
export function builtinConstantsObject(lowerer: Lowerer, loc: SrcLoc): IrExpr {
|
||||
const name = "%builtin.constants.crypto";
|
||||
if (!lowerer.builtinCallableValueFns.has(name)) {
|
||||
lowerer.builtinCallableValueFns.set(name, name);
|
||||
const fields = Object.entries(CRYPTO_CONSTANTS).map(([key, value]) => ({
|
||||
key: strLit(key, loc),
|
||||
value: box(builtinConstLit(value, loc)),
|
||||
}));
|
||||
lowerer.liftedFns.push({
|
||||
name,
|
||||
params: [],
|
||||
returnType: DYN,
|
||||
locals: [],
|
||||
body: [{ kind: "return", value: { kind: "dynObjLit", fields, type: DYN, loc }, loc }],
|
||||
loc,
|
||||
});
|
||||
}
|
||||
const table: IrExpr = {
|
||||
kind: "closure",
|
||||
fnName: name,
|
||||
captures: [],
|
||||
type: { kind: "func", params: [], ret: DYN },
|
||||
loc,
|
||||
};
|
||||
return { kind: "libCall", fn: "constants.object", args: [box(table)], type: DYN, loc };
|
||||
}
|
||||
|
||||
@@ -216,6 +216,7 @@ import {
|
||||
} from "./class-prototypes.js";
|
||||
import { isClassCallback } from "./class-callbacks.js";
|
||||
import {
|
||||
builtinConstantsObject,
|
||||
builtinPrototypeMethod,
|
||||
lowerArrayIsArrayValue,
|
||||
lowerCheckedPredicateValue,
|
||||
@@ -1164,6 +1165,17 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
if (bi.module === "os" && bi.member === "constants") {
|
||||
return { kind: "libCall", fn: "os.constants", args: [], type: DYN, loc };
|
||||
}
|
||||
// `import { O_RDONLY } from "constants"`: the member of the frozen
|
||||
// module object.
|
||||
if (bi.module === "constants") {
|
||||
return {
|
||||
kind: "dynKeyGet",
|
||||
value: builtinConstantsObject(lowerer, loc),
|
||||
key: { kind: "strLit", value: bi.member, type: STRING, loc },
|
||||
type: DYN,
|
||||
loc,
|
||||
};
|
||||
}
|
||||
// tls.rootCertificates: a runtime-valued module constant (the
|
||||
// cached bundled-CA array) — the one member read that lowers
|
||||
// to a libCall instead of a baked literal.
|
||||
@@ -1206,6 +1218,7 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
// their access sites only. The CommonJS namespace binding
|
||||
// (`const lib = require("./lib.js")`) gets the same fence.
|
||||
const builtinNamespace = lowerer.builtinNamespaceModuleOf(expr);
|
||||
if (builtinNamespace === "constants") return builtinConstantsObject(lowerer, loc);
|
||||
if (builtinNamespace !== null) {
|
||||
const type: IrType = { kind: "moduleNs", moduleId: `builtin:${builtinNamespace}` };
|
||||
return { kind: "moduleNsRef", moduleId: type.moduleId, type, loc };
|
||||
@@ -1495,6 +1508,7 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
return { kind: "moduleNsRef", moduleId: moduleNs.moduleId, type: moduleNs, loc };
|
||||
}
|
||||
const builtinNs = lowerer.builtinNamespaceModuleOf(expr);
|
||||
if (builtinNs === "constants") return builtinConstantsObject(lowerer, loc);
|
||||
if (builtinNs !== null) {
|
||||
const type: IrType = { kind: "moduleNs", moduleId: `builtin:${builtinNs}` };
|
||||
return { kind: "moduleNsRef", moduleId: type.moduleId, type, loc };
|
||||
|
||||
@@ -2656,6 +2656,7 @@ export function lowerFileInit(
|
||||
loc: loc0,
|
||||
});
|
||||
}
|
||||
if (sf === lowerer.entry) header.push(...lowerer.punycodeLinkWarning());
|
||||
for (const { stmt, dep } of orderedImportsOf(lowerer.program, sf)) {
|
||||
const npm = lowerer.npmInitActions.get(sf)?.get(stmt);
|
||||
if (npm !== undefined && npm.length > 0) {
|
||||
|
||||
@@ -1557,7 +1557,9 @@ export function lowerVarStatement(lowerer: Lowerer, stmt: ts.VariableStatement):
|
||||
// Relative requires keep the fence: their module-init-at-position
|
||||
// semantics needs storage this model doesn't represent.
|
||||
if (canonicalBuiltinModule(spec) !== null) {
|
||||
return [];
|
||||
return canonicalBuiltinModule(spec) === "punycode"
|
||||
? [lowerer.punycodeRequireWarning(decl)]
|
||||
: [];
|
||||
}
|
||||
lowerer.unsupported(
|
||||
"SC1090",
|
||||
|
||||
@@ -128,6 +128,7 @@ import { resolve } from "node:path";
|
||||
import { bindingSource } from "../binding-source.js";
|
||||
import { tsgoPath } from "../dts-paths.js";
|
||||
import * as ts from "../ts7/adapter.js";
|
||||
import { erasedTypeOnlyImport } from "../type-only-imports.js";
|
||||
import { literalValues } from "../literal-values.js";
|
||||
import { discriminantOwners, literalUnionArm, type UnionLiteral } from "../union-discriminants.js";
|
||||
import type { ScrDiagnostic } from "../../diagnostics/diagnostic.js";
|
||||
@@ -3745,6 +3746,65 @@ export class Lowerer {
|
||||
for (const fp of parts) if (!indexOf.has(fp.sf)) visit(fp.sf);
|
||||
}
|
||||
|
||||
/** node:punycode's load at a require() call: the module body reports
|
||||
* DEP0040 when it first runs, unless isInsideNodeModules() finds the
|
||||
* requiring frame in a dependency, and process.emitWarning delivers the
|
||||
* report on the next tick. Later loads are cache hits either way. */
|
||||
punycodeRequireWarning(node: ts.Node): IrStmt {
|
||||
const loc = locOf(node);
|
||||
const fromDependency = /[\\/]node_modules[\\/]/.test(node.getSourceFile().fileName);
|
||||
return {
|
||||
kind: "exprStmt",
|
||||
expr: {
|
||||
kind: "libCall",
|
||||
fn: "punycode.warn",
|
||||
args: [
|
||||
{ kind: "boolLit", value: false, type: BOOL, loc },
|
||||
{ kind: "boolLit", value: !fromDependency, type: BOOL, loc },
|
||||
],
|
||||
type: VOID,
|
||||
loc,
|
||||
},
|
||||
loc,
|
||||
};
|
||||
}
|
||||
|
||||
/** node:punycode's DEP0040 for a static ES import anywhere in the module
|
||||
* graph: Node links builtins before any module evaluates, so the report
|
||||
* comes first, before the program can register a 'warning' listener —
|
||||
* whichever file imports it (a dependency's ES import has no requiring
|
||||
* frame either). Prepended to the entry's %init. */
|
||||
punycodeLinkWarning(): IrStmt[] {
|
||||
const imports = this.moduleOrder.some((sf) =>
|
||||
sf.statements.some(
|
||||
(stmt) =>
|
||||
((ts.isImportDeclaration(stmt) && !erasedTypeOnlyImport(stmt)) ||
|
||||
(ts.isExportDeclaration(stmt) && !stmt.isTypeOnly)) &&
|
||||
stmt.moduleSpecifier !== undefined &&
|
||||
ts.isStringLiteral(stmt.moduleSpecifier) &&
|
||||
canonicalBuiltinModule(stmt.moduleSpecifier.text) === "punycode",
|
||||
),
|
||||
);
|
||||
if (!imports) return [];
|
||||
const loc: SrcLoc = { file: this.entry.fileName, start: 0, end: 0 };
|
||||
return [
|
||||
{
|
||||
kind: "exprStmt",
|
||||
expr: {
|
||||
kind: "libCall",
|
||||
fn: "punycode.warn",
|
||||
args: [
|
||||
{ kind: "boolLit", value: true, type: BOOL, loc },
|
||||
{ kind: "boolLit", value: true, type: BOOL, loc },
|
||||
],
|
||||
type: VOID,
|
||||
loc,
|
||||
},
|
||||
loc,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** The lowering of a CommonJS `require("./local")` occurrence: a call of
|
||||
* the required module's run-once %init at exactly this statement's
|
||||
* position — Node's inline evaluation, with the guard supplying the
|
||||
@@ -3754,6 +3814,7 @@ export class Lowerer {
|
||||
* their external dependencies by name). Null for everything else
|
||||
* (builtins load nothing; the rest kept its preflight fence). */
|
||||
requireInitStmt(spec: string, node: ts.Node): IrStmt | null {
|
||||
if (canonicalBuiltinModule(spec) === "punycode") return this.punycodeRequireWarning(node);
|
||||
// Project requires resolve within the program; another bare require can
|
||||
// be a program-module edge when it names an opted-in --npm-static package
|
||||
// (one package requiring another — the resolution answered its shipped
|
||||
@@ -11286,7 +11347,23 @@ export class Lowerer {
|
||||
return { module: "timers/promises", member: `scheduler.${access.name.text}` };
|
||||
}
|
||||
}
|
||||
// punycode.ucs2.decode / encode: methods of the module's ucs2 object,
|
||||
// dispatched as module members.
|
||||
if (access.name.text === "decode" || access.name.text === "encode") {
|
||||
const owner = access.expression;
|
||||
const imported = ts.isIdentifier(owner)
|
||||
? this.builtinImportOf(owner)
|
||||
: ts.isPropertyAccessExpression(owner)
|
||||
? this.builtinMemberOf(owner)
|
||||
: null;
|
||||
if (imported?.module === "punycode" && imported.member === "ucs2") {
|
||||
return { module: "punycode", member: `ucs2.${access.name.text}` };
|
||||
}
|
||||
}
|
||||
const module = this.builtinNamespaceModuleOf(access.expression);
|
||||
// node:constants is one checked-dynamic object: its members read
|
||||
// through the object itself (builtinConstantsObject), not the tables.
|
||||
if (module === "constants") return null;
|
||||
if (module !== null) return { module, member: access.name.text };
|
||||
// The events module object IS the EventEmitter class, so the class's
|
||||
// defaultMaxListeners is the module property.
|
||||
|
||||
@@ -1801,6 +1801,22 @@ export const BUILTIN_MODULE_FNS: Record<
|
||||
valueParams: [{ mode: "required", type: STRING }],
|
||||
},
|
||||
},
|
||||
// node:punycode (deprecated): punycode.js 2.1.0's conversions over
|
||||
// strings (scr_url.c). ucs2.decode/encode are members of the module's
|
||||
// ucs2 object, dispatched as module members (builtinMemberOf). The
|
||||
// DEP0040 report rides the module's load sites (punycodeLoadWarning).
|
||||
punycode: {
|
||||
decode: { fn: "punycode.decode", params: [STRING], result: STRING },
|
||||
encode: { fn: "punycode.encode", params: [STRING], result: STRING },
|
||||
toASCII: { fn: "punycode.toASCII", params: [STRING], result: STRING },
|
||||
toUnicode: { fn: "punycode.toUnicode", params: [STRING], result: STRING },
|
||||
"ucs2.decode": { fn: "punycode.ucs2Decode", params: [STRING], result: arrayOf(F64) },
|
||||
"ucs2.encode": { fn: "punycode.ucs2Encode", params: [arrayOf(F64)], result: STRING },
|
||||
},
|
||||
// node:constants (deprecated) is one frozen object (Object.assign of
|
||||
// os.constants' groups, fs.constants and crypto.constants): bindings of
|
||||
// the module read it as a checked-dynamic value (builtinConstantsObject).
|
||||
constants: {},
|
||||
// node:readline: createInterface's options are entirely special-cased
|
||||
// (exactly { input: process.stdin, output?: process.stdout } — see
|
||||
// lowerBuiltinModuleCall); the entry carries the canonical shape. The
|
||||
@@ -1930,6 +1946,7 @@ export const BUILTIN_MODULE_CONSTS: Record<
|
||||
os: { EOL: "\n", devNull: "/dev/null" },
|
||||
worker_threads: { isMainThread: true, threadId: 0 },
|
||||
cluster: { isPrimary: true, isMaster: true, isWorker: false },
|
||||
punycode: { version: "2.1.0" },
|
||||
// zlib's module-level copies of its constants (every member outside
|
||||
// BROTLI_*, Node's own loop over zlib.constants).
|
||||
zlib: Object.fromEntries(
|
||||
|
||||
@@ -466,6 +466,13 @@ export const MAY_THROW_LIB_FNS: ReadonlySet<IrLibFn> = new Set([
|
||||
"str.encodeUri",
|
||||
"qs.escape",
|
||||
"qs.stringify",
|
||||
// node:punycode's RangeErrors (encode/toASCII only past 32-bit deltas)
|
||||
// and String.fromCodePoint's for ucs2.encode.
|
||||
"punycode.decode",
|
||||
"punycode.encode",
|
||||
"punycode.toASCII",
|
||||
"punycode.toUnicode",
|
||||
"punycode.ucs2Encode",
|
||||
// The base64 globals: atob/btoa throw the catchable DOMException
|
||||
// InvalidCharacterError on malformed input; the zero-argument form
|
||||
// always throws Node's TypeError [ERR_MISSING_ARGS].
|
||||
|
||||
@@ -559,6 +559,10 @@ export const LIB_FN_SIGS = defineLibFnSignatures({
|
||||
/** os.constants: the per-thread null-prototype constants object (dlopen,
|
||||
* errno, signals, priority, UV_UDP_REUSEADDR). Never throws. */
|
||||
"os.constants": { argTypes: [], result: DYN },
|
||||
/** The deprecated node:constants object (scr_os.c): the os groups and
|
||||
* fs.constants merged with the borrowed baked crypto.constants table,
|
||||
* frozen, one per thread. */
|
||||
"constants.object": { argTypes: [DYN], result: DYN },
|
||||
/** umask(2): arg < 0 reads without setting (umask has no read-only form
|
||||
* — set 0, restore); otherwise sets and answers the PREVIOUS mask.
|
||||
* Never throws. */
|
||||
@@ -856,6 +860,19 @@ export const LIB_FN_SIGS = defineLibFnSignatures({
|
||||
"url.legacyResolve": { argTypes: [DYN, DYN, BOOL], result: STRING },
|
||||
"url.domainToASCII": { argTypes: [DYN, BOOL], result: STRING },
|
||||
"url.domainToUnicode": { argTypes: [DYN, BOOL], result: STRING },
|
||||
/** node:punycode (scr_url.c): punycode.js 2.1.0's string conversions;
|
||||
* decode/toUnicode (and, past 32-bit deltas, encode/toASCII) throw the
|
||||
* module's RangeErrors, ucs2Encode String.fromCodePoint's. warn marks the
|
||||
* module's first load (scr_async_dyn.c) and reports DEP0040 then unless
|
||||
* the second argument is false: at once for a static ES import, on the
|
||||
* next tick for a require() call. */
|
||||
"punycode.decode": { argTypes: [STRING], result: STRING },
|
||||
"punycode.encode": { argTypes: [STRING], result: STRING },
|
||||
"punycode.toASCII": { argTypes: [STRING], result: STRING },
|
||||
"punycode.toUnicode": { argTypes: [STRING], result: STRING },
|
||||
"punycode.ucs2Decode": { argTypes: [STRING], result: arrayOf(F64) },
|
||||
"punycode.ucs2Encode": { argTypes: [arrayOf(F64)], result: STRING },
|
||||
"punycode.warn": { argTypes: [BOOL, BOOL], result: VOID },
|
||||
"url.fileURLToPathBuffer": { argTypes: [DYN, DYN], result: BYTES_U8 },
|
||||
"url.pathToFileURLChecked": { argTypes: [DYN, DYN], result: URL_T },
|
||||
"url.fileURLToPathStr": { argTypes: [STRING], result: STRING },
|
||||
|
||||
@@ -43,6 +43,8 @@ export interface RuntimeFeatures {
|
||||
}
|
||||
|
||||
const DYN_ASYNC_LIB_FNS: ReadonlySet<IrLibFn> = new Set([
|
||||
// DEP0040 rides the dyn-async unit's warning machinery.
|
||||
"punycode.warn",
|
||||
"fs.callbackValue",
|
||||
"fs.callbackCall",
|
||||
"fs.callbackGlob",
|
||||
|
||||
@@ -466,6 +466,13 @@
|
||||
"status": "static",
|
||||
"note": "recognized module (bare and node:-prefixed specifiers)"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.constants",
|
||||
"kind": "node-builtin",
|
||||
"name": "constants",
|
||||
"status": "static",
|
||||
"note": "recognized module (bare and node:-prefixed specifiers)"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.crypto",
|
||||
"kind": "node-builtin",
|
||||
@@ -2095,6 +2102,56 @@
|
||||
"status": "static",
|
||||
"note": "shared version dictionary containing node and openssl; other components are absent unless defined by the program"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.punycode",
|
||||
"kind": "node-builtin",
|
||||
"name": "punycode",
|
||||
"status": "static",
|
||||
"note": "recognized module (bare and node:-prefixed specifiers)"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.punycode.decode",
|
||||
"kind": "node-builtin",
|
||||
"name": "punycode.decode",
|
||||
"status": "static"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.punycode.encode",
|
||||
"kind": "node-builtin",
|
||||
"name": "punycode.encode",
|
||||
"status": "static"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.punycode.toASCII",
|
||||
"kind": "node-builtin",
|
||||
"name": "punycode.toASCII",
|
||||
"status": "static"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.punycode.toUnicode",
|
||||
"kind": "node-builtin",
|
||||
"name": "punycode.toUnicode",
|
||||
"status": "static"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.punycode.ucs2.decode",
|
||||
"kind": "node-builtin",
|
||||
"name": "punycode.ucs2.decode",
|
||||
"status": "static"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.punycode.ucs2.encode",
|
||||
"kind": "node-builtin",
|
||||
"name": "punycode.ucs2.encode",
|
||||
"status": "static"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.punycode.version",
|
||||
"kind": "node-builtin",
|
||||
"name": "punycode.version",
|
||||
"status": "static",
|
||||
"note": "constant value read"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.querystring",
|
||||
"kind": "node-builtin",
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/6122-punycode-conversions.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/6124-punycode-require-warnings.cjs"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/6125-constants-module.cjs"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/6126-punycode-dependency/main.cjs"
|
||||
],
|
||||
"diags": [
|
||||
{
|
||||
"code": "SC1010",
|
||||
"message": "the 'puny-dep' module is not supported yet",
|
||||
"loc": {
|
||||
"file": "<repo>/tests/corpus/6126-punycode-dependency/main.cjs",
|
||||
"start": 347,
|
||||
"end": 376
|
||||
},
|
||||
"milestone": "M4",
|
||||
"hint": "relative imports (./file, ../dir/file), package.json-mediated project imports (#alias via the imports field, self-name references via exports), statically compiled npm packages, and the built-in fs, fs/promises, path, os, url, crypto, zlib, child_process, net, http, tls, https, http2, dgram, dns, util, util/types, string_decoder, querystring, readline, events, stream, stream/promises, stream/consumers, buffer, assert, assert/strict, worker_threads, cluster, tty, async_hooks, timers, timers/promises, diagnostics_channel, perf_hooks, module, and console modules (bare or node:-prefixed) and node:test (node:-prefixed only, like in Node) are supported"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -212,6 +212,11 @@ void scr_process_on_warning(ScrDyn *fn);
|
||||
void scr_process_off_warning(ScrDyn *fn);
|
||||
void scr_process_emit_warning(ScrDyn *args);
|
||||
void scr_emit_warning(const char *name, const char *code, ScrStr *message);
|
||||
/* node:punycode's first load (scr_async_dyn.c): later calls are module
|
||||
* cache hits. The first reports DEP0040 when `report` (false for a require
|
||||
* made from node_modules) — at once for a static ES import, which Node
|
||||
* links before any module evaluates, otherwise on the next tick. */
|
||||
void scr_punycode_warn(bool immediate, bool report);
|
||||
/* scr_emit_warning once a 'warning' listener exists (scr_lib.c; set by the
|
||||
* listener registration): units that cannot link the dyn-async unit route
|
||||
* their warnings through it, and print the default report otherwise. */
|
||||
|
||||
@@ -813,6 +813,27 @@ void scr_warning_emit_deferred(ScrDyn *w) {
|
||||
scr_warning_defer(w, scr_warning_tick);
|
||||
}
|
||||
|
||||
static SCR_TL bool scr_punycode_loaded = false;
|
||||
|
||||
void scr_punycode_warn(bool immediate, bool report) {
|
||||
if (scr_punycode_loaded) return;
|
||||
scr_punycode_loaded = true;
|
||||
if (!report) return;
|
||||
static const char text[] =
|
||||
"The `punycode` module is deprecated. Please use a userland alternative instead.";
|
||||
ScrStr *message = scr_str_new(text, sizeof text - 1);
|
||||
ScrStr *code = scr_str_new("DEP0040", 7);
|
||||
ScrDyn *w = scr_warning_new(message, "DeprecationWarning", code);
|
||||
if (immediate) {
|
||||
if (!scr_process_deprecation_flag_on(0)) scr_warning_dispatch(w);
|
||||
} else {
|
||||
scr_warning_emit_deferred(w);
|
||||
}
|
||||
scr_dyn_release(w);
|
||||
scr_str_release(code);
|
||||
scr_str_release(message);
|
||||
}
|
||||
|
||||
/* The console members' warnings. Node's emitWarning emits on
|
||||
* process.nextTick, so these queue in order and each rides one raw tick
|
||||
* on the shared tick queue; any left at exit are dropped with it. */
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/sysinfo.h>
|
||||
#endif
|
||||
@@ -1286,3 +1288,195 @@ ScrDyn *scr_os_constants(void) {
|
||||
scr_atexit(scr_os_constants_clear);
|
||||
return scr_dyn_retain(os);
|
||||
}
|
||||
|
||||
/* ── node:constants (deprecated, DEP0008) ──────────────────────────────
|
||||
* Node's lib/constants.js: Object.assign({}, os.constants.dlopen, errno,
|
||||
* priority, signals, fs.constants, crypto.constants), frozen, with an
|
||||
* ordinary prototype. The fs group follows node_constants.cc's
|
||||
* DefineFsConstants order and guards (libuv's UV_* values are fixed on
|
||||
* POSIX); crypto_table (borrowed) is a compiler-emitted function that
|
||||
* answers the baked crypto.constants table, called only on first use. One
|
||||
* object per thread. */
|
||||
#define SCR_FS_CONSTANT(o, name) scr_os_constant((o), #name, (double)(name))
|
||||
|
||||
static void scr_fs_constants(ScrDyn *o) {
|
||||
scr_os_constant(o, "UV_FS_SYMLINK_DIR", 1);
|
||||
scr_os_constant(o, "UV_FS_SYMLINK_JUNCTION", 2);
|
||||
#ifdef O_RDONLY
|
||||
SCR_FS_CONSTANT(o, O_RDONLY);
|
||||
#endif
|
||||
#ifdef O_WRONLY
|
||||
SCR_FS_CONSTANT(o, O_WRONLY);
|
||||
#endif
|
||||
#ifdef O_RDWR
|
||||
SCR_FS_CONSTANT(o, O_RDWR);
|
||||
#endif
|
||||
scr_os_constant(o, "UV_DIRENT_UNKNOWN", 0);
|
||||
scr_os_constant(o, "UV_DIRENT_FILE", 1);
|
||||
scr_os_constant(o, "UV_DIRENT_DIR", 2);
|
||||
scr_os_constant(o, "UV_DIRENT_LINK", 3);
|
||||
scr_os_constant(o, "UV_DIRENT_FIFO", 4);
|
||||
scr_os_constant(o, "UV_DIRENT_SOCKET", 5);
|
||||
scr_os_constant(o, "UV_DIRENT_CHAR", 6);
|
||||
scr_os_constant(o, "UV_DIRENT_BLOCK", 7);
|
||||
#ifdef S_IFMT
|
||||
SCR_FS_CONSTANT(o, S_IFMT);
|
||||
#endif
|
||||
#ifdef S_IFREG
|
||||
SCR_FS_CONSTANT(o, S_IFREG);
|
||||
#endif
|
||||
#ifdef S_IFDIR
|
||||
SCR_FS_CONSTANT(o, S_IFDIR);
|
||||
#endif
|
||||
#ifdef S_IFCHR
|
||||
SCR_FS_CONSTANT(o, S_IFCHR);
|
||||
#endif
|
||||
#ifdef S_IFBLK
|
||||
SCR_FS_CONSTANT(o, S_IFBLK);
|
||||
#endif
|
||||
#ifdef S_IFIFO
|
||||
SCR_FS_CONSTANT(o, S_IFIFO);
|
||||
#endif
|
||||
#ifdef S_IFLNK
|
||||
SCR_FS_CONSTANT(o, S_IFLNK);
|
||||
#endif
|
||||
#ifdef S_IFSOCK
|
||||
SCR_FS_CONSTANT(o, S_IFSOCK);
|
||||
#endif
|
||||
#ifdef O_CREAT
|
||||
SCR_FS_CONSTANT(o, O_CREAT);
|
||||
#endif
|
||||
#ifdef O_EXCL
|
||||
SCR_FS_CONSTANT(o, O_EXCL);
|
||||
#endif
|
||||
/* libuv's Windows-only open flags are 0 everywhere else. */
|
||||
scr_os_constant(o, "UV_FS_O_FILEMAP", 0);
|
||||
scr_os_constant(o, "UV_FS_O_TEMPORARY", 0);
|
||||
scr_os_constant(o, "UV_FS_O_SHORT_LIVED", 0);
|
||||
scr_os_constant(o, "UV_FS_O_SEQUENTIAL", 0);
|
||||
scr_os_constant(o, "UV_FS_O_RANDOM", 0);
|
||||
#ifdef O_NOCTTY
|
||||
SCR_FS_CONSTANT(o, O_NOCTTY);
|
||||
#endif
|
||||
#ifdef O_TRUNC
|
||||
SCR_FS_CONSTANT(o, O_TRUNC);
|
||||
#endif
|
||||
#ifdef O_APPEND
|
||||
SCR_FS_CONSTANT(o, O_APPEND);
|
||||
#endif
|
||||
#ifdef O_DIRECTORY
|
||||
SCR_FS_CONSTANT(o, O_DIRECTORY);
|
||||
#endif
|
||||
#ifdef O_NOATIME
|
||||
SCR_FS_CONSTANT(o, O_NOATIME);
|
||||
#endif
|
||||
#ifdef O_NOFOLLOW
|
||||
SCR_FS_CONSTANT(o, O_NOFOLLOW);
|
||||
#endif
|
||||
#ifdef O_SYNC
|
||||
SCR_FS_CONSTANT(o, O_SYNC);
|
||||
#endif
|
||||
#ifdef O_DSYNC
|
||||
SCR_FS_CONSTANT(o, O_DSYNC);
|
||||
#endif
|
||||
#ifdef O_SYMLINK
|
||||
SCR_FS_CONSTANT(o, O_SYMLINK);
|
||||
#endif
|
||||
#ifdef O_DIRECT
|
||||
SCR_FS_CONSTANT(o, O_DIRECT);
|
||||
#endif
|
||||
#ifdef O_NONBLOCK
|
||||
SCR_FS_CONSTANT(o, O_NONBLOCK);
|
||||
#endif
|
||||
#ifdef S_IRWXU
|
||||
SCR_FS_CONSTANT(o, S_IRWXU);
|
||||
#endif
|
||||
#ifdef S_IRUSR
|
||||
SCR_FS_CONSTANT(o, S_IRUSR);
|
||||
#endif
|
||||
#ifdef S_IWUSR
|
||||
SCR_FS_CONSTANT(o, S_IWUSR);
|
||||
#endif
|
||||
#ifdef S_IXUSR
|
||||
SCR_FS_CONSTANT(o, S_IXUSR);
|
||||
#endif
|
||||
#ifdef S_IRWXG
|
||||
SCR_FS_CONSTANT(o, S_IRWXG);
|
||||
#endif
|
||||
#ifdef S_IRGRP
|
||||
SCR_FS_CONSTANT(o, S_IRGRP);
|
||||
#endif
|
||||
#ifdef S_IWGRP
|
||||
SCR_FS_CONSTANT(o, S_IWGRP);
|
||||
#endif
|
||||
#ifdef S_IXGRP
|
||||
SCR_FS_CONSTANT(o, S_IXGRP);
|
||||
#endif
|
||||
#ifdef S_IRWXO
|
||||
SCR_FS_CONSTANT(o, S_IRWXO);
|
||||
#endif
|
||||
#ifdef S_IROTH
|
||||
SCR_FS_CONSTANT(o, S_IROTH);
|
||||
#endif
|
||||
#ifdef S_IWOTH
|
||||
SCR_FS_CONSTANT(o, S_IWOTH);
|
||||
#endif
|
||||
#ifdef S_IXOTH
|
||||
SCR_FS_CONSTANT(o, S_IXOTH);
|
||||
#endif
|
||||
#ifdef F_OK
|
||||
SCR_FS_CONSTANT(o, F_OK);
|
||||
#endif
|
||||
#ifdef R_OK
|
||||
SCR_FS_CONSTANT(o, R_OK);
|
||||
#endif
|
||||
#ifdef W_OK
|
||||
SCR_FS_CONSTANT(o, W_OK);
|
||||
#endif
|
||||
#ifdef X_OK
|
||||
SCR_FS_CONSTANT(o, X_OK);
|
||||
#endif
|
||||
scr_os_constant(o, "UV_FS_COPYFILE_EXCL", 1);
|
||||
scr_os_constant(o, "COPYFILE_EXCL", 1);
|
||||
scr_os_constant(o, "UV_FS_COPYFILE_FICLONE", 2);
|
||||
scr_os_constant(o, "COPYFILE_FICLONE", 2);
|
||||
scr_os_constant(o, "UV_FS_COPYFILE_FICLONE_FORCE", 4);
|
||||
scr_os_constant(o, "COPYFILE_FICLONE_FORCE", 4);
|
||||
}
|
||||
#undef SCR_FS_CONSTANT
|
||||
|
||||
static SCR_TL ScrDyn *scr_node_constants_value;
|
||||
static void scr_node_constants_clear(void) {
|
||||
ScrDyn *value = scr_node_constants_value;
|
||||
scr_node_constants_value = NULL;
|
||||
scr_dyn_release(value);
|
||||
}
|
||||
|
||||
ScrDyn *scr_node_constants(const ScrDyn *crypto_table) {
|
||||
if (scr_node_constants_value) return scr_dyn_retain(scr_node_constants_value);
|
||||
ScrDyn *crypto = scr_dyn_call(crypto_table, NULL, 0, "constants");
|
||||
if (!crypto) return NULL;
|
||||
ScrDyn *o = scr_dyn_new_obj();
|
||||
scr_os_dlopen_constants(o);
|
||||
scr_os_errno_constants(o);
|
||||
scr_os_constant(o, "PRIORITY_LOW", SCR_OS_PRIORITY_LOW);
|
||||
scr_os_constant(o, "PRIORITY_BELOW_NORMAL", SCR_OS_PRIORITY_BELOW_NORMAL);
|
||||
scr_os_constant(o, "PRIORITY_NORMAL", SCR_OS_PRIORITY_NORMAL);
|
||||
scr_os_constant(o, "PRIORITY_ABOVE_NORMAL", SCR_OS_PRIORITY_ABOVE_NORMAL);
|
||||
scr_os_constant(o, "PRIORITY_HIGH", SCR_OS_PRIORITY_HIGH);
|
||||
scr_os_constant(o, "PRIORITY_HIGHEST", SCR_OS_PRIORITY_HIGHEST);
|
||||
scr_os_signal_constants(o);
|
||||
scr_fs_constants(o);
|
||||
if (crypto && crypto->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < crypto->v.obj.len; i++) {
|
||||
const ScrDynEntry *entry = &crypto->v.obj.entries[i];
|
||||
if (entry->accessor || !entry->value) continue;
|
||||
scr_dyn_obj_set(o, entry->key, entry->key_len, scr_dyn_retain(entry->value));
|
||||
}
|
||||
}
|
||||
scr_dyn_release(crypto);
|
||||
scr_dyn_release(scr_dyn_freeze(o));
|
||||
scr_node_constants_value = o;
|
||||
scr_atexit(scr_node_constants_clear);
|
||||
return scr_dyn_retain(o);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@ ScrStr *scr_os_cpus_model(double i);
|
||||
double scr_os_cpus_field(double i, double field);
|
||||
/* os.constants: the per-thread null-prototype constants object (+1). */
|
||||
ScrDyn *scr_os_constants(void);
|
||||
/* The deprecated node:constants module object (scr_os.c): the os groups,
|
||||
* fs.constants and the crypto table the borrowed function answers, merged
|
||||
* and frozen (+1). */
|
||||
ScrDyn *scr_node_constants(const ScrDyn *crypto_table);
|
||||
double scr_os_available_parallelism(void); /* uv_available_parallelism: CPUs this process may use, >= 1 */
|
||||
/* os.userInfo()'s field trio (pw_name / pw_shell / pw_dir — the passwd
|
||||
* home, not the $HOME cascade). +1 fresh; abort on lookup failure. */
|
||||
|
||||
@@ -1988,3 +1988,342 @@ ScrBytes *scr_url_checked_to_path_buffer(const ScrDyn *value, const ScrDyn *opti
|
||||
scr_url_release(url);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ── node:punycode (deprecated, DEP0040) ───────────────────────────────
|
||||
* A port of the punycode.js 2.1.0 that Node 24 bundles as lib/punycode.js.
|
||||
* It works on UTF-16 code units: ucs2.decode pairs surrogates and keeps
|
||||
* lone ones, which is exactly a code-point walk over WTF-8 storage.
|
||||
* Errors throw the module's RangeErrors ("Overflow: ...", "Illegal input
|
||||
* >= 0x80 ...", "Invalid input"); decoded code points past U+10FFFF throw
|
||||
* String.fromCodePoint's "Invalid code point N". All inputs are borrowed;
|
||||
* results are +1, or NULL with the error pending. The DEP0040 report is
|
||||
* scr_punycode_warn (scr_async_dyn.c). */
|
||||
|
||||
enum {
|
||||
PC_MAX_INT = 2147483647,
|
||||
PC_BASE = 36,
|
||||
PC_TMIN = 1,
|
||||
PC_TMAX = 26,
|
||||
PC_SKEW = 38,
|
||||
PC_DAMP = 700,
|
||||
PC_INITIAL_BIAS = 72,
|
||||
PC_INITIAL_N = 128
|
||||
};
|
||||
|
||||
static void pc_error(const char *message) {
|
||||
scr_throw_error_msg(SCR_ERR_RANGE, message, strlen(message));
|
||||
}
|
||||
#define PC_OVERFLOW "Overflow: input needs wider integers to process"
|
||||
#define PC_NOT_BASIC "Illegal input >= 0x80 (not a basic code point)"
|
||||
#define PC_INVALID "Invalid input"
|
||||
|
||||
typedef struct {
|
||||
uint32_t *data;
|
||||
size_t len, cap;
|
||||
} PcPoints;
|
||||
|
||||
static void pc_push(PcPoints *p, uint32_t cp) {
|
||||
if (p->len == p->cap) {
|
||||
size_t cap = p->cap ? p->cap * 2 : 16;
|
||||
uint32_t *grown = realloc(p->data, cap * sizeof *grown);
|
||||
if (!grown) scr_trap("scriptc: out of memory\n");
|
||||
p->data = grown;
|
||||
p->cap = cap;
|
||||
}
|
||||
p->data[p->len++] = cp;
|
||||
}
|
||||
|
||||
/* ucs2decode over WTF-8 storage: a pair is one 4-byte sequence, a lone
|
||||
* surrogate one 3-byte sequence carrying its own value. */
|
||||
static void pc_code_points(const char *s, size_t n, PcPoints *out) {
|
||||
const unsigned char *b = (const unsigned char *)s;
|
||||
for (size_t i = 0; i < n;) {
|
||||
uint32_t c = b[i];
|
||||
if (c < 0x80) {
|
||||
i += 1;
|
||||
} else if (c < 0xE0 && i + 1 < n) {
|
||||
c = ((c & 0x1F) << 6) | (b[i + 1] & 0x3F);
|
||||
i += 2;
|
||||
} else if (c < 0xF0 && i + 2 < n) {
|
||||
c = ((c & 0x0F) << 12) | ((uint32_t)(b[i + 1] & 0x3F) << 6) | (b[i + 2] & 0x3F);
|
||||
i += 3;
|
||||
} else if (i + 3 < n) {
|
||||
c = ((c & 0x07) << 18) | ((uint32_t)(b[i + 1] & 0x3F) << 12) |
|
||||
((uint32_t)(b[i + 2] & 0x3F) << 6) | (b[i + 3] & 0x3F);
|
||||
i += 4;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
pc_push(out, c);
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t pc_adapt(int64_t delta, int64_t points, bool first) {
|
||||
int64_t k = 0;
|
||||
delta = first ? delta / PC_DAMP : delta >> 1;
|
||||
delta += delta / points;
|
||||
for (; delta > ((PC_BASE - PC_TMIN) * PC_TMAX) >> 1; k += PC_BASE) delta /= PC_BASE - PC_TMIN;
|
||||
return k + (PC_BASE - PC_TMIN + 1) * delta / (delta + PC_SKEW);
|
||||
}
|
||||
|
||||
static int64_t pc_basic_to_digit(unsigned char c) {
|
||||
if (c >= 0x30 && c < 0x3A) return 26 + (c - 0x30);
|
||||
if (c >= 0x41 && c < 0x5B) return c - 0x41;
|
||||
if (c >= 0x61 && c < 0x7B) return c - 0x61;
|
||||
return PC_BASE;
|
||||
}
|
||||
|
||||
static char pc_digit_to_basic(int64_t digit) {
|
||||
return (char)(digit + 22 + 75 * (digit < 26));
|
||||
}
|
||||
|
||||
/* String.fromCodePoint(...points). */
|
||||
static ScrStr *pc_from_points(const PcPoints *p) {
|
||||
for (size_t i = 0; i < p->len; i++) {
|
||||
if (p->data[i] > 0x10FFFF) {
|
||||
char message[48];
|
||||
int size = snprintf(message, sizeof message, "Invalid code point %u", (unsigned)p->data[i]);
|
||||
scr_throw_error_msg(SCR_ERR_RANGE, message, (size_t)size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
char *out = malloc(p->len * 4 + 1);
|
||||
if (!out) scr_trap("scriptc: out of memory\n");
|
||||
size_t offset = 0;
|
||||
for (size_t i = 0; i < p->len; i++) {
|
||||
uint32_t point = p->data[i];
|
||||
if (point >= 0xD800 && point <= 0xDBFF && i + 1 < p->len && p->data[i + 1] >= 0xDC00 &&
|
||||
p->data[i + 1] <= 0xDFFF) {
|
||||
point = 0x10000 + ((point - 0xD800) << 10) + (p->data[i + 1] - 0xDC00);
|
||||
i++;
|
||||
}
|
||||
offset += scr_wtf8_put(out + offset, point);
|
||||
}
|
||||
ScrStr *result = scr_str_new(out, offset);
|
||||
free(out);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* punycode.decode over the bytes of one label. Any non-ASCII byte fails
|
||||
* where its first code unit would: before the last delimiter it is not
|
||||
* basic, after it it is no digit — so byte positions stand in for code
|
||||
* unit positions until the first error. */
|
||||
static ScrStr *pc_decode(const char *s, size_t n) {
|
||||
PcPoints output = {0};
|
||||
size_t basic = 0;
|
||||
for (size_t k = n; k > 0; k--) {
|
||||
if (s[k - 1] == '-') {
|
||||
basic = k - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ScrStr *result = NULL;
|
||||
for (size_t j = 0; j < basic; j++) {
|
||||
if ((unsigned char)s[j] >= 0x80) {
|
||||
pc_error(PC_NOT_BASIC);
|
||||
goto done;
|
||||
}
|
||||
pc_push(&output, (unsigned char)s[j]);
|
||||
}
|
||||
int64_t i = 0, cp = PC_INITIAL_N, bias = PC_INITIAL_BIAS;
|
||||
for (size_t index = basic > 0 ? basic + 1 : 0; index < n;) {
|
||||
int64_t old = i;
|
||||
for (int64_t w = 1, k = PC_BASE;; k += PC_BASE) {
|
||||
if (index >= n) {
|
||||
pc_error(PC_INVALID);
|
||||
goto done;
|
||||
}
|
||||
int64_t digit = pc_basic_to_digit((unsigned char)s[index++]);
|
||||
if (digit >= PC_BASE) {
|
||||
pc_error(PC_INVALID);
|
||||
goto done;
|
||||
}
|
||||
if (digit > (PC_MAX_INT - i) / w) {
|
||||
pc_error(PC_OVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
i += digit * w;
|
||||
int64_t t = k <= bias ? PC_TMIN : (k >= bias + PC_TMAX ? PC_TMAX : k - bias);
|
||||
if (digit < t) break;
|
||||
if (w > PC_MAX_INT / (PC_BASE - t)) {
|
||||
pc_error(PC_OVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
w *= PC_BASE - t;
|
||||
}
|
||||
int64_t out = (int64_t)output.len + 1;
|
||||
bias = pc_adapt(i - old, out, old == 0);
|
||||
if (i / out > PC_MAX_INT - cp) {
|
||||
pc_error(PC_OVERFLOW);
|
||||
goto done;
|
||||
}
|
||||
cp += i / out;
|
||||
i %= out;
|
||||
pc_push(&output, 0);
|
||||
memmove(output.data + i + 1, output.data + i, (output.len - 1 - (size_t)i) * sizeof *output.data);
|
||||
output.data[i++] = (uint32_t)cp;
|
||||
}
|
||||
result = pc_from_points(&output);
|
||||
done:
|
||||
free(output.data);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* punycode.encode of one label's code points, appended to buf. */
|
||||
static bool pc_encode(const PcPoints *input, ScrJsonBuf *buf) {
|
||||
int64_t cp = PC_INITIAL_N, delta = 0, bias = PC_INITIAL_BIAS;
|
||||
size_t basic_length = 0;
|
||||
for (size_t k = 0; k < input->len; k++) {
|
||||
if (input->data[k] < 0x80) {
|
||||
scr_jb_putc(buf, (char)input->data[k]);
|
||||
basic_length++;
|
||||
}
|
||||
}
|
||||
size_t handled = basic_length;
|
||||
if (basic_length) scr_jb_putc(buf, '-');
|
||||
while (handled < input->len) {
|
||||
int64_t m = PC_MAX_INT;
|
||||
for (size_t k = 0; k < input->len; k++)
|
||||
if (input->data[k] >= cp && input->data[k] < m) m = input->data[k];
|
||||
int64_t handled_plus_one = (int64_t)handled + 1;
|
||||
if (m - cp > (PC_MAX_INT - delta) / handled_plus_one) {
|
||||
pc_error(PC_OVERFLOW);
|
||||
return false;
|
||||
}
|
||||
delta += (m - cp) * handled_plus_one;
|
||||
cp = m;
|
||||
for (size_t k = 0; k < input->len; k++) {
|
||||
int64_t current = input->data[k];
|
||||
if (current < cp && ++delta > PC_MAX_INT) {
|
||||
pc_error(PC_OVERFLOW);
|
||||
return false;
|
||||
}
|
||||
if (current == cp) {
|
||||
int64_t q = delta;
|
||||
for (int64_t j = PC_BASE;; j += PC_BASE) {
|
||||
int64_t t = j <= bias ? PC_TMIN : (j >= bias + PC_TMAX ? PC_TMAX : j - bias);
|
||||
if (q < t) break;
|
||||
scr_jb_putc(buf, pc_digit_to_basic(t + (q - t) % (PC_BASE - t)));
|
||||
q = (q - t) / (PC_BASE - t);
|
||||
}
|
||||
scr_jb_putc(buf, pc_digit_to_basic(q));
|
||||
bias = pc_adapt(delta, handled_plus_one, handled == basic_length);
|
||||
delta = 0;
|
||||
handled++;
|
||||
}
|
||||
}
|
||||
delta++;
|
||||
cp++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ScrStr *scr_punycode_decode(const ScrStr *input) { return pc_decode(input->data, input->len); }
|
||||
|
||||
ScrStr *scr_punycode_encode(const ScrStr *input) {
|
||||
PcPoints points = {0};
|
||||
pc_code_points(input->data, input->len, &points);
|
||||
ScrJsonBuf buf;
|
||||
scr_jb_init(&buf);
|
||||
bool ok = pc_encode(&points, &buf);
|
||||
free(points.data);
|
||||
ScrStr *result = scr_jb_finish(&buf);
|
||||
if (ok) return result;
|
||||
scr_str_release(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ScrArr *scr_punycode_ucs2_decode(const ScrStr *input) {
|
||||
PcPoints points = {0};
|
||||
pc_code_points(input->data, input->len, &points);
|
||||
ScrArr *out = scr_arr_new(SCR_ELEM_F64, points.len);
|
||||
for (size_t i = 0; i < points.len; i++) scr_arr_push_f64(out, (double)points.data[i]);
|
||||
free(points.data);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* mapDomain: only the part after the first '@' maps (and only up to a
|
||||
* second one — punycode.js keeps parts[0] and parts[1]); the RFC 3490
|
||||
* separators U+002E, U+3002, U+FF0E and U+FF61 all split labels, and the
|
||||
* labels rejoin with '.'. */
|
||||
static ScrStr *pc_map_domain(const ScrStr *input, bool to_ascii) {
|
||||
const char *s = input->data;
|
||||
size_t n = input->len;
|
||||
ScrJsonBuf buf;
|
||||
scr_jb_init(&buf);
|
||||
const char *at = memchr(s, '@', n);
|
||||
if (at) {
|
||||
scr_jb_write(&buf, s, (size_t)(at - s) + 1);
|
||||
const char *rest = at + 1;
|
||||
const char *second = memchr(rest, '@', n - (size_t)(rest - s));
|
||||
n = (second ? (size_t)(second - rest) : n - (size_t)(rest - s));
|
||||
s = rest;
|
||||
}
|
||||
size_t start = 0;
|
||||
bool ok = true;
|
||||
for (size_t i = 0; ok && i <= n;) {
|
||||
size_t sep = 0;
|
||||
if (i == n) sep = 1;
|
||||
else if (s[i] == '.') sep = 1;
|
||||
else if (i + 2 < n && (unsigned char)s[i] == 0xE3 && (unsigned char)s[i + 1] == 0x80 &&
|
||||
(unsigned char)s[i + 2] == 0x82)
|
||||
sep = 3;
|
||||
else if (i + 2 < n && (unsigned char)s[i] == 0xEF &&
|
||||
(((unsigned char)s[i + 1] == 0xBC && (unsigned char)s[i + 2] == 0x8E) ||
|
||||
((unsigned char)s[i + 1] == 0xBD && (unsigned char)s[i + 2] == 0xA1)))
|
||||
sep = 3;
|
||||
if (!sep) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
const char *label = s + start;
|
||||
size_t len = i - start;
|
||||
bool ascii = true;
|
||||
for (size_t k = 0; k < len; k++) ascii = ascii && (unsigned char)label[k] < 0x80;
|
||||
if (to_ascii && !ascii) {
|
||||
PcPoints points = {0};
|
||||
pc_code_points(label, len, &points);
|
||||
scr_jb_puts(&buf, "xn--");
|
||||
ok = pc_encode(&points, &buf);
|
||||
free(points.data);
|
||||
} else if (!to_ascii && len >= 4 && memcmp(label, "xn--", 4) == 0) {
|
||||
/* string.slice(4).toLowerCase(): ASCII letters fold; the one other
|
||||
* code point whose lowercase is ASCII is KELVIN SIGN (U+212A → k).
|
||||
* Any other non-ASCII stays non-ASCII and fails in decode either
|
||||
* way, at the same position. */
|
||||
ScrJsonBuf lower;
|
||||
scr_jb_init(&lower);
|
||||
for (size_t k = 4; k < len; k++) {
|
||||
unsigned char c = (unsigned char)label[k];
|
||||
if (c == 0xE2 && k + 2 < len && (unsigned char)label[k + 1] == 0x84 &&
|
||||
(unsigned char)label[k + 2] == 0xAA) {
|
||||
scr_jb_putc(&lower, 'k');
|
||||
k += 2;
|
||||
} else {
|
||||
scr_jb_putc(&lower, (char)(c >= 'A' && c <= 'Z' ? c + 32 : c));
|
||||
}
|
||||
}
|
||||
ScrStr *folded = scr_jb_finish(&lower);
|
||||
ScrStr *decoded = pc_decode(folded->data, folded->len);
|
||||
scr_str_release(folded);
|
||||
if (decoded) {
|
||||
scr_jb_put_str(&buf, decoded);
|
||||
scr_str_release(decoded);
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
} else {
|
||||
scr_jb_write(&buf, label, len);
|
||||
}
|
||||
if (ok && i < n) scr_jb_putc(&buf, '.');
|
||||
i += sep;
|
||||
start = i;
|
||||
}
|
||||
ScrStr *result = scr_jb_finish(&buf);
|
||||
if (ok) return result;
|
||||
scr_str_release(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ScrStr *scr_punycode_to_ascii(const ScrStr *input) { return pc_map_domain(input, true); }
|
||||
ScrStr *scr_punycode_to_unicode(const ScrStr *input) { return pc_map_domain(input, false); }
|
||||
|
||||
@@ -53,6 +53,15 @@ ScrDyn *scr_url_legacy_parse(const ScrDyn *url, const ScrDyn *parse_query, const
|
||||
ScrStr *scr_url_legacy_format(const ScrDyn *object, const ScrDyn *options, bool warn);
|
||||
ScrStr *scr_url_legacy_resolve(const ScrDyn *from, const ScrDyn *to, bool warn);
|
||||
ScrStr *scr_url_domain_to_ascii(const ScrDyn *domain, bool missing);
|
||||
/* node:punycode (scr_url.c): punycode.js 2.1.0's encode/decode, toASCII/
|
||||
* toUnicode (mapDomain over RFC 3490 separators) and ucs2.decode (UTF-16
|
||||
* code points as an f64 array). Borrowed input; +1, or NULL with the
|
||||
* module's RangeError pending. */
|
||||
ScrStr *scr_punycode_decode(const ScrStr *input);
|
||||
ScrStr *scr_punycode_encode(const ScrStr *input);
|
||||
ScrStr *scr_punycode_to_ascii(const ScrStr *input);
|
||||
ScrStr *scr_punycode_to_unicode(const ScrStr *input);
|
||||
ScrArr *scr_punycode_ucs2_decode(const ScrStr *input);
|
||||
ScrStr *scr_url_domain_to_unicode(const ScrDyn *domain, bool missing);
|
||||
ScrStr *scr_url_to_path(ScrUrl *u); /* +1, or throws */
|
||||
ScrStr *scr_url_str_to_path(ScrStr *s); /* +1, or throws */
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// @exit: 1
|
||||
// @no-node-shims
|
||||
// node:punycode's conversions (punycode.js 2.1.0): encode/decode of bare
|
||||
// labels, toASCII/toUnicode over domains and email addresses (only the part
|
||||
// after '@' maps; every RFC 3490 separator splits labels), ucs2 code point
|
||||
// arrays with astral pairs and lone surrogates, and the RangeErrors of
|
||||
// malformed input. A static import links the module before anything runs,
|
||||
// so its DEP0040 report precedes the program and no 'warning' listener the
|
||||
// program registers sees it (the Node side runs without the preload shim,
|
||||
// which would delay that report past the program's first turn). The report
|
||||
// carries the process id, so the @exit directive keeps stderr out of the
|
||||
// comparison.
|
||||
import * as punycode from "node:punycode";
|
||||
|
||||
process.on("warning", (w) => console.log("listener", w.name));
|
||||
|
||||
const show = (label: string, f: () => unknown): void => {
|
||||
try {
|
||||
console.log(label, JSON.stringify(f()));
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
console.log(label, "threw", err instanceof RangeError, err.name, err.message);
|
||||
}
|
||||
};
|
||||
|
||||
console.log(punycode.version);
|
||||
for (const s of ["mañana", "bücher", "ü", "abc", "", "-> $1.00 <-", "ليهمابتكلموشعربي؟", "他们为什么不说中文", "😀x", "MaJiでKoiする5秒前"]) {
|
||||
show(`encode ${s}`, () => punycode.encode(s));
|
||||
show(`roundtrip ${s}`, () => punycode.decode(punycode.encode(s)));
|
||||
}
|
||||
for (const s of ["maana-pta", "bcher-kva", "tda", "abc-", "-abc", "ABC-kva", "a-b-c-kva", "ü-kva", "kva-ü", "99999999999", "zzzzzzzzzzzzz", "a-", "-"]) {
|
||||
show(`decode ${s}`, () => punycode.decode(s));
|
||||
}
|
||||
for (const d of ["mañana.com", "bücher.de", "example.com", "", "a..b", "ex@mple@bücher.de", "user@bücher.de", "日本。jp", "a.b。c", "ÄÖÜ.test", "a.b."]) {
|
||||
show(`toASCII ${d}`, () => punycode.toASCII(d));
|
||||
}
|
||||
for (const d of ["xn--maana-pta.com", "xn--bcher-kva.de", "XN--bcher-kva.de", "xn--BCHER-KVA.de", "example.com", "user@xn--bcher-kva.de", "xn--.x", "xn--ü.x", "xn--zzzzzzzzzzzzz.x", "xn--a-Kva.x"]) {
|
||||
show(`toUnicode ${d}`, () => punycode.toUnicode(d));
|
||||
}
|
||||
show("ucs2.decode", () => punycode.ucs2.decode("aé😀\ud800b\udc00"));
|
||||
show("ucs2.encode", () => punycode.ucs2.encode([97, 0xe9, 0x1f600, 0xd800, 0xdc00, 98]));
|
||||
show("ucs2.encode join", () => punycode.ucs2.encode([0xd83d, 0xde00]).length);
|
||||
show("ucs2.encode range", () => punycode.ucs2.encode([0x110000]));
|
||||
show("ucs2 roundtrip", () => punycode.ucs2.encode(punycode.ucs2.decode("x😀\udfffy")) === "x😀\udfffy");
|
||||
process.exitCode = 1;
|
||||
@@ -0,0 +1,32 @@
|
||||
// DEP0040 for require("punycode"): reported once, on the next tick after
|
||||
// the requiring turn, to the stderr report and the 'warning' listeners;
|
||||
// require("node:punycode") is the same module and does not report again.
|
||||
// process.noDeprecation drops the report and the listener call. The program
|
||||
// re-runs itself per case and prints each child's output with process ids
|
||||
// normalized.
|
||||
"use strict";
|
||||
const { spawnSync } = require("child_process");
|
||||
|
||||
const mode = process.argv[2];
|
||||
if (mode === "direct") {
|
||||
process.on("warning", (w) => console.log("listener", w.name, w.code, w.message));
|
||||
process.nextTick(() => console.log("earlier tick"));
|
||||
console.log("before require");
|
||||
const direct = require("punycode");
|
||||
console.log("after require", direct.toASCII("bücher.de"));
|
||||
const prefixed = require("node:punycode");
|
||||
console.log("prefixed", prefixed.toUnicode("xn--bcher-kva.de"));
|
||||
setTimeout(() => console.log("timer"), 0);
|
||||
} else if (mode === "silenced") {
|
||||
process.on("warning", (w) => console.log("listener", w.code));
|
||||
process.noDeprecation = true;
|
||||
const silencedModule = require("punycode");
|
||||
console.log("silenced", silencedModule.encode("ü"));
|
||||
} else {
|
||||
for (const child of ["direct", "silenced"]) {
|
||||
const run = spawnSync(process.execPath, [process.argv[1], child], { encoding: "utf8" });
|
||||
console.log(`== ${child}: status ${run.status}`);
|
||||
console.log(run.stdout);
|
||||
console.log(run.stderr.replace(/\(node:\d+\)/g, "(node:<pid>)"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// node:constants (deprecated in documentation only, so no warning): one
|
||||
// frozen object merging os.constants' dlopen, errno, priority and signals
|
||||
// groups with fs.constants and crypto.constants, in that order. Members
|
||||
// read like the owning modules' constants, and a constant the platform
|
||||
// lacks is absent (graceful-fs probes O_SYMLINK with hasOwnProperty).
|
||||
const constants = require("constants");
|
||||
const nodeConstants = require("node:constants");
|
||||
const os = require("os");
|
||||
|
||||
console.log(typeof constants, Object.isFrozen(constants), constants === nodeConstants);
|
||||
console.log(constants.O_RDONLY, constants.O_WRONLY, constants.O_RDWR);
|
||||
console.log(constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC);
|
||||
console.log(constants.S_IFMT, constants.S_IFREG, constants.S_IFDIR, constants.S_IRWXU);
|
||||
console.log(constants.F_OK, constants.R_OK, constants.W_OK, constants.X_OK);
|
||||
console.log(constants.COPYFILE_EXCL, constants.UV_FS_COPYFILE_FICLONE, constants.UV_DIRENT_DIR);
|
||||
console.log(constants.SIGTERM === os.constants.signals.SIGTERM, constants.SIGINT);
|
||||
console.log(constants.ENOENT === os.constants.errno.ENOENT, constants.EACCES);
|
||||
console.log(constants.PRIORITY_HIGH, constants.PRIORITY_LOW, constants.RTLD_LAZY);
|
||||
console.log(constants.TLS1_2_VERSION, constants.RSA_PKCS1_PADDING, typeof constants.defaultCoreCipherList);
|
||||
console.log(constants.hasOwnProperty("O_SYMLINK") === ("O_SYMLINK" in constants));
|
||||
console.log(constants.hasOwnProperty("O_RDWR"), "SIGKILL" in constants, "UV_UDP_REUSEADDR" in constants);
|
||||
console.log(constants.hasOwnProperty("NOT_A_CONSTANT"), "dlopen" in constants, "errno" in constants);
|
||||
const keys = Object.keys(constants);
|
||||
console.log(keys.indexOf("RTLD_LAZY") < keys.indexOf("E2BIG"), keys.indexOf("E2BIG") < keys.indexOf("PRIORITY_LOW"));
|
||||
console.log(keys.indexOf("PRIORITY_LOW") < keys.indexOf("SIGHUP"), keys.indexOf("SIGHUP") < keys.indexOf("O_RDONLY"));
|
||||
console.log(keys.indexOf("O_RDONLY") < keys.indexOf("OPENSSL_VERSION_NUMBER"), keys.includes("POINT_CONVERSION_HYBRID"));
|
||||
@@ -0,0 +1,12 @@
|
||||
// A dependency under node_modules that requires node:punycode: Node's
|
||||
// isInsideNodeModules() rule skips DEP0040 for it, so nothing reaches stderr
|
||||
// or the 'warning' listeners, and the program's own later require of the
|
||||
// cached module does not report either.
|
||||
"use strict";
|
||||
process.on("warning", (w) => console.log("listener", w.code));
|
||||
const toAscii = require("puny-dep");
|
||||
const punycode = require("punycode");
|
||||
|
||||
console.log(toAscii("mañana.com"), toAscii("example.org"));
|
||||
console.log(punycode.toUnicode("xn--maana-pta.com"));
|
||||
setTimeout(() => console.log("timer"), 0);
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
declare function toAscii(domain: string): string;
|
||||
export = toAscii;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// A dependency requiring node:punycode: Node's isInsideNodeModules() rule
|
||||
// skips DEP0040 for it.
|
||||
"use strict";
|
||||
const punycode = require("punycode");
|
||||
|
||||
module.exports = function toAscii(domain) {
|
||||
return punycode.toASCII(domain);
|
||||
};
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "puny-dep",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js"
|
||||
}
|
||||
Reference in New Issue
Block a user