/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
ext/bundle/src/lib.rs
252 строки
6 KB
Nathan Whitaker
fix(bundle): respect runtime file permissions (#36107)
05 авг 2026, 00:04
Не верифицирован
05 авг 2026, 00:04
3a10142
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. use std::cell::RefCell; use std::rc::Rc; use std::sync::Arc; use async_trait::async_trait; use deno_core::FromV8; use deno_core::OpState; use deno_core::ToV8; use deno_core::convert::Uint8Array; use deno_core::error::AnyError; use deno_core::op2; use deno_error::JsErrorBox; use deno_permissions::PermissionsContainer; deno_core::extension!( deno_bundle_runtime, deps = [ deno_web ], ops = [ op_bundle, ], esm = [ "bundle.ts" ], options = { bundle_provider: Option<Arc<dyn BundleProvider>>, }, state = |state, options| { if let Some(bundle_provider) = options.bundle_provider { state.put(bundle_provider); } else { state.put::<Arc<dyn BundleProvider>>(Arc::new(())); } }, ); #[async_trait] impl BundleProvider for () { async fn bundle( &self, _options: BundleOptions, _permissions: PermissionsContainer, ) -> Result<BuildResponse, AnyError> { // Embedders that don't wire up a real provider (notably `denort`, used // by `deno compile` outputs) fall through to this no-op implementation. // Surface that limitation directly to the user instead of leaking the // historical "default BundleProvider does not do anything" string. // See denoland/deno#31597. Err(deno_core::anyhow::anyhow!( "Deno.bundle() is not available in compiled binaries (`deno compile`). \ Run with `deno run` instead, or pre-bundle the entrypoints at build time." )) } } #[async_trait] pub trait BundleProvider: Send + Sync { async fn bundle( &self, options: BundleOptions, permissions: PermissionsContainer, ) -> Result<BuildResponse, AnyError>; } #[derive(Clone, Debug, Eq, PartialEq, Default, FromV8)] pub struct BundleOptions { pub entrypoints: Vec<String>, pub output_path: Option<String>, pub output_dir: Option<String>, #[from_v8(default)] pub external: Vec<String>, #[from_v8(serde, default)] pub format: BundleFormat, #[from_v8(default)] pub minify: bool, #[from_v8(default)] pub keep_names: bool, #[from_v8(default)] pub code_splitting: bool, #[from_v8(default = true)] pub inline_imports: bool, #[from_v8(serde, default)] pub packages: PackageHandling, #[from_v8(serde)] pub sourcemap: Option<SourceMapType>, #[from_v8(serde, default)] pub platform: BundlePlatform, #[from_v8(default = true)] pub write: bool, } #[derive(Clone, Debug, Eq, PartialEq, Copy, Default, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub enum BundlePlatform { Browser, #[default] Deno, } #[derive(Clone, Debug, Eq, PartialEq, Copy, Default, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub enum BundleFormat { #[default] Esm, Cjs, Iife, } #[derive(Clone, Debug, Eq, PartialEq, Copy, Default, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub enum SourceMapType { #[default] Linked, Inline, External, } impl std::fmt::Display for BundleFormat { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { BundleFormat::Esm => write!(f, "esm"), BundleFormat::Cjs => write!(f, "cjs"), BundleFormat::Iife => write!(f, "iife"), } } } impl std::fmt::Display for SourceMapType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { SourceMapType::Linked => write!(f, "linked"), SourceMapType::Inline => write!(f, "inline"), SourceMapType::External => write!(f, "external"), } } } #[derive(Clone, Debug, Eq, PartialEq, Copy, Default, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub enum PackageHandling { #[default] Bundle, External, } impl std::fmt::Display for PackageHandling { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { PackageHandling::Bundle => write!(f, "bundle"), PackageHandling::External => write!(f, "external"), } } } #[derive(Debug, Clone, FromV8, ToV8)] pub struct Message { pub text: String, pub location: Option<Location>, pub notes: Vec<Note>, } #[derive(Debug, Clone, FromV8, ToV8)] pub struct PartialMessage { pub id: Option<String>, pub plugin_name: Option<String>, pub text: Option<String>, pub location: Option<Location>, pub notes: Option<Vec<Note>>, pub detail: Option<u32>, } #[derive(Debug, Clone, ToV8)] pub struct BuildOutputFile { pub path: String, pub contents: Option<Uint8Array>, pub hash: String, } #[derive(Debug, Clone, ToV8)] pub struct BuildResponse { pub errors: Vec<Message>, pub warnings: Vec<Message>, pub output_files: Option<Vec<BuildOutputFile>>, } #[derive(Debug, Clone, FromV8, ToV8)] pub struct Note { pub text: String, pub location: Option<Location>, } #[derive(Debug, Clone, FromV8, ToV8)] pub struct Location { pub file: String, pub namespace: Option<String>, pub line: u32, pub column: u32, pub length: Option<u32>, pub suggestion: Option<String>, } fn deserialize_regex<'de, D>(deserializer: D) -> Result<regex::Regex, D::Error> where D: serde::Deserializer<'de>, { use serde::Deserialize; let s = String::deserialize(deserializer)?; regex::Regex::new(&s).map_err(serde::de::Error::custom) } #[derive(Debug, Clone, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct OnResolveOptions { #[serde(deserialize_with = "deserialize_regex")] pub filter: regex::Regex, pub namespace: Option<String>, } #[derive(Debug, Clone, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct OnLoadOptions { #[serde(deserialize_with = "deserialize_regex")] pub filter: regex::Regex, pub namespace: Option<String>, } #[op2] pub async fn op_bundle( state: Rc<RefCell<OpState>>, #[scoped] options: BundleOptions, ) -> Result<BuildResponse, JsErrorBox> { // eprintln!("op_bundle: {:?}", options); let (provider, permissions) = { let state = state.borrow(); let permissions = state .try_borrow::<PermissionsContainer>() .cloned() .ok_or_else(|| { JsErrorBox::generic( "Deno.bundle() requires a runtime permissions context", ) })?; ( state.borrow::<Arc<dyn BundleProvider>>().clone(), permissions, ) }; provider .bundle(options, permissions) .await .map_err(|e| JsErrorBox::generic(e.to_string())) }