1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_ast::swc::ast::ExportDefaultDecl;
use deno_ast::swc::ast::ExportSpecifier;
use deno_ast::swc::ast::ModuleExportName;
use deno_ast::swc::ast::NamedExport;
use deno_ast::swc::ast::Program;
use deno_ast::swc::visit::noop_visit_type;
use deno_ast::swc::visit::Visit;
use deno_ast::swc::visit::VisitWith;
use deno_ast::ParsedSource;
/// Gets if the parsed source has a default export.
pub fn has_default_export(source: &ParsedSource) -> bool {
let mut visitor = DefaultExportFinder {
has_default_export: false,
};
let program = source.program();
let program: &Program = &program;
program.visit_with(&mut visitor);
visitor.has_default_export
}
struct DefaultExportFinder {
has_default_export: bool,
}
impl Visit for DefaultExportFinder {
noop_visit_type!();
fn visit_export_default_decl(&mut self, _: &ExportDefaultDecl) {
self.has_default_export = true;
}
fn visit_named_export(&mut self, named_export: &NamedExport) {
if named_export
.specifiers
.iter()
.any(export_specifier_has_default)
{
self.has_default_export = true;
}
}
}
fn export_specifier_has_default(s: &ExportSpecifier) -> bool {
match s {
ExportSpecifier::Default(_) => true,
ExportSpecifier::Namespace(_) => false,
ExportSpecifier::Named(named) => {
let export_name = named.exported.as_ref().unwrap_or(&named.orig);
match export_name {
ModuleExportName::Str(_) => false,
ModuleExportName::Ident(ident) => &*ident.sym == "default",
}
}
}
}
#[cfg(test)]
mod test {
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_ast::ParseParams;
use deno_ast::ParsedSource;
use deno_ast::SourceTextInfo;
use super::has_default_export;
#[test]
fn has_default_when_export_default_decl() {
let parsed_source = parse_module("export default class Class {}");
assert!(has_default_export(&parsed_source));
}
#[test]
fn has_default_when_named_export() {
let parsed_source = parse_module("export {default} from './test.ts';");
assert!(has_default_export(&parsed_source));
}
#[test]
fn has_default_when_named_export_alias() {
let parsed_source =
parse_module("export {test as default} from './test.ts';");
assert!(has_default_export(&parsed_source));
}
#[test]
fn not_has_default_when_named_export_not_exported() {
let parsed_source =
parse_module("export {default as test} from './test.ts';");
assert!(!has_default_export(&parsed_source));
}
#[test]
fn not_has_default_when_not() {
let parsed_source = parse_module("export {test} from './test.ts'; export class Test{} export * from './test';");
assert!(!has_default_export(&parsed_source));
}
fn parse_module(text: &str) -> ParsedSource {
deno_ast::parse_module(ParseParams {
specifier: ModuleSpecifier::parse("file:///mod.ts").unwrap(),
capture_tokens: false,
maybe_syntax: None,
media_type: MediaType::TypeScript,
scope_analysis: false,
text_info: SourceTextInfo::from_string(text.to_string()),
})
.unwrap()
}
}
|