summaryrefslogtreecommitdiff
path: root/cli/tools/vendor/analyze.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools/vendor/analyze.rs')
-rw-r--r--cli/tools/vendor/analyze.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/cli/tools/vendor/analyze.rs b/cli/tools/vendor/analyze.rs
new file mode 100644
index 000000000..0639c0487
--- /dev/null
+++ b/cli/tools/vendor/analyze.rs
@@ -0,0 +1,113 @@
+// Copyright 2018-2022 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<'a> 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::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: "file:///mod.ts".to_string(),
+ capture_tokens: false,
+ maybe_syntax: None,
+ media_type: MediaType::TypeScript,
+ scope_analysis: false,
+ source: SourceTextInfo::from_string(text.to_string()),
+ })
+ .unwrap()
+ }
+}