Skip to content

Commit

Permalink
compiling
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Oct 31, 2024
1 parent ec4efcb commit 1bacaae
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 60 deletions.
6 changes: 4 additions & 2 deletions src/fast_check/range_finder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,7 @@ fn is_module_typed(module: &crate::Module) -> bool {
crate::Module::Js(m) => {
m.media_type.is_typed() || m.maybe_types_dependency.is_some()
}
crate::Module::Json(_) => true,
crate::Module::Json(_) | crate::Module::Wasm(_) => true,
crate::Module::Npm(_)
| crate::Module::Node(_)
| crate::Module::External(_) => false,
Expand All @@ -1280,7 +1280,9 @@ fn is_module_typed(module: &crate::Module) -> bool {

fn is_module_external(module: &crate::Module) -> bool {
match module {
crate::Module::Js(_) | crate::Module::Json(_) => false,
crate::Module::Js(_) | crate::Module::Json(_) | crate::Module::Wasm(_) => {
false
}
crate::Module::External(_)
| crate::Module::Node(_)
| crate::Module::Npm(_) => true,
Expand Down
133 changes: 106 additions & 27 deletions src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ use std::fmt;
use std::sync::Arc;
use thiserror::Error;
use url::Url;
use wasm::wasm_module_to_dts;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct Position {
Expand Down Expand Up @@ -243,6 +244,7 @@ pub enum ModuleError {
Missing(ModuleSpecifier, Option<Range>),
MissingDynamic(ModuleSpecifier, Range),
ParseErr(ModuleSpecifier, deno_ast::ParseDiagnostic),
WasmParseErr(ModuleSpecifier, wasm_dep_analyzer::ParseError),
UnsupportedMediaType(ModuleSpecifier, MediaType, Option<Range>),
InvalidTypeAssertion {
specifier: ModuleSpecifier,
Expand All @@ -262,6 +264,7 @@ impl ModuleError {
match self {
Self::LoadingErr(s, _, _)
| Self::ParseErr(s, _)
| Self::WasmParseErr(s, _)
| Self::UnsupportedMediaType(s, _, _)
| Self::Missing(s, _)
| Self::MissingDynamic(s, _)
Expand All @@ -279,6 +282,7 @@ impl ModuleError {
maybe_referrer.as_ref()
}
Self::ParseErr { .. } => None,
Self::WasmParseErr { .. } => None,
Self::InvalidTypeAssertion { range, .. } => Some(range),
Self::UnsupportedImportAttributeType { range, .. } => Some(range),
}
Expand All @@ -301,6 +305,7 @@ impl std::error::Error for ModuleError {
Self::Missing { .. }
| Self::MissingDynamic { .. }
| Self::ParseErr { .. }
| Self::WasmParseErr { .. }
| Self::UnsupportedMediaType { .. }
| Self::InvalidTypeAssertion { .. }
| Self::UnsupportedImportAttributeType { .. } => None,
Expand All @@ -313,6 +318,7 @@ impl fmt::Display for ModuleError {
match self {
Self::LoadingErr(_, _, err) => err.fmt(f),
Self::ParseErr(_, diagnostic) => write!(f, "The module's source code could not be parsed: {diagnostic}"),
Self::WasmParseErr(specifier, diagnostic) => write!(f, "The Wasm module could not be parsed: {diagnostic}\n Specifier: {specifier}"),
Self::UnsupportedMediaType(specifier, MediaType::Json, ..) => write!(f, "Expected a JavaScript or TypeScript module, but identified a Json module. Consider importing Json modules with an import attribute with the type of \"json\".\n Specifier: {specifier}"),
Self::UnsupportedMediaType(specifier, MediaType::Cjs | MediaType::Cts, ..) if specifier.scheme() != "file" => write!(f, "Remote CJS modules are not supported.\n Specifier: {specifier}"),
Self::UnsupportedMediaType(specifier, media_type, ..) => write!(f, "Expected a JavaScript or TypeScript module, but identified a {media_type} module. Importing these types of modules is currently not supported.\n Specifier: {specifier}"),
Expand Down Expand Up @@ -2208,27 +2214,36 @@ pub(crate) enum ModuleSourceAndInfo {
maybe_headers: Option<HashMap<String, String>>,
module_info: Box<JsModuleInfo>,
},
Wasm {
specifier: ModuleSpecifier,
source: Arc<[u8]>,
source_dts: Arc<str>,
module_info: Box<JsModuleInfo>,
},
}

impl ModuleSourceAndInfo {
pub fn specifier(&self) -> &ModuleSpecifier {
match self {
Self::Json { specifier, .. } => specifier,
Self::Js { specifier, .. } => specifier,
Self::Wasm { specifier, .. } => specifier,
}
}

pub fn media_type(&self) -> MediaType {
match self {
Self::Json { .. } => MediaType::Json,
Self::Js { media_type, .. } => *media_type,
Self::Wasm { .. } => MediaType::Wasm,
}
}

pub fn source(&self) -> &str {
pub fn source_bytes(&self) -> &[u8] {
match self {
Self::Json { source, .. } => source,
Self::Js { source, .. } => source,
Self::Json { source, .. } => source.as_bytes(),
Self::Js { source, .. } => source.as_bytes(),
Self::Wasm { source, .. } => source,
}
}
}
Expand Down Expand Up @@ -2350,9 +2365,37 @@ pub(crate) async fn parse_module_source_and_info(
}
}
}
MediaType::Wasm => {
let analysis_result = wasm_dep_analyzer::WasmDeps::parse(
&opts.content,
wasm_dep_analyzer::ParseOptions { skip_types: false },
);
match analysis_result {
Ok(wasm_deps) => {
let source_dts: Arc<str> = wasm_module_to_dts(&wasm_deps).into();
match module_analyzer
.analyze(&opts.specifier, source_dts.clone(), MediaType::Dts)
.await
{
Ok(module_info) => {
// Return the module as a valid module
Ok(ModuleSourceAndInfo::Wasm {
specifier: opts.specifier,
module_info: Box::new(module_info),
source: opts.content,
source_dts,
})
}
Err(diagnostic) => {
Err(ModuleError::ParseErr(opts.specifier, diagnostic))
}
}
}
Err(err) => Err(ModuleError::WasmParseErr(opts.specifier, err)),
}
}
MediaType::Css
| MediaType::Json
| MediaType::Wasm
| MediaType::SourceMap
| MediaType::Unknown => Err(ModuleError::UnsupportedMediaType(
opts.specifier,
Expand Down Expand Up @@ -2403,6 +2446,22 @@ pub(crate) fn parse_module(
maybe_resolver,
maybe_npm_resolver,
))),
ModuleSourceAndInfo::Wasm {
specifier,
source,
source_dts,
module_info,
} => Ok(Module::Wasm(parse_wasm_module_from_module_info(
options.graph_kind,
specifier,
*module_info,
source,
source_dts,
file_system,
jsr_url_provider,
maybe_resolver,
maybe_npm_resolver,
))),
}
}

Expand Down Expand Up @@ -2744,6 +2803,37 @@ pub(crate) fn parse_js_module_from_module_info(
module
}

fn parse_wasm_module_from_module_info(
graph_kind: GraphKind,
specifier: Url,
module_info: JsModuleInfo,
source: Arc<[u8]>,
source_dts: Arc<str>,
file_system: &dyn FileSystem,
jsr_url_provider: &dyn JsrUrlProvider,
maybe_resolver: Option<&dyn Resolver>,
maybe_npm_resolver: Option<&dyn NpmResolver>,
) -> WasmModule {
let mut module = WasmModule {
specifier,
dependencies: Default::default(),
source,
source_dts,
maybe_cache_info: None,
};
fill_module_dependencies(
graph_kind,
module_info.dependencies,
&module.specifier,
&mut module.dependencies,
file_system,
jsr_url_provider,
maybe_resolver,
maybe_npm_resolver,
);
module
}

#[allow(clippy::too_many_arguments)]
fn fill_module_dependencies(
graph_kind: GraphKind,
Expand Down Expand Up @@ -3752,14 +3842,22 @@ impl<'a, 'graph> Builder<'a, 'graph> {
}
}
Module::Wasm(module) => {
// we never skip types because we use it to store the
match wasm_dep_analyzer::WasmDeps::parse(
&content,
wasm_dep_analyzer::ParseOptions { skip_types: true },
wasm_dep_analyzer::ParseOptions { skip_types: false },
) {
Ok(imports_exports) => {
Ok(wasm_deps) => {
module.source = content.clone();
module.source_dts =
wasm_module_to_dts(&wasm_deps).into();
}
Err(err) => {
*slot = ModuleSlot::Err(ModuleError::WasmParseErr(
module.specifier.clone(),
err,
));
}
Err(err) => {}
}
}
Module::Npm(_) | Module::Node(_) | Module::External(_) => {
Expand Down Expand Up @@ -4706,7 +4804,7 @@ impl<'a, 'graph> Builder<'a, 'graph> {
locker.set_remote_checksum(
&specifier,
LoaderChecksum::new(LoaderChecksum::gen(
module_source_and_info.source().as_bytes(),
module_source_and_info.source_bytes(),
)),
);
}
Expand Down Expand Up @@ -5156,25 +5254,6 @@ where
seq.end()
}

fn serialize_wasm_dependencies<S>(
dependencies: &IndexMap<String, Resolution>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[derive(Serialize)]
struct DependencyWithSpecifier<'a> {
specifier: &'a str,
code: &'a Resolution,
}
let mut seq = serializer.serialize_seq(Some(dependencies.len()))?;
for (specifier, code) in dependencies {
seq.serialize_element(&DependencyWithSpecifier { specifier, code })?
}
seq.end()
}

fn serialize_source<S>(
source: &Arc<str>,
serializer: S,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2477,7 +2477,7 @@ export const foo = 'bar';"#,
},
{
"specifier": "file:///a/e.wasm",
"error": "Expected a JavaScript or TypeScript module, but identified a Wasm module. Importing these types of modules is currently not supported.\n Specifier: file:///a/e.wasm"
"error": "The Wasm module could not be parsed: not a Wasm module\n Specifier: file:///a/e.wasm"
},
{
"dependencies": [
Expand Down
72 changes: 42 additions & 30 deletions src/symbols/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use deno_ast::swc::ast::*;
use deno_ast::swc::atoms::Atom;
use deno_ast::swc::utils::find_pat_ids;
use deno_ast::swc::utils::is_valid_ident;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_ast::ParsedSource;
use deno_ast::SourceRange;
Expand Down Expand Up @@ -167,30 +168,7 @@ impl<'a> RootSymbol<'a> {
let Ok(source) = self.parsed_source(script_module) else {
return None;
};
let specifier = &script_module.specifier;
let program = source.program();

let module_id = ModuleId(self.ids_to_modules.len() as u32);
let builder = ModuleBuilder::new(module_id);
let filler = SymbolFiller {
source: &source,
builder: &builder,
};
filler.fill(program.as_ref());
let module_symbol = EsModuleInfo {
specifier: specifier.clone(),
module_id,
source: source.clone(),
re_exports: builder.re_exports.take(),
swc_id_to_symbol_id: builder.swc_id_to_symbol_id.take(),
symbols: builder
.symbols
.take()
.into_iter()
.map(|(k, v)| (k, v.0.into_inner()))
.collect(),
};
Some(self.finalize_insert(ModuleInfo::Esm(module_symbol)))
Some(self.build_raw_es_module_info(&script_module.specifier, &source))
}

fn analyze_json_module(&self, json_module: &JsonModule) -> ModuleInfoRef {
Expand Down Expand Up @@ -245,12 +223,46 @@ impl<'a> RootSymbol<'a> {
&self,
wasm_module: &WasmModule,
) -> Option<ModuleInfoRef> {
let specifier = &wasm_module.specifier;
let imports_and_exports = wasm_dep_analyzer::WasmDeps::parse(
&wasm_module.source,
wasm_dep_analyzer::ParseOptions { skip_types: true },
)
.ok()?;
let maybe_parsed_source = self.parser.parse_program(ParseOptions {
specifier: &wasm_module.specifier,
source: wasm_module.source_dts.clone(),
media_type: MediaType::Dts,
scope_analysis: true,
});
let Ok(source) = maybe_parsed_source else {
return None;
};
Some(self.build_raw_es_module_info(&wasm_module.specifier, &source))
}

fn build_raw_es_module_info(
&self,
specifier: &ModuleSpecifier,
source: &ParsedSource,
) -> ModuleInfoRef {
let program = source.program();

let module_id = ModuleId(self.ids_to_modules.len() as u32);
let builder = ModuleBuilder::new(module_id);
let filler = SymbolFiller {
source: &source,
builder: &builder,
};
filler.fill(program.as_ref());
let module_symbol = EsModuleInfo {
specifier: specifier.clone(),
module_id,
source: source.clone(),
re_exports: builder.re_exports.take(),
swc_id_to_symbol_id: builder.swc_id_to_symbol_id.take(),
symbols: builder
.symbols
.take()
.into_iter()
.map(|(k, v)| (k, v.0.into_inner()))
.collect(),
};
self.finalize_insert(ModuleInfo::Esm(module_symbol))
}

fn finalize_insert(&self, module: ModuleInfo) -> ModuleInfoRef {
Expand Down

0 comments on commit 1bacaae

Please sign in to comment.