summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2024-08-21 13:12:56 -0400
committerGitHub <noreply@github.com>2024-08-21 17:12:56 +0000
commit1d4169204cdc870a084a3371500d7b3ab8546bc2 (patch)
treee70a6a99ab7d937dd789f58af5d656b0555f8507
parente2c50f7e8ada214f3a44a49da2faa0716d24970e (diff)
fix: warn about import assertions when using typescript (#25135)
1. On emit, checks for the prescence of import assertions. 1. Warns and doesn't store the parsed source in the emit cache in this case.
-rw-r--r--cli/emit.rs144
-rw-r--r--runtime/lib.rs1
-rw-r--r--tests/specs/run/ts_import_assertions/__test__.jsonc18
-rw-r--r--tests/specs/run/ts_import_assertions/assertion.out14
-rw-r--r--tests/specs/run/ts_import_assertions/assertion.ts5
-rw-r--r--tests/specs/run/ts_import_assertions/data.json3
-rw-r--r--tests/specs/run/ts_import_assertions/with.out2
-rw-r--r--tests/specs/run/ts_import_assertions/with.ts3
-rw-r--r--tests/testdata/import_attributes/json_with_shebang.ts3
-rw-r--r--tests/testdata/import_attributes/static_export.out6
-rw-r--r--tests/testdata/import_attributes/static_import.out6
-rw-r--r--tests/testdata/run/config_json_import.ts2
12 files changed, 173 insertions, 34 deletions
diff --git a/cli/emit.rs b/cli/emit.rs
index 61397d1ab..6adcfd79b 100644
--- a/cli/emit.rs
+++ b/cli/emit.rs
@@ -5,6 +5,9 @@ use crate::cache::FastInsecureHasher;
use crate::cache::ParsedSourceCache;
use deno_ast::SourceMapOption;
+use deno_ast::SourceRange;
+use deno_ast::SourceRanged;
+use deno_ast::SourceRangedForSpanned;
use deno_ast::TranspileResult;
use deno_core::error::AnyError;
use deno_core::futures::stream::FuturesUnordered;
@@ -109,26 +112,28 @@ impl Emitter {
let parsed_source_cache = self.parsed_source_cache.clone();
let transpile_and_emit_options =
self.transpile_and_emit_options.clone();
- let transpile_result = deno_core::unsync::spawn_blocking({
- let specifier = specifier.clone();
- let source = source.clone();
- move || -> Result<_, AnyError> {
- EmitParsedSourceHelper::transpile(
- &parsed_source_cache,
- &specifier,
- source.clone(),
- media_type,
- &transpile_and_emit_options.0,
- &transpile_and_emit_options.1,
- )
- }
- })
- .await
- .unwrap()?;
+ let (should_cache, transpile_result) =
+ deno_core::unsync::spawn_blocking({
+ let specifier = specifier.clone();
+ let source = source.clone();
+ move || -> Result<_, AnyError> {
+ EmitParsedSourceHelper::transpile(
+ &parsed_source_cache,
+ &specifier,
+ source.clone(),
+ media_type,
+ &transpile_and_emit_options.0,
+ &transpile_and_emit_options.1,
+ )
+ }
+ })
+ .await
+ .unwrap()?;
Ok(helper.post_emit_parsed_source(
specifier,
transpile_result,
source_hash,
+ should_cache,
))
}
}
@@ -145,18 +150,20 @@ impl Emitter {
match helper.pre_emit_parsed_source(specifier, source) {
PreEmitResult::Cached(emitted_text) => Ok(emitted_text),
PreEmitResult::NotCached { source_hash } => {
- let transpile_result = EmitParsedSourceHelper::transpile(
- &self.parsed_source_cache,
- specifier,
- source.clone(),
- media_type,
- &self.transpile_and_emit_options.0,
- &self.transpile_and_emit_options.1,
- )?;
+ let (should_cache, transpile_result) =
+ EmitParsedSourceHelper::transpile(
+ &self.parsed_source_cache,
+ specifier,
+ source.clone(),
+ media_type,
+ &self.transpile_and_emit_options.0,
+ &self.transpile_and_emit_options.1,
+ )?;
Ok(helper.post_emit_parsed_source(
specifier,
transpile_result,
source_hash,
+ should_cache,
))
}
}
@@ -254,12 +261,16 @@ impl<'a> EmitParsedSourceHelper<'a> {
media_type: MediaType,
transpile_options: &deno_ast::TranspileOptions,
emit_options: &deno_ast::EmitOptions,
- ) -> Result<TranspileResult, AnyError> {
+ ) -> Result<(bool, TranspileResult), AnyError> {
// nothing else needs the parsed source at this point, so remove from
// the cache in order to not transpile owned
let parsed_source = parsed_source_cache
.remove_or_parse_module(specifier, source, media_type)?;
- Ok(parsed_source.transpile(transpile_options, emit_options)?)
+ let should_cache = !has_import_assertion(&parsed_source);
+ Ok((
+ should_cache,
+ parsed_source.transpile(transpile_options, emit_options)?,
+ ))
}
pub fn post_emit_parsed_source(
@@ -267,6 +278,8 @@ impl<'a> EmitParsedSourceHelper<'a> {
specifier: &ModuleSpecifier,
transpile_result: TranspileResult,
source_hash: u64,
+ // todo(dsherret): remove after Deno 2.0
+ should_cache: bool,
) -> ModuleCodeBytes {
let transpiled_source = match transpile_result {
TranspileResult::Owned(source) => source,
@@ -276,11 +289,80 @@ impl<'a> EmitParsedSourceHelper<'a> {
}
};
debug_assert!(transpiled_source.source_map.is_none());
- self.0.emit_cache.set_emit_code(
- specifier,
- source_hash,
- &transpiled_source.source,
- );
+ if should_cache {
+ self.0.emit_cache.set_emit_code(
+ specifier,
+ source_hash,
+ &transpiled_source.source,
+ );
+ }
transpiled_source.source.into_boxed_slice().into()
}
}
+
+fn has_import_assertion(parsed_source: &deno_ast::ParsedSource) -> bool {
+ fn has_import_assertion(text: &str) -> bool {
+ // good enough
+ text.contains(" assert ") && !text.contains(" with ")
+ }
+
+ fn warn_import_attribute(
+ parsed_source: &deno_ast::ParsedSource,
+ range: SourceRange,
+ ) {
+ let text_info = parsed_source.text_info_lazy();
+ let loc = text_info.line_and_column_display(range.start);
+ deno_runtime::import_assertion_callback(
+ deno_core::ImportAssertionsSupportCustomCallbackArgs {
+ maybe_specifier: Some(parsed_source.specifier().to_string()),
+ maybe_line_number: Some(loc.line_number),
+ column_number: loc.column_number,
+ maybe_source_line: Some(range.text_fast(text_info).to_string()),
+ },
+ )
+ }
+
+ let Some(module) = parsed_source.program_ref().as_module() else {
+ return false;
+ };
+
+ let mut had_import_assertion = false;
+ for item in &module.body {
+ match item {
+ deno_ast::swc::ast::ModuleItem::ModuleDecl(decl) => match decl {
+ deno_ast::swc::ast::ModuleDecl::Import(n) => {
+ if n.with.is_some()
+ && has_import_assertion(n.text_fast(parsed_source.text_info_lazy()))
+ {
+ had_import_assertion = true;
+ warn_import_attribute(parsed_source, n.range());
+ }
+ }
+ deno_ast::swc::ast::ModuleDecl::ExportAll(n) => {
+ if n.with.is_some()
+ && has_import_assertion(n.text_fast(parsed_source.text_info_lazy()))
+ {
+ had_import_assertion = true;
+ warn_import_attribute(parsed_source, n.range());
+ }
+ }
+ deno_ast::swc::ast::ModuleDecl::ExportNamed(n) => {
+ if n.with.is_some()
+ && has_import_assertion(n.text_fast(parsed_source.text_info_lazy()))
+ {
+ had_import_assertion = true;
+ warn_import_attribute(parsed_source, n.range());
+ }
+ }
+ deno_ast::swc::ast::ModuleDecl::ExportDecl(_)
+ | deno_ast::swc::ast::ModuleDecl::ExportDefaultDecl(_)
+ | deno_ast::swc::ast::ModuleDecl::ExportDefaultExpr(_)
+ | deno_ast::swc::ast::ModuleDecl::TsImportEquals(_)
+ | deno_ast::swc::ast::ModuleDecl::TsExportAssignment(_)
+ | deno_ast::swc::ast::ModuleDecl::TsNamespaceExport(_) => {}
+ },
+ deno_ast::swc::ast::ModuleItem::Stmt(_) => {}
+ }
+ }
+ had_import_assertion
+}
diff --git a/runtime/lib.rs b/runtime/lib.rs
index a729d88f7..6b89d0611 100644
--- a/runtime/lib.rs
+++ b/runtime/lib.rs
@@ -44,6 +44,7 @@ pub use worker_bootstrap::WorkerExecutionMode;
pub use worker_bootstrap::WorkerLogLevel;
mod shared;
+pub use shared::import_assertion_callback;
pub use shared::runtime;
// NOTE(bartlomieju): keep IDs in sync with `runtime/90_deno_ns.js` (search for `unstableFeatures`)
diff --git a/tests/specs/run/ts_import_assertions/__test__.jsonc b/tests/specs/run/ts_import_assertions/__test__.jsonc
new file mode 100644
index 000000000..dc5576bd1
--- /dev/null
+++ b/tests/specs/run/ts_import_assertions/__test__.jsonc
@@ -0,0 +1,18 @@
+{
+ "tests": {
+ "assertion": {
+ "steps": [{
+ "args": "run assertion.ts",
+ "output": "assertion.out"
+ }, {
+ // should output the same because the emit won't be cached
+ "args": "run assertion.ts",
+ "output": "assertion.out"
+ }]
+ },
+ "with": {
+ "args": "run with.ts",
+ "output": "with.out"
+ }
+ }
+}
diff --git a/tests/specs/run/ts_import_assertions/assertion.out b/tests/specs/run/ts_import_assertions/assertion.out
new file mode 100644
index 000000000..3cc900d64
--- /dev/null
+++ b/tests/specs/run/ts_import_assertions/assertion.out
@@ -0,0 +1,14 @@
+⚠️ Import assertions are deprecated. Use `with` keyword, instead of 'assert' keyword.
+
+import test from "./data.json" assert { type: "json" };
+
+ at file:///[WILDLINE]/assertion.ts:1:1
+
+{ prop: "data" }
+⚠️ Import assertions are deprecated. Use `with` keyword, instead of 'assert' keyword.
+
+console.log((await import("./data.json", {
+
+ at file:///[WILDLINE]/assertion.ts:5:13
+
+{ prop: "data" }
diff --git a/tests/specs/run/ts_import_assertions/assertion.ts b/tests/specs/run/ts_import_assertions/assertion.ts
new file mode 100644
index 000000000..cb653ffc7
--- /dev/null
+++ b/tests/specs/run/ts_import_assertions/assertion.ts
@@ -0,0 +1,5 @@
+import test from "./data.json" assert { type: "json" };
+console.log(test);
+console.log(
+ (await import("./data.json", { assert: { type: "json" } })).default,
+);
diff --git a/tests/specs/run/ts_import_assertions/data.json b/tests/specs/run/ts_import_assertions/data.json
new file mode 100644
index 000000000..e5b07266c
--- /dev/null
+++ b/tests/specs/run/ts_import_assertions/data.json
@@ -0,0 +1,3 @@
+{
+ "prop": "data"
+}
diff --git a/tests/specs/run/ts_import_assertions/with.out b/tests/specs/run/ts_import_assertions/with.out
new file mode 100644
index 000000000..6141f8c07
--- /dev/null
+++ b/tests/specs/run/ts_import_assertions/with.out
@@ -0,0 +1,2 @@
+{ prop: "data" }
+{ prop: "data" }
diff --git a/tests/specs/run/ts_import_assertions/with.ts b/tests/specs/run/ts_import_assertions/with.ts
new file mode 100644
index 000000000..58b7fb03d
--- /dev/null
+++ b/tests/specs/run/ts_import_assertions/with.ts
@@ -0,0 +1,3 @@
+import test from "./data.json" with { type: "json" };
+console.log(test);
+console.log((await import("./data.json", { with: { type: "json" } })).default);
diff --git a/tests/testdata/import_attributes/json_with_shebang.ts b/tests/testdata/import_attributes/json_with_shebang.ts
index 0a785210f..9524026bc 100644
--- a/tests/testdata/import_attributes/json_with_shebang.ts
+++ b/tests/testdata/import_attributes/json_with_shebang.ts
@@ -1,4 +1,3 @@
-// deno-lint-ignore no-import-assertions
-import json from "./json_with_shebang.json" assert { type: "json" };
+import json from "./json_with_shebang.json" with { type: "json" };
console.log(json);
diff --git a/tests/testdata/import_attributes/static_export.out b/tests/testdata/import_attributes/static_export.out
index 41af79d7c..d7e19c80f 100644
--- a/tests/testdata/import_attributes/static_export.out
+++ b/tests/testdata/import_attributes/static_export.out
@@ -1 +1,7 @@
+⚠️ Import assertions are deprecated. Use `with` keyword, instead of 'assert' keyword.
+
+export { default } from "./data.json" assert { type: "json" };
+
+ at file:///[WILDLINE]
+
{ a: "b", c: { d: 10 } }
diff --git a/tests/testdata/import_attributes/static_import.out b/tests/testdata/import_attributes/static_import.out
index e57dffa99..85c75d3eb 100644
--- a/tests/testdata/import_attributes/static_import.out
+++ b/tests/testdata/import_attributes/static_import.out
@@ -1,2 +1,8 @@
+⚠️ Import assertions are deprecated. Use `with` keyword, instead of 'assert' keyword.
+
+import data2 from "./data.json" assert { type: "json" };
+
+ at file:///[WILDLINE]
+
{ a: "b", c: { d: 10 } }
{ a: "b", c: { d: 10 } }
diff --git a/tests/testdata/run/config_json_import.ts b/tests/testdata/run/config_json_import.ts
index 9cf1cceaa..7141f1495 100644
--- a/tests/testdata/run/config_json_import.ts
+++ b/tests/testdata/run/config_json_import.ts
@@ -1,2 +1,2 @@
-import config from "../jsx/deno-jsx.json" assert { type: "json" };
+import config from "../jsx/deno-jsx.json" with { type: "json" };
console.log(config);