mirror of
https://github.com/denoland/deno.git
synced 2025-01-12 00:54:02 -05:00
feat: granular --unstable-* flags (#20968)
This commit adds granular `--unstable-*` flags: - "--unstable-broadcast-channel" - "--unstable-ffi" - "--unstable-fs" - "--unstable-http" - "--unstable-kv" - "--unstable-net" - "--unstable-worker-options" - "--unstable-cron" These flags are meant to replace a "catch-all" flag - "--unstable", that gives a binary control whether unstable features are enabled or not. The downside of this flag that allowing eg. Deno KV API also enables the FFI API (though the latter is still gated with a permission). These flags can also be specified in `deno.json` file under `unstable` key. Currently, "--unstable" flag works the same way - I will open a follow up PR that will print a warning when using "--unstable" and suggest to use concrete "--unstable-*" flag instead. We plan to phase out "--unstable" completely in Deno 2.
This commit is contained in:
parent
42c426e769
commit
24c3c96958
13 changed files with 266 additions and 27 deletions
|
@ -419,6 +419,7 @@ pub struct Flags {
|
|||
pub unstable: bool,
|
||||
pub unstable_bare_node_builtlins: bool,
|
||||
pub unstable_byonm: bool,
|
||||
pub unstable_features: Vec<String>,
|
||||
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
|
||||
pub v8_flags: Vec<String>,
|
||||
}
|
||||
|
@ -814,6 +815,46 @@ pub fn flags_from_vec(args: Vec<String>) -> clap::error::Result<Flags> {
|
|||
if matches.get_flag("unstable") {
|
||||
flags.unstable = true;
|
||||
}
|
||||
if matches.get_flag("unstable-broadcast-channel") {
|
||||
flags.unstable_features.push(
|
||||
deno_runtime::deno_broadcast_channel::UNSTABLE_FEATURE_NAME.to_string(),
|
||||
);
|
||||
}
|
||||
if matches.get_flag("unstable-ffi") {
|
||||
flags
|
||||
.unstable_features
|
||||
.push(deno_runtime::deno_ffi::UNSTABLE_FEATURE_NAME.to_string());
|
||||
}
|
||||
if matches.get_flag("unstable-fs") {
|
||||
flags
|
||||
.unstable_features
|
||||
.push(deno_runtime::deno_fs::UNSTABLE_FEATURE_NAME.to_string());
|
||||
}
|
||||
if matches.get_flag("unstable-http") {
|
||||
flags
|
||||
.unstable_features
|
||||
.push(deno_runtime::ops::http::UNSTABLE_FEATURE_NAME.to_string());
|
||||
}
|
||||
if matches.get_flag("unstable-kv") {
|
||||
flags
|
||||
.unstable_features
|
||||
.push(deno_runtime::deno_kv::UNSTABLE_FEATURE_NAME.to_string());
|
||||
}
|
||||
if matches.get_flag("unstable-net") {
|
||||
flags
|
||||
.unstable_features
|
||||
.push(deno_runtime::deno_net::UNSTABLE_FEATURE_NAME.to_string());
|
||||
}
|
||||
if matches.get_flag("unstable-worker-options") {
|
||||
flags
|
||||
.unstable_features
|
||||
.push(deno_runtime::ops::worker_host::UNSTABLE_FEATURE_NAME.to_string());
|
||||
}
|
||||
if matches.get_flag("unstable-cron") {
|
||||
flags
|
||||
.unstable_features
|
||||
.push(deno_runtime::deno_cron::UNSTABLE_FEATURE_NAME.to_string());
|
||||
}
|
||||
|
||||
flags.unstable_bare_node_builtlins =
|
||||
matches.get_flag("unstable-bare-node-builtins");
|
||||
|
@ -901,7 +942,7 @@ fn clap_root() -> Command {
|
|||
crate::version::TYPESCRIPT
|
||||
);
|
||||
|
||||
Command::new("deno")
|
||||
let mut cmd = Command::new("deno")
|
||||
.bin_name("deno")
|
||||
.color(ColorChoice::Never)
|
||||
.max_term_width(80)
|
||||
|
@ -931,7 +972,19 @@ fn clap_root() -> Command {
|
|||
.value_parser(FalseyValueParser::new())
|
||||
.action(ArgAction::SetTrue)
|
||||
.global(true),
|
||||
)
|
||||
);
|
||||
|
||||
for (flag_name, help, _) in crate::UNSTABLE_GRANULAR_FLAGS {
|
||||
cmd = cmd.arg(
|
||||
Arg::new(format!("unstable-{}", flag_name))
|
||||
.long(format!("unstable-{}", flag_name))
|
||||
.help(help)
|
||||
.action(ArgAction::SetTrue)
|
||||
.global(true),
|
||||
);
|
||||
}
|
||||
|
||||
cmd
|
||||
.arg(
|
||||
Arg::new("log-level")
|
||||
.short('L')
|
||||
|
|
|
@ -723,7 +723,14 @@ impl CliOptions {
|
|||
}
|
||||
|
||||
pub fn ts_type_lib_window(&self) -> TsTypeLib {
|
||||
if self.flags.unstable {
|
||||
if self.flags.unstable
|
||||
|| !self.flags.unstable_features.is_empty()
|
||||
|| self
|
||||
.maybe_config_file
|
||||
.as_ref()
|
||||
.map(|f| !f.json.unstable.is_empty())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
TsTypeLib::UnstableDenoWindow
|
||||
} else {
|
||||
TsTypeLib::DenoWindow
|
||||
|
@ -1264,6 +1271,17 @@ impl CliOptions {
|
|||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn unstable_features(&self) -> Vec<String> {
|
||||
let mut from_config_file = self
|
||||
.maybe_config_file()
|
||||
.as_ref()
|
||||
.map(|c| c.json.unstable.clone())
|
||||
.unwrap_or_default();
|
||||
|
||||
from_config_file.extend_from_slice(&self.flags.unstable_features);
|
||||
from_config_file
|
||||
}
|
||||
|
||||
pub fn v8_flags(&self) -> &Vec<String> {
|
||||
&self.flags.v8_flags
|
||||
}
|
||||
|
|
|
@ -595,6 +595,12 @@ impl CliFactory {
|
|||
if self.options.unstable() {
|
||||
checker.enable_legacy_unstable();
|
||||
}
|
||||
let unstable_features = self.options.unstable_features();
|
||||
for (flag_name, _, _) in crate::UNSTABLE_GRANULAR_FLAGS {
|
||||
if unstable_features.contains(&flag_name.to_string()) {
|
||||
checker.enable_feature(flag_name);
|
||||
}
|
||||
}
|
||||
|
||||
Arc::new(checker)
|
||||
})
|
||||
|
|
51
cli/main.rs
51
cli/main.rs
|
@ -256,6 +256,57 @@ fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE(bartlomieju): keep IDs in sync with `runtime/90_deno_ns.js`.
|
||||
pub(crate) static UNSTABLE_GRANULAR_FLAGS: &[(
|
||||
// flag name
|
||||
&str,
|
||||
// help text
|
||||
&str,
|
||||
// id to enable it in runtime/99_main.js
|
||||
i32,
|
||||
)] = &[
|
||||
(
|
||||
deno_runtime::deno_broadcast_channel::UNSTABLE_FEATURE_NAME,
|
||||
"Enable unstable `BroadcastChannel` API",
|
||||
1,
|
||||
),
|
||||
(
|
||||
deno_runtime::deno_ffi::UNSTABLE_FEATURE_NAME,
|
||||
"Enable unstable FFI APIs",
|
||||
2,
|
||||
),
|
||||
(
|
||||
deno_runtime::deno_fs::UNSTABLE_FEATURE_NAME,
|
||||
"Enable unstable file system APIs",
|
||||
3,
|
||||
),
|
||||
(
|
||||
deno_runtime::deno_kv::UNSTABLE_FEATURE_NAME,
|
||||
"Enable unstable Key-Value store APIs",
|
||||
4,
|
||||
),
|
||||
(
|
||||
deno_runtime::deno_net::UNSTABLE_FEATURE_NAME,
|
||||
"Enable unstable net APIs",
|
||||
5,
|
||||
),
|
||||
(
|
||||
deno_runtime::ops::http::UNSTABLE_FEATURE_NAME,
|
||||
"Enable unstable HTTP APIs",
|
||||
6,
|
||||
),
|
||||
(
|
||||
deno_runtime::ops::worker_host::UNSTABLE_FEATURE_NAME,
|
||||
"Enable unstable Web Worker APIs",
|
||||
7,
|
||||
),
|
||||
(
|
||||
deno_runtime::deno_cron::UNSTABLE_FEATURE_NAME,
|
||||
"Enable unstable Deno.cron API",
|
||||
8,
|
||||
),
|
||||
];
|
||||
|
||||
pub(crate) fn unstable_exit_cb(_feature: &str, api_name: &str) {
|
||||
// TODO(bartlomieju): change to "The `--unstable-{feature}` flag must be provided.".
|
||||
eprintln!("Unstable API '{api_name}'. The --unstable flag must be provided.");
|
||||
|
|
|
@ -123,11 +123,16 @@ itest!(check_deno_not_found {
|
|||
});
|
||||
|
||||
itest!(check_deno_unstable_not_found {
|
||||
args: "check --quiet check/deno_unstable_not_found/main.ts",
|
||||
args: "check --quiet --no-config check/deno_unstable_not_found/main.ts",
|
||||
output: "check/deno_unstable_not_found/main.out",
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
itest!(check_deno_unstable_from_config {
|
||||
args: "check --quiet --config check/deno_unstable_not_found/deno.json check/deno_unstable_not_found/main.ts",
|
||||
output_str: Some(""),
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn cache_switching_config_then_no_config() {
|
||||
let context = TestContext::default();
|
||||
|
|
3
cli/tests/testdata/check/deno_unstable_not_found/deno.json
vendored
Normal file
3
cli/tests/testdata/check/deno_unstable_not_found/deno.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"unstable": ["cron", "http", "kv"]
|
||||
}
|
|
@ -529,6 +529,16 @@ impl CliMainWorkerFactory {
|
|||
let mut extensions = ops::cli_exts(shared.npm_resolver.clone());
|
||||
extensions.append(&mut custom_extensions);
|
||||
|
||||
// TODO(bartlomieju): this is cruft, update FeatureChecker to spit out
|
||||
// list of enabled features.
|
||||
let feature_checker = shared.feature_checker.clone();
|
||||
let mut unstable_features = Vec::with_capacity(8);
|
||||
for (feature_name, _, id) in crate::UNSTABLE_GRANULAR_FLAGS {
|
||||
if feature_checker.check(feature_name) {
|
||||
unstable_features.push(*id);
|
||||
}
|
||||
}
|
||||
|
||||
let options = WorkerOptions {
|
||||
bootstrap: BootstrapOptions {
|
||||
args: shared.options.argv.clone(),
|
||||
|
@ -544,6 +554,7 @@ impl CliMainWorkerFactory {
|
|||
runtime_version: version::deno().to_string(),
|
||||
ts_version: version::TYPESCRIPT.to_string(),
|
||||
unstable: shared.options.unstable,
|
||||
unstable_features,
|
||||
user_agent: version::get_user_agent().to_string(),
|
||||
inspect: shared.options.is_inspecting,
|
||||
has_node_modules_dir: shared.options.has_node_modules_dir,
|
||||
|
@ -580,7 +591,7 @@ impl CliMainWorkerFactory {
|
|||
shared.compiled_wasm_module_store.clone(),
|
||||
),
|
||||
stdio,
|
||||
feature_checker: shared.feature_checker.clone(),
|
||||
feature_checker,
|
||||
};
|
||||
|
||||
let worker = MainWorker::bootstrap_from_options(
|
||||
|
@ -704,6 +715,16 @@ fn create_web_worker_callback(
|
|||
.join(checksum::gen(&[key.as_bytes()]))
|
||||
});
|
||||
|
||||
// TODO(bartlomieju): this is cruft, update FeatureChecker to spit out
|
||||
// list of enabled features.
|
||||
let feature_checker = shared.feature_checker.clone();
|
||||
let mut unstable_features = Vec::with_capacity(8);
|
||||
for (feature_name, _, id) in crate::UNSTABLE_GRANULAR_FLAGS {
|
||||
if feature_checker.check(feature_name) {
|
||||
unstable_features.push(*id);
|
||||
}
|
||||
}
|
||||
|
||||
let options = WebWorkerOptions {
|
||||
bootstrap: BootstrapOptions {
|
||||
args: shared.options.argv.clone(),
|
||||
|
@ -719,6 +740,7 @@ fn create_web_worker_callback(
|
|||
runtime_version: version::deno().to_string(),
|
||||
ts_version: version::TYPESCRIPT.to_string(),
|
||||
unstable: shared.options.unstable,
|
||||
unstable_features,
|
||||
user_agent: version::get_user_agent().to_string(),
|
||||
inspect: shared.options.is_inspecting,
|
||||
has_node_modules_dir: shared.options.has_node_modules_dir,
|
||||
|
@ -752,7 +774,7 @@ fn create_web_worker_callback(
|
|||
),
|
||||
stdio: stdio.clone(),
|
||||
cache_storage_dir,
|
||||
feature_checker: shared.feature_checker.clone(),
|
||||
feature_checker,
|
||||
};
|
||||
|
||||
WebWorker::bootstrap_from_options(
|
||||
|
|
|
@ -21,5 +21,5 @@ MacOS.
|
|||
To run benchmarks:
|
||||
|
||||
```bash
|
||||
target/release/deno bench --allow-ffi --allow-read --unstable ./test_ffi/tests/bench.js
|
||||
target/release/deno bench --allow-ffi --allow-read --unstable-ffi ./test_ffi/tests/bench.js
|
||||
```
|
||||
|
|
|
@ -154,6 +154,62 @@ const denoNs = {
|
|||
ChildProcess: process.ChildProcess,
|
||||
};
|
||||
|
||||
// NOTE(bartlomieju): keep IDs in sync with `cli/main.rs`
|
||||
const denoNsUnstableById = {
|
||||
// BroadcastChannel is always available?
|
||||
// 1: {},
|
||||
|
||||
// FFI
|
||||
2: {
|
||||
dlopen: ffi.dlopen,
|
||||
UnsafeCallback: ffi.UnsafeCallback,
|
||||
UnsafePointer: ffi.UnsafePointer,
|
||||
UnsafePointerView: ffi.UnsafePointerView,
|
||||
UnsafeFnPointer: ffi.UnsafeFnPointer,
|
||||
},
|
||||
|
||||
// FS
|
||||
3: {
|
||||
flock: fs.flock,
|
||||
flockSync: fs.flockSync,
|
||||
funlock: fs.funlock,
|
||||
funlockSync: fs.funlockSync,
|
||||
umask: fs.umask,
|
||||
},
|
||||
|
||||
// KV
|
||||
4: {
|
||||
openKv: kv.openKv,
|
||||
AtomicOperation: kv.AtomicOperation,
|
||||
Kv: kv.Kv,
|
||||
KvU64: kv.KvU64,
|
||||
KvListIterator: kv.KvListIterator,
|
||||
},
|
||||
|
||||
// net
|
||||
5: {
|
||||
listenDatagram: net.createListenDatagram(
|
||||
ops.op_net_listen_udp,
|
||||
ops.op_net_listen_unixpacket,
|
||||
),
|
||||
},
|
||||
|
||||
// HTTP
|
||||
6: {
|
||||
HttpClient: httpClient.HttpClient,
|
||||
createHttpClient: httpClient.createHttpClient,
|
||||
// TODO(bartlomieju): why is it needed?
|
||||
http,
|
||||
upgradeHttp: http.upgradeHttp,
|
||||
},
|
||||
// Worker options
|
||||
// 7: {}
|
||||
|
||||
8: {
|
||||
cron: cron.cron,
|
||||
},
|
||||
};
|
||||
|
||||
// when editing this list, also update unstableDenoProps in cli/tsc/99_main_compiler.js
|
||||
const denoNsUnstable = {
|
||||
listenDatagram: net.createListenDatagram(
|
||||
|
@ -183,4 +239,4 @@ const denoNsUnstable = {
|
|||
cron: cron.cron,
|
||||
};
|
||||
|
||||
export { denoNs, denoNsUnstable };
|
||||
export { denoNs, denoNsUnstable, denoNsUnstableById };
|
||||
|
|
|
@ -57,7 +57,11 @@ import * as performance from "ext:deno_web/15_performance.js";
|
|||
import * as url from "ext:deno_url/00_url.js";
|
||||
import * as fetch from "ext:deno_fetch/26_fetch.js";
|
||||
import * as messagePort from "ext:deno_web/13_message_port.js";
|
||||
import { denoNs, denoNsUnstable } from "ext:runtime/90_deno_ns.js";
|
||||
import {
|
||||
denoNs,
|
||||
denoNsUnstable,
|
||||
denoNsUnstableById,
|
||||
} from "ext:runtime/90_deno_ns.js";
|
||||
import { errors } from "ext:runtime/01_errors.js";
|
||||
import * as webidl from "ext:deno_webidl/00_webidl.js";
|
||||
import DOMException from "ext:deno_web/01_dom_exception.js";
|
||||
|
@ -467,14 +471,15 @@ function bootstrapMainRuntime(runtimeOptions) {
|
|||
7: isTty,
|
||||
8: tsVersion,
|
||||
9: unstableFlag,
|
||||
10: pid,
|
||||
11: target,
|
||||
12: v8Version,
|
||||
13: userAgent,
|
||||
14: inspectFlag,
|
||||
// 15: enableTestingFeaturesFlag
|
||||
16: hasNodeModulesDir,
|
||||
17: maybeBinaryNpmCommandName,
|
||||
10: unstableFeatures,
|
||||
11: pid,
|
||||
12: target,
|
||||
13: v8Version,
|
||||
14: userAgent,
|
||||
15: inspectFlag,
|
||||
// 16: enableTestingFeaturesFlag
|
||||
17: hasNodeModulesDir,
|
||||
18: maybeBinaryNpmCommandName,
|
||||
} = runtimeOptions;
|
||||
|
||||
performance.setTimeOrigin(DateNow());
|
||||
|
@ -557,6 +562,7 @@ function bootstrapMainRuntime(runtimeOptions) {
|
|||
mainModule: util.getterOnly(opMainModule),
|
||||
});
|
||||
|
||||
// TODO(bartlomieju): deprecate --unstable
|
||||
if (unstableFlag) {
|
||||
ObjectAssign(finalDenoNs, denoNsUnstable);
|
||||
// TODO(bartlomieju): this is not ideal, but because we use `ObjectAssign`
|
||||
|
@ -576,6 +582,11 @@ function bootstrapMainRuntime(runtimeOptions) {
|
|||
jupyterNs = val;
|
||||
},
|
||||
});
|
||||
} else {
|
||||
for (let i = 0; i <= unstableFeatures.length; i++) {
|
||||
const id = unstableFeatures[i];
|
||||
ObjectAssign(finalDenoNs, denoNsUnstableById[id]);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup `Deno` global - we're actually overriding already existing global
|
||||
|
@ -611,14 +622,15 @@ function bootstrapWorkerRuntime(
|
|||
7: isTty,
|
||||
8: tsVersion,
|
||||
9: unstableFlag,
|
||||
10: pid,
|
||||
11: target,
|
||||
12: v8Version,
|
||||
13: userAgent,
|
||||
// 14: inspectFlag,
|
||||
15: enableTestingFeaturesFlag,
|
||||
16: hasNodeModulesDir,
|
||||
17: maybeBinaryNpmCommandName,
|
||||
10: unstableFeatures,
|
||||
11: pid,
|
||||
12: target,
|
||||
13: v8Version,
|
||||
14: userAgent,
|
||||
// 15: inspectFlag,
|
||||
16: enableTestingFeaturesFlag,
|
||||
17: hasNodeModulesDir,
|
||||
18: maybeBinaryNpmCommandName,
|
||||
} = runtimeOptions;
|
||||
|
||||
performance.setTimeOrigin(DateNow());
|
||||
|
@ -688,8 +700,14 @@ function bootstrapWorkerRuntime(
|
|||
|
||||
globalThis.pollForMessages = pollForMessages;
|
||||
|
||||
// TODO(bartlomieju): deprecate --unstable
|
||||
if (unstableFlag) {
|
||||
ObjectAssign(finalDenoNs, denoNsUnstable);
|
||||
} else {
|
||||
for (let i = 0; i <= unstableFeatures.length; i++) {
|
||||
const id = unstableFeatures[i];
|
||||
ObjectAssign(finalDenoNs, denoNsUnstableById[id]);
|
||||
}
|
||||
}
|
||||
ObjectDefineProperties(finalDenoNs, {
|
||||
pid: util.readOnly(pid),
|
||||
|
|
|
@ -26,7 +26,7 @@ use std::collections::HashMap;
|
|||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub const UNSTABLE_FEATURE_NAME: &str = "worker";
|
||||
pub const UNSTABLE_FEATURE_NAME: &str = "worker-options";
|
||||
|
||||
pub struct CreateWebWorkerArgs {
|
||||
pub name: String,
|
||||
|
|
|
@ -54,7 +54,10 @@ pub struct BootstrapOptions {
|
|||
pub runtime_version: String,
|
||||
/// Sets `Deno.version.typescript` in JS runtime.
|
||||
pub ts_version: String,
|
||||
// --unstable flag, deprecated
|
||||
pub unstable: bool,
|
||||
// --unstable-* flags
|
||||
pub unstable_features: Vec<i32>,
|
||||
pub user_agent: String,
|
||||
pub inspect: bool,
|
||||
pub has_node_modules_dir: bool,
|
||||
|
@ -82,6 +85,7 @@ impl Default for BootstrapOptions {
|
|||
locale: "en".to_string(),
|
||||
location: Default::default(),
|
||||
unstable: Default::default(),
|
||||
unstable_features: Default::default(),
|
||||
inspect: Default::default(),
|
||||
args: Default::default(),
|
||||
has_node_modules_dir: Default::default(),
|
||||
|
@ -121,6 +125,8 @@ struct BootstrapV8<'a>(
|
|||
&'a str,
|
||||
// unstable
|
||||
bool,
|
||||
// granular unstable flags
|
||||
&'a [i32],
|
||||
// process_id
|
||||
i32,
|
||||
// env!("TARGET")
|
||||
|
@ -159,6 +165,7 @@ impl BootstrapOptions {
|
|||
self.is_tty,
|
||||
&self.ts_version,
|
||||
self.unstable,
|
||||
self.unstable_features.as_ref(),
|
||||
std::process::id() as _,
|
||||
env!("TARGET"),
|
||||
deno_core::v8_version(),
|
||||
|
|
|
@ -29,7 +29,7 @@ fn basic() {
|
|||
.arg("run")
|
||||
.arg("--allow-ffi")
|
||||
.arg("--allow-read")
|
||||
.arg("--unstable")
|
||||
.arg("--unstable-ffi")
|
||||
.arg("--quiet")
|
||||
.arg(r#"--v8-flags=--allow-natives-syntax"#)
|
||||
.arg("tests/test.js")
|
||||
|
|
Loading…
Reference in a new issue