From f3ad4b099ed30162f2d2835f836fa5fbeabc1bef Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Thu, 12 Mar 2026 21:05:54 -0700 Subject: [PATCH 1/4] port to oxc --- Cargo.lock | 1362 ++++++++-------- Cargo.toml | 7 +- benches/doc_parser.rs | 15 +- examples/ddoc/main.rs | 2 + lib/lib.rs | 2 + rust-toolchain.toml | 2 +- src/class.rs | 206 +-- src/decorators.rs | 33 +- src/diagnostics.rs | 6 +- src/diff/class.rs | 2 +- src/diff/variable.rs | 2 +- src/display.rs | 17 +- src/enum.rs | 20 +- src/function.rs | 206 +-- src/html/mod.rs | 14 +- src/html/symbols/class.rs | 4 +- src/html/symbols/mod.rs | 2 +- src/html/symbols/namespace.rs | 12 +- src/html/types.rs | 4 +- src/html/util.rs | 8 +- src/interface.rs | 270 ++-- src/js_doc.rs | 92 +- src/lib.rs | 1 + src/params.rs | 279 +++- src/parser.rs | 416 ++--- src/printer.rs | 14 +- src/tests.rs | 50 +- src/ts_type.rs | 1587 ++++++++++--------- src/ts_type_param.rs | 10 +- src/type_alias.rs | 7 +- src/util/mod.rs | 1 + src/util/swc.rs | 150 +- src/util/symbol.rs | 2 +- src/util/types.rs | 88 + src/variable.rs | 314 ++-- src/visibility.rs | 10 +- tests/helpers/mod.rs | 4 + tests/html_test.rs | 4 + tests/specs/export_const_destructured.txt | 200 ++- tests/specs/export_namespace.txt | 306 ++-- tests/specs/infer_object_literal.txt | 536 ++++--- tests/specs/namespace_exports_self.txt | 4 +- tests/specs/private_type_class_property.txt | 267 +--- tests/specs/re_export_all_as_with_jsdoc.txt | 83 +- 44 files changed, 3366 insertions(+), 3255 deletions(-) create mode 100644 src/util/types.rs diff --git a/Cargo.lock b/Cargo.lock index 06aaf1e81..84a9918c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,18 +17,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -112,23 +100,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - -[[package]] -name = "ast_node" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb025ef00a6da925cf40870b9c8d008526b6004ece399cb0974209720f0b194" -dependencies = [ - "quote", - "swc_macros_common", - "syn", -] - [[package]] name = "async-trait" version = "0.1.89" @@ -146,7 +117,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", "winapi", ] @@ -188,15 +159,6 @@ dependencies = [ "vsimd", ] -[[package]] -name = "better_scoped_tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd228125315b132eed175bf47619ac79b945b26e56b848ba203ae4ea8603609" -dependencies = [ - "scoped-tls", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -205,29 +167,26 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.3" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] -name = "bitvec" -version = "1.0.1" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "funty", - "radium", - "tap", - "wyz", + "generic-array", ] [[package]] name = "block-buffer" -version = "0.10.4" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] @@ -245,9 +204,6 @@ name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" -dependencies = [ - "allocator-api2", -] [[package]] name = "bytes" @@ -255,16 +211,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -[[package]] -name = "bytes-str" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c60b5ce37e0b883c37eb89f79a1e26fbe9c1081945d024eee93e8d91a7e18b3" -dependencies = [ - "bytes", - "serde", -] - [[package]] name = "capacity_builder" version = "0.5.0" @@ -311,15 +257,6 @@ dependencies = [ "rustversion", ] -[[package]] -name = "cc" -version = "1.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" -dependencies = [ - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.3" @@ -424,6 +361,15 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] + [[package]] name = "colorchoice" version = "1.0.4" @@ -432,13 +378,14 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "compact_str" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" dependencies = [ "castaway", "cfg-if", "itoa", + "rustversion", "ryu", "static_assertions", ] @@ -492,6 +439,18 @@ dependencies = [ "vte", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cow-utils" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417bef24afe1460300965a25ff4a24b8b45ad011948302ec221e8a0a81eb2c79" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -501,6 +460,24 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "criterion" version = "0.4.0" @@ -514,7 +491,7 @@ dependencies = [ "clap 3.2.25", "criterion-plot", "futures", - "itertools", + "itertools 0.10.5", "lazy_static", "num-traits", "oorandom", @@ -535,7 +512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -588,6 +565,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "darling" version = "0.20.11" @@ -623,57 +609,25 @@ dependencies = [ "syn", ] -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - [[package]] name = "data-url" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" -[[package]] -name = "debugid" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" -dependencies = [ - "serde", - "uuid", -] - [[package]] name = "deno_ast" version = "0.53.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05792fb2b77938767ffeb0853289e86501fddc84b1cdba9e5dc860c52baa2ff7" dependencies = [ "base64", "capacity_builder", "deno_error", "deno_media_type", "deno_terminal", - "dprint-swc-ext", + "oxc", + "oxc_str", "percent-encoding", "serde", - "swc_atoms", - "swc_common", - "swc_ecma_ast", - "swc_ecma_codegen", - "swc_ecma_codegen_macros", - "swc_ecma_lexer", - "swc_ecma_loader", - "swc_ecma_parser", - "swc_ecma_transforms_base", - "swc_ecma_utils", - "swc_ecma_visit", - "swc_eq_ignore_macros", - "swc_macros_common", - "swc_sourcemap", - "swc_visit", "text_lines", "thiserror", "unicode-width 0.2.1", @@ -762,9 +716,7 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0ece7ecde2db52b86b1a1ebbe368bedded631e449dd0293a2c317bb25f7641c" +version = "0.108.2" dependencies = [ "async-trait", "boxed_error", @@ -780,7 +732,7 @@ dependencies = [ "futures", "indexmap 2.11.0", "log", - "monch 0.6.0", + "monch", "once_cell", "parking_lot", "regex", @@ -820,15 +772,15 @@ dependencies = [ [[package]] name = "deno_semver" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2625b7107cc3f61a462886d5fa77c23e063c1fd15b90e3d5ee2646e9f6178d55" +checksum = "147261611819fb4dfe339b53e3b45d6704c7e32c86ce33a88511d5bcebebaaa3" dependencies = [ "capacity_builder", "deno_error", "ecow", "hipstr", - "monch 0.5.0", + "monch", "once_cell", "serde", "thiserror", @@ -905,8 +857,19 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.6", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.0", + "const-oid", + "crypto-common 0.2.2", ] [[package]] @@ -921,20 +884,10 @@ dependencies = [ ] [[package]] -name = "dprint-swc-ext" -version = "0.26.0" +name = "dragonbox_ecma" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33175ddb7a6d418589cab2966bd14a710b3b1139459d3d5ca9edf783c4833f4c" -dependencies = [ - "num-bigint", - "rustc-hash", - "swc_atoms", - "swc_common", - "swc_ecma_ast", - "swc_ecma_lexer", - "swc_ecma_parser", - "text_lines", -] +checksum = "fd8e701084c37e7ef62d3f9e453b618130cbc0ef3573847785952a3ac3f746bf" [[package]] name = "ecow" @@ -951,6 +904,18 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encode_unicode" version = "1.0.0" @@ -978,6 +943,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "file_test_runner" version = "0.7.4" @@ -992,6 +963,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1007,22 +988,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "from_variant" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ff35a391aef949120a0340d690269b3d9f63460a6106e99bd07b961f345ea9" -dependencies = [ - "swc_macros_common", - "syn", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - [[package]] name = "futures" version = "0.3.31" @@ -1163,19 +1128,18 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", +] [[package]] name = "heck" @@ -1192,12 +1156,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - [[package]] name = "hipstr" version = "0.6.0" @@ -1210,26 +1168,21 @@ dependencies = [ ] [[package]] -name = "hstr" -version = "3.0.3" +name = "html-escape" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c43c0a9e8fbdb3bb9dc8eee85e1e2ac81605418b4c83b6b7413cbf14d56ca5c" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" dependencies = [ - "hashbrown 0.14.5", - "new_debug_unreachable", - "once_cell", - "rustc-hash", - "serde", - "triomphe", + "utf8-width", ] [[package]] -name = "html-escape" -version = "0.2.13" +name = "hybrid-array" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" dependencies = [ - "utf8-width", + "typenum", ] [[package]] @@ -1345,12 +1298,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "if_chain" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" - [[package]] name = "import_map" version = "0.25.0" @@ -1407,23 +1354,11 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.11.0", "cfg-if", "libc", ] -[[package]] -name = "is-macro" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d57a3e447e24c22647738e4607f1df1e0ec6f72e16182c4cd199f647cdfb0e4" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1439,11 +1374,20 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "js-sys" @@ -1454,6 +1398,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-escape-simd" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c2a6c0b4b5637c41719973ef40c6a1cf564f9db6958350de6193fbee9c23f5" + [[package]] name = "lazy_static" version = "1.5.0" @@ -1490,9 +1440,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" -version = "2.7.5" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "miniz_oxide" @@ -1501,6 +1451,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -1514,12 +1465,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "monch" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b52c1b33ff98142aecea13138bd399b68aa7ab5d9546c300988c345004001eea" - [[package]] name = "monch" version = "0.6.0" @@ -1527,10 +1472,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bcc6ad3b93f756f2532d29f7c7291b8d246a2c460a99a3611327bb726830014" [[package]] -name = "new_debug_unreachable" -version = "1.0.6" +name = "nonmax" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" [[package]] name = "num-bigint" @@ -1540,7 +1485,6 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "serde", ] [[package]] @@ -1576,16 +1520,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi 0.5.2", - "libc", -] - [[package]] name = "object" version = "0.36.7" @@ -1626,72 +1560,457 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] -name = "par-core" -version = "2.0.0" +name = "owo-colors" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" + +[[package]] +name = "oxc" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96cbd21255b7fb29a5d51ef38a779b517a91abd59e2756c039583f43ef4c90f" +checksum = "d804f86548486ce1b6c92bb5511214f44074ea1e5bc94eded8ee4de2f7ca98c7" dependencies = [ - "once_cell", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_codegen", + "oxc_diagnostics", + "oxc_parser", + "oxc_regular_expression", + "oxc_semantic", + "oxc_span", + "oxc_syntax", + "oxc_transformer", + "oxc_transformer_plugins", ] [[package]] -name = "parking_lot" -version = "0.12.4" +name = "oxc-browserslist" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "c86f358f5705f4da4bce0af2792b6d24d64be9c465bdc70a752b2f168c5ff721" dependencies = [ - "lock_api", - "parking_lot_core", + "flate2", + "postcard", + "rustc-hash", + "serde", + "thiserror", ] [[package]] -name = "parking_lot_core" -version = "0.9.11" +name = "oxc-miette" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "4356a61f2ed4c9b3610245215fbf48970eb277126919f87db9d0efa93a74245c" dependencies = [ "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", + "owo-colors", + "oxc-miette-derive", + "textwrap", + "thiserror", + "unicode-segmentation", + "unicode-width 0.2.1", ] [[package]] -name = "pathdiff" -version = "0.2.3" +name = "oxc-miette-derive" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +checksum = "b237422b014f8f8fff75bb9379e697d13f8d57551a22c88bebb39f073c1bf696" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "percent-encoding" -version = "2.3.2" +name = "oxc_allocator" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +checksum = "2303e54d087d40064154f2ec243fff0bf7641c078efae9bb14216a8869577ba7" +dependencies = [ + "allocator-api2", + "hashbrown 0.17.1", + "oxc_data_structures", + "rustc-hash", +] [[package]] -name = "pest" -version = "2.8.1" +name = "oxc_ast" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +checksum = "5f628429436867a51e5d623b4b27c02807aec3ea241f01deadd21b0d1604c8ef" dependencies = [ - "memchr", - "thiserror", - "ucd-trie", + "bitflags 2.11.0", + "oxc_allocator", + "oxc_ast_macros", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_estree", + "oxc_regular_expression", + "oxc_span", + "oxc_str", + "oxc_syntax", ] [[package]] -name = "pest_derive" -version = "2.8.1" +name = "oxc_ast_macros" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" +checksum = "52b3190e5f69284b59a4876a3b42431c8e2309b4de3670553aab4888f15aa6f2" dependencies = [ - "pest", - "pest_generator", + "phf", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "pest_generator" +name = "oxc_ast_visit" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfe1897cf38bab83c998346184cba50db2849943b9d9e8634d09a2dc303ceaee" +dependencies = [ + "oxc_allocator", + "oxc_ast", + "oxc_span", + "oxc_syntax", +] + +[[package]] +name = "oxc_codegen" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d690df0e909b1663c19a368cdfcf0cac94fd57ddf068230442ff82b27ad000" +dependencies = [ + "bitflags 2.11.0", + "cow-utils", + "dragonbox_ecma", + "itoa", + "oxc_allocator", + "oxc_ast", + "oxc_data_structures", + "oxc_index", + "oxc_semantic", + "oxc_sourcemap", + "oxc_span", + "oxc_str", + "oxc_syntax", + "rustc-hash", +] + +[[package]] +name = "oxc_compat" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ae9249b8fc4604f787cbe39457565f21f7747a59cb94333bcc1ff85f9327323" +dependencies = [ + "cow-utils", + "oxc-browserslist", + "oxc_syntax", + "rustc-hash", + "serde", +] + +[[package]] +name = "oxc_data_structures" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6aa082cf4bbc5b3c189e9331f31823e31a5452533da36dfa5b174f20e72c1c" +dependencies = [ + "ropey", +] + +[[package]] +name = "oxc_diagnostics" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67daf165d8abff1577825a4303a5d0b61ae29c7b66c9e0e0e7f97f77705667ed" +dependencies = [ + "cow-utils", + "oxc-miette", + "percent-encoding", +] + +[[package]] +name = "oxc_ecmascript" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41e701220c14cc0d0733a6501f1837fe9d913e891e25647132389fdfd78dd7d3" +dependencies = [ + "cow-utils", + "num-bigint", + "num-traits", + "oxc_allocator", + "oxc_ast", + "oxc_regular_expression", + "oxc_span", + "oxc_syntax", +] + +[[package]] +name = "oxc_estree" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d42104865cba688a62c0cf5691592a890eef9de359bccb18a97b2be088478d" + +[[package]] +name = "oxc_index" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3e6120999627ec9703025eab7c9f410ebb7e95557632a8902ca48210416c2b" +dependencies = [ + "nonmax", + "serde", +] + +[[package]] +name = "oxc_parser" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d671cb199fc83d8fc9764926c3c8f7979affbd2d916e3b2e22e403745305b6" +dependencies = [ + "bitflags 2.11.0", + "cow-utils", + "memchr", + "num-bigint", + "num-traits", + "oxc_allocator", + "oxc_ast", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_regular_expression", + "oxc_span", + "oxc_str", + "oxc_syntax", + "rustc-hash", + "seq-macro", +] + +[[package]] +name = "oxc_regular_expression" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06eb61d28a8b83b0bda7dc75bf886f178155dead57746fab874312c81baa359" +dependencies = [ + "bitflags 2.11.0", + "oxc_allocator", + "oxc_ast_macros", + "oxc_diagnostics", + "oxc_span", + "oxc_str", + "phf", + "rustc-hash", + "unicode-id-start", +] + +[[package]] +name = "oxc_semantic" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8573ff803b00bdacc550475aacc72305621d2992988e5f7886391fa9d9bfa611" +dependencies = [ + "itertools 0.14.0", + "memchr", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_index", + "oxc_span", + "oxc_str", + "oxc_syntax", + "rustc-hash", + "self_cell", + "smallvec", +] + +[[package]] +name = "oxc_sourcemap" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3866f9075027840e0711b52e15d2e1ba076fc5f5f01c96eeedd26375410641" +dependencies = [ + "base64-simd", + "json-escape-simd", + "rustc-hash", + "serde", + "serde_json", +] + +[[package]] +name = "oxc_span" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ff77b2ca10d57dc7645c4af838b1aa455cac6569992fe544ed041a8021ae10" +dependencies = [ + "compact_str", + "oxc-miette", + "oxc_allocator", + "oxc_ast_macros", + "oxc_estree", + "oxc_str", +] + +[[package]] +name = "oxc_str" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbcd6412fde266b6ffdbcdf118cba2c8dc0d6ddba6aa4e361842ebaf320a4eed" +dependencies = [ + "compact_str", + "hashbrown 0.17.1", + "oxc_allocator", + "oxc_estree", +] + +[[package]] +name = "oxc_syntax" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab19e002e05e4d107483ace848ca2d6ce5c714f238d70d591f91d17fef54be98" +dependencies = [ + "bitflags 2.11.0", + "cow-utils", + "dragonbox_ecma", + "nonmax", + "oxc_allocator", + "oxc_ast_macros", + "oxc_estree", + "oxc_index", + "oxc_span", + "oxc_str", + "phf", + "unicode-id-start", +] + +[[package]] +name = "oxc_transformer" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c753c4eb41524071c4d13650642b5622b7b23fca6b4d92872dc43f6e71686e16" +dependencies = [ + "base64", + "compact_str", + "indexmap 2.11.0", + "itoa", + "memchr", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_compat", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_regular_expression", + "oxc_semantic", + "oxc_span", + "oxc_str", + "oxc_syntax", + "oxc_traverse", + "rustc-hash", + "serde", + "serde_json", + "sha1", +] + +[[package]] +name = "oxc_transformer_plugins" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dbd5a19932bc3aded01f5f2ff18f448cadbd921b26cffa2b90294fd1a44f4ce" +dependencies = [ + "cow-utils", + "itoa", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_parser", + "oxc_semantic", + "oxc_span", + "oxc_str", + "oxc_syntax", + "oxc_transformer", + "oxc_traverse", + "rustc-hash", +] + +[[package]] +name = "oxc_traverse" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d817fd3459ecb0c0ea37042e796954d8caff9a6c5e23bf60a41f002cacdd5c79" +dependencies = [ + "itoa", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_data_structures", + "oxc_ecmascript", + "oxc_semantic", + "oxc_span", + "oxc_str", + "oxc_syntax", + "rustc-hash", +] + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" @@ -1715,29 +2034,30 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ "phf_macros", "phf_shared", + "serde", ] [[package]] name = "phf_generator" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ + "fastrand", "phf_shared", - "rand", ] [[package]] name = "phf_macros" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ "phf_generator", "phf_shared", @@ -1748,11 +2068,11 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ - "siphasher 1.0.1", + "siphasher", ] [[package]] @@ -1795,6 +2115,18 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + [[package]] name = "potential_utf" version = "0.1.2" @@ -1823,15 +2155,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "psm" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" -dependencies = [ - "cc", -] - [[package]] name = "quote" version = "1.0.40" @@ -1841,27 +2164,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - [[package]] name = "rayon" version = "1.11.0" @@ -1888,7 +2190,7 @@ version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.11.0", ] [[package]] @@ -1920,6 +2222,16 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +[[package]] +name = "ropey" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93411e420bcd1a75ddd1dc3caf18c23155eda2c090631a85af21ba19e97093b5" +dependencies = [ + "smallvec", + "str_indices", +] + [[package]] name = "rustc-demangle" version = "0.1.26" @@ -1944,12 +2256,6 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" -[[package]] -name = "ryu-js" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd29631678d6fb0903b69223673e122c32e9ae559d0960a38d574695ebc0ea15" - [[package]] name = "same-file" version = "1.0.6" @@ -1959,18 +2265,18 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "self_cell" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" + [[package]] name = "seq-macro" version = "0.3.6" @@ -2041,21 +2347,26 @@ dependencies = [ ] [[package]] -name = "sha2" -version = "0.10.9" +name = "sha1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] -name = "shlex" -version = "1.3.0" +name = "sha2" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] [[package]] name = "signal-hook-registry" @@ -2067,16 +2378,16 @@ dependencies = [ ] [[package]] -name = "similar" -version = "2.7.0" +name = "simd-adler32" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] -name = "siphasher" -version = "0.3.11" +name = "similar" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "siphasher" @@ -2105,17 +2416,15 @@ name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] -name = "smartstring" -version = "1.0.1" +name = "smawk" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" @@ -2139,19 +2448,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "stacker" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b" -dependencies = [ - "cc", - "cfg-if", - "libc", - "psm", - "windows-sys 0.59.0", -] - [[package]] name = "static_assertions" version = "1.1.0" @@ -2159,15 +2455,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "string_enum" -version = "1.0.2" +name = "str_indices" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae36a4951ca7bd1cfd991c241584a9824a70f6aff1e7d4f693fb3f2465e4030e" -dependencies = [ - "quote", - "swc_macros_common", - "syn", -] +checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6" [[package]] name = "strsim" @@ -2175,276 +2466,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "swc_allocator" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d7eefd2c8b228a8c73056482b2ae4b3a1071fbe07638e3b55ceca8570cc48bb" -dependencies = [ - "allocator-api2", - "bumpalo", - "hashbrown 0.14.5", - "rustc-hash", -] - -[[package]] -name = "swc_atoms" -version = "9.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ccbe2ecad10ad7432100f878a107b1d972a8aee83ca53184d00c23a078bb8a" -dependencies = [ - "hstr", - "once_cell", - "serde", -] - -[[package]] -name = "swc_common" -version = "17.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "259b675d633a26d24efe3802a9d88858c918e6e8f062d3222d3aa02d56a2cf4c" -dependencies = [ - "anyhow", - "ast_node", - "better_scoped_tls", - "bytes-str", - "either", - "from_variant", - "new_debug_unreachable", - "num-bigint", - "once_cell", - "rustc-hash", - "serde", - "siphasher 0.3.11", - "swc_atoms", - "swc_eq_ignore_macros", - "swc_sourcemap", - "swc_visit", - "tracing", - "unicode-width 0.2.1", - "url", -] - -[[package]] -name = "swc_ecma_ast" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a573a0c72850dec8d4d8085f152d5778af35a2520c3093b242d2d1d50776da7c" -dependencies = [ - "bitflags 2.9.3", - "is-macro", - "num-bigint", - "once_cell", - "phf", - "rustc-hash", - "serde", - "string_enum", - "swc_atoms", - "swc_common", - "swc_visit", - "unicode-id-start", -] - -[[package]] -name = "swc_ecma_codegen" -version = "20.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2a6ee1ec49dda8dedeac54e4147b4e8b3f278d9bb34ab28983257a393d34ed" -dependencies = [ - "ascii", - "compact_str", - "memchr", - "num-bigint", - "once_cell", - "regex", - "rustc-hash", - "ryu-js", - "serde", - "swc_allocator", - "swc_atoms", - "swc_common", - "swc_ecma_ast", - "swc_ecma_codegen_macros", - "swc_sourcemap", - "tracing", -] - -[[package]] -name = "swc_ecma_codegen_macros" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e276dc62c0a2625a560397827989c82a93fd545fcf6f7faec0935a82cc4ddbb8" -dependencies = [ - "proc-macro2", - "swc_macros_common", - "syn", -] - -[[package]] -name = "swc_ecma_lexer" -version = "26.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e82f7747e052c6ff6e111fa4adeb14e33b46ee6e94fe5ef717601f651db48fc" -dependencies = [ - "bitflags 2.9.3", - "either", - "num-bigint", - "rustc-hash", - "seq-macro", - "serde", - "smallvec", - "smartstring", - "stacker", - "swc_atoms", - "swc_common", - "swc_ecma_ast", - "swc_ecma_parser", - "tracing", -] - -[[package]] -name = "swc_ecma_loader" -version = "17.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbcababb48f0d46587a0a854b2c577eb3a56fa99687de558338021e93cd2c8f5" -dependencies = [ - "anyhow", - "pathdiff", - "rustc-hash", - "serde", - "swc_atoms", - "swc_common", - "tracing", -] - -[[package]] -name = "swc_ecma_parser" -version = "27.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f1a51af1a92cd4904c073b293e491bbc0918400a45d58227b34c961dd6f52d7" -dependencies = [ - "bitflags 2.9.3", - "either", - "num-bigint", - "phf", - "rustc-hash", - "seq-macro", - "serde", - "smartstring", - "stacker", - "swc_atoms", - "swc_common", - "swc_ecma_ast", - "tracing", -] - -[[package]] -name = "swc_ecma_transforms_base" -version = "30.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f6f165578ca4fee47bd57585c1b9597c94bf4ea6591df47f2b5fa5b1883fe" -dependencies = [ - "better_scoped_tls", - "indexmap 2.11.0", - "once_cell", - "par-core", - "phf", - "rustc-hash", - "serde", - "swc_atoms", - "swc_common", - "swc_ecma_ast", - "swc_ecma_parser", - "swc_ecma_utils", - "swc_ecma_visit", - "tracing", -] - -[[package]] -name = "swc_ecma_utils" -version = "24.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fb99e179988cabd473779a4452ab942bcb777176983ca3cbaf22a8f056a65b0" -dependencies = [ - "indexmap 2.11.0", - "num_cpus", - "once_cell", - "par-core", - "rustc-hash", - "ryu-js", - "swc_atoms", - "swc_common", - "swc_ecma_ast", - "swc_ecma_visit", - "tracing", -] - -[[package]] -name = "swc_ecma_visit" -version = "18.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9611a72a4008d62608547a394e5d72a5245413104db096d95a52368a8cc1d63" -dependencies = [ - "new_debug_unreachable", - "num-bigint", - "swc_atoms", - "swc_common", - "swc_ecma_ast", - "swc_visit", - "tracing", -] - -[[package]] -name = "swc_eq_ignore_macros" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c16ce73424a6316e95e09065ba6a207eba7765496fed113702278b7711d4b632" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "swc_macros_common" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1efbaa74943dc5ad2a2fb16cbd78b77d7e4d63188f3c5b4df2b4dcd2faaae" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "swc_sourcemap" -version = "9.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de08ef00f816acdd1a58ee8a81c0e1a59eefef2093aefe5611f256fa6b64c4d7" -dependencies = [ - "base64-simd", - "bitvec", - "bytes-str", - "data-encoding", - "debugid", - "if_chain", - "rustc-hash", - "serde", - "serde_json", - "unicode-id-start", - "url", -] - -[[package]] -name = "swc_visit" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62fb71484b486c185e34d2172f0eabe7f4722742aad700f426a494bb2de232a2" -dependencies = [ - "either", - "new_debug_unreachable", -] - [[package]] name = "syn" version = "2.0.106" @@ -2487,12 +2508,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "termcolor" version = "1.4.1" @@ -2516,6 +2531,11 @@ name = "textwrap" version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width 0.2.1", +] [[package]] name = "thiserror" @@ -2603,47 +2623,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", -] - -[[package]] -name = "triomphe" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" -dependencies = [ - "serde", - "stable_deref_trait", -] - [[package]] name = "typed-arena" version = "2.0.2" @@ -2652,9 +2631,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.18.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "ucd-trie" @@ -2674,6 +2653,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + [[package]] name = "unicode-normalization" version = "0.1.24" @@ -2683,6 +2668,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-width" version = "0.1.14" @@ -2731,12 +2722,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" - [[package]] name = "version_check" version = "0.9.5" @@ -3062,15 +3047,6 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - [[package]] name = "yansi" version = "1.0.1" @@ -3101,26 +3077,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "zerofrom" version = "0.1.6" diff --git a/Cargo.toml b/Cargo.toml index 6bc2e70a9..5400e0957 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,15 +11,18 @@ repository = "https://github.com/denoland/deno_doc" members = ["lib"] [workspace.dependencies] -deno_graph = { version = "0.108.0", default-features = false, features = [ +deno_graph = { path = "../deno_graph", default-features = false, features = [ "swc", "symbols", ] } -deno_ast = { version = "0.53.2" } +deno_ast = { path = "../deno_ast" } import_map = "0.25.0" serde = { version = "1.0.204", features = ["derive"] } serde_json = { version = "1.0.122", features = ["preserve_order"] } +[patch."https://github.com/nathanwhit/deno_ast"] +deno_ast = { path = "../deno_ast" } + [lib] name = "deno_doc" diff --git a/benches/doc_parser.rs b/benches/doc_parser.rs index 55b70f093..bce1dc340 100644 --- a/benches/doc_parser.rs +++ b/benches/doc_parser.rs @@ -42,10 +42,17 @@ async fn parse() -> ParseOutput { }, ) .await; - DocParser::new(&graph, &analyzer, &[root], DocParserOptions::default()) - .unwrap() - .parse() - .unwrap() + let allocator = deno_ast::oxc::allocator::Allocator::default(); + DocParser::new( + &graph, + &analyzer, + &allocator, + &[root], + DocParserOptions::default(), + ) + .unwrap() + .parse() + .unwrap() } fn doc_parser(c: &mut Criterion) { diff --git a/examples/ddoc/main.rs b/examples/ddoc/main.rs index 4478e3f69..06ac4aafd 100644 --- a/examples/ddoc/main.rs +++ b/examples/ddoc/main.rs @@ -161,9 +161,11 @@ async fn parse_sources( let mut source_files = source_files; source_files.sort(); + let allocator = deno_ast::oxc::allocator::Allocator::default(); let parser = DocParser::new( &graph, &analyzer, + &allocator, &source_files, DocParserOptions { diagnostics: false, diff --git a/lib/lib.rs b/lib/lib.rs index 1253e9889..b03e9a071 100644 --- a/lib/lib.rs +++ b/lib/lib.rs @@ -269,9 +269,11 @@ async fn inner_doc( }, ) .await; + let allocator = deno_doc::OxcAllocator::default(); let entries = DocParser::new( &graph, &analyzer, + &allocator, &root_specifiers, deno_doc::DocParserOptions { diagnostics: false, diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 908d2ecba..1a2165581 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.89.0" +channel = "1.92.0" components = ["rustfmt", "clippy"] diff --git a/src/class.rs b/src/class.rs index 801fd5d00..207e78068 100644 --- a/src/class.rs +++ b/src/class.rs @@ -1,6 +1,12 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_ast::SourceRangedForSpanned; +use deno_ast::oxc::ast::ast::Class; +use deno_ast::oxc::ast::ast::ClassElement; +use deno_ast::oxc::ast::ast::Expression; +use deno_ast::oxc::ast::ast::MethodDefinitionKind; +use deno_ast::oxc::ast::ast::MethodDefinitionType; +use deno_ast::oxc::ast::ast::PropertyDefinitionType; +use deno_ast::oxc::span::GetSpan; use deno_graph::symbols::EsModuleInfo; use serde::Deserialize; use serde::Serialize; @@ -14,11 +20,9 @@ use crate::function::function_to_function_def; use crate::js_doc::JsDoc; use crate::node::DeclarationKind; use crate::node::Symbol; -use crate::params::assign_pat_to_param_def; -use crate::params::ident_to_param_def; +use crate::params::ParamPatternDef; use crate::params::param_to_param_def; use crate::params::prop_name_to_string; -use crate::params::ts_fn_param_to_param_def; use crate::ts_type::IndexSignatureDef; use crate::ts_type::TsTypeDef; use crate::ts_type::infer_ts_type_from_expr; @@ -28,6 +32,9 @@ use crate::ts_type_param::maybe_type_param_decl_to_type_param_defs; use crate::util::swc::get_location; use crate::util::swc::is_false; use crate::util::swc::js_doc_for_range; +use crate::util::types::Accessibility; +use crate::util::types::MethodKind; +use crate::util::types::VarDeclKind; use crate::variable::VariableDef; cfg_if! { @@ -54,7 +61,7 @@ cfg_if! { #[serde(rename_all = "camelCase")] pub struct ClassConstructorParamDef { #[serde(skip_serializing_if = "Option::is_none", default)] - pub accessibility: Option, + pub accessibility: Option, #[serde(skip_serializing_if = "is_false", default)] pub is_override: bool, #[serde(flatten)] @@ -83,7 +90,7 @@ pub struct ClassConstructorDef { #[serde(skip_serializing_if = "JsDoc::is_empty", default)] pub js_doc: JsDoc, #[serde(skip_serializing_if = "Option::is_none", default)] - pub accessibility: Option, + pub accessibility: Option, #[serde(skip_serializing_if = "is_false", default)] pub is_optional: bool, #[serde(skip_serializing_if = "is_false", default)] @@ -116,7 +123,7 @@ pub struct ClassPropertyDef { #[serde(skip_serializing_if = "is_false", default)] pub readonly: bool, #[serde(skip_serializing_if = "Option::is_none", default)] - pub accessibility: Option, + pub accessibility: Option, #[serde(skip_serializing_if = "<[_]>::is_empty", default)] pub decorators: Box<[DecoratorDef]>, #[serde(skip_serializing_if = "is_false", default)] @@ -141,7 +148,7 @@ impl From for Symbol { def.js_doc, VariableDef { ts_type: def.ts_type, - kind: deno_ast::swc::ast::VarDeclKind::Const, + kind: VarDeclKind::Const, }, ) } @@ -174,7 +181,7 @@ pub struct ClassMethodDef { #[serde(skip_serializing_if = "JsDoc::is_empty", default)] pub js_doc: JsDoc, #[serde(skip_serializing_if = "Option::is_none", default)] - pub accessibility: Option, + pub accessibility: Option, #[serde(skip_serializing_if = "is_false", default)] pub optional: bool, #[serde(skip_serializing_if = "is_false", default)] @@ -184,7 +191,7 @@ pub struct ClassMethodDef { #[serde(skip_serializing_if = "is_false", default)] pub is_override: bool, pub name: Box, - pub kind: deno_ast::swc::ast::MethodKind, + pub kind: MethodKind, pub function_def: FunctionDef, pub location: Location, } @@ -256,22 +263,20 @@ pub struct ClassDef { pub fn class_to_class_def( module_info: &EsModuleInfo, - class: &deno_ast::swc::ast::Class, + class: &Class, def_name: Option>, ) -> (ClassDef, JsDoc) { - use deno_ast::swc::ast::Expr; - let mut constructors = vec![]; let mut methods = vec![]; let mut properties = vec![]; let mut index_signatures = vec![]; - fn walk_class_extends(expr: &Expr) -> Option { + fn walk_class_extends(expr: &Expression) -> Option { match expr { - Expr::Ident(ident) => Some(ident.sym.to_string()), - Expr::Member(member_expr) => { - let prop = &member_expr.prop.as_ident()?.sym; - let mut string_path = walk_class_extends(&member_expr.obj)?; + Expression::Identifier(ident) => Some(ident.name.to_string()), + Expression::StaticMemberExpression(member_expr) => { + let prop = &member_expr.property.name; + let mut string_path = walk_class_extends(&member_expr.object)?; string_path.push('.'); string_path.push_str(prop); @@ -284,7 +289,7 @@ pub fn class_to_class_def( let extends: Option> = match &class.super_class { Some(boxed) => { - let expr: &Expr = boxed; + let expr: &Expression = boxed; walk_class_extends(expr).map(|s| s.into_boxed_str()) } None => None, @@ -293,94 +298,91 @@ pub fn class_to_class_def( let implements = class .implements .iter() - .map(|expr| TsTypeDef::ts_expr_with_type_args(module_info, expr)) + .map(|expr| TsTypeDef::ts_class_implements(module_info, expr)) .collect::>(); - for member in &class.body { - use deno_ast::swc::ast::ClassMember::*; - + for member in &class.body.body { match member { - Constructor(ctor) => { - if let Some(ctor_js_doc) = js_doc_for_range(module_info, &ctor.range()) - { + ClassElement::MethodDefinition(method_def) + if method_def.kind == MethodDefinitionKind::Constructor => + { + let ctor = method_def; + if let Some(ctor_js_doc) = js_doc_for_range(module_info, ctor.span()) { let constructor_name = prop_name_to_string(module_info, &ctor.key); let mut params = vec![]; - for param in &ctor.params { - use deno_ast::swc::ast::ParamOrTsParamProp::*; + for param in &ctor.value.params.items { + let param_def = ClassConstructorParamDef { + accessibility: Accessibility::from_oxc(param.accessibility), + is_override: param.r#override, + param: param_to_param_def(module_info, param), + readonly: param.readonly, + }; + params.push(param_def); + } - let param_def = match param { - Param(param) => ClassConstructorParamDef { - accessibility: None, - is_override: false, - param: param_to_param_def(module_info, param), - readonly: false, - }, - TsParamProp(ts_param_prop) => { - use deno_ast::swc::ast::TsParamPropParam; - - let param = match &ts_param_prop.param { - TsParamPropParam::Ident(ident) => { - ident_to_param_def(module_info, ident) - } - TsParamPropParam::Assign(assign_pat) => { - assign_pat_to_param_def(module_info, assign_pat) - } - }; - - ClassConstructorParamDef { - accessibility: ts_param_prop.accessibility, - is_override: ts_param_prop.is_override, - param, - readonly: ts_param_prop.readonly, - } - } + if let Some(rest) = &ctor.value.params.rest { + let param_def = ClassConstructorParamDef { + accessibility: None, + is_override: false, + param: crate::params::rest_element_to_param_def( + module_info, + &rest.rest, + rest.type_annotation.as_deref(), + ), + readonly: false, }; params.push(param_def); } let constructor_def = ClassConstructorDef { js_doc: ctor_js_doc, - accessibility: ctor.accessibility, - is_optional: ctor.is_optional, - has_body: ctor.body.is_some(), + accessibility: Accessibility::from_oxc(ctor.accessibility), + is_optional: ctor.optional, + has_body: ctor.value.body.is_some(), name: constructor_name, params, - location: get_location(module_info, ctor.start()), + location: get_location(module_info, ctor.span().start), }; constructors.push(constructor_def); } } - Method(class_method) => { + ClassElement::MethodDefinition(class_method) => { if let Some(method_js_doc) = - js_doc_for_range(module_info, &class_method.range()) + js_doc_for_range(module_info, class_method.span()) { let method_name = prop_name_to_string(module_info, &class_method.key); - let fn_def = - function_to_function_def(module_info, &class_method.function, None); + let mut fn_def = + function_to_function_def(module_info, &class_method.value, None); + fn_def.decorators = + decorators_to_defs(module_info, &class_method.decorators); let method_def = ClassMethodDef { js_doc: method_js_doc, - accessibility: class_method.accessibility, - optional: class_method.is_optional, - is_abstract: class_method.is_abstract, - is_static: class_method.is_static, - is_override: class_method.is_override, + accessibility: Accessibility::from_oxc(class_method.accessibility), + optional: class_method.optional, + is_abstract: class_method.r#type + == MethodDefinitionType::TSAbstractMethodDefinition, + is_static: class_method.r#static, + is_override: class_method.r#override, name: method_name.into_boxed_str(), - kind: class_method.kind, + kind: MethodKind::from(class_method.kind), function_def: fn_def, - location: get_location(module_info, class_method.start()), + location: get_location(module_info, class_method.span().start), }; methods.push(method_def); } } - ClassProp(class_prop) => { + ClassElement::PropertyDefinition(class_prop) => { + if class_prop.key.is_private_identifier() { + continue; + } if let Some(prop_js_doc) = - js_doc_for_range(module_info, &class_prop.range()) + js_doc_for_range(module_info, class_prop.span()) { - let ts_type = if let Some(type_ann) = &class_prop.type_ann { + let ts_type = if let Some(type_ann) = &class_prop.type_annotation { // if the property has a type annotation, use it - Some(TsTypeDef::new(module_info, &type_ann.type_ann)) + Some(TsTypeDef::new(module_info, &type_ann.type_annotation)) } else if let Some(value) = &class_prop.value { // else, if it has an initializer, try to infer the type infer_ts_type_from_expr(module_info, value, false) @@ -398,35 +400,46 @@ pub fn class_to_class_def( js_doc: prop_js_doc, ts_type, readonly: class_prop.readonly, - optional: class_prop.is_optional, - is_abstract: class_prop.is_abstract, - is_static: class_prop.is_static, - is_override: class_prop.is_override, - accessibility: class_prop.accessibility, + optional: class_prop.optional, + is_abstract: class_prop.r#type + == PropertyDefinitionType::TSAbstractPropertyDefinition, + is_static: class_prop.r#static, + is_override: class_prop.r#override, + accessibility: Accessibility::from_oxc(class_prop.accessibility), name: prop_name.into_boxed_str(), decorators, - location: get_location(module_info, class_prop.start()), + location: get_location(module_info, class_prop.span().start), }; properties.push(prop_def); } } - TsIndexSignature(ts_index_sig) => { - if let Some(js_doc) = - js_doc_for_range(module_info, &ts_index_sig.range()) + ClassElement::TSIndexSignature(ts_index_sig) => { + if let Some(js_doc) = js_doc_for_range(module_info, ts_index_sig.span()) { let mut params = vec![]; - for param in &ts_index_sig.params { - let param_def = ts_fn_param_to_param_def(module_info, param); + for param in &ts_index_sig.parameters { + let ts_type = Some(TsTypeDef::new( + module_info, + ¶m.type_annotation.type_annotation, + )); + let param_def = ParamDef { + pattern: ParamPatternDef::Identifier { + name: param.name.to_string(), + optional: false, + }, + decorators: Box::new([]), + ts_type, + }; params.push(param_def); } - let ts_type = ts_index_sig - .type_ann - .as_ref() - .map(|rt| TsTypeDef::new(module_info, &rt.type_ann)); + let ts_type = Some(TsTypeDef::new( + module_info, + &ts_index_sig.type_annotation.type_annotation, + )); let index_sig_def = IndexSignatureDef { - location: get_location(module_info, ts_index_sig.start()), + location: get_location(module_info, ts_index_sig.span().start), js_doc, readonly: ts_index_sig.readonly, params, @@ -435,21 +448,18 @@ pub fn class_to_class_def( index_signatures.push(index_sig_def); } } - // TODO(bartlomieju): - PrivateMethod(_) => {} - PrivateProp(_) => {} _ => {} } } let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - class.type_params.as_deref(), + class.type_parameters.as_deref(), ); let super_type_params = maybe_type_param_instantiation_to_type_defs( module_info, - class.super_type_params.as_deref(), + class.super_type_arguments.as_deref(), ); let decorators = decorators_to_defs(module_info, &class.decorators); @@ -457,7 +467,7 @@ pub fn class_to_class_def( // JSDoc associated with the class may actually be a leading comment on a // decorator, and so we should parse out the JSDoc for the first decorator let js_doc = if !class.decorators.is_empty() { - js_doc_for_range(module_info, &class.decorators[0].range()).unwrap() + js_doc_for_range(module_info, class.decorators[0].span()).unwrap() } else { JsDoc::default() }; @@ -465,7 +475,7 @@ pub fn class_to_class_def( ( ClassDef { def_name, - is_abstract: class.is_abstract, + is_abstract: class.r#abstract, extends, implements, constructors: constructors.into_boxed_slice(), @@ -482,7 +492,7 @@ pub fn class_to_class_def( pub fn get_doc_for_class_decl( module_info: &EsModuleInfo, - class_decl: &deno_ast::swc::ast::ClassDecl, + class: &Class, ) -> (ClassDef, JsDoc) { - class_to_class_def(module_info, &class_decl.class, None) + class_to_class_def(module_info, class, None) } diff --git a/src/decorators.rs b/src/decorators.rs index d6dc1f5fb..006c0d9c9 100644 --- a/src/decorators.rs +++ b/src/decorators.rs @@ -3,9 +3,9 @@ use crate::node::Location; use crate::util::swc::get_location; -use deno_ast::SourceRangedForSpanned; -use deno_ast::swc::ast::Decorator; -use deno_ast::swc::ast::Expr; +use deno_ast::oxc::ast::ast::Decorator; +use deno_ast::oxc::ast::ast::Expression; +use deno_ast::oxc::span::GetSpan; use deno_graph::symbols::EsModuleInfo; use deno_terminal::colors; use serde::Deserialize; @@ -44,40 +44,39 @@ impl DecoratorDef { module_info: &EsModuleInfo, decorator: &Decorator, ) -> Self { - match decorator.expr.as_ref() { - Expr::Call(call_expr) => { - if let Some(expr) = call_expr.callee.clone().expr() - && let Expr::Ident(ident) = expr.as_ref() - { + match &decorator.expression { + Expression::CallExpression(call_expr) => { + if let Expression::Identifier(ident) = &call_expr.callee { let args = call_expr - .args + .arguments .iter() .map(|a| { - a.text_fast(module_info.source().text_info_lazy()) + let span = a.span(); + module_info.source_text()[span.start as usize..span.end as usize] .to_string() }) .collect(); return Self { - name: ident.sym.to_string(), + name: ident.name.to_string(), args, - location: get_location(module_info, ident.start()), + location: get_location(module_info, ident.span.start), }; } Self { name: "[UNSUPPORTED]".to_string(), args: vec![], - location: get_location(module_info, call_expr.start()), + location: get_location(module_info, call_expr.span.start), } } - Expr::Ident(ident) => Self { - name: ident.sym.to_string(), + Expression::Identifier(ident) => Self { + name: ident.name.to_string(), args: vec![], - location: get_location(module_info, ident.start()), + location: get_location(module_info, ident.span.start), }, _ => Self { name: "[UNSUPPORTED]".to_string(), args: vec![], - location: get_location(module_info, decorator.start()), + location: get_location(module_info, decorator.span.start), }, } } diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 39cb9d4bd..1a2b97763 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -10,10 +10,10 @@ use crate::ts_type::TsTypeDef; use crate::util::swc::get_text_info_location; use crate::util::swc::has_ignorable_js_doc_tag; use crate::util::symbol::symbol_has_ignorable_js_doc_tag; +use crate::util::types::Accessibility; use crate::variable::VariableDef; use deno_ast::ModuleSpecifier; -use deno_ast::SourceRange; use deno_ast::SourceTextInfo; use deno_ast::diagnostics::Diagnostic; use deno_ast::diagnostics::DiagnosticLevel; @@ -23,7 +23,7 @@ use deno_ast::diagnostics::DiagnosticSnippetHighlight; use deno_ast::diagnostics::DiagnosticSnippetHighlightStyle; use deno_ast::diagnostics::DiagnosticSourcePos; use deno_ast::diagnostics::DiagnosticSourceRange; -use deno_ast::swc::ast::Accessibility; +use deno_ast::oxc::span::Span; use deno_graph::symbols::ModuleInfoRef; use deno_graph::symbols::RootSymbol; use deno_graph::symbols::Symbol as GraphSymbol; @@ -204,7 +204,7 @@ impl<'a> DiagnosticsCollector<'a> { &mut self, decl_module: ModuleInfoRef, decl_name: &str, - decl_range: SourceRange, + decl_range: Span, doc_symbol_id: UniqueSymbolId, referenced_module: ModuleInfoRef, referenced_symbol: &GraphSymbol, diff --git a/src/diff/class.rs b/src/diff/class.rs index fe101cf43..9620f6708 100644 --- a/src/diff/class.rs +++ b/src/diff/class.rs @@ -16,7 +16,7 @@ use crate::class::ClassMethodDef; use crate::class::ClassPropertyDef; use crate::ts_type::IndexSignatureDef; use crate::ts_type::TsTypeDef; -use deno_ast::swc::ast::Accessibility; +use crate::util::types::Accessibility; use indexmap::IndexMap; use indexmap::IndexSet; use serde::Deserialize; diff --git a/src/diff/variable.rs b/src/diff/variable.rs index 3d91a6c4a..a28e3ff46 100644 --- a/src/diff/variable.rs +++ b/src/diff/variable.rs @@ -2,8 +2,8 @@ use super::Change; use super::ts_type::TsTypeDiff; +use crate::util::types::VarDeclKind; use crate::variable::VariableDef; -use deno_ast::swc::ast::VarDeclKind; use serde::Deserialize; use serde::Serialize; diff --git a/src/display.rs b/src/display.rs index aba3b5596..8fb77be7a 100644 --- a/src/display.rs +++ b/src/display.rs @@ -54,19 +54,22 @@ pub(crate) fn display_readonly(is_readonly: bool) -> impl Display { cfg_if! { if #[cfg(feature = "rust")] { + use crate::util::types::Accessibility; + use crate::util::types::MethodKind; + pub(crate) fn display_abstract(is_abstract: bool) -> impl Display { colors::magenta(if is_abstract { "abstract " } else { "" }) } pub(crate) fn display_accessibility( - accessibility: Option, show_public: bool + accessibility: Option, show_public: bool ) -> impl Display { colors::magenta( match accessibility { None => "", - Some(deno_ast::swc::ast::Accessibility::Public) => if show_public { "public " } else { "" }, - Some(deno_ast::swc::ast::Accessibility::Protected) => "protected ", - Some(deno_ast::swc::ast::Accessibility::Private) => "private ", + Some(Accessibility::Public) => if show_public { "public " } else { "" }, + Some(Accessibility::Protected) => "protected ", + Some(Accessibility::Private) => "private ", }, ) } @@ -80,11 +83,11 @@ cfg_if! { } pub(crate) fn display_method( - method: deno_ast::swc::ast::MethodKind, + method: MethodKind, ) -> impl Display { colors::magenta(match method { - deno_ast::swc::ast::MethodKind::Getter => "get ", - deno_ast::swc::ast::MethodKind::Setter => "set ", + MethodKind::Getter => "get ", + MethodKind::Setter => "set ", _ => "", }) } diff --git a/src/enum.rs b/src/enum.rs index cd6090064..04ccaac08 100644 --- a/src/enum.rs +++ b/src/enum.rs @@ -1,6 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_ast::SourceRangedForSpanned; +use deno_ast::oxc::ast::ast::TSEnumDeclaration; +use deno_ast::oxc::span::GetSpan; use deno_graph::symbols::EsModuleInfo; use serde::Deserialize; use serde::Serialize; @@ -31,19 +32,14 @@ pub struct EnumDef { pub fn get_doc_for_ts_enum_decl( module_info: &EsModuleInfo, - enum_decl: &deno_ast::swc::ast::TsEnumDecl, + enum_decl: &TSEnumDeclaration, ) -> EnumDef { let mut members = vec![]; - for enum_member in &enum_decl.members { - use deno_ast::swc::ast::TsEnumMemberId::*; - - if let Some(js_doc) = js_doc_for_range(module_info, &enum_member.range()) { - let name = match &enum_member.id { - Ident(ident) => ident.sym.to_string(), - Str(str_) => str_.value.to_string_lossy().into_owned(), - }; - let init = if let Some(expr) = &enum_member.init { + for enum_member in &enum_decl.body.members { + if let Some(js_doc) = js_doc_for_range(module_info, enum_member.span()) { + let name = enum_member.id.static_name().to_string(); + let init = if let Some(expr) = &enum_member.initializer { infer_ts_type_from_expr(module_info, expr, true) } else { None @@ -53,7 +49,7 @@ pub fn get_doc_for_ts_enum_decl( name, init, js_doc, - location: get_location(module_info, enum_member.start()), + location: get_location(module_info, enum_member.span().start), }; members.push(member_def); } diff --git a/src/function.rs b/src/function.rs index d91346e3d..76b5ca550 100644 --- a/src/function.rs +++ b/src/function.rs @@ -2,14 +2,14 @@ use crate::ParamDef; use crate::decorators::DecoratorDef; -use crate::decorators::decorators_to_defs; use crate::params::param_to_param_def; use crate::ts_type::TsTypeDef; use crate::ts_type_param::TsTypeParamDef; use crate::ts_type_param::maybe_type_param_decl_to_type_param_defs; use crate::util::swc::is_false; -use deno_ast::swc::ast::ReturnStmt; -use deno_ast::swc::ast::Stmt; +use deno_ast::oxc::ast::ast::Function; +use deno_ast::oxc::ast::ast::ReturnStatement; +use deno_ast::oxc::ast::ast::Statement; use deno_graph::symbols::EsModuleInfo; use serde::Deserialize; use serde::Serialize; @@ -37,60 +37,67 @@ pub struct FunctionDef { pub fn function_to_function_def( module_info: &EsModuleInfo, - function: &deno_ast::swc::ast::Function, + function: &Function, def_name: Option, ) -> FunctionDef { - let params = function + let mut params = function .params + .items .iter() .map(|param| param_to_param_def(module_info, param)) - .collect(); - - let maybe_return_type = match function - .return_type - .as_deref() - .map(|return_type| TsTypeDef::new(module_info, &return_type.type_ann)) - { - Some(return_type) => Some(return_type), - None - if !function.is_generator - && function.body.is_some() - && get_return_stmt_with_arg_from_function(function).is_none() => - { - if function.is_async { - Some(TsTypeDef { - repr: "Promise".to_string(), - kind: crate::ts_type::TsTypeDefKind::TypeRef( - crate::ts_type::TsTypeRefDef { - type_params: Some(Box::new([TsTypeDef::keyword("void")])), - type_name: "Promise".to_string(), - resolution: None, - }, - ), - }) - } else { - Some(TsTypeDef::keyword("void")) + .collect::>(); + if let Some(rest) = &function.params.rest { + params.push(crate::params::rest_element_to_param_def( + module_info, + &rest.rest, + rest.type_annotation.as_deref(), + )); + } + + let maybe_return_type = + match function.return_type.as_ref().map(|return_type| { + TsTypeDef::new(module_info, &return_type.type_annotation) + }) { + Some(return_type) => Some(return_type), + None + if !function.generator + && function.body.is_some() + && get_return_stmt_with_arg_from_function(function).is_none() => + { + if function.r#async { + Some(TsTypeDef { + repr: "Promise".to_string(), + kind: crate::ts_type::TsTypeDefKind::TypeRef( + crate::ts_type::TsTypeRefDef { + type_params: Some(Box::new([TsTypeDef::keyword("void")])), + type_name: "Promise".to_string(), + resolution: None, + }, + ), + }) + } else { + Some(TsTypeDef::keyword("void")) + } } - } - None => None, - }; + None => None, + }; let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - function.type_params.as_deref(), + function.type_parameters.as_deref(), ); let has_body = function.body.is_some(); - let decorators = decorators_to_defs(module_info, &function.decorators); + let decorators = Box::new([]); FunctionDef { def_name, params, return_type: maybe_return_type, has_body, - is_async: function.is_async, - is_generator: function.is_generator, + is_async: function.r#async, + is_generator: function.generator, type_params, decorators, } @@ -98,22 +105,29 @@ pub fn function_to_function_def( pub fn arrow_to_function_def( module_info: &EsModuleInfo, - arrow: &deno_ast::swc::ast::ArrowExpr, + arrow: &deno_ast::oxc::ast::ast::ArrowFunctionExpression, ) -> FunctionDef { - let params = arrow + let mut params = arrow .params + .items .iter() - .map(|pat| crate::params::pat_to_param_def(module_info, pat)) - .collect(); + .map(|param| param_to_param_def(module_info, param)) + .collect::>(); + if let Some(rest) = &arrow.params.rest { + params.push(crate::params::rest_element_to_param_def( + module_info, + &rest.rest, + rest.type_annotation.as_deref(), + )); + } - let maybe_return_type = arrow - .return_type - .as_deref() - .map(|return_type| TsTypeDef::new(module_info, &return_type.type_ann)); + let maybe_return_type = arrow.return_type.as_ref().map(|return_type| { + TsTypeDef::new(module_info, &return_type.type_annotation) + }); let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - arrow.type_params.as_deref(), + arrow.type_parameters.as_deref(), ); FunctionDef { @@ -121,8 +135,8 @@ pub fn arrow_to_function_def( params, return_type: maybe_return_type, has_body: true, - is_async: arrow.is_async, - is_generator: arrow.is_generator, + is_async: arrow.r#async, + is_generator: false, type_params, decorators: Box::new([]), } @@ -130,21 +144,23 @@ pub fn arrow_to_function_def( pub fn get_doc_for_fn_decl( module_info: &EsModuleInfo, - fn_decl: &deno_ast::swc::ast::FnDecl, + function: &Function, ) -> FunctionDef { - function_to_function_def(module_info, &fn_decl.function, None) + function_to_function_def(module_info, function, None) } -fn get_return_stmt_with_arg_from_function( - func: &deno_ast::swc::ast::Function, -) -> Option<&ReturnStmt> { +fn get_return_stmt_with_arg_from_function<'a>( + func: &'a Function<'a>, +) -> Option<&'a ReturnStatement<'a>> { let body = func.body.as_ref()?; - let stmt = get_return_stmt_with_arg_from_stmts(&body.stmts)?; - debug_assert!(stmt.arg.is_some()); + let stmt = get_return_stmt_with_arg_from_stmts(&body.statements)?; + debug_assert!(stmt.argument.is_some()); Some(stmt) } -fn get_return_stmt_with_arg_from_stmts(stmts: &[Stmt]) -> Option<&ReturnStmt> { +fn get_return_stmt_with_arg_from_stmts<'a>( + stmts: &'a [Statement<'a>], +) -> Option<&'a ReturnStatement<'a>> { for stmt in stmts { if let Some(return_stmt) = get_return_stmt_with_arg_from_stmt(stmt) { return Some(return_stmt); @@ -154,45 +170,57 @@ fn get_return_stmt_with_arg_from_stmts(stmts: &[Stmt]) -> Option<&ReturnStmt> { None } -fn get_return_stmt_with_arg_from_stmt(stmt: &Stmt) -> Option<&ReturnStmt> { +fn get_return_stmt_with_arg_from_stmt<'a>( + stmt: &'a Statement<'a>, +) -> Option<&'a ReturnStatement<'a>> { match stmt { - Stmt::Block(n) => get_return_stmt_with_arg_from_stmts(&n.stmts), - Stmt::With(n) => get_return_stmt_with_arg_from_stmt(&n.body), - Stmt::Return(n) => { - if n.arg.is_none() { + Statement::BlockStatement(n) => { + get_return_stmt_with_arg_from_stmts(&n.body) + } + Statement::WithStatement(n) => get_return_stmt_with_arg_from_stmt(&n.body), + Statement::ReturnStatement(n) => { + if n.argument.is_none() { None } else { Some(n) } } - Stmt::Labeled(n) => get_return_stmt_with_arg_from_stmt(&n.body), - Stmt::If(n) => get_return_stmt_with_arg_from_stmt(&n.cons), - Stmt::Switch(n) => n + Statement::LabeledStatement(n) => { + get_return_stmt_with_arg_from_stmt(&n.body) + } + Statement::IfStatement(n) => { + get_return_stmt_with_arg_from_stmt(&n.consequent) + } + Statement::SwitchStatement(n) => n .cases .iter() - .find_map(|case| get_return_stmt_with_arg_from_stmts(&case.cons)), - Stmt::Try(n) => get_return_stmt_with_arg_from_stmts(&n.block.stmts) - .or_else(|| { - n.handler - .as_ref() - .and_then(|h| get_return_stmt_with_arg_from_stmts(&h.body.stmts)) - }) - .or_else(|| { - n.finalizer - .as_ref() - .and_then(|f| get_return_stmt_with_arg_from_stmts(&f.stmts)) - }), - Stmt::While(n) => get_return_stmt_with_arg_from_stmt(&n.body), - Stmt::DoWhile(n) => get_return_stmt_with_arg_from_stmt(&n.body), - Stmt::For(n) => get_return_stmt_with_arg_from_stmt(&n.body), - Stmt::ForIn(n) => get_return_stmt_with_arg_from_stmt(&n.body), - Stmt::ForOf(n) => get_return_stmt_with_arg_from_stmt(&n.body), - Stmt::Break(_) - | Stmt::Continue(_) - | Stmt::Throw(_) - | Stmt::Debugger(_) - | Stmt::Decl(_) - | Stmt::Expr(_) - | Stmt::Empty(_) => None, + .find_map(|case| get_return_stmt_with_arg_from_stmts(&case.consequent)), + Statement::TryStatement(n) => { + get_return_stmt_with_arg_from_stmts(&n.block.body) + .or_else(|| { + n.handler + .as_ref() + .and_then(|h| get_return_stmt_with_arg_from_stmts(&h.body.body)) + }) + .or_else(|| { + n.finalizer + .as_ref() + .and_then(|f| get_return_stmt_with_arg_from_stmts(&f.body)) + }) + } + Statement::WhileStatement(n) => get_return_stmt_with_arg_from_stmt(&n.body), + Statement::DoWhileStatement(n) => { + get_return_stmt_with_arg_from_stmt(&n.body) + } + Statement::ForStatement(n) => get_return_stmt_with_arg_from_stmt(&n.body), + Statement::ForInStatement(n) => get_return_stmt_with_arg_from_stmt(&n.body), + Statement::ForOfStatement(n) => get_return_stmt_with_arg_from_stmt(&n.body), + Statement::BreakStatement(_) + | Statement::ContinueStatement(_) + | Statement::ThrowStatement(_) + | Statement::DebuggerStatement(_) + | Statement::ExpressionStatement(_) + | Statement::EmptyStatement(_) => None, + _ => None, } } diff --git a/src/html/mod.rs b/src/html/mod.rs index b0478b757..c23f47c48 100644 --- a/src/html/mod.rs +++ b/src/html/mod.rs @@ -907,12 +907,12 @@ pub enum MethodKind { Setter, } -impl From for MethodKind { - fn from(value: deno_ast::swc::ast::MethodKind) -> Self { +impl From for MethodKind { + fn from(value: crate::util::types::MethodKind) -> Self { match value { - deno_ast::swc::ast::MethodKind::Method => Self::Method, - deno_ast::swc::ast::MethodKind::Getter => Self::Getter, - deno_ast::swc::ast::MethodKind::Setter => Self::Setter, + crate::util::types::MethodKind::Method => Self::Method, + crate::util::types::MethodKind::Getter => Self::Getter, + crate::util::types::MethodKind::Setter => Self::Setter, } } } @@ -1019,7 +1019,7 @@ impl DocNodeWithContext { &self, mut method_doc_node: Symbol, is_static: bool, - method_kind: deno_ast::swc::ast::MethodKind, + method_kind: crate::util::types::MethodKind, ) -> Self { let original_name = method_doc_node.name.clone(); method_doc_node.name = @@ -1040,7 +1040,7 @@ impl DocNodeWithContext { parent: &Arc, mut method_doc_node: Symbol, is_static: bool, - method_kind: deno_ast::swc::ast::MethodKind, + method_kind: crate::util::types::MethodKind, ) -> Self { let original_name = method_doc_node.name.clone(); method_doc_node.name = qualify_drilldown_name( diff --git a/src/html/symbols/class.rs b/src/html/symbols/class.rs index 620b6831a..b1a08c4b0 100644 --- a/src/html/symbols/class.rs +++ b/src/html/symbols/class.rs @@ -17,8 +17,8 @@ use crate::html::util::*; use crate::interface::InterfaceDef; use crate::js_doc::JsDocTag; use crate::ts_type::TsTypeDefKind; -use deno_ast::swc::ast::Accessibility; -use deno_ast::swc::ast::MethodKind; +use crate::util::types::Accessibility; +use crate::util::types::MethodKind; use indexmap::IndexMap; use serde::Deserialize; use serde::Serialize; diff --git a/src/html/symbols/mod.rs b/src/html/symbols/mod.rs index 3c8420acf..76b4540cd 100644 --- a/src/html/symbols/mod.rs +++ b/src/html/symbols/mod.rs @@ -663,7 +663,7 @@ impl SymbolInnerCtx { pub(crate) fn compute_old_tags( current_tags: &indexmap::IndexSet, accessibility_change: Option< - &crate::diff::Change>, + &crate::diff::Change>, >, readonly_change: Option<&crate::diff::Change>, abstract_change: Option<&crate::diff::Change>, diff --git a/src/html/symbols/namespace.rs b/src/html/symbols/namespace.rs index ba4df8f23..f633f6896 100644 --- a/src/html/symbols/namespace.rs +++ b/src/html/symbols/namespace.rs @@ -550,14 +550,14 @@ fn inject_removed_subitems( for method in &mc.removed { if matches!( method.accessibility, - Some(deno_ast::swc::ast::Accessibility::Private) + Some(crate::util::types::Accessibility::Private) ) { continue; } let target_id = if matches!( method.kind, - deno_ast::swc::ast::MethodKind::Getter - | deno_ast::swc::ast::MethodKind::Setter + crate::util::types::MethodKind::Getter + | crate::util::types::MethodKind::Setter ) { IdBuilder::new(ctx) .kind(IdKind::Accessor) @@ -596,7 +596,7 @@ fn inject_removed_subitems( for prop in &pc.removed { if matches!( prop.accessibility, - Some(deno_ast::swc::ast::Accessibility::Private) + Some(crate::util::types::Accessibility::Private) ) { continue; } @@ -629,8 +629,8 @@ fn inject_removed_subitems( for method in &mc.removed { let target_id = if matches!( method.kind, - deno_ast::swc::ast::MethodKind::Getter - | deno_ast::swc::ast::MethodKind::Setter + crate::util::types::MethodKind::Getter + | crate::util::types::MethodKind::Setter ) { IdBuilder::new(ctx) .kind(IdKind::Accessor) diff --git a/src/html/types.rs b/src/html/types.rs index 8dfb7b634..64fe46a3d 100644 --- a/src/html/types.rs +++ b/src/html/types.rs @@ -5,10 +5,10 @@ use super::util::*; use crate::js_doc::JsDoc; use crate::js_doc::JsDocTag; use crate::ts_type::LiteralDefKind; +use crate::ts_type::TruePlusMinus; use crate::ts_type::TsTypeDefKind; use crate::ts_type_param::TsTypeParamDef; -use deno_ast::swc::ast::MethodKind; -use deno_ast::swc::ast::TruePlusMinus; +use crate::util::types::MethodKind; const MAX_INLINE_LEN: usize = 60; diff --git a/src/html/util.rs b/src/html/util.rs index 8a6780efc..4b3ba3031 100644 --- a/src/html/util.rs +++ b/src/html/util.rs @@ -13,8 +13,7 @@ use crate::js_doc::JsDoc; use crate::js_doc::JsDocTag; use crate::node::DeclarationDef; use crate::node::DocNodeKind; -use deno_ast::swc::ast::Accessibility; -use deno_ast::swc::atoms::once_cell::sync::Lazy; +use crate::util::types::Accessibility; use indexmap::IndexSet; use regex::Regex; use serde::Deserialize; @@ -24,6 +23,7 @@ use std::collections::HashMap; use std::fmt::Display; use std::fmt::Formatter; use std::sync::Arc; +use std::sync::LazyLock; lazy_static! { static ref TARGET_RE: Regex = Regex::new(r"\s*\* ?|\.").unwrap(); @@ -948,8 +948,8 @@ impl ToCCtx { } pub fn slugify(name: &str) -> String { - static REJECTED_CHARS: Lazy = - Lazy::new(|| Regex::new(r"[^\p{L}\p{M}\p{N}\p{Pc} -]").unwrap()); + static REJECTED_CHARS: LazyLock = + LazyLock::new(|| Regex::new(r"[^\p{L}\p{M}\p{N}\p{Pc} -]").unwrap()); REJECTED_CHARS .replace_all(&name.to_lowercase(), "") diff --git a/src/interface.rs b/src/interface.rs index 2793d183f..aff0d5371 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -1,11 +1,15 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_ast::SourceRangedForSpanned; +use deno_ast::oxc::ast::ast::Expression; +use deno_ast::oxc::ast::ast::TSInterfaceDeclaration; +use deno_ast::oxc::ast::ast::TSSignature; use deno_graph::symbols::EsModuleInfo; use serde::Deserialize; use serde::Serialize; -use crate::params::ts_fn_param_to_param_def; +use crate::ParamDef; +use crate::params::ParamPatternDef; +use crate::params::formal_params_to_param_defs; use crate::ts_type::CallSignatureDef; use crate::ts_type::ConstructorDef; use crate::ts_type::IndexSignatureDef; @@ -16,6 +20,7 @@ use crate::ts_type_param::TsTypeParamDef; use crate::ts_type_param::maybe_type_param_decl_to_type_param_defs; use crate::util::swc::get_location; use crate::util::swc::js_doc_for_range; +use crate::util::types::MethodKind; #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] @@ -39,50 +44,63 @@ pub struct InterfaceDef { pub type_params: Box<[TsTypeParamDef]>, } -pub fn expr_to_name(expr: &deno_ast::swc::ast::Expr) -> String { - use deno_ast::swc::ast::Expr::*; - use deno_ast::swc::ast::MemberProp; - +pub fn expr_to_name(expr: &Expression) -> String { match expr { - Ident(ident) => ident.sym.to_string(), - Member(member_expr) => { - let left = expr_to_name(&member_expr.obj); - let right = match &member_expr.prop { - MemberProp::Ident(ident) => format!(".{}", ident.sym), - MemberProp::Computed(_) | MemberProp::PrivateName(_) => { - "[UNSUPPORTED]".to_string() - } - }; + Expression::Identifier(ident) => ident.name.to_string(), + Expression::StaticMemberExpression(member_expr) => { + let left = expr_to_name(&member_expr.object); + let right = format!(".{}", member_expr.property.name); format!("[{}{}]", left, right) } - Lit(lit) => { - use deno_ast::swc::ast::BigInt; - use deno_ast::swc::ast::Bool; - use deno_ast::swc::ast::JSXText; - use deno_ast::swc::ast::Lit; - use deno_ast::swc::ast::Number; - use deno_ast::swc::ast::Regex; - use deno_ast::swc::ast::Str; - match lit { - Lit::Str(Str { value, .. }) => value.to_string_lossy().into_owned(), - Lit::Bool(Bool { value, .. }) => { - let str_val = if *value { "true" } else { "false" }; - str_val.to_string() + Expression::ComputedMemberExpression(_) + | Expression::PrivateFieldExpression(_) => "[UNSUPPORTED]".to_string(), + Expression::StringLiteral(str_) => str_.value.to_string(), + Expression::BooleanLiteral(bool_) => { + if bool_.value { "true" } else { "false" }.to_string() + } + Expression::NullLiteral(_) => "null".to_string(), + Expression::NumericLiteral(num) => num.value.to_string(), + Expression::BigIntLiteral(num) => num + .raw + .as_ref() + .map(|r| r.as_str().to_string()) + .unwrap_or_default(), + Expression::RegExpLiteral(regex) => { + format!("/{}/", regex.regex.pattern.text) + } + Expression::TemplateLiteral(tpl) => { + let mut result = String::new(); + for (i, quasi) in tpl.quasis.iter().enumerate() { + result.push_str(quasi.value.raw.as_str()); + if i < tpl.expressions.len() { + result.push_str(&expr_to_name(&tpl.expressions[i])); } - Lit::Null(_) => "null".to_string(), - Lit::Num(Number { value, .. }) => value.to_string(), - Lit::BigInt(BigInt { value, .. }) => value.to_string(), - Lit::Regex(Regex { exp, .. }) => format!("/{}/", exp), - Lit::JSXText(JSXText { raw, .. }) => raw.to_string(), } + result } _ => "[UNSUPPORTED]".to_string(), } } +pub fn property_key_name(key: &deno_ast::oxc::ast::ast::PropertyKey) -> String { + use deno_ast::oxc::ast::ast::PropertyKey; + if let Some(name) = key.static_name() { + return name.to_string(); + } + // For computed keys, resolve common expression patterns + match key { + PropertyKey::StaticIdentifier(ident) => ident.name.to_string(), + // Computed keys that are identifiers (e.g., `[pc]`) + PropertyKey::Identifier(ident) => ident.name.to_string(), + PropertyKey::StringLiteral(s) => s.value.to_string(), + PropertyKey::NumericLiteral(n) => n.value.to_string(), + _ => "[UNSUPPORTED]".to_string(), + } +} + pub fn get_doc_for_ts_interface_decl( module_info: &EsModuleInfo, - interface_decl: &deno_ast::swc::ast::TsInterfaceDecl, + interface_decl: &TSInterfaceDeclaration, def_name: Option, ) -> InterfaceDef { let mut constructors = vec![]; @@ -92,37 +110,31 @@ pub fn get_doc_for_ts_interface_decl( let mut index_signatures = vec![]; for type_element in &interface_decl.body.body { - use deno_ast::swc::ast::TsTypeElement::*; - - match &type_element { - TsMethodSignature(ts_method_sig) => { + match type_element { + TSSignature::TSMethodSignature(ts_method_sig) => { if let Some(method_js_doc) = - js_doc_for_range(module_info, &ts_method_sig.range()) + js_doc_for_range(module_info, ts_method_sig.span) { - let mut params = vec![]; - - for param in &ts_method_sig.params { - let param_def = ts_fn_param_to_param_def(module_info, param); - params.push(param_def); - } + let params = + formal_params_to_param_defs(module_info, &ts_method_sig.params); - let name = expr_to_name(&ts_method_sig.key); + let name = property_key_name(&ts_method_sig.key); - let maybe_return_type = ts_method_sig - .type_ann - .as_deref() - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)); + let maybe_return_type = + ts_method_sig.return_type.as_ref().map(|type_ann| { + TsTypeDef::new(module_info, &type_ann.type_annotation) + }); let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - ts_method_sig.type_params.as_deref(), + ts_method_sig.type_parameters.as_deref(), ); let method_def = MethodDef { name, - kind: deno_ast::swc::ast::MethodKind::Method, + kind: MethodKind::from(ts_method_sig.kind), js_doc: method_js_doc, - location: get_location(module_info, ts_method_sig.start()), + location: get_location(module_info, ts_method_sig.span.start), computed: ts_method_sig.computed, optional: ts_method_sig.optional, params, @@ -132,65 +144,15 @@ pub fn get_doc_for_ts_interface_decl( methods.push(method_def); } } - TsGetterSignature(ts_getter_sig) => { - if let Some(method_js_doc) = - js_doc_for_range(module_info, &ts_getter_sig.range()) - { - let name = expr_to_name(&ts_getter_sig.key); - - let maybe_return_type = ts_getter_sig - .type_ann - .as_deref() - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)); - - let method_def = MethodDef { - name, - kind: deno_ast::swc::ast::MethodKind::Getter, - js_doc: method_js_doc, - location: get_location(module_info, ts_getter_sig.start()), - computed: ts_getter_sig.computed, - optional: false, - params: vec![], - return_type: maybe_return_type, - type_params: Box::new([]), - }; - methods.push(method_def); - } - } - TsSetterSignature(ts_setter_sig) => { - if let Some(method_js_doc) = - js_doc_for_range(module_info, &ts_setter_sig.range()) - { - let name = expr_to_name(&ts_setter_sig.key); - - let param_def = - ts_fn_param_to_param_def(module_info, &ts_setter_sig.param); - let params = vec![param_def]; - - let method_def = MethodDef { - name, - kind: deno_ast::swc::ast::MethodKind::Setter, - js_doc: method_js_doc, - location: get_location(module_info, ts_setter_sig.start()), - computed: ts_setter_sig.computed, - optional: false, - params, - return_type: None, - type_params: Box::new([]), - }; - methods.push(method_def); - } - } - TsPropertySignature(ts_prop_sig) => { + TSSignature::TSPropertySignature(ts_prop_sig) => { if let Some(prop_js_doc) = - js_doc_for_range(module_info, &ts_prop_sig.range()) + js_doc_for_range(module_info, ts_prop_sig.span) { - let name = expr_to_name(&ts_prop_sig.key); + let name = property_key_name(&ts_prop_sig.key); - let ts_type = ts_prop_sig - .type_ann - .as_deref() - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)); + let ts_type = ts_prop_sig.type_annotation.as_ref().map(|type_ann| { + TsTypeDef::new(module_info, &type_ann.type_annotation) + }); let type_params = maybe_type_param_decl_to_type_param_defs(module_info, None); @@ -198,7 +160,7 @@ pub fn get_doc_for_ts_interface_decl( let prop_def = PropertyDef { name, js_doc: prop_js_doc, - location: get_location(module_info, ts_prop_sig.start()), + location: get_location(module_info, ts_prop_sig.span.start), params: vec![], ts_type, readonly: ts_prop_sig.readonly, @@ -209,29 +171,25 @@ pub fn get_doc_for_ts_interface_decl( properties.push(prop_def); } } - TsCallSignatureDecl(ts_call_sig) => { + TSSignature::TSCallSignatureDeclaration(ts_call_sig) => { if let Some(call_sig_js_doc) = - js_doc_for_range(module_info, &ts_call_sig.range()) + js_doc_for_range(module_info, ts_call_sig.span) { - let mut params = vec![]; - for param in &ts_call_sig.params { - let param_def = ts_fn_param_to_param_def(module_info, param); - params.push(param_def); - } + let params = + formal_params_to_param_defs(module_info, &ts_call_sig.params); - let ts_type = ts_call_sig - .type_ann - .as_deref() - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)); + let ts_type = ts_call_sig.return_type.as_ref().map(|type_ann| { + TsTypeDef::new(module_info, &type_ann.type_annotation) + }); let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - ts_call_sig.type_params.as_deref(), + ts_call_sig.type_parameters.as_deref(), ); let call_sig_def = CallSignatureDef { js_doc: call_sig_js_doc, - location: get_location(module_info, ts_call_sig.start()), + location: get_location(module_info, ts_call_sig.span.start), params, ts_type, type_params, @@ -239,23 +197,35 @@ pub fn get_doc_for_ts_interface_decl( call_signatures.push(call_sig_def); } } - TsIndexSignature(ts_index_sig) => { - if let Some(js_doc) = - js_doc_for_range(module_info, &ts_index_sig.range()) - { - let mut params = vec![]; - for param in &ts_index_sig.params { - let param_def = ts_fn_param_to_param_def(module_info, param); - params.push(param_def); - } - - let ts_type = ts_index_sig - .type_ann - .as_ref() - .map(|rt| TsTypeDef::new(module_info, &rt.type_ann)); + TSSignature::TSIndexSignature(ts_index_sig) => { + if let Some(js_doc) = js_doc_for_range(module_info, ts_index_sig.span) { + // TSIndexSignature uses TSIndexSignatureName, not FormalParameter + let params = ts_index_sig + .parameters + .iter() + .map(|param| { + let ts_type = Some(TsTypeDef::new( + module_info, + ¶m.type_annotation.type_annotation, + )); + ParamDef { + pattern: ParamPatternDef::Identifier { + name: param.name.to_string(), + optional: false, + }, + decorators: Box::new([]), + ts_type, + } + }) + .collect(); + + let ts_type = Some(TsTypeDef::new( + module_info, + &ts_index_sig.type_annotation.type_annotation, + )); let index_sig_def = IndexSignatureDef { - location: get_location(module_info, ts_index_sig.start()), + location: get_location(module_info, ts_index_sig.span.start), js_doc, readonly: ts_index_sig.readonly, params, @@ -264,30 +234,26 @@ pub fn get_doc_for_ts_interface_decl( index_signatures.push(index_sig_def); } } - TsConstructSignatureDecl(ts_construct_sig) => { + TSSignature::TSConstructSignatureDeclaration(ts_construct_sig) => { if let Some(js_doc) = - js_doc_for_range(module_info, &ts_construct_sig.range()) + js_doc_for_range(module_info, ts_construct_sig.span) { - let mut params = vec![]; - - for param in &ts_construct_sig.params { - let param_def = ts_fn_param_to_param_def(module_info, param); - params.push(param_def); - } + let params = + formal_params_to_param_defs(module_info, &ts_construct_sig.params); let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - ts_construct_sig.type_params.as_deref(), + ts_construct_sig.type_parameters.as_deref(), ); let maybe_return_type = ts_construct_sig - .type_ann + .return_type .as_ref() - .map(|rt| TsTypeDef::new(module_info, &rt.type_ann)); + .map(|rt| TsTypeDef::new(module_info, &rt.type_annotation)); let construct_sig_def = ConstructorDef { js_doc, - location: get_location(module_info, ts_construct_sig.start()), + location: get_location(module_info, ts_construct_sig.span.start), params, return_type: maybe_return_type, type_params, @@ -301,13 +267,13 @@ pub fn get_doc_for_ts_interface_decl( let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - interface_decl.type_params.as_deref(), + interface_decl.type_parameters.as_deref(), ); let extends = interface_decl .extends .iter() - .map(|expr| TsTypeDef::ts_expr_with_type_args(module_info, expr)) + .map(|expr| TsTypeDef::ts_interface_heritage(module_info, expr)) .collect::>(); InterfaceDef { diff --git a/src/js_doc.rs b/src/js_doc.rs index 567825c36..a46d441b1 100644 --- a/src/js_doc.rs +++ b/src/js_doc.rs @@ -49,47 +49,32 @@ fn make_ts_type(type_str: &str, module_info: &EsModuleInfo) -> TsTypeDef { } } -fn parse_jsdoc_type_source(type_str: &str) -> Option { +pub fn parse_jsdoc_type( + module_info: &EsModuleInfo, + type_str: &str, +) -> Option { let source = format!("type _temp = {type_str}"); let specifier = ModuleSpecifier::parse("file:///jsdoc_type.ts").unwrap(); - let parsed = deno_ast::parse_module(ParseParams { - specifier, - text: Arc::from(source.as_str()), - media_type: MediaType::TypeScript, - capture_tokens: false, - scope_analysis: false, - maybe_syntax: None, - }) + let allocator = deno_ast::oxc::allocator::Allocator::default(); + let parsed = deno_ast::parse_module( + &allocator, + ParseParams { + specifier, + text: Arc::from(source.as_str()), + media_type: MediaType::TypeScript, + capture_tokens: false, + scope_analysis: false, + maybe_source_type: None, + }, + ) .ok()?; - let program_ref = parsed.program_ref(); - let module = program_ref.unwrap_module(); - let type_alias = module.body.first()?; - if !matches!( + let type_alias = parsed.program().body.first()?; + if let deno_ast::oxc::ast::ast::Statement::TSTypeAliasDeclaration( type_alias, - deno_ast::swc::ast::ModuleItem::Stmt(deno_ast::swc::ast::Stmt::Decl( - deno_ast::swc::ast::Decl::TsTypeAlias(_), - )) - ) { - return None; - } - - Some(parsed) -} - -pub fn parse_jsdoc_type( - module_info: &EsModuleInfo, - type_str: &str, -) -> Option { - let parsed = parse_jsdoc_type_source(type_str)?; - let program_ref = parsed.program_ref(); - let module = program_ref.unwrap_module(); - let type_alias = module.body.first()?; - if let deno_ast::swc::ast::ModuleItem::Stmt(deno_ast::swc::ast::Stmt::Decl( - deno_ast::swc::ast::Decl::TsTypeAlias(type_alias), - )) = type_alias + ) = type_alias { - Some(TsTypeDef::new(module_info, &type_alias.type_ann)) + Some(TsTypeDef::new(module_info, &type_alias.type_annotation)) } else { None } @@ -570,7 +555,9 @@ mod tests { }, ) .await; - let root_symbol = deno_graph::symbols::RootSymbol::new(&graph, &analyzer); + let allocator = deno_ast::oxc::allocator::Allocator::default(); + let root_symbol = + deno_graph::symbols::RootSymbol::new(&graph, &analyzer, &allocator); let module_info = root_symbol.module_from_specifier(&specifier).unwrap(); let esm = match module_info { deno_graph::symbols::ModuleInfoRef::Esm(esm) => esm, @@ -580,6 +567,39 @@ mod tests { }) } + fn parse_jsdoc_type_source(input: &str) -> Option { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { + let specifier = + deno_ast::ModuleSpecifier::parse("file:///test.ts").unwrap(); + let mut loader = deno_graph::source::MemoryLoader::default(); + loader.add_source_with_text(specifier.as_str(), "export {};"); + let analyzer = deno_graph::ast::CapturingModuleAnalyzer::default(); + let mut graph = + deno_graph::ModuleGraph::new(deno_graph::GraphKind::TypesOnly); + graph + .build( + vec![specifier.clone()], + Vec::new(), + &loader, + deno_graph::BuildOptions { + module_analyzer: &analyzer, + ..Default::default() + }, + ) + .await; + let allocator = deno_ast::oxc::allocator::Allocator::default(); + let root_symbol = + deno_graph::symbols::RootSymbol::new(&graph, &analyzer, &allocator); + let module_info = root_symbol.module_from_specifier(&specifier).unwrap(); + let esm = match module_info { + deno_graph::symbols::ModuleInfoRef::Esm(esm) => esm, + _ => panic!("expected esm module"), + }; + parse_jsdoc_type(esm, input) + }) + } + fn ts_keyword(name: &str) -> serde_json::Value { serde_json::json!({ "repr": name, diff --git a/src/lib.rs b/src/lib.rs index 23c7c49bc..ba33738ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,7 @@ cfg_if! { } } +pub use deno_ast::oxc::allocator::Allocator as OxcAllocator; pub use parser::DocError; pub use parser::DocParser; pub use parser::DocParserOptions; diff --git a/src/params.rs b/src/params.rs index 457f55288..fbb6d5a94 100644 --- a/src/params.rs +++ b/src/params.rs @@ -6,10 +6,17 @@ use crate::display::SliceDisplayer; use crate::display::display_optional; use crate::ts_type::TsTypeDef; -use deno_ast::SourceRangedForSpanned; -use deno_ast::swc::ast::ObjectPatProp; -use deno_ast::swc::ast::Pat; -use deno_ast::swc::ast::TsFnParam; +use deno_ast::oxc::ast::ast::ArrayPattern; +use deno_ast::oxc::ast::ast::AssignmentPattern; +use deno_ast::oxc::ast::ast::BindingIdentifier; +use deno_ast::oxc::ast::ast::BindingPattern; +use deno_ast::oxc::ast::ast::BindingProperty; +use deno_ast::oxc::ast::ast::BindingRestElement; +use deno_ast::oxc::ast::ast::FormalParameter; +use deno_ast::oxc::ast::ast::FormalParameters; +use deno_ast::oxc::ast::ast::ObjectPattern; +use deno_ast::oxc::ast::ast::PropertyKey; +use deno_ast::oxc::span::GetSpan; use deno_graph::symbols::EsModuleInfo; use serde::Deserialize; use serde::Serialize; @@ -84,8 +91,6 @@ impl Display for ParamDef { if let Some(ts_type) = &self.ts_type { write!(f, ": {}", ts_type)?; } - // TODO(SyrupThinker) As we cannot display expressions the value is just omitted - // write!(f, " = {}", right)?; Ok(()) } ParamPatternDef::Identifier { name, optional } => { @@ -131,11 +136,9 @@ impl Display for ObjectPatPropDef { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { match self { ObjectPatPropDef::KeyValue { key, .. } => { - // The internal identifier does not need to be exposed write!(f, "{}", key) } ObjectPatPropDef::Assign { key, .. } => { - // TODO(SyrupThinker) As we cannot display expressions the value is just omitted write!(f, "{}", key) } ObjectPatPropDef::Rest { arg } => write!(f, "...{}", arg), @@ -145,78 +148,99 @@ impl Display for ObjectPatPropDef { pub fn ident_to_param_def( module_info: &EsModuleInfo, - ident: &deno_ast::swc::ast::BindingIdent, + ident: &BindingIdentifier, + type_ann: Option<&deno_ast::oxc::ast::ast::TSTypeAnnotation>, ) -> ParamDef { - let ts_type = ident - .type_ann - .as_deref() - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)); + let ts_type = type_ann + .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_annotation)); ParamDef { pattern: ParamPatternDef::Identifier { - name: ident.id.sym.to_string(), - optional: ident.id.optional, + name: ident.name.to_string(), + optional: false, }, decorators: Box::new([]), ts_type, } } -fn rest_pat_to_param_def( +pub fn rest_element_to_param_def( module_info: &EsModuleInfo, - rest_pat: &deno_ast::swc::ast::RestPat, + rest: &BindingRestElement, + type_ann: Option<&deno_ast::oxc::ast::ast::TSTypeAnnotation>, ) -> ParamDef { - let ts_type = rest_pat - .type_ann - .as_deref() - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)); + let ts_type = type_ann + .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_annotation)); ParamDef { pattern: ParamPatternDef::Rest { - arg: Box::new(pat_to_param_def(module_info, &rest_pat.arg)), + arg: Box::new(binding_pat_to_param_def( + module_info, + &rest.argument, + None, + )), }, decorators: Box::new([]), ts_type, } } -fn object_pat_prop_to_def( +fn binding_prop_to_def( module_info: &EsModuleInfo, - object_pat_prop: &ObjectPatProp, + prop: &BindingProperty, ) -> ObjectPatPropDef { - match object_pat_prop { - ObjectPatProp::Assign(assign) => ObjectPatPropDef::Assign { - key: assign.key.sym.to_string(), - value: assign.value.as_ref().map(|_| "[UNSUPPORTED]".to_string()), - }, - ObjectPatProp::KeyValue(keyvalue) => ObjectPatPropDef::KeyValue { - key: prop_name_to_string(module_info, &keyvalue.key), - value: Box::new(pat_to_param_def(module_info, &keyvalue.value)), - }, - ObjectPatProp::Rest(rest) => ObjectPatPropDef::Rest { - arg: Box::new(pat_to_param_def(module_info, &rest.arg)), - }, + if prop.shorthand { + // Shorthand: `{ x }` or `{ x = default }` + let key = match &prop.value { + BindingPattern::BindingIdentifier(ident) => ident.name.to_string(), + BindingPattern::AssignmentPattern(assign) => match &assign.left { + BindingPattern::BindingIdentifier(ident) => ident.name.to_string(), + _ => "[UNSUPPORTED]".to_string(), + }, + _ => "[UNSUPPORTED]".to_string(), + }; + let value = match &prop.value { + BindingPattern::AssignmentPattern(_) => Some("[UNSUPPORTED]".to_string()), + _ => None, + }; + ObjectPatPropDef::Assign { key, value } + } else { + // KeyValue: `{ key: value }` + ObjectPatPropDef::KeyValue { + key: prop_name_to_string(module_info, &prop.key), + value: Box::new(binding_pat_to_param_def(module_info, &prop.value, None)), + } } } fn object_pat_to_param_def( module_info: &EsModuleInfo, - object_pat: &deno_ast::swc::ast::ObjectPat, + object_pat: &ObjectPattern, + type_ann: Option<&deno_ast::oxc::ast::ast::TSTypeAnnotation>, ) -> ParamDef { - let props = object_pat - .props + let mut props = object_pat + .properties .iter() - .map(|prop| object_pat_prop_to_def(module_info, prop)) + .map(|prop| binding_prop_to_def(module_info, prop)) .collect::>(); - let ts_type = object_pat - .type_ann - .as_deref() - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)); + + if let Some(rest) = &object_pat.rest { + props.push(ObjectPatPropDef::Rest { + arg: Box::new(binding_pat_to_param_def( + module_info, + &rest.argument, + None, + )), + }); + } + + let ts_type = type_ann + .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_annotation)); ParamDef { pattern: ParamPatternDef::Object { props, - optional: object_pat.optional, + optional: false, }, decorators: Box::new([]), ts_type, @@ -225,22 +249,41 @@ fn object_pat_to_param_def( fn array_pat_to_param_def( module_info: &EsModuleInfo, - array_pat: &deno_ast::swc::ast::ArrayPat, + array_pat: &ArrayPattern, + type_ann: Option<&deno_ast::oxc::ast::ast::TSTypeAnnotation>, ) -> ParamDef { - let elements = array_pat - .elems + let mut elements = array_pat + .elements .iter() - .map(|elem| elem.as_ref().map(|e| pat_to_param_def(module_info, e))) + .map(|elem| { + elem + .as_ref() + .map(|e| binding_pat_to_param_def(module_info, e, None)) + }) .collect::>>(); - let ts_type = array_pat - .type_ann - .as_deref() - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)); + + // If there's a rest element, add it + if let Some(rest) = &array_pat.rest { + elements.push(Some(ParamDef { + pattern: ParamPatternDef::Rest { + arg: Box::new(binding_pat_to_param_def( + module_info, + &rest.argument, + None, + )), + }, + decorators: Box::new([]), + ts_type: None, + })); + } + + let ts_type = type_ann + .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_annotation)); ParamDef { pattern: ParamPatternDef::Array { elements, - optional: array_pat.optional, + optional: false, }, decorators: Box::new([]), ts_type, @@ -249,9 +292,11 @@ fn array_pat_to_param_def( pub fn assign_pat_to_param_def( module_info: &EsModuleInfo, - assign_pat: &deno_ast::swc::ast::AssignPat, + assign_pat: &AssignmentPattern, + type_ann: Option<&deno_ast::oxc::ast::ast::TSTypeAnnotation>, ) -> ParamDef { - let mut left = pat_to_param_def(module_info, &assign_pat.left); + let mut left = + binding_pat_to_param_def(module_info, &assign_pat.left, type_ann); if left.ts_type.is_none() { left.ts_type = crate::ts_type::infer_ts_type_from_expr( @@ -273,55 +318,113 @@ pub fn assign_pat_to_param_def( pub fn param_to_param_def( module_info: &EsModuleInfo, - param: &deno_ast::swc::ast::Param, + param: &FormalParameter, ) -> ParamDef { - let mut def = pat_to_param_def(module_info, ¶m.pat); + let mut def = binding_pat_to_param_def( + module_info, + ¶m.pattern, + param.type_annotation.as_deref(), + ); + // Set optional from the FormalParameter (BindingIdentifier doesn't have it) + if param.optional { + match &mut def.pattern { + ParamPatternDef::Identifier { optional, .. } => *optional = true, + ParamPatternDef::Array { optional, .. } => *optional = true, + ParamPatternDef::Object { optional, .. } => *optional = true, + _ => {} + } + } def.decorators = decorators_to_defs(module_info, ¶m.decorators); + + // Wrap in Assign if the parameter has a default initializer + if let Some(init) = ¶m.initializer { + let right = crate::interface::expr_to_name(init); + // Infer type from initializer if not already set + if def.ts_type.is_none() { + def.ts_type = + crate::ts_type::infer_ts_type_from_expr(module_info, init, false); + } + def = ParamDef { + pattern: ParamPatternDef::Assign { + left: Box::new(def), + right, + }, + decorators: Box::new([]), + ts_type: None, + }; + } + def } -pub fn pat_to_param_def( +pub fn binding_pat_to_param_def( module_info: &EsModuleInfo, - pat: &deno_ast::swc::ast::Pat, + pat: &BindingPattern, + type_ann: Option<&deno_ast::oxc::ast::ast::TSTypeAnnotation>, ) -> ParamDef { match pat { - Pat::Ident(ident) => ident_to_param_def(module_info, ident), - Pat::Array(array_pat) => array_pat_to_param_def(module_info, array_pat), - Pat::Rest(rest_pat) => rest_pat_to_param_def(module_info, rest_pat), - Pat::Object(object_pat) => object_pat_to_param_def(module_info, object_pat), - Pat::Assign(assign_pat) => assign_pat_to_param_def(module_info, assign_pat), - _ => unreachable!(), + BindingPattern::BindingIdentifier(ident) => { + ident_to_param_def(module_info, ident, type_ann) + } + BindingPattern::ArrayPattern(array_pat) => { + array_pat_to_param_def(module_info, array_pat, type_ann) + } + BindingPattern::ObjectPattern(object_pat) => { + object_pat_to_param_def(module_info, object_pat, type_ann) + } + BindingPattern::AssignmentPattern(assign_pat) => { + assign_pat_to_param_def(module_info, assign_pat, type_ann) + } } } -pub fn ts_fn_param_to_param_def( +/// Collect all params from FormalParameters, including the rest element. +pub fn formal_params_to_param_defs( module_info: &EsModuleInfo, - ts_fn_param: &deno_ast::swc::ast::TsFnParam, -) -> ParamDef { - match ts_fn_param { - TsFnParam::Ident(ident) => ident_to_param_def(module_info, ident), - TsFnParam::Array(array_pat) => { - array_pat_to_param_def(module_info, array_pat) - } - TsFnParam::Rest(rest_pat) => rest_pat_to_param_def(module_info, rest_pat), - TsFnParam::Object(object_pat) => { - object_pat_to_param_def(module_info, object_pat) - } + params: &FormalParameters, +) -> Vec { + let mut result: Vec = params + .items + .iter() + .map(|param| param_to_param_def(module_info, param)) + .collect(); + if let Some(rest) = ¶ms.rest { + result.push(rest_element_to_param_def( + module_info, + &rest.rest, + rest.type_annotation.as_deref(), + )); } + result } pub fn prop_name_to_string( module_info: &EsModuleInfo, - prop_name: &deno_ast::swc::ast::PropName, + prop_key: &PropertyKey, ) -> String { - use deno_ast::swc::ast::PropName; - match prop_name { - PropName::Ident(ident) => ident.sym.to_string(), - PropName::Str(str_) => str_.value.to_string_lossy().into_owned(), - PropName::Num(num) => num.value.to_string(), - PropName::BigInt(num) => num.value.to_string(), - PropName::Computed(comp_prop_name) => comp_prop_name - .text_fast(module_info.source().text_info_lazy()) - .to_string(), + match prop_key { + PropertyKey::StaticIdentifier(ident) => ident.name.to_string(), + PropertyKey::StringLiteral(str_) => str_.value.to_string(), + PropertyKey::NumericLiteral(num) => num.value.to_string(), + PropertyKey::BigIntLiteral(num) => num + .raw + .as_ref() + .map(|r| r.as_str().to_string()) + .unwrap_or_default(), + // Computed expression keys - use the PropertyKey's expression nature + // Member expressions like Symbol.iterator should produce [Symbol.iterator] + PropertyKey::PrivateIdentifier(ident) => { + format!("#{}", ident.name) + } + PropertyKey::StaticMemberExpression(member) => { + let left: String = crate::interface::expr_to_name(&member.object); + let right = member.property.name.to_string(); + format!("[{}.{}]", left, right) + } + _ => { + let span = prop_key.span(); + module_info.source_text()[span.start as usize..span.end as usize] + .to_string() + } } } diff --git a/src/parser.rs b/src/parser.rs index ca8cfa0bd..a8466f8b8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,26 +1,24 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_ast::ModuleItemRef; -use deno_ast::SourceRange; -use deno_ast::SourceRanged; -use deno_ast::SourceRangedForSpanned; -use deno_ast::swc::ast::ClassDecl; -use deno_ast::swc::ast::Decl; -use deno_ast::swc::ast::DefaultDecl; -use deno_ast::swc::ast::ExportDecl; -use deno_ast::swc::ast::ExportDefaultDecl; -use deno_ast::swc::ast::ExportDefaultExpr; -use deno_ast::swc::ast::FnDecl; -use deno_ast::swc::ast::Ident; -use deno_ast::swc::ast::ModuleDecl; -use deno_ast::swc::ast::TsEnumDecl; -use deno_ast::swc::ast::TsInterfaceDecl; -use deno_ast::swc::ast::TsModuleDecl; -use deno_ast::swc::ast::TsModuleName; -use deno_ast::swc::ast::TsTypeAliasDecl; -use deno_ast::swc::ast::VarDecl; -use deno_ast::swc::ast::VarDeclKind; -use deno_ast::swc::ast::VarDeclarator; +use deno_ast::oxc::ast::ast::BindingIdentifier as Ident; +use deno_ast::oxc::ast::ast::Class; +use deno_ast::oxc::ast::ast::Declaration as OxcDeclaration; +use deno_ast::oxc::ast::ast::ExportDefaultDeclaration; +use deno_ast::oxc::ast::ast::ExportDefaultDeclarationKind; +use deno_ast::oxc::ast::ast::ExportNamedDeclaration; +use deno_ast::oxc::ast::ast::Expression; +use deno_ast::oxc::ast::ast::Function as FnDecl; +use deno_ast::oxc::ast::ast::ImportDeclarationSpecifier; +use deno_ast::oxc::ast::ast::Statement; +use deno_ast::oxc::ast::ast::TSEnumDeclaration as TsEnumDecl; +use deno_ast::oxc::ast::ast::TSInterfaceDeclaration as TsInterfaceDecl; +use deno_ast::oxc::ast::ast::TSModuleDeclaration as TsModuleDecl; +use deno_ast::oxc::ast::ast::TSModuleDeclarationName; +use deno_ast::oxc::ast::ast::TSTypeAliasDeclaration as TsTypeAliasDecl; +use deno_ast::oxc::ast::ast::VariableDeclaration as VarDecl; +use deno_ast::oxc::ast::ast::VariableDeclarator as VarDeclarator; +use deno_ast::oxc::span::GetSpan; +use deno_ast::oxc::span::Span; use deno_graph::Module; use deno_graph::ModuleGraph; use deno_graph::ModuleSpecifier; @@ -34,7 +32,6 @@ use deno_graph::symbols::SymbolDecl; use deno_graph::symbols::SymbolNodeRef; use deno_graph::symbols::UniqueSymbolId; use indexmap::IndexMap; -use std::borrow::Cow; use std::cell::RefCell; use std::collections::HashSet; use std::error::Error; @@ -64,10 +61,38 @@ use crate::util::swc::js_doc_for_range; use crate::util::swc::module_export_name_value; use crate::util::swc::module_js_doc_for_source; use crate::util::symbol::get_module_info; +use crate::util::types::VarDeclKind; use crate::variable::VariableDef; use crate::visibility::SymbolVisibility; use crate::{Declaration, Symbol}; +type SourceRange = Span; + +trait SpanCompat { + fn contains(self, other: Span) -> bool; +} + +impl SpanCompat for Span { + fn contains(self, other: Span) -> bool { + self.contains_inclusive(other) + } +} + +trait GetSpanCompat { + fn range(&self) -> Span; + fn start(&self) -> u32; +} + +impl GetSpanCompat for T { + fn range(&self) -> Span { + self.span() + } + + fn start(&self) -> u32 { + self.span().start + } +} + #[derive(Debug)] pub enum DocError { Resolve(String), @@ -121,11 +146,13 @@ impl<'a> DocParser<'a> { pub fn new( graph: &'a ModuleGraph, parser: &'a dyn EsParser, + allocator: &'a deno_ast::oxc::allocator::Allocator, specifiers: &'a [ModuleSpecifier], options: DocParserOptions, ) -> Result { - let root_symbol = - Rc::new(deno_graph::symbols::RootSymbol::new(graph, parser)); + let root_symbol = Rc::new(deno_graph::symbols::RootSymbol::new( + graph, parser, allocator, + )); let visibility = SymbolVisibility::build(graph, &root_symbol)?; let diagnostics = if options.diagnostics { @@ -473,18 +500,15 @@ impl<'a> DocParser<'a> { if let ModuleInfoRef::Esm(esm) = export.module { // Find the full export statement range, since the // definition range may start at `*` rather than `export`. - for item in esm.source().program_ref().body() { - if let ModuleItemRef::ModuleDecl(decl) = item { - let decl_range = decl.range(); - if decl_range.contains(first_def.range()) - && let Some(js_doc) = - js_doc_for_range(esm, &decl_range) - { - if !js_doc.is_empty() { - return js_doc; - } - break; + for item in esm.statements() { + let decl_range = item.span(); + if decl_range.contains(*first_def.range()) + && let Some(js_doc) = js_doc_for_range(esm, decl_range) + { + if !js_doc.is_empty() { + return js_doc; } + break; } } } @@ -535,49 +559,47 @@ impl<'a> DocParser<'a> { &self, module_info: &EsModuleInfo, ) -> Result, DocError> { - let parsed_source = module_info.source(); let referrer = module_info.specifier(); let mut imports = vec![]; - for node in parsed_source.program_ref().body() { - if let ModuleItemRef::ModuleDecl(ModuleDecl::Import(import_decl)) = node - && let Some(js_doc) = - js_doc_for_range(module_info, &import_decl.range()) + for stmt in module_info.statements() { + if let Statement::ImportDeclaration(import_decl) = stmt + && let Some(js_doc) = js_doc_for_range(module_info, import_decl.span) { - for specifier in &import_decl.specifiers { - use deno_ast::swc::ast::ImportSpecifier::*; - - let (imported_name, original_name, src) = match specifier { - Named(named_specifier) => ( - named_specifier.local.sym.to_string(), - named_specifier - .imported - .as_ref() - .map(module_export_name_value) - .or_else(|| Some(named_specifier.local.sym.to_string())), - &import_decl.src.value, - ), - Default(default_specifier) => ( - default_specifier.local.sym.to_string(), - Some("default".to_string()), - &import_decl.src.value, - ), - Namespace(namespace_specifier) => ( - namespace_specifier.local.sym.to_string(), - None, - &import_decl.src.value, - ), - }; - - let resolved_specifier = - self.resolve_dependency(&src.to_string_lossy(), referrer)?; - - imports.push(Import { - imported_name: imported_name.into_boxed_str(), - js_doc: js_doc.clone(), - src: resolved_specifier.to_string(), - original_name, - }); + if let Some(specifiers) = &import_decl.specifiers { + for specifier in specifiers { + let (imported_name, original_name, src) = match specifier { + ImportDeclarationSpecifier::ImportSpecifier(named_specifier) => ( + named_specifier.local.name.to_string(), + Some(module_export_name_value(&named_specifier.imported)), + &import_decl.source.value, + ), + ImportDeclarationSpecifier::ImportDefaultSpecifier( + default_specifier, + ) => ( + default_specifier.local.name.to_string(), + Some("default".to_string()), + &import_decl.source.value, + ), + ImportDeclarationSpecifier::ImportNamespaceSpecifier( + namespace_specifier, + ) => ( + namespace_specifier.local.name.to_string(), + None, + &import_decl.source.value, + ), + }; + + let resolved_specifier = + self.resolve_dependency(&src.to_string(), referrer)?; + + imports.push(Import { + imported_name: imported_name.into_boxed_str(), + js_doc: js_doc.clone(), + src: resolved_specifier.to_string(), + original_name, + }); + } } } } @@ -591,9 +613,8 @@ impl<'a> DocParser<'a> { expando_property: ExpandoPropertyRef, ) -> Option { let location = - get_location(module_info, expando_property.prop_name_range().start()); - let js_doc = - js_doc_for_range(module_info, &expando_property.inner().range())?; + get_location(module_info, expando_property.prop_name_span().start); + let js_doc = js_doc_for_range(module_info, expando_property.inner().span)?; let init = expando_property.assignment(); Some(decl_from_expr(module_info, init, location, js_doc)) @@ -605,24 +626,24 @@ impl<'a> DocParser<'a> { var_decl: &VarDecl, var_declarator: &VarDeclarator, ident: &Ident, - full_range: &SourceRange, + full_range: SourceRange, ) -> Option { - let full_range = if ident.start() != var_declarator.start() { - Cow::Owned(ident.range()) + let full_range = if ident.span.start != var_declarator.span.start { + ident.span } else { - Cow::Borrowed(full_range) + full_range }; - let js_doc = js_doc_for_range(module_info, &full_range)?; + let js_doc = js_doc_for_range(module_info, full_range)?; if let Some(init) = &var_declarator.init && matches!( - &**init, - deno_ast::swc::ast::Expr::Class(_) - | deno_ast::swc::ast::Expr::Fn(_) - | deno_ast::swc::ast::Expr::Arrow(_) + init, + Expression::ClassExpression(_) + | Expression::FunctionExpression(_) + | Expression::ArrowFunctionExpression(_) ) { - let location = get_location(module_info, ident.start()); + let location = get_location(module_info, ident.span.start); return Some(decl_from_expr(module_info, init, location, js_doc)); } @@ -635,9 +656,9 @@ impl<'a> DocParser<'a> { var_declarator, ) .into_iter() - .find(|(name, _)| name.as_str() == &*ident.sym) + .find(|(name, _)| name.as_str() == &*ident.name) .map(|(_name, var_def)| { - let location = get_location(module_info, ident.start()); + let location = get_location(module_info, ident.span.start); Declaration::variable(location, DeclarationKind::Declare, js_doc, var_def) }) } @@ -645,16 +666,16 @@ impl<'a> DocParser<'a> { fn get_doc_for_class_decl( &self, module_info: &EsModuleInfo, - class_decl: &ClassDecl, - full_range: &SourceRange, + class_decl: &Class, + full_range: SourceRange, ) -> Option { - let jsdoc_range = match class_decl.class.decorators.first() { - Some(decorator) if decorator.start() < full_range.start => { - Cow::Owned(SourceRange::new(decorator.start(), full_range.end)) + let jsdoc_range = match class_decl.decorators.first() { + Some(decorator) if decorator.span.start < full_range.start => { + SourceRange::new(decorator.span.start, full_range.end) } - _ => Cow::Borrowed(full_range), + _ => full_range, }; - let js_doc = js_doc_for_range(module_info, &jsdoc_range)?; + let js_doc = js_doc_for_range(module_info, jsdoc_range)?; // declared classes cannot have decorators, so we ignore that return let (class_def, _) = super::class::get_doc_for_class_decl(module_info, class_decl); @@ -671,7 +692,7 @@ impl<'a> DocParser<'a> { &self, module_info: &EsModuleInfo, fn_decl: &FnDecl, - full_range: &SourceRange, + full_range: SourceRange, ) -> Option { let js_doc = js_doc_for_range(module_info, full_range)?; let function_def = @@ -689,7 +710,7 @@ impl<'a> DocParser<'a> { &self, module_info: &EsModuleInfo, ts_interface_decl: &TsInterfaceDecl, - full_range: &SourceRange, + full_range: SourceRange, ) -> Option { let js_doc = js_doc_for_range(module_info, full_range)?; let interface_def = super::interface::get_doc_for_ts_interface_decl( @@ -710,7 +731,7 @@ impl<'a> DocParser<'a> { &self, module_info: &EsModuleInfo, ts_type_alias: &TsTypeAliasDecl, - full_range: &SourceRange, + full_range: SourceRange, ) -> Option { let js_doc = js_doc_for_range(module_info, full_range)?; let type_alias_def = super::type_alias::get_doc_for_ts_type_alias_decl( @@ -730,7 +751,7 @@ impl<'a> DocParser<'a> { &self, module_info: &EsModuleInfo, ts_enum: &TsEnumDecl, - full_range: &SourceRange, + full_range: SourceRange, ) -> Option { let js_doc = js_doc_for_range(module_info, full_range)?; let enum_def = @@ -749,7 +770,7 @@ impl<'a> DocParser<'a> { module_info: &EsModuleInfo, ns_symbol: &GraphSymbol, ts_module: &TsModuleDecl, - full_range: &SourceRange, + full_range: SourceRange, ) -> Option { fn symbol_in_ancestors( id: UniqueSymbolId, @@ -771,13 +792,12 @@ impl<'a> DocParser<'a> { .iter() .filter_map(|d| { d.maybe_node().and_then(|n| match n { - SymbolNodeRef::ExportDecl( - ExportDecl { - decl: Decl::TsModule(n), - .. - }, - _, - ) => Some(&**n), + SymbolNodeRef::ExportDecl(export_decl, _) => { + match &export_decl.declaration { + Some(OxcDeclaration::TSModuleDeclaration(n)) => Some(&**n), + _ => None, + } + } SymbolNodeRef::TsNamespace(n) => Some(n), _ => None, }) @@ -789,8 +809,8 @@ impl<'a> DocParser<'a> { } let _namespace_name = match &ts_module.id { - TsModuleName::Ident(ident) => ident.sym.to_string(), - TsModuleName::Str(str_) => str_.value.to_string_lossy().into_owned(), + TSModuleDeclarationName::Identifier(ident) => ident.name.to_string(), + TSModuleDeclarationName::StringLiteral(str_) => str_.value.to_string(), }; let mut elements = Vec::new(); let mut handled_symbols = HashSet::new(); @@ -915,18 +935,24 @@ impl<'a> DocParser<'a> { .and_then(|n| { use deno_graph::symbols::SymbolNodeRef; match n { - SymbolNodeRef::ClassDecl(n) => Some(n.ident.sym.to_string()), - SymbolNodeRef::FnDecl(n) => Some(n.ident.sym.to_string()), - SymbolNodeRef::TsEnum(n) => Some(n.id.sym.to_string()), - SymbolNodeRef::TsInterface(n) => Some(n.id.sym.to_string()), - SymbolNodeRef::TsTypeAlias(n) => Some(n.id.sym.to_string()), + SymbolNodeRef::ClassDecl(n) => { + n.id.as_ref().map(|id| id.name.to_string()) + } + SymbolNodeRef::FnDecl(n) => { + n.id.as_ref().map(|id| id.name.to_string()) + } + SymbolNodeRef::TsEnum(n) => Some(n.id.name.to_string()), + SymbolNodeRef::TsInterface(n) => Some(n.id.name.to_string()), + SymbolNodeRef::TsTypeAlias(n) => Some(n.id.name.to_string()), SymbolNodeRef::TsNamespace(n) => match &n.id { - TsModuleName::Ident(ident) => Some(ident.sym.to_string()), - TsModuleName::Str(s) => { - Some(s.value.to_string_lossy().into_owned()) + TSModuleDeclarationName::Identifier(ident) => { + Some(ident.name.to_string()) + } + TSModuleDeclarationName::StringLiteral(s) => { + Some(s.value.to_string()) } }, - SymbolNodeRef::Var(_, _, ident) => Some(ident.sym.to_string()), + SymbolNodeRef::Var(_, _, ident) => Some(ident.name.to_string()), SymbolNodeRef::ExportDefaultDecl(_) => { Some("default".to_string()) } @@ -955,21 +981,18 @@ impl<'a> DocParser<'a> { fn get_doc_for_export_default_decl( &self, module_info: &EsModuleInfo, - export_default_decl: &ExportDefaultDecl, + export_default_decl: &ExportDefaultDeclaration, ) -> Option { - let js_doc = js_doc_for_range(module_info, &export_default_decl.range())?; - let location = get_location(module_info, export_default_decl.start()); - let doc_node = match &export_default_decl.decl { - DefaultDecl::Class(class_expr) => { - let default_name = class_expr - .ident + let js_doc = js_doc_for_range(module_info, export_default_decl.span)?; + let location = get_location(module_info, export_default_decl.span.start); + let doc_node = match &export_default_decl.declaration { + ExportDefaultDeclarationKind::ClassDeclaration(class) => { + let default_name = class + .id .as_ref() - .map(|ident| ident.sym.to_string().into_boxed_str()); - let (class_def, decorator_js_doc) = crate::class::class_to_class_def( - module_info, - &class_expr.class, - default_name, - ); + .map(|ident| ident.name.to_string().into_boxed_str()); + let (class_def, decorator_js_doc) = + crate::class::class_to_class_def(module_info, class, default_name); let js_doc = if js_doc.is_empty() { decorator_js_doc } else { @@ -977,12 +1000,12 @@ impl<'a> DocParser<'a> { }; Declaration::class(location, DeclarationKind::Export, js_doc, class_def) } - DefaultDecl::Fn(fn_expr) => { + ExportDefaultDeclarationKind::FunctionDeclaration(function) => { let default_name = - fn_expr.ident.as_ref().map(|ident| ident.sym.to_string()); + function.id.as_ref().map(|ident| ident.name.to_string()); let function_def = crate::function::function_to_function_def( module_info, - &fn_expr.function, + function, default_name, ); Declaration::function( @@ -992,8 +1015,8 @@ impl<'a> DocParser<'a> { function_def, ) } - DefaultDecl::TsInterfaceDecl(interface_decl) => { - let default_name = interface_decl.id.sym.to_string(); + ExportDefaultDeclarationKind::TSInterfaceDeclaration(interface_decl) => { + let default_name = interface_decl.id.name.to_string(); let interface_def = crate::interface::get_doc_for_ts_interface_decl( module_info, interface_decl, @@ -1006,6 +1029,14 @@ impl<'a> DocParser<'a> { interface_def, ) } + _ => { + return self.get_decl_for_export_default_expr( + module_info, + &export_default_decl.declaration, + js_doc, + location, + ); + } }; Some(doc_node) @@ -1014,11 +1045,13 @@ impl<'a> DocParser<'a> { fn get_decl_for_export_default_expr( &self, module_info: &EsModuleInfo, - export_expr: &ExportDefaultExpr, + export_expr: &ExportDefaultDeclarationKind, + js_doc: JsDoc, + location: Location, ) -> Option { - let js_doc = js_doc_for_range(module_info, &export_expr.range())?; - let location = get_location(module_info, export_expr.start()); - if let deno_ast::swc::ast::Expr::Arrow(arrow_expr) = &*export_expr.expr { + if let ExportDefaultDeclarationKind::ArrowFunctionExpression(arrow_expr) = + export_expr + { let function_def = crate::function::arrow_to_function_def(module_info, arrow_expr); Some(Declaration::function( @@ -1036,7 +1069,7 @@ impl<'a> DocParser<'a> { kind: VarDeclKind::Var, ts_type: super::ts_type::infer_ts_type_from_expr( module_info, - export_expr.expr.as_ref(), + export_expr.as_expression()?, true, ), }, @@ -1052,7 +1085,7 @@ impl<'a> DocParser<'a> { target_range: &SourceRange, ) -> Option { if let Some(js_doc) = - js_doc_for_range(reference_module_info, &reference_range.range()) + js_doc_for_range(reference_module_info, reference_range.range()) { let location = get_location(reference_module_info, reference_range.start()); @@ -1371,7 +1404,7 @@ impl<'a> DocParser<'a> { ) -> Option { match node { SymbolNodeRef::ClassDecl(n) => { - self.get_doc_for_class_decl(module_info, n, &n.class.range()) + self.get_doc_for_class_decl(module_info, n, n.span) } SymbolNodeRef::ExpandoProperty(n) => { self.get_doc_for_expando_property(module_info, n) @@ -1380,22 +1413,24 @@ impl<'a> DocParser<'a> { self.get_doc_for_export_default_decl(module_info, n) } SymbolNodeRef::ExportDefaultExpr(n) => { - self.get_decl_for_export_default_expr(module_info, n) + let js_doc = js_doc_for_range(module_info, n.span())?; + let location = get_location(module_info, n.span().start); + self.get_decl_for_export_default_expr(module_info, n, js_doc, location) } SymbolNodeRef::FnDecl(n) => { - self.get_decl_for_fn_decl(module_info, n, &n.function.range()) + self.get_decl_for_fn_decl(module_info, n, n.span) } SymbolNodeRef::TsEnum(n) => { - self.get_decl_for_enum(module_info, n, &n.range()) + self.get_decl_for_enum(module_info, n, n.range()) } SymbolNodeRef::TsInterface(n) => { - self.get_decl_for_interface_decl(module_info, n, &n.range()) + self.get_decl_for_interface_decl(module_info, n, n.range()) } SymbolNodeRef::TsNamespace(n) => { - self.get_decl_for_ts_namespace(module_info, symbol, n, &n.range()) + self.get_decl_for_ts_namespace(module_info, symbol, n, n.range()) } SymbolNodeRef::TsTypeAlias(n) => { - self.get_decl_for_type_alias(module_info, n, &n.range()) + self.get_decl_for_type_alias(module_info, n, n.range()) } SymbolNodeRef::Var(parent_decl, n, ident) => self .get_doc_for_var_declarator_ident( @@ -1403,7 +1438,7 @@ impl<'a> DocParser<'a> { parent_decl, n, ident, - &parent_decl.range(), + parent_decl.range(), ), SymbolNodeRef::UsingVar(_, _, _) => { // makes no sense for using declarations to be in the public API @@ -1411,25 +1446,25 @@ impl<'a> DocParser<'a> { } SymbolNodeRef::ExportDecl(export_decl, inner) => match inner { ExportDeclRef::Class(n) => { - self.get_doc_for_class_decl(module_info, n, &export_decl.range()) + self.get_doc_for_class_decl(module_info, n, export_decl.range()) } ExportDeclRef::Fn(n) => { - self.get_decl_for_fn_decl(module_info, n, &export_decl.range()) + self.get_decl_for_fn_decl(module_info, n, export_decl.range()) } ExportDeclRef::TsEnum(n) => { - self.get_decl_for_enum(module_info, n, &export_decl.range()) + self.get_decl_for_enum(module_info, n, export_decl.range()) } ExportDeclRef::TsModule(n) => self.get_decl_for_ts_namespace( module_info, symbol, n, - &export_decl.range(), + export_decl.range(), ), ExportDeclRef::TsInterface(n) => { - self.get_decl_for_interface_decl(module_info, n, &export_decl.range()) + self.get_decl_for_interface_decl(module_info, n, export_decl.range()) } ExportDeclRef::TsTypeAlias(n) => { - self.get_decl_for_type_alias(module_info, n, &export_decl.range()) + self.get_decl_for_type_alias(module_info, n, export_decl.range()) } ExportDeclRef::Var(var_decl, var_declarator, ident) => self .get_doc_for_var_declarator_ident( @@ -1437,8 +1472,9 @@ impl<'a> DocParser<'a> { var_decl, var_declarator, ident, - &export_decl.range(), + export_decl.range(), ), + ExportDeclRef::TsImportEquals(_) => None, }, SymbolNodeRef::Module(_) | SymbolNodeRef::AutoAccessor(_) @@ -1462,7 +1498,9 @@ impl<'a> DocParser<'a> { fn get_declare_for_symbol_node(&self, node: SymbolNodeRef) -> bool { match node { SymbolNodeRef::ClassDecl(n) => n.declare, - SymbolNodeRef::ExportDecl(n, _) => self.get_declare_for_ast_decl(&n.decl), + SymbolNodeRef::ExportDecl(n, _) => { + self.get_declare_for_export_decl_declaration(n) + } SymbolNodeRef::ExportDefaultDecl(_) => false, SymbolNodeRef::ExportDefaultExpr(_) => false, SymbolNodeRef::FnDecl(n) => n.declare, @@ -1492,16 +1530,27 @@ impl<'a> DocParser<'a> { } } - fn get_declare_for_ast_decl(&self, decl: &Decl) -> bool { - match decl { - Decl::Class(class_decl) => class_decl.declare, - Decl::Fn(fn_decl) => fn_decl.declare, - Decl::TsEnum(ts_enum_decl) => ts_enum_decl.declare, - Decl::TsInterface(ts_interface_decl) => ts_interface_decl.declare, - Decl::TsModule(ts_module_decl) => ts_module_decl.declare, - Decl::TsTypeAlias(ts_type_alias_decl) => ts_type_alias_decl.declare, - Decl::Var(var_decl) => var_decl.declare, - Decl::Using(_) => false, + fn get_declare_for_export_decl_declaration( + &self, + export_decl: &ExportNamedDeclaration, + ) -> bool { + match &export_decl.declaration { + Some(OxcDeclaration::ClassDeclaration(class_decl)) => class_decl.declare, + Some(OxcDeclaration::FunctionDeclaration(fn_decl)) => fn_decl.declare, + Some(OxcDeclaration::TSEnumDeclaration(ts_enum_decl)) => { + ts_enum_decl.declare + } + Some(OxcDeclaration::TSInterfaceDeclaration(ts_interface_decl)) => { + ts_interface_decl.declare + } + Some(OxcDeclaration::TSModuleDeclaration(ts_module_decl)) => { + ts_module_decl.declare + } + Some(OxcDeclaration::TSTypeAliasDeclaration(ts_type_alias_decl)) => { + ts_type_alias_decl.declare + } + Some(OxcDeclaration::VariableDeclaration(var_decl)) => var_decl.declare, + _ => false, } } @@ -1524,21 +1573,18 @@ impl<'a> DocParser<'a> { fn decl_from_expr( module_info: &EsModuleInfo, - expr: &deno_ast::swc::ast::Expr, + expr: &Expression, location: Location, js_doc: JsDoc, ) -> Declaration { match expr { - deno_ast::swc::ast::Expr::Class(class_expr) => { + Expression::ClassExpression(class_expr) => { let def_name = class_expr - .ident + .id .as_ref() - .map(|id| id.sym.to_string().into_boxed_str()); - let (class_def, decorator_js_doc) = crate::class::class_to_class_def( - module_info, - &class_expr.class, - def_name, - ); + .map(|id| id.name.to_string().into_boxed_str()); + let (class_def, decorator_js_doc) = + crate::class::class_to_class_def(module_info, class_expr, def_name); let js_doc = if js_doc.is_empty() { decorator_js_doc } else { @@ -1546,11 +1592,11 @@ fn decl_from_expr( }; Declaration::class(location, DeclarationKind::Declare, js_doc, class_def) } - deno_ast::swc::ast::Expr::Fn(fn_expr) => { - let def_name = fn_expr.ident.as_ref().map(|id| id.sym.to_string()); + Expression::FunctionExpression(fn_expr) => { + let def_name = fn_expr.id.as_ref().map(|id| id.name.to_string()); let function_def = crate::function::function_to_function_def( module_info, - &fn_expr.function, + fn_expr, def_name, ); Declaration::function( @@ -1560,7 +1606,7 @@ fn decl_from_expr( function_def, ) } - deno_ast::swc::ast::Expr::Arrow(arrow_expr) => { + Expression::ArrowFunctionExpression(arrow_expr) => { let function_def = crate::function::arrow_to_function_def(module_info, arrow_expr); Declaration::function( @@ -1656,12 +1702,10 @@ fn parse_json_module_type(value: &serde_json::Value) -> TsTypeDef { } fn module_has_import(module_info: &EsModuleInfo) -> bool { - module_info.source().program_ref().body().any(|m| { + module_info.statements().iter().any(|m| { matches!( m, - ModuleItemRef::ModuleDecl( - ModuleDecl::Import(_) | ModuleDecl::TsImportEquals(_) - ) + Statement::ImportDeclaration(_) | Statement::TSImportEqualsDeclaration(_) ) }) } diff --git a/src/printer.rs b/src/printer.rs index 60b1eedc5..0ef112a47 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -494,8 +494,8 @@ impl DocPrinter<'_> { self.private || node .accessibility - .unwrap_or(deno_ast::swc::ast::Accessibility::Public) - != deno_ast::swc::ast::Accessibility::Private + .unwrap_or(crate::util::types::Accessibility::Public) + != crate::util::types::Accessibility::Private }) { for d in node.decorators.iter() { writeln!(w, "{}{}", Indent(1), d)?; @@ -510,8 +510,8 @@ impl DocPrinter<'_> { self.private || node .accessibility - .unwrap_or(deno_ast::swc::ast::Accessibility::Public) - != deno_ast::swc::ast::Accessibility::Private + .unwrap_or(crate::util::types::Accessibility::Public) + != crate::util::types::Accessibility::Private }) { let has_overloads = class_def .methods @@ -814,9 +814,9 @@ impl DocPrinter<'_> { Indent(indent), fmt_visibility(decl.declaration_kind), colors::magenta(match variable_def.kind { - deno_ast::swc::ast::VarDeclKind::Const => "const", - deno_ast::swc::ast::VarDeclKind::Let => "let", - deno_ast::swc::ast::VarDeclKind::Var => "var", + crate::util::types::VarDeclKind::Const => "const", + crate::util::types::VarDeclKind::Let => "let", + crate::util::types::VarDeclKind::Var => "var", }), colors::bold(&node.name), )?; diff --git a/src/tests.rs b/src/tests.rs index ba8f0a8fc..39f8ce914 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -51,6 +51,17 @@ pub(crate) async fn setup + Copy, C: AsRef<[u8]>>( (graph, analyzer, root) } +fn new_doc_parser<'a>( + graph: &'a ModuleGraph, + analyzer: &'a CapturingModuleAnalyzer, + roots: &'a [ModuleSpecifier], + options: DocParserOptions, +) -> DocParser<'a> { + let allocator = + Box::leak(Box::new(deno_ast::oxc::allocator::Allocator::default())); + DocParser::new(graph, analyzer, allocator, roots, options).unwrap() +} + #[tokio::test] async fn content_type_handling() { let sources = vec![( @@ -82,8 +93,7 @@ async fn content_type_handling() { ) .await; let entries = - DocParser::new(&graph, &analyzer, &[root], DocParserOptions::default()) - .unwrap() + new_doc_parser(&graph, &analyzer, &[root], DocParserOptions::default()) .parse() .unwrap() .into_values() @@ -135,8 +145,7 @@ async fn types_header_handling() { ) .await; let entries = - DocParser::new(&graph, &analyzer, &[root], DocParserOptions::default()) - .unwrap() + new_doc_parser(&graph, &analyzer, &[root], DocParserOptions::default()) .parse() .unwrap() .into_values() @@ -224,13 +233,12 @@ export function fooFn(a: number) { ], ) .await; - let output = DocParser::new( + let output = new_doc_parser( &graph, &analyzer, &[specifier], DocParserOptions::default(), ) - .unwrap() .parse() .unwrap(); let document = output.values().next().unwrap(); @@ -361,13 +369,12 @@ export { Hello } from "./reexport.ts"; ], ) .await; - let output = DocParser::new( + let output = new_doc_parser( &graph, &analyzer, &[specifier], DocParserOptions::default(), ) - .unwrap() .parse() .unwrap(); let entries = &output.values().next().unwrap().symbols; @@ -424,13 +431,12 @@ async fn deep_reexports() { ], ) .await; - let output = DocParser::new( + let output = new_doc_parser( &graph, &analyzer, &[specifier], DocParserOptions::default(), ) - .unwrap() .parse() .unwrap(); let entries = &output.values().next().unwrap().symbols; @@ -491,13 +497,12 @@ export * as b from "./mod_doc.ts"; ], ) .await; - let entries = DocParser::new( + let entries = new_doc_parser( &graph, &analyzer, &[specifier], DocParserOptions::default(), ) - .unwrap() .parse() .unwrap() .into_values() @@ -596,13 +601,12 @@ export namespace Deno { vec![("file:///test.ts", None, source_code)], ) .await; - let entries = DocParser::new( + let entries = new_doc_parser( &graph, &analyzer, &[specifier], DocParserOptions::default(), ) - .unwrap() .parse() .unwrap() .into_values() @@ -690,13 +694,12 @@ async fn exports_imported_earlier() { ], ) .await; - let document = DocParser::new( + let document = new_doc_parser( &graph, &analyzer, &[specifier], DocParserOptions::default(), ) - .unwrap() .parse() .unwrap() .into_values() @@ -757,13 +760,12 @@ async fn exports_imported_earlier_renamed() { ], ) .await; - let document = DocParser::new( + let document = new_doc_parser( &graph, &analyzer, &[specifier], DocParserOptions::default(), ) - .unwrap() .parse() .unwrap() .into_values() @@ -825,13 +827,12 @@ async fn exports_imported_earlier_default() { ], ) .await; - let document = DocParser::new( + let document = new_doc_parser( &graph, &analyzer, &[specifier], DocParserOptions::default(), ) - .unwrap() .parse() .unwrap() .into_values() @@ -892,7 +893,7 @@ async fn exports_imported_earlier_private() { ], ) .await; - let document = DocParser::new( + let document = new_doc_parser( &graph, &analyzer, &[specifier], @@ -901,7 +902,6 @@ async fn exports_imported_earlier_private() { ..Default::default() }, ) - .unwrap() .parse() .unwrap() .into_values() @@ -957,8 +957,7 @@ async fn variable_syntax() { .await; // This just needs to not throw a syntax error - DocParser::new(&graph, &analyzer, &[specifier], DocParserOptions::default()) - .unwrap() + new_doc_parser(&graph, &analyzer, &[specifier], DocParserOptions::default()) .parse() .unwrap(); } @@ -974,13 +973,12 @@ async fn json_module() { ) .await; - let entries = DocParser::new( + let entries = new_doc_parser( &graph, &analyzer, &[specifier], DocParserOptions::default(), ) - .unwrap() .parse() .unwrap() .into_values() diff --git a/src/ts_type.rs b/src/ts_type.rs index 9a1355dfe..40c436092 100644 --- a/src/ts_type.rs +++ b/src/ts_type.rs @@ -8,22 +8,24 @@ use crate::display::display_optional; use crate::display::display_readonly; use crate::interface::expr_to_name; use crate::node::Symbol; -use crate::params::param_to_param_def; -use crate::params::pat_to_param_def; +use crate::params::ParamPatternDef; +use crate::params::formal_params_to_param_defs; use crate::params::prop_name_to_string; -use crate::params::ts_fn_param_to_param_def; use crate::ts_type_param::TsTypeParamDef; use crate::ts_type_param::maybe_type_param_decl_to_type_param_defs; use crate::util::swc::get_location; use crate::util::swc::is_false; use crate::util::swc::js_doc_for_range; +use crate::util::types::MethodKind; +use crate::util::types::VarDeclKind; use crate::function::FunctionDef; use crate::js_doc::JsDoc; use crate::node::DeclarationKind; use crate::variable::VariableDef; -use deno_ast::SourceRangedForSpanned; -use deno_ast::swc::ast::*; +use deno_ast::oxc::ast::ast::*; +use deno_ast::oxc::span::GetSpan; +use deno_ast::oxc::syntax::operator::BinaryOperator; use deno_graph::symbols::EsModuleInfo; use deno_terminal::colors; use serde::Deserialize; @@ -32,26 +34,107 @@ use std::fmt::Display; use std::fmt::Formatter; use std::fmt::Result as FmtResult; +/// Mirrors the old SWC `TruePlusMinus` enum with matching serde. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TruePlusMinus { + True, + Plus, + Minus, +} + +impl Serialize for TruePlusMinus { + fn serialize( + &self, + serializer: S, + ) -> Result { + match self { + TruePlusMinus::True => serializer.serialize_bool(true), + TruePlusMinus::Plus => serializer.serialize_str("plus"), + TruePlusMinus::Minus => serializer.serialize_str("minus"), + } + } +} + +impl<'de> Deserialize<'de> for TruePlusMinus { + fn deserialize>( + deserializer: D, + ) -> Result { + use serde::de; + struct TruePlusMinusVisitor; + impl<'de> de::Visitor<'de> for TruePlusMinusVisitor { + type Value = TruePlusMinus; + + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("true, \"plus\", or \"minus\"") + } + + fn visit_bool(self, v: bool) -> Result { + if v { + Ok(TruePlusMinus::True) + } else { + Err(E::custom("expected true, got false")) + } + } + + fn visit_str(self, v: &str) -> Result { + match v { + "plus" => Ok(TruePlusMinus::Plus), + "minus" => Ok(TruePlusMinus::Minus), + _ => Err(E::custom(format!("unknown value: {}", v))), + } + } + } + deserializer.deserialize_any(TruePlusMinusVisitor) + } +} + +impl From for TruePlusMinus { + fn from(op: TSMappedTypeModifierOperator) -> Self { + match op { + TSMappedTypeModifierOperator::True => TruePlusMinus::True, + TSMappedTypeModifierOperator::Plus => TruePlusMinus::Plus, + TSMappedTypeModifierOperator::Minus => TruePlusMinus::Minus, + } + } +} + impl TsTypeDef { - fn ts_lit_type(module_info: &EsModuleInfo, other: &TsLitType) -> Self { - match &other.lit { - TsLit::Number(num) => TsTypeDef::number_literal(num), - TsLit::Str(str_) => TsTypeDef::string_literal(str_), - TsLit::Tpl(tpl) => TsTypeDef::tpl_literal( + fn ts_lit_type(module_info: &EsModuleInfo, other: &TSLiteralType) -> Self { + match &other.literal { + TSLiteral::NumericLiteral(num) => TsTypeDef::number_literal(num), + TSLiteral::StringLiteral(str_) => { + TsTypeDef::string_value(str_.value.to_string()) + } + TSLiteral::TemplateLiteral(tpl) => TsTypeDef::tpl_literal( tpl - .types + .expressions .iter() - .map(|types| TsTypeDef::new(module_info, types)) + .filter_map(|expr| infer_ts_type_from_expr(module_info, expr, true)) .collect::>(), &tpl.quasis, ), - TsLit::Bool(bool_) => TsTypeDef::bool_literal(bool_), - TsLit::BigInt(bigint_) => TsTypeDef::bigint_literal(bigint_), + TSLiteral::BooleanLiteral(bool_) => TsTypeDef::bool_literal(bool_), + TSLiteral::BigIntLiteral(bigint_) => TsTypeDef::bigint_literal(bigint_), + TSLiteral::UnaryExpression(_) => TsTypeDef::keyword("number"), } } - fn ts_array_type(module_info: &EsModuleInfo, other: &TsArrayType) -> Self { - let ts_type_def = TsTypeDef::new(module_info, &other.elem_type); + fn ts_template_literal_type( + module_info: &EsModuleInfo, + other: &TSTemplateLiteralType, + ) -> Self { + TsTypeDef::tpl_literal( + other + .types + .iter() + .map(|t| TsTypeDef::new(module_info, t)) + .collect::>(), + &other.quasis, + ) + } + + fn ts_array_type(module_info: &EsModuleInfo, other: &TSArrayType) -> Self { + let ts_type_def = TsTypeDef::new(module_info, &other.element_type); TsTypeDef { kind: TsTypeDefKind::Array(Box::new(ts_type_def)), @@ -59,11 +142,11 @@ impl TsTypeDef { } } - fn ts_tuple_type(module_info: &EsModuleInfo, other: &TsTupleType) -> Self { + fn ts_tuple_type(module_info: &EsModuleInfo, other: &TSTupleType) -> Self { let type_defs = other - .elem_types + .element_types .iter() - .map(|type_box| TsTypeDef::new(module_info, &type_box.ty)) + .map(|elem| ts_tuple_element_to_ts_type_def(module_info, elem)) .collect::>(); TsTypeDef { @@ -72,69 +155,47 @@ impl TsTypeDef { } } - fn ts_union_or_intersection_type( - module_info: &EsModuleInfo, - other: &TsUnionOrIntersectionType, - ) -> Self { - use deno_ast::swc::ast::TsUnionOrIntersectionType::*; - - match other { - TsUnionType(union_type) => { - let types_union = union_type - .types - .iter() - .map(|ts_type| TsTypeDef::new(module_info, ts_type)) - .collect::>(); - - TsTypeDef { - kind: TsTypeDefKind::Union(types_union), - repr: String::new(), - } - } - TsIntersectionType(intersection_type) => { - let types_intersection = intersection_type - .types - .iter() - .map(|ts_type| TsTypeDef::new(module_info, ts_type)) - .collect::>(); + fn ts_union_type(module_info: &EsModuleInfo, other: &TSUnionType) -> Self { + let types_union = other + .types + .iter() + .map(|ts_type| TsTypeDef::new(module_info, ts_type)) + .collect::>(); - TsTypeDef { - kind: TsTypeDefKind::Intersection(types_intersection), - repr: String::new(), - } - } + TsTypeDef { + kind: TsTypeDefKind::Union(types_union), + repr: String::new(), } } - fn ts_keyword_type(other: &TsKeywordType) -> Self { - use deno_ast::swc::ast::TsKeywordTypeKind::*; - - let keyword_str = match other.kind { - TsAnyKeyword => "any", - TsUnknownKeyword => "unknown", - TsNumberKeyword => "number", - TsObjectKeyword => "object", - TsBooleanKeyword => "boolean", - TsBigIntKeyword => "bigint", - TsStringKeyword => "string", - TsSymbolKeyword => "symbol", - TsVoidKeyword => "void", - TsUndefinedKeyword => "undefined", - TsNullKeyword => "null", - TsNeverKeyword => "never", - TsIntrinsicKeyword => "intrinsic", - }; + fn ts_intersection_type( + module_info: &EsModuleInfo, + other: &TSIntersectionType, + ) -> Self { + let types_intersection = other + .types + .iter() + .map(|ts_type| TsTypeDef::new(module_info, ts_type)) + .collect::>(); - TsTypeDef::keyword(keyword_str) + TsTypeDef { + kind: TsTypeDefKind::Intersection(types_intersection), + repr: String::new(), + } } fn ts_type_operator( module_info: &EsModuleInfo, - other: &TsTypeOperator, + other: &TSTypeOperator, ) -> Self { - let ts_type = TsTypeDef::new(module_info, &other.type_ann); + let ts_type = TsTypeDef::new(module_info, &other.type_annotation); + let operator = match other.operator { + TSTypeOperatorOperator::Keyof => "keyof", + TSTypeOperatorOperator::Unique => "unique", + TSTypeOperatorOperator::Readonly => "readonly", + }; let type_operator_def = TsTypeOperatorDef { - operator: other.op.as_str().to_string(), + operator: operator.to_string(), ts_type, }; @@ -146,9 +207,9 @@ impl TsTypeDef { fn ts_parenthesized_type( module_info: &EsModuleInfo, - other: &TsParenthesizedType, + other: &TSParenthesizedType, ) -> Self { - let ts_type = TsTypeDef::new(module_info, &other.type_ann); + let ts_type = TsTypeDef::new(module_info, &other.type_annotation); TsTypeDef { kind: TsTypeDefKind::Parenthesized(Box::new(ts_type)), @@ -156,8 +217,8 @@ impl TsTypeDef { } } - fn ts_rest_type(module_info: &EsModuleInfo, other: &TsRestType) -> Self { - let ts_type = TsTypeDef::new(module_info, &other.type_ann); + fn ts_rest_type(module_info: &EsModuleInfo, other: &TSRestType) -> Self { + let ts_type = TsTypeDef::new(module_info, &other.type_annotation); TsTypeDef { kind: TsTypeDefKind::Rest(Box::new(ts_type)), @@ -167,9 +228,9 @@ impl TsTypeDef { fn ts_optional_type( module_info: &EsModuleInfo, - other: &TsOptionalType, + other: &TSOptionalType, ) -> Self { - let ts_type = TsTypeDef::new(module_info, &other.type_ann); + let ts_type = TsTypeDef::new(module_info, &other.type_annotation); TsTypeDef { kind: TsTypeDefKind::Optional(Box::new(ts_type)), @@ -177,7 +238,7 @@ impl TsTypeDef { } } - fn ts_this_type(_other: &TsThisType) -> Self { + fn ts_this_type(_other: &TSThisType) -> Self { TsTypeDef { repr: "this".to_string(), kind: TsTypeDefKind::This, @@ -186,15 +247,15 @@ impl TsTypeDef { fn ts_type_predicate( module_info: &EsModuleInfo, - other: &TsTypePredicate, + other: &TSTypePredicate, ) -> Self { let pred = TsTypePredicateDef { asserts: other.asserts, - param: (&other.param_name).into(), + param: ts_type_predicate_name_to_this_or_ident(&other.parameter_name), r#type: other - .type_ann + .type_annotation .as_ref() - .map(|t| Box::new(TsTypeDef::new(module_info, &t.type_ann))), + .map(|t| Box::new(TsTypeDef::new(module_info, &t.type_annotation))), }; let mut repr_parts = Vec::new(); if pred.asserts { @@ -214,15 +275,8 @@ impl TsTypeDef { } } - fn ts_type_query(other: &TsTypeQuery) -> Self { - use deno_ast::swc::ast::TsTypeQueryExpr::*; - - let type_name = match &other.expr_name { - TsEntityName(entity_name) => ts_entity_name_to_name(entity_name), - Import(import_type) => { - import_type.arg.value.to_string_lossy().into_owned() - } - }; + fn ts_type_query(other: &TSTypeQuery) -> Self { + let type_name = ts_type_query_expr_name_to_name(&other.expr_name); TsTypeDef { repr: type_name.to_string(), @@ -230,10 +284,10 @@ impl TsTypeDef { } } - fn ts_type_ref(module_info: &EsModuleInfo, other: &TsTypeRef) -> Self { - let type_name = ts_entity_name_to_name(&other.type_name); + fn ts_type_ref(module_info: &EsModuleInfo, other: &TSTypeReference) -> Self { + let type_name = ts_type_name_to_name(&other.type_name); - let type_params = if let Some(type_params_inst) = &other.type_params { + let type_params = if let Some(type_params_inst) = &other.type_arguments { let ts_type_defs = type_params_inst .params .iter() @@ -245,8 +299,8 @@ impl TsTypeDef { None }; - let root_ident = ts_entity_name_root_ident(&other.type_name); - let resolution = resolve_type_ref(module_info, root_ident); + let resolution = ts_type_name_root_ident(&other.type_name) + .and_then(|ident| resolve_type_ref(module_info, ident)); TsTypeDef { repr: type_name.clone(), @@ -260,11 +314,49 @@ impl TsTypeDef { pub fn ts_expr_with_type_args( module_info: &EsModuleInfo, - other: &TsExprWithTypeArgs, + other: &TSClassImplements, + ) -> Self { + let type_name = ts_type_name_to_name(&other.expression); + + let type_params = if let Some(type_params_inst) = &other.type_arguments { + let ts_type_defs = type_params_inst + .params + .iter() + .map(|ts_type| TsTypeDef::new(module_info, ts_type)) + .collect::>(); + + Some(ts_type_defs) + } else { + None + }; + + let resolution = ts_type_name_root_ident(&other.expression) + .and_then(|i| resolve_type_ref(module_info, i)); + + TsTypeDef { + repr: type_name.clone(), + kind: TsTypeDefKind::TypeRef(TsTypeRefDef { + type_params, + type_name, + resolution, + }), + } + } + + pub fn ts_class_implements( + module_info: &EsModuleInfo, + other: &TSClassImplements, ) -> Self { - let type_name = expr_to_name(&other.expr); + Self::ts_expr_with_type_args(module_info, other) + } - let type_params = if let Some(type_params_inst) = &other.type_args { + pub fn ts_interface_heritage( + module_info: &EsModuleInfo, + other: &TSInterfaceHeritage, + ) -> Self { + let type_name = expr_to_name(&other.expression); + + let type_params = if let Some(type_params_inst) = &other.type_arguments { let ts_type_defs = type_params_inst .params .iter() @@ -276,7 +368,7 @@ impl TsTypeDef { None }; - let resolution = expr_root_ident(&other.expr) + let resolution = expr_root_ident(&other.expression) .and_then(|i| resolve_type_ref(module_info, i)); TsTypeDef { @@ -291,11 +383,11 @@ impl TsTypeDef { fn ts_indexed_access_type( module_info: &EsModuleInfo, - other: &TsIndexedAccessType, + other: &TSIndexedAccessType, ) -> Self { let indexed_access_def = TsIndexedAccessDef { - readonly: other.readonly, - obj_type: Box::new(TsTypeDef::new(module_info, &other.obj_type)), + readonly: false, + obj_type: Box::new(TsTypeDef::new(module_info, &other.object_type)), index_type: Box::new(TsTypeDef::new(module_info, &other.index_type)), }; @@ -305,17 +397,21 @@ impl TsTypeDef { } } - fn ts_mapped_type(module_info: &EsModuleInfo, other: &TsMappedType) -> Self { + fn ts_mapped_type(module_info: &EsModuleInfo, other: &TSMappedType) -> Self { let mapped_type_def = TsMappedTypeDef { - readonly: other.readonly, - type_param: Box::new(TsTypeParamDef::new(module_info, &other.type_param)), + readonly: other.readonly.map(TruePlusMinus::from), + type_param: Box::new(TsTypeParamDef { + name: other.key.name.to_string(), + constraint: Some(TsTypeDef::new(module_info, &other.constraint)), + default: None, + }), name_type: other .name_type .as_ref() .map(|nt| Box::new(TsTypeDef::new(module_info, nt))), - optional: other.optional, + optional: other.optional.map(TruePlusMinus::from), ts_type: other - .type_ann + .type_annotation .as_ref() .map(|a| Box::new(TsTypeDef::new(module_info, a))), }; @@ -326,7 +422,7 @@ impl TsTypeDef { } } - fn ts_type_lit(module_info: &EsModuleInfo, other: &TsTypeLit) -> Self { + fn ts_type_lit(module_info: &EsModuleInfo, other: &TSTypeLiteral) -> Self { let mut constructors = vec![]; let mut methods = vec![]; let mut properties = vec![]; @@ -334,33 +430,32 @@ impl TsTypeDef { let mut index_signatures = vec![]; for type_element in &other.members { - use deno_ast::swc::ast::TsTypeElement::*; - - match &type_element { - TsMethodSignature(ts_method_sig) => { - let js_doc = js_doc_for_range(module_info, &ts_method_sig.range()) + match type_element { + TSSignature::TSMethodSignature(ts_method_sig) => { + let js_doc = js_doc_for_range(module_info, ts_method_sig.span) .unwrap_or_default(); - let params = ts_method_sig - .params - .iter() - .map(|param| ts_fn_param_to_param_def(module_info, param)) - .collect::>(); + let params = + formal_params_to_param_defs(module_info, &ts_method_sig.params); let maybe_return_type = ts_method_sig - .type_ann + .return_type .as_ref() - .map(|rt| TsTypeDef::new(module_info, &rt.type_ann)); + .map(|rt| TsTypeDef::new(module_info, &rt.type_annotation)); let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - ts_method_sig.type_params.as_deref(), + ts_method_sig.type_parameters.as_deref(), ); - let name = expr_to_name(&ts_method_sig.key); - let location = get_location(module_info, ts_method_sig.start()); + let name = ts_method_sig + .key + .static_name() + .map(|name| name.to_string()) + .unwrap_or_else(|| "[UNSUPPORTED]".to_string()); + let location = get_location(module_info, ts_method_sig.span.start); let method_def = MethodDef { name, js_doc, - kind: MethodKind::Method, + kind: MethodKind::from(ts_method_sig.kind), location, params, computed: ts_method_sig.computed, @@ -370,64 +465,23 @@ impl TsTypeDef { }; methods.push(method_def); } - TsGetterSignature(ts_getter_sig) => { - let js_doc = js_doc_for_range(module_info, &ts_getter_sig.range()) - .unwrap_or_default(); - let maybe_return_type = ts_getter_sig - .type_ann - .as_ref() - .map(|rt| TsTypeDef::new(module_info, &rt.type_ann)); - - let name = expr_to_name(&ts_getter_sig.key); - let location = get_location(module_info, ts_getter_sig.start()); - let method_def = MethodDef { - name, - js_doc, - kind: MethodKind::Getter, - location, - params: vec![], - computed: ts_getter_sig.computed, - optional: false, - return_type: maybe_return_type, - type_params: Box::new([]), - }; - methods.push(method_def); - } - TsSetterSignature(ts_setter_sig) => { - let js_doc = js_doc_for_range(module_info, &ts_setter_sig.range()) - .unwrap_or_default(); - let name = expr_to_name(&ts_setter_sig.key); - - let params = - vec![ts_fn_param_to_param_def(module_info, &ts_setter_sig.param)]; - - let location = get_location(module_info, ts_setter_sig.start()); - let method_def = MethodDef { - name, - js_doc, - kind: MethodKind::Setter, - location, - params, - computed: ts_setter_sig.computed, - optional: false, - return_type: None, - type_params: Box::new([]), - }; - methods.push(method_def); - } - TsPropertySignature(ts_prop_sig) => { - let js_doc = js_doc_for_range(module_info, &ts_prop_sig.range()) - .unwrap_or_default(); - let name = expr_to_name(&ts_prop_sig.key); + TSSignature::TSPropertySignature(ts_prop_sig) => { + let js_doc = + js_doc_for_range(module_info, ts_prop_sig.span).unwrap_or_default(); + let name = ts_prop_sig + .key + .static_name() + .map(|name| name.to_string()) + .unwrap_or_else(|| "[UNSUPPORTED]".to_string()); let ts_type = ts_prop_sig - .type_ann + .type_annotation .as_ref() - .map(|rt| TsTypeDef::new(module_info, &rt.type_ann)); + .map(|rt| TsTypeDef::new(module_info, &rt.type_annotation)); let type_params = maybe_type_param_decl_to_type_param_defs(module_info, None); - let location = get_location(module_info, ts_prop_sig.start()); + let location = get_location(module_info, ts_prop_sig.span.start); let prop_def = PropertyDef { name, js_doc, @@ -441,26 +495,23 @@ impl TsTypeDef { }; properties.push(prop_def); } - TsCallSignatureDecl(ts_call_sig) => { - let js_doc = js_doc_for_range(module_info, &ts_call_sig.range()) - .unwrap_or_default(); - let params = ts_call_sig - .params - .iter() - .map(|param| ts_fn_param_to_param_def(module_info, param)) - .collect(); + TSSignature::TSCallSignatureDeclaration(ts_call_sig) => { + let js_doc = + js_doc_for_range(module_info, ts_call_sig.span).unwrap_or_default(); + let params = + formal_params_to_param_defs(module_info, &ts_call_sig.params); let ts_type = ts_call_sig - .type_ann + .return_type .as_ref() - .map(|rt| TsTypeDef::new(module_info, &rt.type_ann)); + .map(|rt| TsTypeDef::new(module_info, &rt.type_annotation)); let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - ts_call_sig.type_params.as_deref(), + ts_call_sig.type_parameters.as_deref(), ); - let location = get_location(module_info, ts_call_sig.start()); + let location = get_location(module_info, ts_call_sig.span.start); let call_sig_def = CallSignatureDef { js_doc, location, @@ -470,21 +521,34 @@ impl TsTypeDef { }; call_signatures.push(call_sig_def); } - TsIndexSignature(ts_index_sig) => { - let js_doc = js_doc_for_range(module_info, &ts_index_sig.range()) + TSSignature::TSIndexSignature(ts_index_sig) => { + let js_doc = js_doc_for_range(module_info, ts_index_sig.span) .unwrap_or_default(); let params = ts_index_sig - .params + .parameters .iter() - .map(|param| ts_fn_param_to_param_def(module_info, param)) + .map(|param| { + let ts_type = Some(TsTypeDef::new( + module_info, + ¶m.type_annotation.type_annotation, + )); + ParamDef { + pattern: ParamPatternDef::Identifier { + name: param.name.to_string(), + optional: false, + }, + decorators: Box::new([]), + ts_type, + } + }) .collect(); - let ts_type = ts_index_sig - .type_ann - .as_ref() - .map(|rt| TsTypeDef::new(module_info, &rt.type_ann)); + let ts_type = Some(TsTypeDef::new( + module_info, + &ts_index_sig.type_annotation.type_annotation, + )); - let location = get_location(module_info, ts_index_sig.start()); + let location = get_location(module_info, ts_index_sig.span.start); let index_sig_def = IndexSignatureDef { js_doc, location, @@ -494,26 +558,23 @@ impl TsTypeDef { }; index_signatures.push(index_sig_def); } - TsConstructSignatureDecl(ts_construct_sig) => { - let js_doc = js_doc_for_range(module_info, &ts_construct_sig.range()) + TSSignature::TSConstructSignatureDeclaration(ts_construct_sig) => { + let js_doc = js_doc_for_range(module_info, ts_construct_sig.span) .unwrap_or_default(); - let params = ts_construct_sig - .params - .iter() - .map(|param| ts_fn_param_to_param_def(module_info, param)) - .collect(); + let params = + formal_params_to_param_defs(module_info, &ts_construct_sig.params); let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - ts_construct_sig.type_params.as_deref(), + ts_construct_sig.type_parameters.as_deref(), ); let maybe_return_type = ts_construct_sig - .type_ann + .return_type .as_ref() - .map(|rt| TsTypeDef::new(module_info, &rt.type_ann)); + .map(|rt| TsTypeDef::new(module_info, &rt.type_annotation)); - let location = get_location(module_info, ts_construct_sig.start()); + let location = get_location(module_info, ts_construct_sig.span.start); let construct_sig_def = ConstructorDef { js_doc, location, @@ -543,7 +604,7 @@ impl TsTypeDef { fn ts_conditional_type( module_info: &EsModuleInfo, - other: &TsConditionalType, + other: &TSConditionalType, ) -> Self { let conditional_type_def = TsConditionalDef { check_type: Box::new(TsTypeDef::new(module_info, &other.check_type)), @@ -558,9 +619,12 @@ impl TsTypeDef { } } - fn ts_infer_type(module_info: &EsModuleInfo, other: &TsInferType) -> Self { + fn ts_infer_type(module_info: &EsModuleInfo, other: &TSInferType) -> Self { let infer = TsInferDef { - type_param: Box::new(TsTypeParamDef::new(module_info, &other.type_param)), + type_param: Box::new(TsTypeParamDef::new( + module_info, + &other.type_parameter, + )), }; TsTypeDef { @@ -569,8 +633,8 @@ impl TsTypeDef { } } - fn ts_import_type(module_info: &EsModuleInfo, other: &TsImportType) -> Self { - let type_params = if let Some(type_params_inst) = &other.type_args { + fn ts_import_type(module_info: &EsModuleInfo, other: &TSImportType) -> Self { + let type_params = if let Some(type_params_inst) = &other.type_arguments { let ts_type_defs = type_params_inst .params .iter() @@ -583,8 +647,11 @@ impl TsTypeDef { }; let import_type_def = TsImportTypeDef { - specifier: other.arg.value.to_string_lossy().into_owned(), - qualifier: other.qualifier.as_ref().map(ts_entity_name_to_name), + specifier: other.source.value.to_string(), + qualifier: other + .qualifier + .as_ref() + .map(ts_import_type_qualifier_to_name), type_params, }; @@ -594,50 +661,25 @@ impl TsTypeDef { } } - fn ts_fn_or_constructor_type( + fn ts_fn_type( module_info: &EsModuleInfo, - other: &TsFnOrConstructorType, + ts_fn_type: &TSFunctionType, ) -> Self { - use deno_ast::swc::ast::TsFnOrConstructorType::*; + let params = formal_params_to_param_defs(module_info, &ts_fn_type.params); - let fn_def = match other { - TsFnType(ts_fn_type) => { - let params = ts_fn_type - .params - .iter() - .map(|param| ts_fn_param_to_param_def(module_info, param)) - .collect(); - - let type_params = maybe_type_param_decl_to_type_param_defs( - module_info, - ts_fn_type.type_params.as_deref(), - ); - - TsFnOrConstructorDef { - constructor: false, - ts_type: TsTypeDef::new(module_info, &ts_fn_type.type_ann.type_ann), - params, - type_params, - } - } - TsConstructorType(ctor_type) => { - let params = ctor_type - .params - .iter() - .map(|param| ts_fn_param_to_param_def(module_info, param)) - .collect(); - - let type_params = maybe_type_param_decl_to_type_param_defs( - module_info, - ctor_type.type_params.as_deref(), - ); - TsFnOrConstructorDef { - constructor: true, - ts_type: TsTypeDef::new(module_info, &ctor_type.type_ann.type_ann), - params, - type_params, - } - } + let type_params = maybe_type_param_decl_to_type_param_defs( + module_info, + ts_fn_type.type_parameters.as_deref(), + ); + + let fn_def = TsFnOrConstructorDef { + constructor: false, + ts_type: TsTypeDef::new( + module_info, + &ts_fn_type.return_type.type_annotation, + ), + params, + type_params, }; TsTypeDef { @@ -646,97 +688,223 @@ impl TsTypeDef { } } - pub fn new(module_info: &EsModuleInfo, other: &TsType) -> Self { - use deno_ast::swc::ast::TsType::*; + fn ts_constructor_type( + module_info: &EsModuleInfo, + ctor_type: &TSConstructorType, + ) -> Self { + let params = formal_params_to_param_defs(module_info, &ctor_type.params); + + let type_params = maybe_type_param_decl_to_type_param_defs( + module_info, + ctor_type.type_parameters.as_deref(), + ); + + let fn_def = TsFnOrConstructorDef { + constructor: true, + ts_type: TsTypeDef::new( + module_info, + &ctor_type.return_type.type_annotation, + ), + params, + type_params, + }; + TsTypeDef { + kind: TsTypeDefKind::FnOrConstructor(Box::new(fn_def)), + repr: String::new(), + } + } + + fn ts_named_tuple_member( + module_info: &EsModuleInfo, + other: &TSNamedTupleMember, + ) -> Self { + ts_tuple_element_to_ts_type_def(module_info, &other.element_type) + } + + pub fn new(module_info: &EsModuleInfo, other: &TSType) -> Self { match other { - TsKeywordType(keyword_type) => TsTypeDef::ts_keyword_type(keyword_type), - TsThisType(this_type) => TsTypeDef::ts_this_type(this_type), - TsFnOrConstructorType(fn_or_con_type) => { - TsTypeDef::ts_fn_or_constructor_type(module_info, fn_or_con_type) + TSType::TSAnyKeyword(_) => TsTypeDef::keyword("any"), + TSType::TSUnknownKeyword(_) => TsTypeDef::keyword("unknown"), + TSType::TSNumberKeyword(_) => TsTypeDef::keyword("number"), + TSType::TSObjectKeyword(_) => TsTypeDef::keyword("object"), + TSType::TSBooleanKeyword(_) => TsTypeDef::keyword("boolean"), + TSType::TSBigIntKeyword(_) => TsTypeDef::keyword("bigint"), + TSType::TSStringKeyword(_) => TsTypeDef::keyword("string"), + TSType::TSSymbolKeyword(_) => TsTypeDef::keyword("symbol"), + TSType::TSVoidKeyword(_) => TsTypeDef::keyword("void"), + TSType::TSUndefinedKeyword(_) => TsTypeDef::keyword("undefined"), + TSType::TSNullKeyword(_) => TsTypeDef::keyword("null"), + TSType::TSNeverKeyword(_) => TsTypeDef::keyword("never"), + TSType::TSIntrinsicKeyword(_) => TsTypeDef::keyword("intrinsic"), + TSType::TSThisType(this_type) => TsTypeDef::ts_this_type(this_type), + TSType::TSFunctionType(fn_type) => { + TsTypeDef::ts_fn_type(module_info, fn_type) + } + TSType::TSConstructorType(ctor_type) => { + TsTypeDef::ts_constructor_type(module_info, ctor_type) + } + TSType::TSTypeReference(type_ref) => { + TsTypeDef::ts_type_ref(module_info, type_ref) } - TsTypeRef(type_ref) => TsTypeDef::ts_type_ref(module_info, type_ref), - TsTypeQuery(type_query) => TsTypeDef::ts_type_query(type_query), - TsTypeLit(type_literal) => { + TSType::TSTypeQuery(type_query) => TsTypeDef::ts_type_query(type_query), + TSType::TSTypeLiteral(type_literal) => { TsTypeDef::ts_type_lit(module_info, type_literal) } - TsArrayType(array_type) => { + TSType::TSArrayType(array_type) => { TsTypeDef::ts_array_type(module_info, array_type) } - TsTupleType(tuple_type) => { + TSType::TSTupleType(tuple_type) => { TsTypeDef::ts_tuple_type(module_info, tuple_type) } - TsOptionalType(optional_type) => { - TsTypeDef::ts_optional_type(module_info, optional_type) + TSType::TSUnionType(union_type) => { + TsTypeDef::ts_union_type(module_info, union_type) } - TsRestType(rest_type) => TsTypeDef::ts_rest_type(module_info, rest_type), - TsUnionOrIntersectionType(union_or_inter) => { - TsTypeDef::ts_union_or_intersection_type(module_info, union_or_inter) + TSType::TSIntersectionType(intersection_type) => { + TsTypeDef::ts_intersection_type(module_info, intersection_type) } - TsConditionalType(conditional_type) => { + TSType::TSConditionalType(conditional_type) => { TsTypeDef::ts_conditional_type(module_info, conditional_type) } - TsInferType(infer_type) => { + TSType::TSInferType(infer_type) => { TsTypeDef::ts_infer_type(module_info, infer_type) } - TsParenthesizedType(paren_type) => { + TSType::TSParenthesizedType(paren_type) => { TsTypeDef::ts_parenthesized_type(module_info, paren_type) } - TsTypeOperator(type_op_type) => { + TSType::TSTypeOperatorType(type_op_type) => { TsTypeDef::ts_type_operator(module_info, type_op_type) } - TsIndexedAccessType(indexed_access_type) => { + TSType::TSIndexedAccessType(indexed_access_type) => { TsTypeDef::ts_indexed_access_type(module_info, indexed_access_type) } - TsMappedType(mapped_type) => { + TSType::TSMappedType(mapped_type) => { TsTypeDef::ts_mapped_type(module_info, mapped_type) } - TsLitType(lit_type) => TsTypeDef::ts_lit_type(module_info, lit_type), - TsTypePredicate(type_predicate_type) => { + TSType::TSLiteralType(lit_type) => { + TsTypeDef::ts_lit_type(module_info, lit_type) + } + TSType::TSTypePredicate(type_predicate_type) => { TsTypeDef::ts_type_predicate(module_info, type_predicate_type) } - TsImportType(import_type) => { + TSType::TSImportType(import_type) => { TsTypeDef::ts_import_type(module_info, import_type) } + TSType::TSNamedTupleMember(named_tuple_member) => { + TsTypeDef::ts_named_tuple_member(module_info, named_tuple_member) + } + TSType::TSTemplateLiteralType(tpl_type) => { + TsTypeDef::ts_template_literal_type(module_info, tpl_type) + } + TSType::JSDocNullableType(_) + | TSType::JSDocNonNullableType(_) + | TSType::JSDocUnknownType(_) => TsTypeDef::keyword("unknown"), } } } -fn ts_entity_name_to_name(entity_name: &TsEntityName) -> String { - use deno_ast::swc::ast::TsEntityName::*; +type Id = (String, usize); + +fn identifier_reference_to_id( + module_info: &EsModuleInfo, + ident: &IdentifierReference, +) -> Id { + let ctxt = ident + .reference_id + .get() + .zip(module_info.scoping()) + .and_then(|(reference_id, scoping)| { + scoping.get_reference(reference_id).symbol_id() + }) + .map(|symbol_id| symbol_id.index() + 1) + .unwrap_or(0); + (ident.name.to_string(), ctxt) +} - match entity_name { - Ident(ident) => ident.sym.to_string(), - TsQualifiedName(ts_qualified_name) => { - let left = ts_entity_name_to_name(&ts_qualified_name.left); - let right = ts_qualified_name.right.sym.to_string(); +fn ts_type_name_to_name(type_name: &TSTypeName) -> String { + match type_name { + TSTypeName::IdentifierReference(ident) => ident.name.to_string(), + TSTypeName::QualifiedName(ts_qualified_name) => { + let left = ts_type_name_to_name(&ts_qualified_name.left); + let right = ts_qualified_name.right.name.to_string(); format!("{}.{}", left, right) } + TSTypeName::ThisExpression(_) => "this".to_string(), } } -fn ts_entity_name_root_ident(entity_name: &TsEntityName) -> &Ident { - match entity_name { - TsEntityName::Ident(ident) => ident, - TsEntityName::TsQualifiedName(ts_qualified_name) => { - ts_entity_name_root_ident(&ts_qualified_name.left) +fn ts_type_name_root_ident<'a>( + type_name: &'a TSTypeName<'a>, +) -> Option<&'a IdentifierReference<'a>> { + match type_name { + TSTypeName::IdentifierReference(ident) => Some(ident), + TSTypeName::QualifiedName(ts_qualified_name) => { + ts_type_name_root_ident(&ts_qualified_name.left) + } + TSTypeName::ThisExpression(_) => None, + } +} + +fn ts_type_query_expr_name_to_name(expr_name: &TSTypeQueryExprName) -> String { + match expr_name { + TSTypeQueryExprName::TSImportType(import_type) => { + import_type.source.value.to_string() + } + TSTypeQueryExprName::IdentifierReference(ident) => ident.name.to_string(), + TSTypeQueryExprName::QualifiedName(qualified) => { + let left = ts_type_name_to_name(&qualified.left); + let right = qualified.right.name.to_string(); + format!("{}.{}", left, right) } + TSTypeQueryExprName::ThisExpression(_) => "this".to_string(), } } -fn expr_root_ident(expr: &Expr) -> Option<&Ident> { +fn ts_import_type_qualifier_to_name( + qualifier: &TSImportTypeQualifier, +) -> String { + match qualifier { + TSImportTypeQualifier::Identifier(ident) => ident.name.to_string(), + TSImportTypeQualifier::QualifiedName(qualified) => { + let left = ts_import_type_qualifier_to_name(&qualified.left); + let right = qualified.right.name.to_string(); + format!("{}.{}", left, right) + } + } +} + +fn ts_type_predicate_name_to_this_or_ident( + name: &TSTypePredicateName, +) -> ThisOrIdent { + match name { + TSTypePredicateName::This(_) => ThisOrIdent::This, + TSTypePredicateName::Identifier(ident) => ThisOrIdent::Identifier { + name: ident.name.to_string(), + }, + } +} + +fn expr_root_ident<'a>( + expr: &'a Expression<'a>, +) -> Option<&'a IdentifierReference<'a>> { match expr { - Expr::Ident(ident) => Some(ident), - Expr::Member(member_expr) => expr_root_ident(&member_expr.obj), + Expression::Identifier(ident) => Some(ident), + Expression::StaticMemberExpression(member_expr) => { + expr_root_ident(&member_expr.object) + } + Expression::ComputedMemberExpression(member_expr) => { + expr_root_ident(&member_expr.object) + } _ => None, } } fn resolve_type_ref( module_info: &EsModuleInfo, - ident: &Ident, + ident: &IdentifierReference, ) -> Option { - if let Some(symbol) = module_info.symbol_from_swc(&ident.to_id()) { + let id = identifier_reference_to_id(module_info, ident); + if let Some(symbol) = module_info.symbol_from_swc(&id) { if let Some(file_dep) = symbol.file_dep() { Some(TypeRefResolution::Import { specifier: file_dep.specifier.clone(), @@ -745,214 +913,89 @@ fn resolve_type_ref( } else { Some(TypeRefResolution::Local) } - } else if ident.ctxt != module_info.source().unresolved_context() { - // The identifier has a resolved syntax context but is not a module-level - // symbol — it's a type parameter or other locally-scoped binding. - let origin = find_type_param_origin(module_info, &ident.to_id()); + } else if id.1 != 0 { Some(TypeRefResolution::TypeParam { - declaring_name: origin.as_ref().map(|o| o.0.clone()), - declaring_kind: origin.as_ref().map(|o| o.1.clone()), + declaring_name: None, + declaring_kind: None, }) } else { - // Unresolved identifier — a global type (Promise, Array, etc.) - // or truly unresolvable. None } } -/// Walks the module AST to find which declaration owns a type parameter. -fn find_type_param_origin( +fn ts_tuple_element_to_ts_type_def( module_info: &EsModuleInfo, - target_id: &Id, -) -> Option<(String, TypeParamDeclaringKind)> { - use deno_ast::ModuleItemRef; - - let program = module_info.source().program_ref(); - - for item in program.body() { - match item { - ModuleItemRef::ModuleDecl(ModuleDecl::ExportDecl(export)) => { - if let Some(origin) = find_type_param_in_decl(&export.decl, target_id) { - return Some(origin); - } - } - ModuleItemRef::Stmt(Stmt::Decl(decl)) => { - if let Some(origin) = find_type_param_in_decl(decl, target_id) { - return Some(origin); - } - } - ModuleItemRef::ModuleDecl(ModuleDecl::ExportDefaultDecl(export)) => { - match &export.decl { - DefaultDecl::Class(class_expr) => { - if let Some(origin) = find_type_param_in_class( - &class_expr.class, - class_expr - .ident - .as_ref() - .map(|i| i.sym.as_ref()) - .unwrap_or("default"), - target_id, - ) { - return Some(origin); - } - } - DefaultDecl::Fn(fn_expr) => { - if has_type_param(&fn_expr.function.type_params, target_id) { - let name = fn_expr - .ident - .as_ref() - .map(|i| i.sym.to_string()) - .unwrap_or_else(|| "default".to_string()); - return Some((name, TypeParamDeclaringKind::Function)); - } - } - DefaultDecl::TsInterfaceDecl(iface) => { - if let Some(origin) = find_type_param_in_interface(iface, target_id) - { - return Some(origin); - } - } - } - } - _ => {} + elem: &TSTupleElement, +) -> TsTypeDef { + match elem { + TSTupleElement::TSOptionalType(opt) => { + TsTypeDef::ts_optional_type(module_info, opt) } - } - - None -} - -fn find_type_param_in_decl( - decl: &Decl, - target_id: &Id, -) -> Option<(String, TypeParamDeclaringKind)> { - match decl { - Decl::Class(class_decl) => find_type_param_in_class( - &class_decl.class, - class_decl.ident.sym.as_ref(), - target_id, - ), - Decl::Fn(fn_decl) => { - if has_type_param(&fn_decl.function.type_params, target_id) { - Some(( - fn_decl.ident.sym.to_string(), - TypeParamDeclaringKind::Function, - )) - } else { - None - } + TSTupleElement::TSRestType(rest) => { + TsTypeDef::ts_rest_type(module_info, rest) } - Decl::TsInterface(iface) => find_type_param_in_interface(iface, target_id), - Decl::TsTypeAlias(alias) => { - if has_type_param(&alias.type_params, target_id) { - Some((alias.id.sym.to_string(), TypeParamDeclaringKind::TypeAlias)) - } else { - None - } + TSTupleElement::TSAnyKeyword(_) => TsTypeDef::keyword("any"), + TSTupleElement::TSUnknownKeyword(_) => TsTypeDef::keyword("unknown"), + TSTupleElement::TSNumberKeyword(_) => TsTypeDef::keyword("number"), + TSTupleElement::TSObjectKeyword(_) => TsTypeDef::keyword("object"), + TSTupleElement::TSBooleanKeyword(_) => TsTypeDef::keyword("boolean"), + TSTupleElement::TSBigIntKeyword(_) => TsTypeDef::keyword("bigint"), + TSTupleElement::TSStringKeyword(_) => TsTypeDef::keyword("string"), + TSTupleElement::TSSymbolKeyword(_) => TsTypeDef::keyword("symbol"), + TSTupleElement::TSVoidKeyword(_) => TsTypeDef::keyword("void"), + TSTupleElement::TSUndefinedKeyword(_) => TsTypeDef::keyword("undefined"), + TSTupleElement::TSNullKeyword(_) => TsTypeDef::keyword("null"), + TSTupleElement::TSNeverKeyword(_) => TsTypeDef::keyword("never"), + TSTupleElement::TSIntrinsicKeyword(_) => TsTypeDef::keyword("intrinsic"), + TSTupleElement::TSThisType(t) => TsTypeDef::ts_this_type(t), + TSTupleElement::TSFunctionType(t) => TsTypeDef::ts_fn_type(module_info, t), + TSTupleElement::TSConstructorType(t) => { + TsTypeDef::ts_constructor_type(module_info, t) } - Decl::TsModule(ts_module) => { - // Check declarations inside namespaces - if let Some(TsNamespaceBody::TsModuleBlock(block)) = &ts_module.body { - for item in &block.body { - let inner_decl = match item { - ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export)) => { - Some(&export.decl) - } - ModuleItem::Stmt(Stmt::Decl(decl)) => Some(decl), - _ => None, - }; - if let Some(origin) = inner_decl.and_then(|inner_decl| { - find_type_param_in_decl(inner_decl, target_id) - }) { - return Some(origin); - } - } - } - None + TSTupleElement::TSTypeReference(t) => { + TsTypeDef::ts_type_ref(module_info, t) } - _ => None, - } -} - -fn find_type_param_in_class( - class: &Class, - class_name: &str, - target_id: &Id, -) -> Option<(String, TypeParamDeclaringKind)> { - if has_type_param(&class.type_params, target_id) { - return Some((class_name.to_string(), TypeParamDeclaringKind::Class)); - } - - // Check method type params - for member in &class.body { - if let ClassMember::Method(method) = member - && has_type_param(&method.function.type_params, target_id) - { - let method_name = simple_prop_name(&method.key); - return Some((method_name, TypeParamDeclaringKind::Method)); + TSTupleElement::TSTypeQuery(t) => TsTypeDef::ts_type_query(t), + TSTupleElement::TSTypeLiteral(t) => TsTypeDef::ts_type_lit(module_info, t), + TSTupleElement::TSArrayType(t) => TsTypeDef::ts_array_type(module_info, t), + TSTupleElement::TSTupleType(t) => TsTypeDef::ts_tuple_type(module_info, t), + TSTupleElement::TSUnionType(t) => TsTypeDef::ts_union_type(module_info, t), + TSTupleElement::TSIntersectionType(t) => { + TsTypeDef::ts_intersection_type(module_info, t) } - } - - None -} - -fn find_type_param_in_interface( - iface: &TsInterfaceDecl, - target_id: &Id, -) -> Option<(String, TypeParamDeclaringKind)> { - if has_type_param(&iface.type_params, target_id) { - return Some((iface.id.sym.to_string(), TypeParamDeclaringKind::Interface)); - } - - // Check method type params - for member in &iface.body.body { - match member { - TsTypeElement::TsMethodSignature(method) => { - if has_type_param(&method.type_params, target_id) { - let method_name = simple_expr_name(&method.key); - return Some((method_name, TypeParamDeclaringKind::Method)); - } - } - TsTypeElement::TsConstructSignatureDecl(ctor) => { - if has_type_param(&ctor.type_params, target_id) { - return Some(("new".to_string(), TypeParamDeclaringKind::Method)); - } - } - TsTypeElement::TsCallSignatureDecl(call) => { - if has_type_param(&call.type_params, target_id) { - return Some(("call".to_string(), TypeParamDeclaringKind::Method)); - } - } - _ => {} + TSTupleElement::TSConditionalType(t) => { + TsTypeDef::ts_conditional_type(module_info, t) } + TSTupleElement::TSInferType(t) => TsTypeDef::ts_infer_type(module_info, t), + TSTupleElement::TSParenthesizedType(t) => { + TsTypeDef::ts_parenthesized_type(module_info, t) + } + TSTupleElement::TSTypeOperatorType(t) => { + TsTypeDef::ts_type_operator(module_info, t) + } + TSTupleElement::TSIndexedAccessType(t) => { + TsTypeDef::ts_indexed_access_type(module_info, t) + } + TSTupleElement::TSMappedType(t) => { + TsTypeDef::ts_mapped_type(module_info, t) + } + TSTupleElement::TSLiteralType(t) => TsTypeDef::ts_lit_type(module_info, t), + TSTupleElement::TSTypePredicate(t) => { + TsTypeDef::ts_type_predicate(module_info, t) + } + TSTupleElement::TSImportType(t) => { + TsTypeDef::ts_import_type(module_info, t) + } + TSTupleElement::TSNamedTupleMember(t) => { + TsTypeDef::ts_named_tuple_member(module_info, t) + } + TSTupleElement::TSTemplateLiteralType(t) => { + TsTypeDef::ts_template_literal_type(module_info, t) + } + TSTupleElement::JSDocNullableType(_) + | TSTupleElement::JSDocNonNullableType(_) + | TSTupleElement::JSDocUnknownType(_) => TsTypeDef::keyword("unknown"), } - - None -} - -fn simple_prop_name(prop_name: &PropName) -> String { - match prop_name { - PropName::Ident(ident) => ident.sym.to_string(), - PropName::Str(str_) => str_.value.to_string_lossy().into_owned(), - PropName::Num(num) => num.value.to_string(), - PropName::BigInt(num) => num.value.to_string(), - PropName::Computed(_) => "[computed]".to_string(), - } -} - -fn simple_expr_name(expr: &Expr) -> String { - match expr { - Expr::Ident(ident) => ident.sym.to_string(), - _ => "[computed]".to_string(), - } -} - -fn has_type_param( - type_params: &Option>, - target_id: &Id, -) -> bool { - type_params - .as_ref() - .is_some_and(|tp| tp.params.iter().any(|p| p.name.to_id() == *target_id)) } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] @@ -1049,20 +1092,21 @@ pub struct TsFnOrConstructorDef { } impl TsFnOrConstructorDef { - fn arrow_expr(module_info: &EsModuleInfo, expr: &ArrowExpr) -> Self { - let params = expr - .params - .iter() - .map(|pat| pat_to_param_def(module_info, pat)) - .collect(); + fn arrow_expr( + module_info: &EsModuleInfo, + expr: &ArrowFunctionExpression, + ) -> Self { + let params = formal_params_to_param_defs(module_info, &expr.params); let ts_type = expr .return_type .as_deref() - .map(|return_type| TsTypeDef::new(module_info, &return_type.type_ann)) + .map(|return_type| { + TsTypeDef::new(module_info, &return_type.type_annotation) + }) .unwrap_or_else(|| TsTypeDef::keyword("unknown")); let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - expr.type_params.as_deref(), + expr.type_parameters.as_deref(), ); Self { @@ -1073,22 +1117,18 @@ impl TsFnOrConstructorDef { } } - fn fn_expr(module_info: &EsModuleInfo, expr: &FnExpr) -> Self { - let params = expr - .function - .params - .iter() - .map(|param| pat_to_param_def(module_info, ¶m.pat)) - .collect(); + fn fn_expr(module_info: &EsModuleInfo, expr: &Function) -> Self { + let params = formal_params_to_param_defs(module_info, &expr.params); let ts_type = expr - .function .return_type .as_deref() - .map(|return_type| TsTypeDef::new(module_info, &return_type.type_ann)) + .map(|return_type| { + TsTypeDef::new(module_info, &return_type.type_annotation) + }) .unwrap_or_else(|| TsTypeDef::keyword("unknown")); let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - expr.function.type_params.as_deref(), + expr.type_parameters.as_deref(), ); Self { @@ -1455,18 +1495,6 @@ pub enum ThisOrIdent { Identifier { name: String }, } -impl From<&TsThisTypeOrIdent> for ThisOrIdent { - fn from(other: &TsThisTypeOrIdent) -> ThisOrIdent { - use TsThisTypeOrIdent::*; - match other { - TsThisType(_) => Self::This, - Ident(ident) => Self::Identifier { - name: ident.sym.to_string(), - }, - } - } -} - /// ```ts /// function foo(param: any): asserts param is SomeType { ... } /// ^^^^^^^ ^^^^^ ^^^^^^^^ @@ -1506,7 +1534,7 @@ impl Display for TsTypePredicateDef { } impl TsTypeDef { - pub fn number_literal(num: &Number) -> Self { + pub fn number_literal(num: &NumericLiteral) -> Self { Self::number_value(num.value) } @@ -1522,8 +1550,8 @@ impl TsTypeDef { Self::literal(repr, lit) } - pub fn string_literal(str_node: &Str) -> Self { - Self::string_value(str_node.value.to_string_lossy().into_owned()) + pub fn string_literal(str_node: &StringLiteral) -> Self { + Self::string_value(str_node.value.to_string()) } pub fn string_value(value: String) -> Self { @@ -1538,7 +1566,10 @@ impl TsTypeDef { Self::literal(repr, lit) } - pub fn tpl_literal(types: Vec, quasis: &[TplElement]) -> Self { + pub fn tpl_literal( + types: Vec, + quasis: &[TemplateElement], + ) -> Self { let mut types_out: Vec<(Self, String)> = Vec::new(); for ts_type in types { let repr = format!("${{{}}}", ts_type); @@ -1546,7 +1577,7 @@ impl TsTypeDef { } let mut qasis_out: Vec<(Self, String)> = Vec::new(); for quasi in quasis { - let repr = quasi.raw.to_string(); + let repr = quasi.value.raw.to_string(); let lit = LiteralDef { kind: LiteralDefKind::String, number: None, @@ -1580,7 +1611,7 @@ impl TsTypeDef { Self::literal(repr, lit) } - pub fn bool_literal(bool_node: &Bool) -> Self { + pub fn bool_literal(bool_node: &BooleanLiteral) -> Self { Self::bool_value(bool_node.value) } @@ -1596,12 +1627,19 @@ impl TsTypeDef { Self::literal(repr, lit) } - pub fn bigint_literal(bigint_node: &BigInt) -> Self { - let repr = bigint_node.value.to_string(); + pub fn bigint_literal(bigint_node: &BigIntLiteral) -> Self { + let repr = bigint_node + .raw + .as_ref() + .map(|r| { + let s = r.as_str(); + s.strip_suffix('n').unwrap_or(s).to_string() + }) + .unwrap_or_default(); let lit = LiteralDef { kind: LiteralDefKind::BigInt, number: None, - string: Some(bigint_node.value.to_string()), + string: Some(repr.clone()), ts_types: None, boolean: None, }; @@ -1667,86 +1705,120 @@ impl TsTypeDef { pub(crate) fn infer_ts_type_from_expr( module_info: &EsModuleInfo, - expr: &Expr, + expr: &Expression, is_const: bool, ) -> Option { match expr { - Expr::Array(arr_lit) => { + Expression::ArrayExpression(arr_lit) => { // e.g.) const n = ["a", 1]; infer_ts_type_from_arr_lit(module_info, arr_lit, false) } - Expr::Arrow(expr) => { + Expression::ArrowFunctionExpression(expr) => { // e.g.) const f = (a: string): void => {}; infer_ts_type_from_arrow_expr(module_info, expr) } - Expr::Fn(expr) => { + Expression::FunctionExpression(expr) => { // e.g.) const f = function a(a:string): void {}; infer_ts_type_from_fn_expr(module_info, expr) } - Expr::Lit(lit) => { - // e.g.) const n = 100; - infer_ts_type_from_lit(lit, is_const) + Expression::NumericLiteral(num) => { + if is_const { + Some(TsTypeDef::number_literal(num)) + } else { + Some(TsTypeDef::number_with_repr("number")) + } + } + Expression::StringLiteral(str_) => { + if is_const && str_.value.len() < 100 { + Some(TsTypeDef::string_literal(str_)) + } else { + Some(TsTypeDef::string_with_repr("string")) + } + } + Expression::BooleanLiteral(bool_) => { + if is_const { + Some(TsTypeDef::bool_literal(bool_)) + } else { + Some(TsTypeDef::bool_with_repr("boolean")) + } + } + Expression::BigIntLiteral(bigint_) => { + if is_const { + Some(TsTypeDef::bigint_literal(bigint_)) + } else { + Some(TsTypeDef::bigint_with_repr("bigint")) + } + } + Expression::RegExpLiteral(regex) => { + Some(TsTypeDef::regexp(regex.regex.pattern.text.to_string())) } - Expr::New(expr) => { + Expression::NullLiteral(_) => Some(TsTypeDef::keyword("null")), + Expression::NewExpression(expr) => { // e.g.) const d = new Date() infer_ts_type_from_new_expr(module_info, expr) } - Expr::Tpl(tpl) => { + Expression::TemplateLiteral(tpl) => { // e.g.) const s = `hello`; Some(infer_ts_type_from_tpl(module_info, tpl, is_const)) } - Expr::TsConstAssertion(assertion) => { - // e.g.) const s = [] as const; - infer_ts_type_from_const_assertion(module_info, assertion) + Expression::TSAsExpression(as_expr) => { + if is_const_assertion(&as_expr.type_annotation) { + match &as_expr.expression { + Expression::ArrayExpression(arr) => { + infer_ts_type_from_arr_lit(module_info, arr, true) + } + _ => infer_ts_type_from_expr(module_info, &as_expr.expression, true), + } + } else { + Some(TsTypeDef::new(module_info, &as_expr.type_annotation)) + } } - Expr::Call(expr) => { + Expression::CallExpression(expr) => { // e.g.) const value = Number(123); infer_ts_type_from_call_expr(expr) } - Expr::Object(obj) => { + Expression::ObjectExpression(obj) => { // e.g.) const value = {foo: "bar"}; infer_ts_type_from_obj(module_info, obj) } - Expr::TsSatisfies(satisfies) => { + Expression::TSSatisfiesExpression(satisfies) => { // e.g.) const value = {foo: "bar"} satifies Record; - infer_ts_type_from_expr(module_info, &satisfies.expr, is_const) + infer_ts_type_from_expr(module_info, &satisfies.expression, is_const) } - Expr::Update(_) => { + Expression::UpdateExpression(_) => { // e.g.) let foo = 0; // const bar = foo++; Some(TsTypeDef::number_with_repr("number")) } - Expr::TsTypeAssertion(assertion) => { + Expression::TSTypeAssertion(assertion) => { // e.g.) export const foo = 1; - Some(TsTypeDef::new(module_info, &assertion.type_ann)) + Some(TsTypeDef::new(module_info, &assertion.type_annotation)) } - Expr::TsAs(as_expr) => { - // e.g.) export const foo = 1 as string; - Some(TsTypeDef::new(module_info, &as_expr.type_ann)) - } - Expr::Paren(paren) => { + Expression::ParenthesizedExpression(paren) => { // e.g.) export const foo = (1); - infer_ts_type_from_expr(module_info, &paren.expr, is_const) + infer_ts_type_from_expr(module_info, &paren.expression, is_const) } - Expr::Await(await_expr) => { + Expression::AwaitExpression(await_expr) => { // e.g.) export const foo = await 1; - infer_ts_type_from_expr(module_info, &await_expr.arg, is_const) + infer_ts_type_from_expr(module_info, &await_expr.argument, is_const) } - Expr::Cond(cond) => { + Expression::ConditionalExpression(cond) => { // e.g.) export const foo = true ? "a" : 1; - let left = infer_ts_type_from_expr(module_info, &cond.cons, is_const)?; - let right = infer_ts_type_from_expr(module_info, &cond.alt, is_const)?; + let left = + infer_ts_type_from_expr(module_info, &cond.consequent, is_const)?; + let right = + infer_ts_type_from_expr(module_info, &cond.alternate, is_const)?; Some(TsTypeDef { kind: TsTypeDefKind::Union(vec![left, right]), repr: String::new(), }) } - Expr::TsNonNull(non_null) => { + Expression::TSNonNullExpression(non_null) => { // e.g.) export const foo = (true ? "a" : null)!; // e.g.) export const foo = null!; let with_null = - infer_ts_type_from_expr(module_info, &non_null.expr, is_const)?; + infer_ts_type_from_expr(module_info, &non_null.expression, is_const)?; if let TsTypeDefKind::Union(union) = with_null.kind { let mut non_null_union = union @@ -1776,63 +1848,65 @@ pub(crate) fn infer_ts_type_from_expr( None } } - Expr::Bin(bin) => { + Expression::BinaryExpression(bin) => { // e.g.) export const foo = 1 == "bar"; // e.g.) export const foo = 1 >> 1; - match bin.op { - BinaryOp::EqEq - | BinaryOp::NotEq - | BinaryOp::EqEqEq - | BinaryOp::NotEqEq - | BinaryOp::Lt - | BinaryOp::LtEq - | BinaryOp::Gt - | BinaryOp::GtEq - | BinaryOp::In - | BinaryOp::InstanceOf => Some(TsTypeDef::bool_with_repr("boolean")), - BinaryOp::LShift - | BinaryOp::RShift - | BinaryOp::ZeroFillRShift - | BinaryOp::Sub - | BinaryOp::Mul - | BinaryOp::Div - | BinaryOp::Mod - | BinaryOp::BitOr - | BinaryOp::BitXor - | BinaryOp::BitAnd - | BinaryOp::Exp => Some(TsTypeDef::number_with_repr("number")), - BinaryOp::LogicalOr - | BinaryOp::LogicalAnd - | BinaryOp::NullishCoalescing - | BinaryOp::Add => None, + match bin.operator { + BinaryOperator::Equality + | BinaryOperator::Inequality + | BinaryOperator::StrictEquality + | BinaryOperator::StrictInequality + | BinaryOperator::LessThan + | BinaryOperator::LessEqualThan + | BinaryOperator::GreaterThan + | BinaryOperator::GreaterEqualThan + | BinaryOperator::In + | BinaryOperator::Instanceof => { + Some(TsTypeDef::bool_with_repr("boolean")) + } + BinaryOperator::ShiftLeft + | BinaryOperator::ShiftRight + | BinaryOperator::ShiftRightZeroFill + | BinaryOperator::Subtraction + | BinaryOperator::Multiplication + | BinaryOperator::Division + | BinaryOperator::Remainder + | BinaryOperator::BitwiseOR + | BinaryOperator::BitwiseXOR + | BinaryOperator::BitwiseAnd + | BinaryOperator::Exponential => { + Some(TsTypeDef::number_with_repr("number")) + } + BinaryOperator::Addition => None, } } - Expr::This(_) - | Expr::Unary(_) - | Expr::Assign(_) - | Expr::Member(_) - | Expr::SuperProp(_) - | Expr::Seq(_) - | Expr::Ident(_) - | Expr::TaggedTpl(_) - | Expr::Class(_) - | Expr::Yield(_) - | Expr::MetaProp(_) - | Expr::JSXMember(_) - | Expr::JSXNamespacedName(_) - | Expr::JSXEmpty(_) - | Expr::JSXElement(_) - | Expr::JSXFragment(_) - | Expr::TsInstantiation(_) - | Expr::PrivateName(_) - | Expr::OptChain(_) - | Expr::Invalid(_) => None, + Expression::LogicalExpression(_) + | Expression::ThisExpression(_) + | Expression::UnaryExpression(_) + | Expression::AssignmentExpression(_) + | Expression::StaticMemberExpression(_) + | Expression::ComputedMemberExpression(_) + | Expression::PrivateFieldExpression(_) + | Expression::Super(_) + | Expression::SequenceExpression(_) + | Expression::Identifier(_) + | Expression::TaggedTemplateExpression(_) + | Expression::ClassExpression(_) + | Expression::YieldExpression(_) + | Expression::MetaProperty(_) + | Expression::JSXElement(_) + | Expression::JSXFragment(_) + | Expression::TSInstantiationExpression(_) + | Expression::ChainExpression(_) + | Expression::ImportExpression(_) + | Expression::PrivateInExpression(_) + | Expression::V8IntrinsicExpression(_) => None, } } pub(crate) fn infer_simple_ts_type_from_init( module_info: &EsModuleInfo, - init: Option<&Expr>, + init: Option<&Expression>, is_const: bool, ) -> Option { if let Some(init_expr) = init { @@ -1844,32 +1918,36 @@ pub(crate) fn infer_simple_ts_type_from_init( fn infer_ts_type_from_arr_lit( module_info: &EsModuleInfo, - arr_lit: &ArrayLit, + arr_lit: &ArrayExpression, is_const: bool, ) -> Option { let mut defs = Vec::new(); - for expr in arr_lit.elems.iter().flatten() { - if expr.spread.is_none() { - if let Some(ts_type) = - infer_ts_type_from_expr(module_info, &expr.expr, is_const) - { - if !defs.contains(&ts_type) { - defs.push(ts_type); - } - } else { - // it is not a trivial type that can be inferred an so will infer an - // an any array. + for elem in &arr_lit.elements { + match elem { + ArrayExpressionElement::SpreadElement(_) => { return Some(TsTypeDef { repr: "any[]".to_string(), kind: TsTypeDefKind::Array(Box::new(TsTypeDef::keyword("any"))), }); } - } else { - // TODO(@kitsonk) we should recursively unwrap the spread here - return Some(TsTypeDef { - repr: "any[]".to_string(), - kind: TsTypeDefKind::Array(Box::new(TsTypeDef::keyword("any"))), - }); + ArrayExpressionElement::Elision(_) => continue, + _ => { + let expr = elem.to_expression(); + if let Some(ts_type) = + infer_ts_type_from_expr(module_info, expr, is_const) + { + if !defs.contains(&ts_type) { + defs.push(ts_type); + } + } else { + // it is not a trivial type that can be inferred an so will infer an + // an any array. + return Some(TsTypeDef { + repr: "any[]".to_string(), + kind: TsTypeDefKind::Array(Box::new(TsTypeDef::keyword("any"))), + }); + } + } } } match defs.len() { @@ -1893,7 +1971,7 @@ fn infer_ts_type_from_arr_lit( fn infer_ts_type_from_arrow_expr( module_info: &EsModuleInfo, - expr: &ArrowExpr, + expr: &ArrowFunctionExpression, ) -> Option { Some(TsTypeDef { kind: TsTypeDefKind::FnOrConstructor(Box::new( @@ -1905,7 +1983,7 @@ fn infer_ts_type_from_arrow_expr( fn infer_ts_type_from_fn_expr( module_info: &EsModuleInfo, - expr: &FnExpr, + expr: &Function, ) -> Option { Some(TsTypeDef { kind: TsTypeDefKind::FnOrConstructor(Box::new( @@ -1915,67 +1993,26 @@ fn infer_ts_type_from_fn_expr( }) } -fn infer_ts_type_from_const_assertion( - module_info: &EsModuleInfo, - assertion: &TsConstAssertion, -) -> Option { - match &*assertion.expr { - Expr::Array(arr_lit) => { - // e.g.) const n = ["a", 1] as const; - infer_ts_type_from_arr_lit(module_info, arr_lit, true) - } - _ => infer_ts_type_from_expr(module_info, &assertion.expr, true), - } -} - -fn infer_ts_type_from_lit(lit: &Lit, is_const: bool) -> Option { - match lit { - Lit::Num(num) => { - if is_const { - Some(TsTypeDef::number_literal(num)) - } else { - Some(TsTypeDef::number_with_repr("number")) - } - } - Lit::Str(str_) => { - if is_const && str_.value.len() < 100 { - Some(TsTypeDef::string_literal(str_)) - } else { - Some(TsTypeDef::string_with_repr("string")) - } - } - Lit::Bool(bool_) => { - if is_const { - Some(TsTypeDef::bool_literal(bool_)) - } else { - Some(TsTypeDef::bool_with_repr("boolean")) - } - } - Lit::BigInt(bigint_) => { - if is_const { - Some(TsTypeDef::bigint_literal(bigint_)) - } else { - Some(TsTypeDef::bigint_with_repr("bigint")) - } - } - Lit::Regex(regex) => Some(TsTypeDef::regexp(regex.exp.to_string())), - Lit::Null(_null) => Some(TsTypeDef::keyword("null")), - Lit::JSXText(_) => None, - } +fn is_const_assertion(ts_type: &TSType) -> bool { + matches!( + ts_type, + TSType::TSTypeReference(type_ref) + if matches!(&type_ref.type_name, TSTypeName::IdentifierReference(ident) if ident.name == "const") + ) } fn infer_ts_type_from_new_expr( module_info: &EsModuleInfo, - new_expr: &NewExpr, + new_expr: &NewExpression, ) -> Option { - match new_expr.callee.as_ref() { - Expr::Ident(ident) => Some(TsTypeDef { - repr: ident.sym.to_string(), + match &new_expr.callee { + Expression::Identifier(ident) => Some(TsTypeDef { + repr: ident.name.to_string(), kind: TsTypeDefKind::TypeRef(TsTypeRefDef { - type_params: new_expr.type_args.as_ref().map(|init| { + type_params: new_expr.type_arguments.as_ref().map(|init| { maybe_type_param_instantiation_to_type_defs(module_info, Some(init)) }), - type_name: ident.sym.to_string(), + type_name: ident.name.to_string(), resolution: resolve_type_ref(module_info, ident), }), }), @@ -1983,33 +2020,27 @@ fn infer_ts_type_from_new_expr( } } -fn infer_ts_type_from_call_expr(call_expr: &CallExpr) -> Option { - match &call_expr.callee { - Callee::Expr(expr) => { - if let Expr::Ident(ident) = expr.as_ref() { - let sym = ident.sym.to_string(); - match sym.as_str() { - "Symbol" | "Number" | "String" | "BigInt" => { - Some(TsTypeDef::keyword_with_repr( - &sym.to_ascii_lowercase(), - &sym.clone(), - )) - } - "Date" => Some(TsTypeDef::string_with_repr(&sym)), - "RegExp" => Some(TsTypeDef::regexp(sym)), - _ => None, - } - } else { - None - } +fn infer_ts_type_from_call_expr( + call_expr: &CallExpression, +) -> Option { + if let Expression::Identifier(ident) = &call_expr.callee { + let sym = ident.name.to_string(); + match sym.as_str() { + "Symbol" | "Number" | "String" | "BigInt" => Some( + TsTypeDef::keyword_with_repr(&sym.to_ascii_lowercase(), &sym.clone()), + ), + "Date" => Some(TsTypeDef::string_with_repr(&sym)), + "RegExp" => Some(TsTypeDef::regexp(sym)), + _ => None, } - _ => None, + } else { + None } } fn infer_ts_type_from_obj( module_info: &EsModuleInfo, - obj: &ObjectLit, + obj: &ObjectExpression, ) -> Option { let (methods, properties) = infer_ts_type_from_obj_inner(module_info, obj); if methods.is_empty() && properties.is_empty() { @@ -2021,24 +2052,27 @@ fn infer_ts_type_from_obj( fn infer_ts_type_from_obj_inner( module_info: &EsModuleInfo, - obj: &ObjectLit, + obj: &ObjectExpression, ) -> (Vec, Vec) { let mut methods = Vec::::new(); let mut properties = Vec::::new(); - for obj_prop in &obj.props { - let Some(js_doc) = js_doc_for_range(module_info, &obj_prop.range()) else { + for obj_prop in &obj.properties { + let Some(js_doc) = js_doc_for_range(module_info, obj_prop.span()) else { continue; }; match obj_prop { - PropOrSpread::Prop(prop) => match &**prop { - Prop::Shorthand(shorthand) => { - // TODO(@crowlKats) we should pass previous nodes and take the type - // from the previous symbol. + ObjectPropertyKind::ObjectProperty(prop) => { + if prop.shorthand { + let name = prop + .key + .static_name() + .map(|name| name.to_string()) + .unwrap_or_else(|| "[UNSUPPORTED]".to_string()); properties.push(PropertyDef { - name: shorthand.sym.to_string(), + name, js_doc, - location: get_location(module_info, shorthand.start()), + location: get_location(module_info, prop.span.start), params: vec![], readonly: false, computed: false, @@ -2046,89 +2080,88 @@ fn infer_ts_type_from_obj_inner( ts_type: None, type_params: Box::new([]), }); - } - Prop::KeyValue(kv) => { - properties.push(PropertyDef { - name: prop_name_to_string(module_info, &kv.key), - js_doc, - location: get_location(module_info, kv.start()), - params: vec![], - readonly: false, - computed: kv.key.is_computed(), - optional: false, - ts_type: infer_ts_type_from_expr(module_info, &kv.value, false), - type_params: Box::new([]), - }); - } - Prop::Assign(_) => unreachable!("This is invalid for object literal!"), - Prop::Getter(getter) => { - let name = prop_name_to_string(module_info, &getter.key); - let computed = getter.key.is_computed(); - let return_type = getter - .type_ann - .as_ref() - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)); + } else if prop.kind == PropertyKind::Get { + let name = prop_name_to_string(module_info, &prop.key); + let computed = prop.key.static_name().is_none(); + let return_type = + if let Expression::FunctionExpression(func) = &prop.value { + func.return_type.as_ref().map(|type_ann| { + TsTypeDef::new(module_info, &type_ann.type_annotation) + }) + } else { + None + }; methods.push(MethodDef { name, js_doc, kind: MethodKind::Getter, - location: get_location(module_info, getter.start()), + location: get_location(module_info, prop.span.start), params: vec![], computed, optional: false, return_type, type_params: Box::new([]), }); - } - Prop::Setter(setter) => { - let name = prop_name_to_string(module_info, &setter.key); - let computed = setter.key.is_computed(); - let param = pat_to_param_def(module_info, setter.param.as_ref()); + } else if prop.kind == PropertyKind::Set { + let name = prop_name_to_string(module_info, &prop.key); + let computed = prop.key.static_name().is_none(); + let params = if let Expression::FunctionExpression(func) = &prop.value + { + formal_params_to_param_defs(module_info, &func.params) + } else { + vec![] + }; methods.push(MethodDef { name, js_doc, kind: MethodKind::Setter, - location: get_location(module_info, setter.start()), - params: vec![param], + location: get_location(module_info, prop.span.start), + params, computed, optional: false, return_type: None, type_params: Box::new([]), }); - } - Prop::Method(method) => { - let name = prop_name_to_string(module_info, &method.key); - let computed = method.key.is_computed(); - let params = method - .function - .params - .iter() - .map(|param| param_to_param_def(module_info, param)) - .collect(); - let return_type = method - .function - .return_type - .as_ref() - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)); - let type_params = maybe_type_param_decl_to_type_param_defs( - module_info, - method.function.type_params.as_deref(), - ); - methods.push(MethodDef { - name, + } else if prop.method { + let name = prop_name_to_string(module_info, &prop.key); + let computed = prop.key.static_name().is_none(); + if let Expression::FunctionExpression(func) = &prop.value { + let params = formal_params_to_param_defs(module_info, &func.params); + let return_type = func.return_type.as_ref().map(|type_ann| { + TsTypeDef::new(module_info, &type_ann.type_annotation) + }); + let type_params = maybe_type_param_decl_to_type_param_defs( + module_info, + func.type_parameters.as_deref(), + ); + methods.push(MethodDef { + name, + js_doc, + kind: MethodKind::Method, + location: get_location(module_info, prop.span.start), + params, + computed, + optional: false, + return_type, + type_params, + }); + } + } else { + properties.push(PropertyDef { + name: prop_name_to_string(module_info, &prop.key), js_doc, - kind: MethodKind::Method, - location: get_location(module_info, method.start()), - params, - computed, + location: get_location(module_info, prop.span.start), + params: vec![], + readonly: false, + computed: prop.key.static_name().is_none(), optional: false, - return_type, - type_params, + ts_type: infer_ts_type_from_expr(module_info, &prop.value, false), + type_params: Box::new([]), }); } - }, - PropOrSpread::Spread(spread) => { - if let Expr::Object(obj) = &*spread.expr { + } + ObjectPropertyKind::SpreadProperty(spread) => { + if let Expression::ObjectExpression(obj) = &spread.argument { let (spread_methods, spread_properties) = infer_ts_type_from_obj_inner(module_info, obj); methods.extend(spread_methods); @@ -2142,11 +2175,11 @@ fn infer_ts_type_from_obj_inner( fn infer_ts_type_from_tpl( module_info: &EsModuleInfo, - tpl: &Tpl, + tpl: &TemplateLiteral, is_const: bool, ) -> TsTypeDef { let exprs = tpl - .exprs + .expressions .iter() .map(|expr| infer_ts_type_from_expr(module_info, expr, is_const)) .collect::>>(); @@ -2350,7 +2383,7 @@ impl Display for TsTypeDef { pub(crate) fn maybe_type_param_instantiation_to_type_defs( module_info: &EsModuleInfo, - maybe_type_param_instantiation: Option<&TsTypeParamInstantiation>, + maybe_type_param_instantiation: Option<&TSTypeParameterInstantiation>, ) -> Box<[TsTypeDef]> { if let Some(type_param_instantiation) = maybe_type_param_instantiation { type_param_instantiation diff --git a/src/ts_type_param.rs b/src/ts_type_param.rs index bd5a87b18..6324d07c3 100644 --- a/src/ts_type_param.rs +++ b/src/ts_type_param.rs @@ -1,8 +1,8 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use crate::ts_type::TsTypeDef; -use deno_ast::swc::ast::TsTypeParam; -use deno_ast::swc::ast::TsTypeParamDecl; +use deno_ast::oxc::ast::ast::TSTypeParameter; +use deno_ast::oxc::ast::ast::TSTypeParameterDeclaration; use deno_graph::symbols::EsModuleInfo; use serde::Deserialize; use serde::Serialize; @@ -36,8 +36,8 @@ impl Display for TsTypeParamDef { } impl TsTypeParamDef { - pub fn new(module_info: &EsModuleInfo, param: &TsTypeParam) -> Self { - let name = param.name.sym.to_string(); + pub fn new(module_info: &EsModuleInfo, param: &TSTypeParameter) -> Self { + let name = param.name.name.to_string(); let constraint = param .constraint .as_ref() @@ -57,7 +57,7 @@ impl TsTypeParamDef { pub(crate) fn maybe_type_param_decl_to_type_param_defs( module_info: &EsModuleInfo, - maybe_type_param_decl: Option<&TsTypeParamDecl>, + maybe_type_param_decl: Option<&TSTypeParameterDeclaration>, ) -> Box<[TsTypeParamDef]> { if let Some(type_params_decl) = maybe_type_param_decl { type_params_decl diff --git a/src/type_alias.rs b/src/type_alias.rs index 91c820cf7..0c59159b6 100644 --- a/src/type_alias.rs +++ b/src/type_alias.rs @@ -2,6 +2,7 @@ use crate::ts_type::TsTypeDef; use crate::ts_type_param::TsTypeParamDef; use crate::ts_type_param::maybe_type_param_decl_to_type_param_defs; +use deno_ast::oxc::ast::ast::TSTypeAliasDeclaration; use deno_graph::symbols::EsModuleInfo; use serde::Deserialize; use serde::Serialize; @@ -16,12 +17,12 @@ pub struct TypeAliasDef { pub fn get_doc_for_ts_type_alias_decl( module_info: &EsModuleInfo, - type_alias_decl: &deno_ast::swc::ast::TsTypeAliasDecl, + type_alias_decl: &TSTypeAliasDeclaration, ) -> TypeAliasDef { - let ts_type = TsTypeDef::new(module_info, &type_alias_decl.type_ann); + let ts_type = TsTypeDef::new(module_info, &type_alias_decl.type_annotation); let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - type_alias_decl.type_params.as_deref(), + type_alias_decl.type_parameters.as_deref(), ); TypeAliasDef { diff --git a/src/util/mod.rs b/src/util/mod.rs index 7b29a3b04..97fd3d938 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -3,3 +3,4 @@ pub mod graph; pub mod swc; pub mod symbol; +pub mod types; diff --git a/src/util/swc.rs b/src/util/swc.rs index cb49aecc2..bcd9ddf4f 100644 --- a/src/util/swc.rs +++ b/src/util/swc.rs @@ -1,12 +1,9 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_ast::SourcePos; -use deno_ast::SourceRange; -use deno_ast::SourceRangedForSpanned; use deno_ast::SourceTextInfo; -use deno_ast::swc::ast::ModuleExportName; -use deno_ast::swc::common::comments::Comment; -use deno_ast::swc::common::comments::CommentKind; +use deno_ast::oxc::ast::ast::Comment; +use deno_ast::oxc::ast::ast::ModuleExportName; +use deno_ast::oxc::span::Span; use deno_graph::symbols::EsModuleInfo; use regex::Regex; @@ -22,8 +19,15 @@ pub(crate) fn is_false(b: &bool) -> bool { !b } -fn parse_js_doc(js_doc_comment: &Comment, module_info: &EsModuleInfo) -> JsDoc { - JsDoc::new(remove_stars_from_js_doc(&js_doc_comment.text), module_info) +fn parse_js_doc( + source_text: &str, + comment: &Comment, + module_info: &EsModuleInfo, +) -> JsDoc { + let content_span = comment.content_span(); + let text = + &source_text[content_span.start as usize..content_span.end as usize]; + JsDoc::new(remove_stars_from_js_doc(text), module_info) } fn remove_stars_from_js_doc(text: &str) -> String { @@ -38,16 +42,22 @@ fn remove_stars_from_js_doc(text: &str) -> String { pub(crate) fn js_doc_for_range_include_ignore( module_info: &EsModuleInfo, - range: &SourceRange, + span: Span, ) -> JsDoc { - let Some(comments) = module_info.source().comments().get_leading(range.start) - else { - return JsDoc::default(); - }; - if let Some(js_doc_comment) = comments.iter().rev().find(|comment| { - comment.kind == CommentKind::Block && comment.text.starts_with('*') - }) { - parse_js_doc(js_doc_comment, module_info) + let source_text = module_info.source_text(); + let comments = module_info.comments(); + if let Some(js_doc_comment) = comments + .iter() + .rev() + .filter(|c| c.attached_to == span.start && c.is_leading() && c.is_block()) + .find(|c| { + let content_span = c.content_span(); + let text = + &source_text[content_span.start as usize..content_span.end as usize]; + text.starts_with('*') + }) + { + parse_js_doc(source_text, js_doc_comment, module_info) } else { JsDoc::default() } @@ -55,9 +65,9 @@ pub(crate) fn js_doc_for_range_include_ignore( pub(crate) fn js_doc_for_range( module_info: &EsModuleInfo, - range: &SourceRange, + span: Span, ) -> Option { - let js_doc = js_doc_for_range_include_ignore(module_info, range); + let js_doc = js_doc_for_range_include_ignore(module_info, span); if js_doc.tags.contains(&JsDocTag::Ignore) { None } else { @@ -70,38 +80,48 @@ pub(crate) fn js_doc_for_range( /// `None`. pub(crate) fn module_js_doc_for_source( module_info: &EsModuleInfo, -) -> Option> { - module_info - .source() - .comments() - .get_vec() - .into_iter() - .filter(|comment| { - comment.kind == CommentKind::Block && comment.text.starts_with('*') - }) - .find_map(|comment| { - let js_doc = parse_js_doc(&comment, module_info); - - if js_doc - .tags - .iter() - .any(|tag| matches!(tag, JsDocTag::Module { .. })) - { - if js_doc.tags.contains(&JsDocTag::Ignore) { - Some(None) - } else { - Some(Some((js_doc, comment.range()))) - } - } else { - None - } +) -> Option> { + let source_text = module_info.source_text(); + let comments = module_info.comments(); + let statements = module_info.statements(); + + // Find the start of the first statement (or end of file) + let first_stmt_start = statements + .first() + .map(|s| { + use deno_ast::oxc::span::GetSpan; + s.span().start }) + .unwrap_or(u32::MAX); + + // Find leading block comments before the first statement that look like JSDoc + let js_doc_comment = comments.iter().find(|comment| { + comment.span.start < first_stmt_start && comment.is_block() && { + let content_span = comment.content_span(); + let text = + &source_text[content_span.start as usize..content_span.end as usize]; + text.starts_with('*') + } + })?; + + let js_doc = parse_js_doc(source_text, js_doc_comment, module_info); + if js_doc + .tags + .iter() + .any(|tag| matches!(tag, JsDocTag::Module { .. })) + { + if js_doc.tags.contains(&JsDocTag::Ignore) { + return Some(None); + } + return Some(Some((js_doc, js_doc_comment.span))); + } + None } -pub fn get_location(module_info: &EsModuleInfo, pos: SourcePos) -> Location { +pub fn get_location(module_info: &EsModuleInfo, pos: u32) -> Location { get_text_info_location( module_info.specifier().as_str(), - module_info.source().text_info_lazy(), + module_info.source_text_info(), pos, ) } @@ -109,15 +129,36 @@ pub fn get_location(module_info: &EsModuleInfo, pos: SourcePos) -> Location { pub fn get_text_info_location( specifier: &str, text_info: &SourceTextInfo, - pos: SourcePos, + pos: u32, ) -> Location { - let line_and_column_index = - text_info.line_and_column_display_with_indent_width(pos, 2); - let byte_index = pos.as_byte_index(text_info.range().start); + let byte_index = pos as usize; + let line_and_column_index = text_info.line_and_column_display(byte_index); + + // Adjust column for tab indentation (tabs count as 4 spaces for display, + // matching the old SWC behavior with indent_width=4) + let line_start_byte = byte_index - (line_and_column_index.column_number - 1); + let text = text_info.text(); + let col = if line_start_byte < text.len() { + let line_prefix = &text[line_start_byte..byte_index]; + let mut col = 0usize; + for ch in line_prefix.chars() { + if ch == '\t' { + // Round up to next multiple of 4 + col = (col + 4) & !3; + } else { + col += 1; + } + } + col + } else { + line_and_column_index.column_number - 1 + }; + Location { filename: specifier.into(), - line: line_and_column_index.line_number - 1, - col: line_and_column_index.column_number - 1, + // todo(#150): make 0-indexed + line: line_and_column_index.line_number, + col, byte_index, } } @@ -126,8 +167,9 @@ pub fn module_export_name_value( module_export_name: &ModuleExportName, ) -> String { match module_export_name { - ModuleExportName::Ident(ident) => ident.sym.to_string(), - ModuleExportName::Str(str) => str.value.to_string_lossy().into_owned(), + ModuleExportName::IdentifierName(ident) => ident.name.to_string(), + ModuleExportName::IdentifierReference(ident) => ident.name.to_string(), + ModuleExportName::StringLiteral(str) => str.value.to_string(), } } diff --git a/src/util/symbol.rs b/src/util/symbol.rs index f2bcc6f24..581933ec1 100644 --- a/src/util/symbol.rs +++ b/src/util/symbol.rs @@ -49,6 +49,6 @@ fn decl_has_ignorable_js_doc_tag( let Some(module) = module.esm() else { return false; }; - let js_doc = js_doc_for_range_include_ignore(module, &decl.range); + let js_doc = js_doc_for_range_include_ignore(module, decl.range); has_ignorable_js_doc_tag(&js_doc) } diff --git a/src/util/types.rs b/src/util/types.rs new file mode 100644 index 000000000..fce8abe7a --- /dev/null +++ b/src/util/types.rs @@ -0,0 +1,88 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +//! Local wrapper enums for OXC types that need serde support +//! with serialization compatible with the old SWC types. + +use deno_ast::oxc::ast::ast::MethodDefinitionKind; +use deno_ast::oxc::ast::ast::TSAccessibility; +use deno_ast::oxc::ast::ast::TSMethodSignatureKind; +use deno_ast::oxc::ast::ast::VariableDeclarationKind; +use serde::Deserialize; +use serde::Serialize; + +/// Mirrors the old SWC `Accessibility` enum with matching serde. +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum Accessibility { + Public, + Protected, + Private, +} + +impl From for Accessibility { + fn from(a: TSAccessibility) -> Self { + match a { + TSAccessibility::Public => Accessibility::Public, + TSAccessibility::Protected => Accessibility::Protected, + TSAccessibility::Private => Accessibility::Private, + } + } +} + +impl Accessibility { + pub fn from_oxc(a: Option) -> Option { + a.map(Self::from) + } +} + +/// Mirrors the old SWC `MethodKind` enum with matching serde. +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)] +#[serde(rename_all = "camelCase")] +pub enum MethodKind { + Method, + Getter, + Setter, +} + +impl From for MethodKind { + fn from(k: MethodDefinitionKind) -> Self { + match k { + MethodDefinitionKind::Method | MethodDefinitionKind::Constructor => { + MethodKind::Method + } + MethodDefinitionKind::Get => MethodKind::Getter, + MethodDefinitionKind::Set => MethodKind::Setter, + } + } +} + +impl From for MethodKind { + fn from(k: TSMethodSignatureKind) -> Self { + match k { + TSMethodSignatureKind::Method => MethodKind::Method, + TSMethodSignatureKind::Get => MethodKind::Getter, + TSMethodSignatureKind::Set => MethodKind::Setter, + } + } +} + +/// Mirrors the old SWC `VarDeclKind` enum with matching serde. +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub enum VarDeclKind { + Var, + Let, + Const, +} + +impl From for VarDeclKind { + fn from(k: VariableDeclarationKind) -> Self { + match k { + VariableDeclarationKind::Var => VarDeclKind::Var, + VariableDeclarationKind::Let => VarDeclKind::Let, + VariableDeclarationKind::Const + | VariableDeclarationKind::Using + | VariableDeclarationKind::AwaitUsing => VarDeclKind::Const, + } + } +} diff --git a/src/variable.rs b/src/variable.rs index 1ec3fd235..99240b935 100644 --- a/src/variable.rs +++ b/src/variable.rs @@ -1,7 +1,8 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_ast::swc::ast::Pat; -use deno_ast::swc::ast::VarDeclKind; +use deno_ast::oxc::ast::ast::BindingPattern; +use deno_ast::oxc::ast::ast::VariableDeclaration; +use deno_ast::oxc::ast::ast::VariableDeclarator; use deno_graph::symbols::EsModuleInfo; use deno_graph::symbols::SymbolNodeRef; use serde::Deserialize; @@ -10,6 +11,7 @@ use serde::Serialize; use crate::ts_type::TsTypeDef; use crate::ts_type::TsTypeDefKind; use crate::ts_type::infer_simple_ts_type_from_init; +use crate::util::types::VarDeclKind; #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] @@ -21,47 +23,53 @@ pub struct VariableDef { pub fn get_docs_for_var_declarator( module_info: &EsModuleInfo, - var_decl: &deno_ast::swc::ast::VarDecl, - var_declarator: &deno_ast::swc::ast::VarDeclarator, + var_decl: &VariableDeclaration, + var_declarator: &VariableDeclarator, ) -> Vec<(String, VariableDef)> { let mut items = Vec::<(String, VariableDef)>::new(); - let ref_name: Option = - var_declarator.init.as_ref().and_then(|init| { - if let deno_ast::swc::ast::Expr::Ident(ident) = &**init { - Some(ident.to_id()) - } else { - None - } - }); + let kind = VarDeclKind::from(var_decl.kind); + + let ref_ident = var_declarator.init.as_ref().and_then(|init| { + if let deno_ast::oxc::ast::ast::Expression::Identifier(ident) = init { + Some(ident) + } else { + None + } + }); + + let maybe_ts_type_ann = var_declarator.type_annotation.as_deref(); - let maybe_ts_type_ann = match &var_declarator.name { - Pat::Ident(ident) => ident.type_ann.as_ref(), - Pat::Object(pat) => pat.type_ann.as_ref(), - Pat::Array(pat) => pat.type_ann.as_ref(), - Pat::Invalid(_) | Pat::Expr(_) | Pat::Rest(_) | Pat::Assign(_) => None, - }; - let maybe_ts_type = maybe_ts_type_ann - .map(|def| TsTypeDef::new(module_info, &def.type_ann)) + // Type from explicit type annotation only (used for both simple and + // destructured patterns). + let explicit_ts_type = maybe_ts_type_ann + .map(|def| TsTypeDef::new(module_info, &def.type_annotation)); + + // Full inferred type (used only for simple identifier patterns, not + // destructured bindings). + let maybe_ts_type = explicit_ts_type + .clone() .or_else(|| { - if let Some(ref_name) = ref_name { - module_info.symbol_from_swc(&ref_name).and_then(|symbol| { - // todo(dsherret): it would be better to go to the declaration - // here, which is somewhat trivial with type tracing. + if let Some(ref_ident) = ref_ident { + let swc_id = (ref_ident.name.to_string(), 0usize); + module_info.symbol_from_swc(&swc_id).and_then(|symbol| { for decl in symbol.decls() { - if let Some(SymbolNodeRef::Var(_, var_declarator, _)) = + if let Some(SymbolNodeRef::Var(_, ref_var_declarator, _)) = decl.maybe_node() - && let Pat::Ident(ident) = &var_declarator.name - && let Some(type_ann) = &ident.type_ann { - return Some(TsTypeDef::new(module_info, &type_ann.type_ann)); - } - let maybe_type_ann = infer_simple_ts_type_from_init( - module_info, - var_declarator.init.as_deref(), - var_decl.kind == VarDeclKind::Const, - ); - if let Some(type_ann) = maybe_type_ann { - return Some(type_ann); + if let Some(type_ann) = &ref_var_declarator.type_annotation { + return Some(TsTypeDef::new( + module_info, + &type_ann.type_annotation, + )); + } + let maybe_type_ann = infer_simple_ts_type_from_init( + module_info, + ref_var_declarator.init.as_ref(), + kind == VarDeclKind::Const, + ); + if let Some(type_ann) = maybe_type_ann { + return Some(type_ann); + } } } None @@ -73,192 +81,156 @@ pub fn get_docs_for_var_declarator( .or_else(|| { infer_simple_ts_type_from_init( module_info, - var_declarator.init.as_deref(), - var_decl.kind == VarDeclKind::Const, + var_declarator.init.as_ref(), + kind == VarDeclKind::Const, ) }); - match &var_declarator.name { - Pat::Ident(ident) => { - let var_name = ident.id.sym.to_string(); + match &var_declarator.id { + BindingPattern::BindingIdentifier(ident) => { + let var_name = ident.name.to_string(); let variable_def = VariableDef { ts_type: maybe_ts_type, - kind: var_decl.kind, + kind, }; items.push((var_name, variable_def)); } - Pat::Object(obj) => get_vars_from_obj_destructuring( + BindingPattern::ObjectPattern(obj) => get_vars_from_obj_destructuring( obj, - var_decl.kind, - maybe_ts_type.as_ref(), + kind, + explicit_ts_type.as_ref(), &mut items, module_info, ), - Pat::Array(arr) => get_vars_from_array_destructuring( + BindingPattern::ArrayPattern(arr) => get_vars_from_array_destructuring( arr, - var_decl.kind, - maybe_ts_type.as_ref(), + kind, + explicit_ts_type.as_ref(), &mut items, module_info, ), - Pat::Expr(_) | Pat::Invalid(_) | Pat::Assign(_) | Pat::Rest(_) => {} + BindingPattern::AssignmentPattern(_) => {} } items } fn get_vars_from_obj_destructuring( - obj: &deno_ast::swc::ast::ObjectPat, + obj: &deno_ast::oxc::ast::ast::ObjectPattern, kind: VarDeclKind, maybe_ts_type: Option<&TsTypeDef>, items: &mut Vec<(String, VariableDef)>, module_info: &EsModuleInfo, ) { - let mut reached_rest = false; - for prop in &obj.props { - assert!(!reached_rest, "object rest is always last"); - let (name, reassign_name, rest_type_ann) = match prop { - deno_ast::swc::ast::ObjectPatProp::KeyValue(kv) => ( - crate::params::prop_name_to_string(module_info, &kv.key), - match &*kv.value { - Pat::Ident(ident) => Some(ident.sym.to_string()), - Pat::Assign(assign) => { - let name = match &*assign.left { - Pat::Ident(ident) => ident.sym.to_string(), - Pat::Rest(_) => unreachable!("assign cannot have rest"), - Pat::Assign(_) => unreachable!("rest cannot have assign"), - Pat::Array(_) | Pat::Object(_) => { - continue; // TODO(@crowlKats): implement recursive destructuring - } - Pat::Invalid(_) | Pat::Expr(_) => continue, - }; - - Some(name) - } - Pat::Array(_) | Pat::Object(_) => { - continue; // TODO(@crowlKats): implement recursive destructuring - } - Pat::Rest(_) | Pat::Invalid(_) | Pat::Expr(_) => { - continue; + for prop in &obj.properties { + let (name, reassign_name) = if prop.shorthand { + let key = match &prop.value { + BindingPattern::BindingIdentifier(ident) => ident.name.to_string(), + BindingPattern::AssignmentPattern(assign) => match &assign.left { + BindingPattern::BindingIdentifier(ident) => ident.name.to_string(), + _ => continue, + }, + _ => continue, + }; + (key, None) + } else { + let key = crate::params::prop_name_to_string(module_info, &prop.key); + let reassign_name = match &prop.value { + BindingPattern::BindingIdentifier(ident) => { + Some(ident.name.to_string()) + } + BindingPattern::AssignmentPattern(assign) => match &assign.left { + BindingPattern::BindingIdentifier(ident) => { + Some(ident.name.to_string()) } + _ => continue, }, - None, - ), - deno_ast::swc::ast::ObjectPatProp::Assign(assign) => { - (assign.key.sym.to_string(), None, None) - } - deno_ast::swc::ast::ObjectPatProp::Rest(rest) => { - reached_rest = true; - - ( - match &*rest.arg { - Pat::Ident(ident) => ident.sym.to_string(), - Pat::Rest(_) => unreachable!("rest cannot have rest"), - Pat::Assign(_) => unreachable!("rest cannot have assign"), - Pat::Array(_) | Pat::Object(_) => { - continue; // TODO(@crowlKats): implement recursive destructuring - } - Pat::Invalid(_) | Pat::Expr(_) => continue, - }, - None, - rest.type_ann.as_ref(), - ) - } - }; - - let ts_type = if !reached_rest { - maybe_ts_type.as_ref().and_then(|ts_type| { - if let TsTypeDefKind::TypeLiteral(type_literal) = &ts_type.kind { - type_literal.properties.iter().find_map(|property| { - if property.name == name { - property.ts_type.clone() - } else { - None - } - }) - } else { - None + BindingPattern::ArrayPattern(_) | BindingPattern::ObjectPattern(_) => { + continue; // TODO(@crowlKats): implement recursive destructuring } - }) - } else { - rest_type_ann - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)) + }; + (key, reassign_name) }; + let ts_type = maybe_ts_type.as_ref().and_then(|ts_type| { + if let TsTypeDefKind::TypeLiteral(type_literal) = &ts_type.kind { + type_literal.properties.iter().find_map(|property| { + if property.name == name { + property.ts_type.clone() + } else { + None + } + }) + } else { + None + } + }); + let variable_def = VariableDef { ts_type, kind }; items.push((reassign_name.unwrap_or(name), variable_def)); } + + // Handle rest element + if let Some(rest) = &obj.rest { + let name = match &rest.argument { + BindingPattern::BindingIdentifier(ident) => ident.name.to_string(), + _ => return, + }; + let variable_def = VariableDef { + ts_type: None, + kind, + }; + items.push((name, variable_def)); + } } fn get_vars_from_array_destructuring( - arr: &deno_ast::swc::ast::ArrayPat, + arr: &deno_ast::oxc::ast::ast::ArrayPattern, kind: VarDeclKind, maybe_ts_type: Option<&TsTypeDef>, items: &mut Vec<(String, VariableDef)>, - module_info: &EsModuleInfo, + _module_info: &EsModuleInfo, ) { - let mut reached_rest = false; - for (i, elem) in arr.elems.iter().enumerate() { - assert!(!reached_rest, "object rest is always last"); + for (i, elem) in arr.elements.iter().enumerate() { let Some(elem) = elem else { continue; }; - let (name, rest_type_ann) = match elem { - Pat::Ident(ident) => (ident.sym.to_string(), None), - Pat::Rest(rest) => { - reached_rest = true; - ( - match &*rest.arg { - Pat::Ident(ident) => ident.sym.to_string(), - Pat::Rest(_) => unreachable!("rest cannot have rest"), - Pat::Assign(_) => unreachable!("rest cannot have assign"), - Pat::Array(_) | Pat::Object(_) => { - continue; // TODO(@crowlKats): implement recursive destructuring - } - Pat::Invalid(_) | Pat::Expr(_) => continue, - }, - rest.type_ann.as_ref(), - ) - } - Pat::Assign(assign) => { - let name = match &*assign.left { - Pat::Ident(ident) => ident.sym.to_string(), - Pat::Rest(_) => unreachable!("assign cannot have rest"), - Pat::Assign(_) => unreachable!("rest cannot have assign"), - Pat::Array(_) | Pat::Object(_) => { - continue; // TODO(@crowlKats): implement recursive destructuring - } - Pat::Invalid(_) | Pat::Expr(_) => continue, - }; - - (name, None) - } - Pat::Array(_) | Pat::Object(_) => { + let name = match elem { + BindingPattern::BindingIdentifier(ident) => ident.name.to_string(), + BindingPattern::AssignmentPattern(assign) => match &assign.left { + BindingPattern::BindingIdentifier(ident) => ident.name.to_string(), + _ => continue, + }, + BindingPattern::ArrayPattern(_) | BindingPattern::ObjectPattern(_) => { continue; // TODO(@crowlKats): implement recursive destructuring } - Pat::Invalid(_) | Pat::Expr(_) => continue, }; - let ts_type = if !reached_rest { - maybe_ts_type.and_then(|ts_type| match &ts_type.kind { - TsTypeDefKind::Array(array) => Some(*array.clone()), - TsTypeDefKind::Tuple(tuple) => tuple.get(i).cloned(), - _ => None, - }) - } else { - rest_type_ann - .map(|type_ann| TsTypeDef::new(module_info, &type_ann.type_ann)) - .or_else(|| { - maybe_ts_type.and_then(|ts_type| { - if matches!(ts_type.kind, TsTypeDefKind::Array(_)) { - Some(ts_type.clone()) - } else { - None - } - }) - }) + let ts_type = maybe_ts_type.and_then(|ts_type| match &ts_type.kind { + TsTypeDefKind::Array(array) => Some(*array.clone()), + TsTypeDefKind::Tuple(tuple) => tuple.get(i).cloned(), + _ => None, + }); + + let variable_def = VariableDef { ts_type, kind }; + items.push((name, variable_def)); + } + + // Handle rest element + if let Some(rest) = &arr.rest { + let name = match &rest.argument { + BindingPattern::BindingIdentifier(ident) => ident.name.to_string(), + _ => return, }; + let ts_type = maybe_ts_type.and_then(|ts_type| { + if matches!(ts_type.kind, TsTypeDefKind::Array(_)) { + Some(ts_type.clone()) + } else { + None + } + }); + let variable_def = VariableDef { ts_type, kind }; items.push((name, variable_def)); } diff --git a/src/visibility.rs b/src/visibility.rs index 1915c2e02..3c7eb1a3c 100644 --- a/src/visibility.rs +++ b/src/visibility.rs @@ -5,7 +5,7 @@ use crate::util::graph::resolve_deno_graph_module; use crate::util::symbol::get_module_info; use crate::util::symbol::symbol_has_ignorable_js_doc_tag; -use deno_ast::SourceRange; +use deno_ast::oxc::span::Span; use deno_graph::ModuleGraph; use deno_graph::symbols::DefinitionPathNode; use deno_graph::symbols::DefinitionPathNodeResolved; @@ -22,14 +22,14 @@ use std::collections::HashSet; #[derive(Debug)] pub struct SymbolDeclDeps { pub symbol_id: UniqueSymbolId, - pub decl_range: SourceRange, + pub decl_range: Span, pub deps: IndexSet, /// If the path to this declaration had an ignorable js doc tag. pub had_ignorable_tag: bool, } #[derive(Default, Debug)] -pub struct SymbolDeps(IndexMap>); +pub struct SymbolDeps(IndexMap>); impl SymbolDeps { pub fn is_empty(&self) -> bool { @@ -90,7 +90,7 @@ impl SymbolVisibility { .filter(|d| !d.has_overloads()) .flat_map(|decl| { decl - .deps(ResolveDepsMode::TypesOnly) + .deps(ResolveDepsMode::TypesOnly, None) .into_iter() .map(move |dep| (decl, dep)) }) @@ -108,7 +108,7 @@ impl SymbolVisibility { .filter(|m| !m.has_overloads()) .flat_map(move |decl| { decl - .deps(ResolveDepsMode::TypesOnly) + .deps(ResolveDepsMode::TypesOnly, None) .into_iter() .map(move |dep| (symbol, decl, dep)) }) diff --git a/tests/helpers/mod.rs b/tests/helpers/mod.rs index 433ce0207..06e920e91 100644 --- a/tests/helpers/mod.rs +++ b/tests/helpers/mod.rs @@ -66,9 +66,11 @@ impl TestBuilder { .await; graph.valid().unwrap(); let entrypoints = &[entry_point_url]; + let allocator = deno_ast::oxc::allocator::Allocator::default(); let parser = DocParser::new( &graph, &analyzer, + &allocator, entrypoints, DocParserOptions { private: self.private, @@ -139,9 +141,11 @@ impl DiffTestBuilder { ) .await; graph.valid().unwrap(); + let allocator = deno_ast::oxc::allocator::Allocator::default(); let parser = DocParser::new( &graph, &analyzer, + &allocator, &roots, DocParserOptions { private: false, diff --git a/tests/html_test.rs b/tests/html_test.rs index 4ac3b60fc..c4cf67239 100644 --- a/tests/html_test.rs +++ b/tests/html_test.rs @@ -145,9 +145,11 @@ async fn get_files(subpath: &str) -> ParseOutput { ) .await; + let allocator = deno_ast::oxc::allocator::Allocator::default(); DocParser::new( &graph, &analyzer, + &allocator, &source_files, DocParserOptions { diagnostics: false, @@ -678,9 +680,11 @@ async fn parse_source(source: &str) -> ParseOutput { ) .await; + let allocator = deno_ast::oxc::allocator::Allocator::default(); DocParser::new( &graph, &analyzer, + &allocator, &[specifier], DocParserOptions { private: false, diff --git a/tests/specs/export_const_destructured.txt b/tests/specs/export_const_destructured.txt index 41bb6ac7d..efc35b30f 100644 --- a/tests/specs/export_const_destructured.txt +++ b/tests/specs/export_const_destructured.txt @@ -24,132 +24,124 @@ error[missing-jsdoc]: exported symbol is missing JSDoc documentation | ^ +error[missing-explicit-type]: exported symbol is missing an explicit type annotation + --> /mod.ts:16:16 + | +16 | export const { f, g: h } = d; + | ^ + + error[missing-jsdoc]: exported symbol is missing JSDoc documentation --> /mod.ts:16:22 | 16 | export const { f, g: h } = d; | ^ + +error[missing-explicit-type]: exported symbol is missing an explicit type annotation + --> /mod.ts:16:22 + | +16 | export const { f, g: h } = d; + | ^ + # output.txt -Defined in file:///mod.ts:5:3 +Defined in file:///mod.ts:6:3 const a: string export a doc -Defined in file:///mod.ts:7:3 +Defined in file:///mod.ts:8:3 const b: number export b doc -Defined in file:///mod.ts:15:16 +Defined in file:///mod.ts:16:16 -const f: string +const f -Defined in file:///mod.ts:15:22 +Defined in file:///mod.ts:16:22 -const h: number +const h # output.json -{ - "symbols": [ - { - "name": "a", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 5, - "col": 2, - "byteIndex": 123 - }, - "declarationKind": "export", - "jsDoc": { - "doc": "export a doc" - }, - "kind": "variable", - "def": { - "tsType": { - "repr": "string", - "kind": "keyword", - "value": "string" - }, - "kind": "const" - } - } - ] +[ + { + "name": "a", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 6, + "col": 2, + "byteIndex": 123 }, - { - "name": "b", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 7, - "col": 2, - "byteIndex": 150 - }, - "declarationKind": "export", - "jsDoc": { - "doc": "export b doc" - }, - "kind": "variable", - "def": { - "tsType": { - "repr": "number", - "kind": "keyword", - "value": "number" - }, - "kind": "const" - } - } - ] + "declarationKind": "export", + "jsDoc": { + "doc": "export a doc" + }, + "kind": "variable", + "variableDef": { + "tsType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" + }, + "kind": "const" + } + }, + { + "name": "b", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 8, + "col": 2, + "byteIndex": 150 }, - { - "name": "f", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 15, - "col": 15, - "byteIndex": 250 - }, - "declarationKind": "export", - "kind": "variable", - "def": { - "tsType": { - "repr": "string", - "kind": "keyword", - "value": "string" - }, - "kind": "const" - } - } - ] + "declarationKind": "export", + "jsDoc": { + "doc": "export b doc" + }, + "kind": "variable", + "variableDef": { + "tsType": { + "repr": "number", + "kind": "keyword", + "keyword": "number" + }, + "kind": "const" + } + }, + { + "name": "f", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 16, + "col": 15, + "byteIndex": 250 + }, + "declarationKind": "export", + "kind": "variable", + "variableDef": { + "tsType": null, + "kind": "const" + } + }, + { + "name": "h", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 16, + "col": 21, + "byteIndex": 256 }, - { - "name": "h", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 15, - "col": 21, - "byteIndex": 256 - }, - "declarationKind": "export", - "kind": "variable", - "def": { - "tsType": { - "repr": "number", - "kind": "keyword", - "value": "number" - }, - "kind": "const" - } - } - ] + "declarationKind": "export", + "kind": "variable", + "variableDef": { + "tsType": null, + "kind": "const" } - ] -} + } +] diff --git a/tests/specs/export_namespace.txt b/tests/specs/export_namespace.txt index cd587bd0c..adf2d9c0a 100644 --- a/tests/specs/export_namespace.txt +++ b/tests/specs/export_namespace.txt @@ -33,10 +33,10 @@ error[missing-jsdoc]: exported symbol is missing JSDoc documentation error[missing-jsdoc]: exported symbol is missing JSDoc documentation - --> /mod.ts:15:8 + --> /mod.ts:15:25 | 15 | export namespace RootNs.OtherNs { - | ^ + | ^ error[missing-jsdoc]: exported symbol is missing JSDoc documentation @@ -46,7 +46,7 @@ error[missing-jsdoc]: exported symbol is missing JSDoc documentation | ^ # output.txt -Defined in file:///mod.ts:1:1 +Defined in file:///mod.ts:2:1 namespace RootNs Namespace JSdoc @@ -58,182 +58,172 @@ namespace RootNs # output.json -{ - "symbols": [ - { - "name": "RootNs", - "declarations": [ +[ + { + "name": "RootNs", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 2, + "col": 0, + "byteIndex": 23 + }, + "declarationKind": "export", + "jsDoc": { + "doc": "Namespace JSdoc" + }, + "kind": "namespace", + "namespaceDef": { + "elements": [ { + "name": "a", + "isDefault": false, "location": { "filename": "file:///mod.ts", - "line": 1, - "col": 0, - "byteIndex": 23 + "line": 3, + "col": 17, + "byteIndex": 66 + }, + "declarationKind": "export", + "kind": "variable", + "variableDef": { + "tsType": { + "repr": "a", + "kind": "literal", + "literal": { + "kind": "string", + "string": "a" + } + }, + "kind": "const" + } + }, + { + "name": "NestedNs", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 6, + "col": 4, + "byteIndex": 114 }, "declarationKind": "export", "jsDoc": { - "doc": "Namespace JSdoc" + "doc": "Nested namespace JSDoc" }, "kind": "namespace", - "def": { + "namespaceDef": { "elements": [ { - "name": "a", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 2, - "col": 17, - "byteIndex": 66 - }, - "declarationKind": "export", - "kind": "variable", - "def": { - "tsType": { - "repr": "a", + "name": "Foo", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 7, + "col": 6, + "byteIndex": 148 + }, + "declarationKind": "export", + "kind": "enum", + "enumDef": { + "members": [ + { + "name": "a", + "init": { + "repr": "1", "kind": "literal", - "value": { - "kind": "string", - "string": "a" + "literal": { + "kind": "number", + "number": 1.0 } }, - "kind": "const" - } - } - ] - }, - { - "name": "NestedNs", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 5, - "col": 4, - "byteIndex": 114 + "location": { + "filename": "file:///mod.ts", + "line": 8, + "col": 8, + "byteIndex": 174 + } }, - "declarationKind": "export", - "jsDoc": { - "doc": "Nested namespace JSDoc" - }, - "kind": "namespace", - "def": { - "elements": [ - { - "name": "Foo", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 6, - "col": 6, - "byteIndex": 148 - }, - "declarationKind": "export", - "kind": "enum", - "def": { - "members": [ - { - "name": "a", - "init": { - "repr": "1", - "kind": "literal", - "value": { - "kind": "number", - "number": 1.0 - } - }, - "location": { - "filename": "file:///mod.ts", - "line": 7, - "col": 8, - "byteIndex": 174 - } - }, - { - "name": "b", - "init": { - "repr": "2", - "kind": "literal", - "value": { - "kind": "number", - "number": 2.0 - } - }, - "location": { - "filename": "file:///mod.ts", - "line": 8, - "col": 8, - "byteIndex": 189 - } - }, - { - "name": "c", - "init": { - "repr": "3", - "kind": "literal", - "value": { - "kind": "number", - "number": 3.0 - } - }, - "location": { - "filename": "file:///mod.ts", - "line": 9, - "col": 8, - "byteIndex": 204 - } - } - ] - } - } - ] + { + "name": "b", + "init": { + "repr": "2", + "kind": "literal", + "literal": { + "kind": "number", + "number": 2.0 } - ] - } - } - ] - }, - { - "name": "OtherNs", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 14, - "col": 7, - "byteIndex": 235 + }, + "location": { + "filename": "file:///mod.ts", + "line": 9, + "col": 8, + "byteIndex": 189 + } }, - "declarationKind": "export", - "kind": "namespace", - "def": { - "elements": [ - { - "name": "Other", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 15, - "col": 2, - "byteIndex": 264 - }, - "declarationKind": "export", - "kind": "class", - "def": {} - } - ] + { + "name": "c", + "init": { + "repr": "3", + "kind": "literal", + "literal": { + "kind": "number", + "number": 3.0 } - ] + }, + "location": { + "filename": "file:///mod.ts", + "line": 10, + "col": 8, + "byteIndex": 204 + } } - } - ] + ] + } + } + ] + } + }, + { + "name": "OtherNs", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 15, + "col": 24, + "byteIndex": 252 + }, + "declarationKind": "export", + "kind": "namespace", + "namespaceDef": { + "elements": [ + { + "name": "Other", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 16, + "col": 2, + "byteIndex": 264 + }, + "declarationKind": "export", + "kind": "class", + "classDef": { + "isAbstract": false, + "constructors": [], + "properties": [], + "indexSignatures": [], + "methods": [], + "extends": null, + "implements": [], + "typeParams": [], + "superTypeParams": [] + } } ] } } ] } - ] -} + } +] diff --git a/tests/specs/infer_object_literal.txt b/tests/specs/infer_object_literal.txt index c298df187..e3401680d 100644 --- a/tests/specs/infer_object_literal.txt +++ b/tests/specs/infer_object_literal.txt @@ -27,268 +27,308 @@ error[missing-jsdoc]: exported symbol is missing JSDoc documentation | ^ # output.txt -Defined in file:///mod.ts:3:14 +Defined in file:///mod.ts:4:14 -const a: { d(e: string): void; h(): string; h(value: string); [[t]](u: string): void; a: string; b: Map; c: { d: string; }; f: (g: string) => void; [[s]]: (number | string)[]; } +const a: { d(e: string): void; h(): string; h(value: string); [t](u: string): void; a: string; b: Map; c: { d: string; }; f: (g: string) => void; [s]: (number | string)[]; } # output.json -{ - "symbols": [ - { - "name": "a", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 3, - "col": 13, - "byteIndex": 84 - }, - "declarationKind": "export", - "kind": "variable", - "def": { - "tsType": { - "kind": "typeLiteral", - "value": { - "methods": [ - { - "name": "d", - "kind": "method", - "location": { - "filename": "file:///mod.ts", - "line": 8, - "col": 2, - "byteIndex": 166 - }, - "params": [ - { - "kind": "identifier", - "name": "e", - "optional": false, - "tsType": { - "repr": "string", - "kind": "keyword", - "value": "string" - } - } - ], - "returnType": { - "repr": "void", - "kind": "keyword", - "value": "void" - } - }, - { - "name": "h", - "kind": "getter", - "location": { - "filename": "file:///mod.ts", - "line": 10, - "col": 2, - "byteIndex": 221 - }, - "params": [], - "returnType": { - "repr": "string", - "kind": "keyword", - "value": "string" - } - }, - { - "name": "h", - "kind": "setter", - "location": { - "filename": "file:///mod.ts", - "line": 13, - "col": 2, - "byteIndex": 262 - }, - "params": [ - { - "kind": "identifier", - "name": "value", - "optional": false, - "tsType": { - "repr": "string", - "kind": "keyword", - "value": "string" - } - } - ] - }, - { - "name": "[t]", - "kind": "method", - "location": { - "filename": "file:///mod.ts", - "line": 17, - "col": 2, - "byteIndex": 316 - }, - "params": [ - { - "kind": "identifier", - "name": "u", - "optional": false, - "tsType": { - "repr": "string", - "kind": "keyword", - "value": "string" - } - } - ], - "computed": true, - "returnType": { - "repr": "void", - "kind": "keyword", - "value": "void" - } +[ + { + "name": "a", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 4, + "col": 13, + "byteIndex": 84 + }, + "declarationKind": "export", + "kind": "variable", + "variableDef": { + "tsType": { + "repr": "", + "kind": "typeLiteral", + "typeLiteral": { + "constructors": [], + "methods": [ + { + "name": "d", + "kind": "method", + "location": { + "filename": "file:///mod.ts", + "line": 9, + "col": 2, + "byteIndex": 166 + }, + "params": [ + { + "kind": "identifier", + "name": "e", + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" } - ], - "properties": [ - { - "name": "a", - "jsDoc": { - "doc": "JSDoc" - }, - "location": { - "filename": "file:///mod.ts", - "line": 5, - "col": 2, - "byteIndex": 107 - }, - "tsType": { + } + ], + "optional": false, + "returnType": { + "repr": "void", + "kind": "keyword", + "keyword": "void" + }, + "typeParams": [] + }, + { + "name": "h", + "kind": "getter", + "location": { + "filename": "file:///mod.ts", + "line": 11, + "col": 2, + "byteIndex": 221 + }, + "params": [], + "optional": false, + "returnType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" + }, + "typeParams": [] + }, + { + "name": "h", + "kind": "setter", + "location": { + "filename": "file:///mod.ts", + "line": 14, + "col": 2, + "byteIndex": 262 + }, + "params": [ + { + "kind": "identifier", + "name": "value", + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" + } + } + ], + "optional": false, + "returnType": null, + "typeParams": [] + }, + { + "name": "t", + "kind": "method", + "location": { + "filename": "file:///mod.ts", + "line": 18, + "col": 2, + "byteIndex": 316 + }, + "params": [ + { + "kind": "identifier", + "name": "u", + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" + } + } + ], + "computed": true, + "optional": false, + "returnType": { + "repr": "void", + "kind": "keyword", + "keyword": "void" + }, + "typeParams": [] + } + ], + "properties": [ + { + "name": "a", + "jsDoc": { + "doc": "JSDoc" + }, + "location": { + "filename": "file:///mod.ts", + "line": 6, + "col": 2, + "byteIndex": 107 + }, + "params": [], + "computed": false, + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" + }, + "typeParams": [] + }, + { + "name": "b", + "location": { + "filename": "file:///mod.ts", + "line": 7, + "col": 2, + "byteIndex": 117 + }, + "params": [], + "computed": false, + "optional": false, + "tsType": { + "repr": "Map", + "kind": "typeRef", + "typeRef": { + "typeParams": [ + { "repr": "string", "kind": "keyword", - "value": "string" - } - }, - { - "name": "b", - "location": { - "filename": "file:///mod.ts", - "line": 6, - "col": 2, - "byteIndex": 117 + "keyword": "string" }, - "tsType": { - "repr": "Map", - "kind": "typeRef", - "value": { - "typeParams": [ - { - "repr": "string", - "kind": "keyword", - "value": "string" - }, - { - "repr": "number", - "kind": "keyword", - "value": "number" - } - ], - "typeName": "Map" - } + { + "repr": "number", + "kind": "keyword", + "keyword": "number" } - }, - { - "name": "c", - "location": { - "filename": "file:///mod.ts", - "line": 7, - "col": 2, - "byteIndex": 149 - }, - "tsType": { - "kind": "typeLiteral", - "value": { - "properties": [ - { - "name": "d", - "location": { - "filename": "file:///mod.ts", - "line": 7, - "col": 7, - "byteIndex": 154 - }, - "tsType": { - "repr": "string", - "kind": "keyword", - "value": "string" - } - } - ] - } + ], + "typeName": "Map" + } + }, + "typeParams": [] + }, + { + "name": "c", + "location": { + "filename": "file:///mod.ts", + "line": 8, + "col": 2, + "byteIndex": 149 + }, + "params": [], + "computed": false, + "optional": false, + "tsType": { + "repr": "", + "kind": "typeLiteral", + "typeLiteral": { + "constructors": [], + "methods": [], + "properties": [ + { + "name": "d", + "location": { + "filename": "file:///mod.ts", + "line": 8, + "col": 7, + "byteIndex": 154 + }, + "params": [], + "computed": false, + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" + }, + "typeParams": [] } + ], + "callSignatures": [], + "indexSignatures": [] + } + }, + "typeParams": [] + }, + { + "name": "f", + "location": { + "filename": "file:///mod.ts", + "line": 10, + "col": 2, + "byteIndex": 191 + }, + "params": [], + "computed": false, + "optional": false, + "tsType": { + "repr": "", + "kind": "fnOrConstructor", + "fnOrConstructor": { + "constructor": false, + "tsType": { + "repr": "void", + "kind": "keyword", + "keyword": "void" }, - { - "name": "f", - "location": { - "filename": "file:///mod.ts", - "line": 9, - "col": 2, - "byteIndex": 191 - }, - "tsType": { - "kind": "fnOrConstructor", - "value": { - "constructor": false, - "tsType": { - "repr": "void", - "kind": "keyword", - "value": "void" - }, - "params": [ - { - "kind": "identifier", - "name": "g", - "optional": false, - "tsType": { - "repr": "string", - "kind": "keyword", - "value": "string" - } - } - ] + "params": [ + { + "kind": "identifier", + "name": "g", + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "keyword": "string" } } - }, - { - "name": "[s]", - "location": { - "filename": "file:///mod.ts", - "line": 16, - "col": 2, - "byteIndex": 293 + ], + "typeParams": [] + } + }, + "typeParams": [] + }, + { + "name": "s", + "location": { + "filename": "file:///mod.ts", + "line": 17, + "col": 2, + "byteIndex": 293 + }, + "params": [], + "computed": true, + "optional": false, + "tsType": { + "repr": "", + "kind": "array", + "array": { + "repr": "", + "kind": "union", + "union": [ + { + "repr": "number", + "kind": "keyword", + "keyword": "number" }, - "computed": true, - "tsType": { - "kind": "array", - "value": { - "kind": "union", - "value": [ - { - "repr": "number", - "kind": "keyword", - "value": "number" - }, - { - "repr": "string", - "kind": "keyword", - "value": "string" - } - ] - } + { + "repr": "string", + "kind": "keyword", + "keyword": "string" } - } - ] - } - }, - "kind": "const" - } + ] + } + }, + "typeParams": [] + } + ], + "callSignatures": [], + "indexSignatures": [] } - ] + }, + "kind": "const" } - ] -} + } +] diff --git a/tests/specs/namespace_exports_self.txt b/tests/specs/namespace_exports_self.txt index 22cc40e03..8a7c08c58 100644 --- a/tests/specs/namespace_exports_self.txt +++ b/tests/specs/namespace_exports_self.txt @@ -41,7 +41,7 @@ Defined in file:///mod.ts:1:1 namespace a Description. - const a: string + private const a: string Description. Defined in file:///mod.ts:8:1 @@ -88,7 +88,7 @@ namespace f "col": 0, "byteIndex": 20 }, - "declarationKind": "export", + "declarationKind": "private", "jsDoc": { "doc": "Description." }, diff --git a/tests/specs/private_type_class_property.txt b/tests/specs/private_type_class_property.txt index dfd56a35d..9d894825c 100644 --- a/tests/specs/private_type_class_property.txt +++ b/tests/specs/private_type_class_property.txt @@ -30,48 +30,20 @@ error[private-type-ref]: public type 'PrivatePropThroughNamespaceRef' references info: to ensure documentation is complete all types that are exposed in the public API must be public -error[private-type-ref]: public type 'PrivatePropThroughNamespaceRef' references private type 'MyNamespace2' +error[private-type-ref]: public type 'PrivatePropThroughNamespaceRef' references private type 'MyNamespace.Export' --> /mod.ts:1:1 | 1 | export type PrivatePropThroughNamespaceRef = typeof MyNamespace.Export.someProp; | ^ = hint: make the referenced type public or remove the reference | -7 | namespace MyNamespace2 { - | - this is the referenced type +4 | export import Export = MyNamespace2.MyClass; + | - this is the referenced type | info: to ensure documentation is complete all types that are exposed in the public API must be public -error[private-type-ref]: public type 'PrivatePropThroughNamespaceRef' references private type 'MyNamespace3' - --> /mod.ts:1:1 - | - 1 | export type PrivatePropThroughNamespaceRef = typeof MyNamespace.Export.someProp; - | ^ - = hint: make the referenced type public or remove the reference - | -11 | namespace MyNamespace3 { - | - this is the referenced type - | - - info: to ensure documentation is complete all types that are exposed in the public API must be public - - -error[private-type-ref]: public type 'PrivatePropThroughNamespaceRef' references private type 'MyNamespace3.MyClass' - --> /mod.ts:1:1 - | - 1 | export type PrivatePropThroughNamespaceRef = typeof MyNamespace.Export.someProp; - | ^ - = hint: make the referenced type public or remove the reference - | -12 | export class MyClass { - | - this is the referenced type - | - - info: to ensure documentation is complete all types that are exposed in the public API must be public - - error[missing-jsdoc]: exported symbol is missing JSDoc documentation --> /mod.ts:1:1 | @@ -79,212 +51,51 @@ error[missing-jsdoc]: exported symbol is missing JSDoc documentation | ^ # output.txt -Defined in file:///mod.ts:0:1 +Defined in file:///mod.ts:1:1 type PrivatePropThroughNamespaceRef = typeof MyNamespace.Export.someProp -Defined in file:///mod.ts:2:1 +Defined in file:///mod.ts:3:1 private namespace MyNamespace - class Export - -Defined in file:///mod.ts:6:1 - -private namespace MyNamespace2 - - class MyClass - -Defined in file:///mod.ts:10:1 - -private namespace MyNamespace3 - - class MyClass # output.json -{ - "symbols": [ - { - "name": "PrivatePropThroughNamespaceRef", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 0, - "col": 0, - "byteIndex": 0 - }, - "declarationKind": "export", - "kind": "typeAlias", - "def": { - "tsType": { - "repr": "MyNamespace.Export.someProp", - "kind": "typeQuery", - "value": "MyNamespace.Export.someProp" - } - } - } - ] +[ + { + "name": "PrivatePropThroughNamespaceRef", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 1, + "col": 0, + "byteIndex": 0 }, - { - "name": "MyNamespace", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 2, - "col": 0, - "byteIndex": 82 - }, - "declarationKind": "private", - "kind": "namespace", - "def": { - "elements": [ - { - "name": "Export", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 11, - "col": 2, - "byteIndex": 259 - }, - "declarationKind": "export", - "kind": "class", - "def": { - "properties": [ - { - "tsType": { - "repr": "string", - "kind": "keyword", - "value": "string" - }, - "isStatic": true, - "name": "someProp", - "location": { - "filename": "file:///mod.ts", - "line": 12, - "col": 4, - "byteIndex": 286 - } - } - ] - } - } - ] - } - ] - } - } - ] - }, - { - "name": "MyNamespace2", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 6, - "col": 0, - "byteIndex": 156 - }, - "declarationKind": "private", - "kind": "namespace", - "def": { - "elements": [ - { - "name": "MyClass", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 11, - "col": 2, - "byteIndex": 259 - }, - "declarationKind": "export", - "kind": "class", - "def": { - "properties": [ - { - "tsType": { - "repr": "string", - "kind": "keyword", - "value": "string" - }, - "isStatic": true, - "name": "someProp", - "location": { - "filename": "file:///mod.ts", - "line": 12, - "col": 4, - "byteIndex": 286 - } - } - ] - } - } - ] - } - ] - } - } - ] + "declarationKind": "export", + "kind": "typeAlias", + "typeAliasDef": { + "tsType": { + "repr": "MyNamespace.Export.someProp", + "kind": "typeQuery", + "typeQuery": "MyNamespace.Export.someProp" + }, + "typeParams": [] + } + }, + { + "name": "MyNamespace", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 3, + "col": 0, + "byteIndex": 82 }, - { - "name": "MyNamespace3", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 10, - "col": 0, - "byteIndex": 232 - }, - "declarationKind": "private", - "kind": "namespace", - "def": { - "elements": [ - { - "name": "MyClass", - "declarations": [ - { - "location": { - "filename": "file:///mod.ts", - "line": 11, - "col": 2, - "byteIndex": 259 - }, - "declarationKind": "export", - "kind": "class", - "def": { - "properties": [ - { - "tsType": { - "repr": "string", - "kind": "keyword", - "value": "string" - }, - "isStatic": true, - "name": "someProp", - "location": { - "filename": "file:///mod.ts", - "line": 12, - "col": 4, - "byteIndex": 286 - } - } - ] - } - } - ] - } - ] - } - } - ] + "declarationKind": "private", + "kind": "namespace", + "namespaceDef": { + "elements": [] } - ] -} + } +] diff --git a/tests/specs/re_export_all_as_with_jsdoc.txt b/tests/specs/re_export_all_as_with_jsdoc.txt index f8ab324cf..99d8a3573 100644 --- a/tests/specs/re_export_all_as_with_jsdoc.txt +++ b/tests/specs/re_export_all_as_with_jsdoc.txt @@ -7,7 +7,7 @@ export function foo(): void {} export * as other from "./other.ts"; # output.txt -Defined in file:///mod.ts:1:8 +Defined in file:///mod.ts:2:1 namespace other Re-exports of other. @@ -17,56 +17,51 @@ namespace other # output.json -{ - "symbols": [ - { - "name": "other", - "declarations": [ +[ + { + "name": "other", + "isDefault": false, + "location": { + "filename": "file:///mod.ts", + "line": 2, + "col": 0, + "byteIndex": 28 + }, + "declarationKind": "export", + "jsDoc": { + "doc": "Re-exports of other." + }, + "kind": "namespace", + "namespaceDef": { + "elements": [ { + "name": "foo", + "isDefault": false, "location": { - "filename": "file:///mod.ts", - "line": 1, - "col": 7, - "byteIndex": 35 + "filename": "file:///other.ts", + "line": 2, + "col": 0, + "byteIndex": 18 }, "declarationKind": "export", "jsDoc": { - "doc": "Re-exports of other." + "doc": "a function" }, - "kind": "namespace", - "def": { - "elements": [ - { - "name": "foo", - "declarations": [ - { - "location": { - "filename": "file:///other.ts", - "line": 1, - "col": 0, - "byteIndex": 18 - }, - "declarationKind": "export", - "jsDoc": { - "doc": "a function" - }, - "kind": "function", - "def": { - "params": [], - "returnType": { - "repr": "void", - "kind": "keyword", - "value": "void" - }, - "hasBody": true - } - } - ] - } - ] + "kind": "function", + "functionDef": { + "params": [], + "returnType": { + "repr": "void", + "kind": "keyword", + "keyword": "void" + }, + "hasBody": true, + "isAsync": false, + "isGenerator": false, + "typeParams": [] } } ] } - ] -} + } +] From f599fa92d61fd6d28218b63f5796f00fadcbbce1 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 17 Mar 2026 13:09:47 -0700 Subject: [PATCH 2/4] use git --- Cargo.lock | 2 +- Cargo.toml | 2 +- rust-toolchain.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84a9918c3..bbe45084b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2879,7 +2879,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 5400e0957..cfbddcc50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ deno_graph = { path = "../deno_graph", default-features = false, features = [ "swc", "symbols", ] } -deno_ast = { path = "../deno_ast" } +deno_ast = { git = "https://github.com/nathanwhit/deno_ast", branch = "oxc-port" } import_map = "0.25.0" serde = { version = "1.0.204", features = ["derive"] } serde_json = { version = "1.0.122", features = ["preserve_order"] } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 1a2165581..4f0430eac 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.92.0" +channel = "1.96.0" components = ["rustfmt", "clippy"] From ef2349f5cca4c87ea13aefb21c8a66f76dd74d74 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 2 Jun 2026 13:36:35 -0700 Subject: [PATCH 3/4] fix tests --- src/html/types.rs | 8 +- src/js_doc.rs | 5 +- src/lib.rs | 41 +- src/parser.rs | 30 +- src/tests.rs | 4 +- src/ts_type.rs | 366 +++++++++++- src/util/swc.rs | 65 +-- tests/diff_specs/function_throws_change.txt | 20 +- ...html_test__html_doc_files_multiple-40.snap | 4 +- tests/snapshots/html_test__symbol_group.snap | 4 +- tests/specs/export_const_destructured.txt | 172 +++--- tests/specs/export_namespace.txt | 302 +++++----- tests/specs/indented_with_tabs.txt | 4 +- tests/specs/infer_object_literal.txt | 534 ++++++++---------- tests/specs/jsdoc_types.txt | 50 +- tests/specs/mapped_types.txt | 5 +- tests/specs/namespace_exports_self.txt | 4 +- tests/specs/private_type_class_property.txt | 81 +-- tests/specs/re_export_all_as_with_jsdoc.txt | 81 +-- tests/specs/structured_jsdoc.txt | 5 +- tests/specs/type_literal_mapped_type.txt | 5 +- 21 files changed, 1044 insertions(+), 746 deletions(-) diff --git a/src/html/types.rs b/src/html/types.rs index 64fe46a3d..093c0c71a 100644 --- a/src/html/types.rs +++ b/src/html/types.rs @@ -166,13 +166,7 @@ pub(crate) fn render_type_def( ) }) } else { - Some(format!( - "#{}", - IdBuilder::new(ctx) - .kind(IdKind::TypeParam) - .name(&type_ref.type_name) - .build_unregistered() - )) + None } } crate::ts_type::TypeRefResolution::Import { specifier, name } => { diff --git a/src/js_doc.rs b/src/js_doc.rs index a46d441b1..d5d68579a 100644 --- a/src/js_doc.rs +++ b/src/js_doc.rs @@ -74,7 +74,9 @@ pub fn parse_jsdoc_type( type_alias, ) = type_alias { - Some(TsTypeDef::new(module_info, &type_alias.type_annotation)) + let mut ts_type = TsTypeDef::new(module_info, &type_alias.type_annotation); + ts_type.clear_resolutions(); + Some(ts_type) } else { None } @@ -615,7 +617,6 @@ mod tests { ) -> serde_json::Value { let mut value = serde_json::json!({ "typeName": name, - "resolution": { "kind": "typeParam" }, }); if let Some(tp) = type_params { value["typeParams"] = serde_json::json!(tp); diff --git a/src/lib.rs b/src/lib.rs index ba33738ba..64ae16023 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -207,16 +207,16 @@ pub fn docnodes_v1_to_v2(value: serde_json::Value) -> Document { let mut declaration = serde_json::Value::Object(obj); migrate_declaration(&mut declaration); - let symbol = symbols.entry(name.clone()).or_insert_with(|| Symbol { - name, - is_default, - declarations: vec![], - }); - // If any entry is marked default, the symbol is default - if is_default { - symbol.is_default = true; - } if let Ok(decl) = serde_json::from_value::(declaration) { + let symbol = symbols.entry(name.clone()).or_insert_with(|| Symbol { + name, + is_default, + declarations: vec![], + }); + // If any entry is marked default, the symbol is default + if is_default { + symbol.is_default = true; + } symbol.declarations.push(decl); } } @@ -313,18 +313,21 @@ fn v1_nodes_to_symbols(nodes: Vec) -> serde_json::Value { let mut decl = serde_json::Value::Object(obj); migrate_declaration(&mut decl); - let symbol = symbols.entry(name.clone()).or_insert_with(|| { - serde_json::json!({ - "name": name, - "declarations": [] - }) - }); + let declaration = serde_json::from_value::(decl.clone()); + if declaration.is_ok() { + let symbol = symbols.entry(name.clone()).or_insert_with(|| { + serde_json::json!({ + "name": name, + "declarations": [] + }) + }); + + if is_default { + symbol["isDefault"] = serde_json::Value::Bool(true); + } - if is_default { - symbol["isDefault"] = serde_json::Value::Bool(true); + symbol["declarations"].as_array_mut().unwrap().push(decl); } - - symbol["declarations"].as_array_mut().unwrap().push(decl); } serde_json::Value::Array(symbols.into_values().collect()) diff --git a/src/parser.rs b/src/parser.rs index a8466f8b8..c32f1240b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1413,8 +1413,14 @@ impl<'a> DocParser<'a> { self.get_doc_for_export_default_decl(module_info, n) } SymbolNodeRef::ExportDefaultExpr(n) => { - let js_doc = js_doc_for_range(module_info, n.span())?; - let location = get_location(module_info, n.span().start); + let (js_doc, location) = self + .export_default_expr_context(module_info, n) + .unwrap_or_else(|| { + ( + js_doc_for_range(module_info, n.span()).unwrap_or_default(), + get_location(module_info, n.span().start), + ) + }); self.get_decl_for_export_default_expr(module_info, n, js_doc, location) } SymbolNodeRef::FnDecl(n) => { @@ -1530,6 +1536,26 @@ impl<'a> DocParser<'a> { } } + fn export_default_expr_context( + &self, + module_info: &EsModuleInfo, + export_expr: &ExportDefaultDeclarationKind, + ) -> Option<(JsDoc, Location)> { + let expr_span = export_expr.span(); + for stmt in module_info.statements() { + let Statement::ExportDefaultDeclaration(export_default) = stmt else { + continue; + }; + if export_default.declaration.span() == expr_span { + return Some(( + js_doc_for_range(module_info, export_default.span)?, + get_location(module_info, export_default.span.start), + )); + } + } + None + } + fn get_declare_for_export_decl_declaration( &self, export_decl: &ExportNamedDeclaration, diff --git a/src/tests.rs b/src/tests.rs index 39f8ce914..e8366df93 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -519,8 +519,8 @@ export * as b from "./mod_doc.ts"; "location": { "filename": "file:///ns.ts", "line": 1, - "col": 7, - "byteIndex": 8 + "col": 0, + "byteIndex": 1 }, "declarationKind": "export", "jsDoc": { diff --git a/src/ts_type.rs b/src/ts_type.rs index 40c436092..85d4252a2 100644 --- a/src/ts_type.rs +++ b/src/ts_type.rs @@ -903,6 +903,13 @@ fn resolve_type_ref( module_info: &EsModuleInfo, ident: &IdentifierReference, ) -> Option { + let reference_symbol_id = ident + .reference_id + .get() + .zip(module_info.scoping()) + .and_then(|(reference_id, scoping)| { + scoping.get_reference(reference_id).symbol_id() + }); let id = identifier_reference_to_id(module_info, ident); if let Some(symbol) = module_info.symbol_from_swc(&id) { if let Some(file_dep) = symbol.file_dep() { @@ -913,16 +920,196 @@ fn resolve_type_ref( } else { Some(TypeRefResolution::Local) } - } else if id.1 != 0 { + } else if let Some((declaring_name, declaring_kind)) = reference_symbol_id + .and_then(|symbol_id| { + module_info.scoping().and_then(|scoping| { + type_param_declaring_info(module_info, scoping.symbol_span(symbol_id)) + }) + }) + { Some(TypeRefResolution::TypeParam { - declaring_name: None, - declaring_kind: None, + declaring_name, + declaring_kind, }) } else { None } } +fn type_param_declaring_info( + module_info: &EsModuleInfo, + type_param_span: Span, +) -> Option<(Option, Option)> { + for stmt in module_info.statements() { + let info = match stmt { + Statement::FunctionDeclaration(function) => { + function_type_param_declaring_info( + function, + type_param_span, + TypeParamDeclaringKind::Function, + ) + } + Statement::ClassDeclaration(class) => class_type_param_declaring_info( + class, + type_param_span, + TypeParamDeclaringKind::Class, + ), + Statement::TSInterfaceDeclaration(interface_decl) => { + named_type_param_declaring_info( + &interface_decl.id.name, + interface_decl.type_parameters.as_deref(), + type_param_span, + TypeParamDeclaringKind::Interface, + ) + } + Statement::TSTypeAliasDeclaration(type_alias) => { + named_type_param_declaring_info( + &type_alias.id.name, + type_alias.type_parameters.as_deref(), + type_param_span, + TypeParamDeclaringKind::TypeAlias, + ) + } + Statement::ExportNamedDeclaration(export) => { + export.declaration.as_ref().and_then(|decl| { + declaration_type_param_declaring_info(decl, type_param_span) + }) + } + Statement::ExportDefaultDeclaration(export) => { + export_default_type_param_declaring_info(export, type_param_span) + } + _ => None, + }; + if info.is_some() { + return info; + } + } + None +} + +fn declaration_type_param_declaring_info( + declaration: &Declaration, + type_param_span: Span, +) -> Option<(Option, Option)> { + match declaration { + Declaration::FunctionDeclaration(function) => { + function_type_param_declaring_info( + function, + type_param_span, + TypeParamDeclaringKind::Function, + ) + } + Declaration::ClassDeclaration(class) => class_type_param_declaring_info( + class, + type_param_span, + TypeParamDeclaringKind::Class, + ), + Declaration::TSInterfaceDeclaration(interface_decl) => { + named_type_param_declaring_info( + &interface_decl.id.name, + interface_decl.type_parameters.as_deref(), + type_param_span, + TypeParamDeclaringKind::Interface, + ) + } + Declaration::TSTypeAliasDeclaration(type_alias) => { + named_type_param_declaring_info( + &type_alias.id.name, + type_alias.type_parameters.as_deref(), + type_param_span, + TypeParamDeclaringKind::TypeAlias, + ) + } + _ => None, + } +} + +fn export_default_type_param_declaring_info( + export: &ExportDefaultDeclaration, + type_param_span: Span, +) -> Option<(Option, Option)> { + match &export.declaration { + ExportDefaultDeclarationKind::FunctionDeclaration(function) => { + function_type_param_declaring_info( + function, + type_param_span, + TypeParamDeclaringKind::Function, + ) + } + ExportDefaultDeclarationKind::ClassDeclaration(class) => { + class_type_param_declaring_info( + class, + type_param_span, + TypeParamDeclaringKind::Class, + ) + } + ExportDefaultDeclarationKind::TSInterfaceDeclaration(interface_decl) => { + named_type_param_declaring_info( + &interface_decl.id.name, + interface_decl.type_parameters.as_deref(), + type_param_span, + TypeParamDeclaringKind::Interface, + ) + } + _ => None, + } +} + +fn function_type_param_declaring_info( + function: &Function, + type_param_span: Span, + kind: TypeParamDeclaringKind, +) -> Option<(Option, Option)> { + named_type_param_declaring_info( + function + .id + .as_ref() + .map(|id| id.name.as_str()) + .unwrap_or("default"), + function.type_parameters.as_deref(), + type_param_span, + kind, + ) +} + +fn class_type_param_declaring_info( + class: &Class, + type_param_span: Span, + kind: TypeParamDeclaringKind, +) -> Option<(Option, Option)> { + named_type_param_declaring_info( + class + .id + .as_ref() + .map(|id| id.name.as_str()) + .unwrap_or("default"), + class.type_parameters.as_deref(), + type_param_span, + kind, + ) +} + +fn named_type_param_declaring_info( + declaring_name: &str, + type_parameters: Option<&TSTypeParameterDeclaration>, + type_param_span: Span, + kind: TypeParamDeclaringKind, +) -> Option<(Option, Option)> { + if type_parameters? + .params + .iter() + .any(|param| span_contains(param.span, type_param_span)) + { + Some((Some(declaring_name.to_string()), Some(kind))) + } else { + None + } +} + +fn span_contains(container: Span, span: Span) -> bool { + container.start <= span.start && span.end <= container.end +} + fn ts_tuple_element_to_ts_type_def( module_info: &EsModuleInfo, elem: &TSTupleElement, @@ -1534,6 +1721,179 @@ impl Display for TsTypePredicateDef { } impl TsTypeDef { + pub(crate) fn clear_resolutions(&mut self) { + fn clear_type_param(type_param: &mut TsTypeParamDef) { + if let Some(constraint) = &mut type_param.constraint { + constraint.clear_resolutions(); + } + if let Some(default) = &mut type_param.default { + default.clear_resolutions(); + } + } + + fn clear_param(param: &mut ParamDef) { + match &mut param.pattern { + ParamPatternDef::Array { elements, .. } => { + for element in elements.iter_mut().flatten() { + clear_param(element); + } + } + ParamPatternDef::Assign { left, .. } => clear_param(left), + ParamPatternDef::Object { props, .. } => { + for prop in props { + match prop { + crate::params::ObjectPatPropDef::KeyValue { value, .. } => { + clear_param(value); + } + crate::params::ObjectPatPropDef::Rest { arg } => { + clear_param(arg); + } + crate::params::ObjectPatPropDef::Assign { .. } => {} + } + } + } + ParamPatternDef::Rest { arg } => clear_param(arg), + ParamPatternDef::Identifier { .. } => {} + } + if let Some(ts_type) = &mut param.ts_type { + ts_type.clear_resolutions(); + } + } + + match &mut self.kind { + TsTypeDefKind::TypeRef(type_ref) => { + type_ref.resolution = None; + if let Some(type_params) = &mut type_ref.type_params { + for type_param in type_params.iter_mut() { + type_param.clear_resolutions(); + } + } + } + TsTypeDefKind::Literal(literal) => { + if let Some(ts_types) = &mut literal.ts_types { + for ts_type in ts_types { + ts_type.clear_resolutions(); + } + } + } + TsTypeDefKind::Union(types) + | TsTypeDefKind::Intersection(types) + | TsTypeDefKind::Tuple(types) => { + for ts_type in types { + ts_type.clear_resolutions(); + } + } + TsTypeDefKind::Array(ts_type) + | TsTypeDefKind::Parenthesized(ts_type) + | TsTypeDefKind::Rest(ts_type) + | TsTypeDefKind::Optional(ts_type) => ts_type.clear_resolutions(), + TsTypeDefKind::TypeOperator(type_operator) => { + type_operator.ts_type.clear_resolutions(); + } + TsTypeDefKind::FnOrConstructor(fn_or_constructor) => { + fn_or_constructor.ts_type.clear_resolutions(); + for param in &mut fn_or_constructor.params { + clear_param(param); + } + for type_param in &mut fn_or_constructor.type_params { + clear_type_param(type_param); + } + } + TsTypeDefKind::Conditional(conditional) => { + conditional.check_type.clear_resolutions(); + conditional.extends_type.clear_resolutions(); + conditional.true_type.clear_resolutions(); + conditional.false_type.clear_resolutions(); + } + TsTypeDefKind::Infer(infer) => { + clear_type_param(&mut infer.type_param); + } + TsTypeDefKind::IndexedAccess(indexed_access) => { + indexed_access.obj_type.clear_resolutions(); + indexed_access.index_type.clear_resolutions(); + } + TsTypeDefKind::Mapped(mapped) => { + clear_type_param(&mut mapped.type_param); + if let Some(name_type) = &mut mapped.name_type { + name_type.clear_resolutions(); + } + if let Some(ts_type) = &mut mapped.ts_type { + ts_type.clear_resolutions(); + } + } + TsTypeDefKind::TypeLiteral(type_literal) => { + for ctor in &mut type_literal.constructors { + for param in &mut ctor.params { + clear_param(param); + } + if let Some(return_type) = &mut ctor.return_type { + return_type.clear_resolutions(); + } + for type_param in &mut ctor.type_params { + clear_type_param(type_param); + } + } + for method in &mut type_literal.methods { + for param in &mut method.params { + clear_param(param); + } + if let Some(return_type) = &mut method.return_type { + return_type.clear_resolutions(); + } + for type_param in &mut method.type_params { + clear_type_param(type_param); + } + } + for property in &mut type_literal.properties { + for param in &mut property.params { + clear_param(param); + } + if let Some(ts_type) = &mut property.ts_type { + ts_type.clear_resolutions(); + } + for type_param in &mut property.type_params { + clear_type_param(type_param); + } + } + for call_signature in &mut type_literal.call_signatures { + for param in &mut call_signature.params { + clear_param(param); + } + if let Some(ts_type) = &mut call_signature.ts_type { + ts_type.clear_resolutions(); + } + for type_param in &mut call_signature.type_params { + clear_type_param(type_param); + } + } + for index_signature in &mut type_literal.index_signatures { + for param in &mut index_signature.params { + clear_param(param); + } + if let Some(ts_type) = &mut index_signature.ts_type { + ts_type.clear_resolutions(); + } + } + } + TsTypeDefKind::TypePredicate(type_predicate) => { + if let Some(ts_type) = &mut type_predicate.r#type { + ts_type.clear_resolutions(); + } + } + TsTypeDefKind::ImportType(import_type) => { + if let Some(type_params) = &mut import_type.type_params { + for type_param in type_params { + type_param.clear_resolutions(); + } + } + } + TsTypeDefKind::Keyword(_) + | TsTypeDefKind::TypeQuery(_) + | TsTypeDefKind::This + | TsTypeDefKind::Unsupported => {} + } + } + pub fn number_literal(num: &NumericLiteral) -> Self { Self::number_value(num.value) } diff --git a/src/util/swc.rs b/src/util/swc.rs index bcd9ddf4f..445cca8c5 100644 --- a/src/util/swc.rs +++ b/src/util/swc.rs @@ -83,37 +83,26 @@ pub(crate) fn module_js_doc_for_source( ) -> Option> { let source_text = module_info.source_text(); let comments = module_info.comments(); - let statements = module_info.statements(); - - // Find the start of the first statement (or end of file) - let first_stmt_start = statements - .first() - .map(|s| { - use deno_ast::oxc::span::GetSpan; - s.span().start - }) - .unwrap_or(u32::MAX); - // Find leading block comments before the first statement that look like JSDoc - let js_doc_comment = comments.iter().find(|comment| { - comment.span.start < first_stmt_start && comment.is_block() && { + for js_doc_comment in comments.iter().filter(|comment| { + comment.is_block() && { let content_span = comment.content_span(); let text = &source_text[content_span.start as usize..content_span.end as usize]; text.starts_with('*') } - })?; - - let js_doc = parse_js_doc(source_text, js_doc_comment, module_info); - if js_doc - .tags - .iter() - .any(|tag| matches!(tag, JsDocTag::Module { .. })) - { - if js_doc.tags.contains(&JsDocTag::Ignore) { - return Some(None); + }) { + let js_doc = parse_js_doc(source_text, js_doc_comment, module_info); + if js_doc + .tags + .iter() + .any(|tag| matches!(tag, JsDocTag::Module { .. })) + { + if js_doc.tags.contains(&JsDocTag::Ignore) { + return Some(None); + } + return Some(Some((js_doc, js_doc_comment.span))); } - return Some(Some((js_doc, js_doc_comment.span))); } None } @@ -132,33 +121,15 @@ pub fn get_text_info_location( pos: u32, ) -> Location { let byte_index = pos as usize; - let line_and_column_index = text_info.line_and_column_display(byte_index); - - // Adjust column for tab indentation (tabs count as 4 spaces for display, - // matching the old SWC behavior with indent_width=4) - let line_start_byte = byte_index - (line_and_column_index.column_number - 1); let text = text_info.text(); - let col = if line_start_byte < text.len() { - let line_prefix = &text[line_start_byte..byte_index]; - let mut col = 0usize; - for ch in line_prefix.chars() { - if ch == '\t' { - // Round up to next multiple of 4 - col = (col + 4) & !3; - } else { - col += 1; - } - } - col - } else { - line_and_column_index.column_number - 1 - }; + let lookup_byte_index = byte_index.min(text.len()); + let line_and_column_index = + text_info.line_and_column_display(lookup_byte_index); Location { filename: specifier.into(), - // todo(#150): make 0-indexed - line: line_and_column_index.line_number, - col, + line: line_and_column_index.line_number - 1, + col: line_and_column_index.column_number - 1, byte_index, } } diff --git a/tests/diff_specs/function_throws_change.txt b/tests/diff_specs/function_throws_change.txt index 5c64ab64c..32fed0513 100644 --- a/tests/diff_specs/function_throws_change.txt +++ b/tests/diff_specs/function_throws_change.txt @@ -32,10 +32,7 @@ export function foo(x: number): void {} "repr": "SyntaxError", "kind": "typeRef", "value": { - "typeName": "SyntaxError", - "resolution": { - "kind": "typeParam" - } + "typeName": "SyntaxError" } }, "doc": "bad syntax" @@ -48,10 +45,7 @@ export function foo(x: number): void {} "repr": "TypeError", "kind": "typeRef", "value": { - "typeName": "TypeError", - "resolution": { - "kind": "typeParam" - } + "typeName": "TypeError" } }, "doc": "wrong type" @@ -65,10 +59,7 @@ export function foo(x: number): void {} "repr": "RangeError", "kind": "typeRef", "value": { - "typeName": "RangeError", - "resolution": { - "kind": "typeParam" - } + "typeName": "RangeError" } }, "doc": "value out of range" @@ -79,10 +70,7 @@ export function foo(x: number): void {} "repr": "RangeError", "kind": "typeRef", "value": { - "typeName": "RangeError", - "resolution": { - "kind": "typeParam" - } + "typeName": "RangeError" } }, "doc": "updated message" diff --git a/tests/snapshots/html_test__html_doc_files_multiple-40.snap b/tests/snapshots/html_test__html_doc_files_multiple-40.snap index 2bebe8505..c33c1d6dc 100644 --- a/tests/snapshots/html_test__html_doc_files_multiple-40.snap +++ b/tests/snapshots/html_test__html_doc_files_multiple-40.snap @@ -145,7 +145,7 @@ expression: files.get(file_name).unwrap() -Hello.computedMethod(a: T extends () => infer R ? R : any): void +Hello.computedMethod(a: T extends () => infer R ? R : any): void

-a: T extends () => infer R ? R : any +a: T extends () => infer R ? R : any
diff --git a/tests/snapshots/html_test__symbol_group.snap b/tests/snapshots/html_test__symbol_group.snap index 0bdc976c7..579599ae6 100644 --- a/tests/snapshots/html_test__symbol_group.snap +++ b/tests/snapshots/html_test__symbol_group.snap @@ -8555,7 +8555,7 @@ expression: files "id": "function_hello_computedmethod_0" }, "name": "Hello.computedMethod", - "summary": "(a: T extends () => infer R ? R : any): void", + "summary": "(a: T extends () => infer R ? R : any): void", "deprecated": null, "content": { "id": "", @@ -8577,7 +8577,7 @@ expression: files "name_prefix": null, "name": "a", "name_href": null, - "content": ": T extends () => infer R ? R : any", + "content": ": T extends () => infer R ? R : any", "anchor": { "id": "function_hello_computedmethod_0_parameter_a" }, diff --git a/tests/specs/export_const_destructured.txt b/tests/specs/export_const_destructured.txt index efc35b30f..bec7d8f63 100644 --- a/tests/specs/export_const_destructured.txt +++ b/tests/specs/export_const_destructured.txt @@ -45,103 +45,115 @@ error[missing-explicit-type]: exported symbol is missing an explicit type annota | ^ # output.txt -Defined in file:///mod.ts:6:3 +Defined in file:///mod.ts:5:3 const a: string export a doc -Defined in file:///mod.ts:8:3 +Defined in file:///mod.ts:7:3 const b: number export b doc -Defined in file:///mod.ts:16:16 +Defined in file:///mod.ts:15:16 const f -Defined in file:///mod.ts:16:22 +Defined in file:///mod.ts:15:22 const h # output.json -[ - { - "name": "a", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 6, - "col": 2, - "byteIndex": 123 +{ + "symbols": [ + { + "name": "a", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 5, + "col": 2, + "byteIndex": 123 + }, + "declarationKind": "export", + "jsDoc": { + "doc": "export a doc" + }, + "kind": "variable", + "def": { + "tsType": { + "repr": "string", + "kind": "keyword", + "value": "string" + }, + "kind": "const" + } + } + ] }, - "declarationKind": "export", - "jsDoc": { - "doc": "export a doc" + { + "name": "b", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 7, + "col": 2, + "byteIndex": 150 + }, + "declarationKind": "export", + "jsDoc": { + "doc": "export b doc" + }, + "kind": "variable", + "def": { + "tsType": { + "repr": "number", + "kind": "keyword", + "value": "number" + }, + "kind": "const" + } + } + ] }, - "kind": "variable", - "variableDef": { - "tsType": { - "repr": "string", - "kind": "keyword", - "keyword": "string" - }, - "kind": "const" - } - }, - { - "name": "b", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 8, - "col": 2, - "byteIndex": 150 - }, - "declarationKind": "export", - "jsDoc": { - "doc": "export b doc" - }, - "kind": "variable", - "variableDef": { - "tsType": { - "repr": "number", - "kind": "keyword", - "keyword": "number" - }, - "kind": "const" - } - }, - { - "name": "f", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 16, - "col": 15, - "byteIndex": 250 - }, - "declarationKind": "export", - "kind": "variable", - "variableDef": { - "tsType": null, - "kind": "const" - } - }, - { - "name": "h", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 16, - "col": 21, - "byteIndex": 256 + { + "name": "f", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 15, + "col": 15, + "byteIndex": 250 + }, + "declarationKind": "export", + "kind": "variable", + "def": { + "kind": "const" + } + } + ] }, - "declarationKind": "export", - "kind": "variable", - "variableDef": { - "tsType": null, - "kind": "const" + { + "name": "h", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 15, + "col": 21, + "byteIndex": 256 + }, + "declarationKind": "export", + "kind": "variable", + "def": { + "kind": "const" + } + } + ] } - } -] + ] +} diff --git a/tests/specs/export_namespace.txt b/tests/specs/export_namespace.txt index adf2d9c0a..f3c3fd31d 100644 --- a/tests/specs/export_namespace.txt +++ b/tests/specs/export_namespace.txt @@ -46,7 +46,7 @@ error[missing-jsdoc]: exported symbol is missing JSDoc documentation | ^ # output.txt -Defined in file:///mod.ts:2:1 +Defined in file:///mod.ts:1:1 namespace RootNs Namespace JSdoc @@ -58,172 +58,182 @@ namespace RootNs # output.json -[ - { - "name": "RootNs", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 2, - "col": 0, - "byteIndex": 23 - }, - "declarationKind": "export", - "jsDoc": { - "doc": "Namespace JSdoc" - }, - "kind": "namespace", - "namespaceDef": { - "elements": [ +{ + "symbols": [ + { + "name": "RootNs", + "declarations": [ { - "name": "a", - "isDefault": false, "location": { "filename": "file:///mod.ts", - "line": 3, - "col": 17, - "byteIndex": 66 - }, - "declarationKind": "export", - "kind": "variable", - "variableDef": { - "tsType": { - "repr": "a", - "kind": "literal", - "literal": { - "kind": "string", - "string": "a" - } - }, - "kind": "const" - } - }, - { - "name": "NestedNs", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 6, - "col": 4, - "byteIndex": 114 + "line": 1, + "col": 0, + "byteIndex": 23 }, "declarationKind": "export", "jsDoc": { - "doc": "Nested namespace JSDoc" + "doc": "Namespace JSdoc" }, "kind": "namespace", - "namespaceDef": { + "def": { "elements": [ { - "name": "Foo", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 7, - "col": 6, - "byteIndex": 148 - }, - "declarationKind": "export", - "kind": "enum", - "enumDef": { - "members": [ - { - "name": "a", - "init": { - "repr": "1", - "kind": "literal", - "literal": { - "kind": "number", - "number": 1.0 - } - }, - "location": { - "filename": "file:///mod.ts", - "line": 8, - "col": 8, - "byteIndex": 174 - } + "name": "a", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 2, + "col": 17, + "byteIndex": 66 }, - { - "name": "b", - "init": { - "repr": "2", + "declarationKind": "export", + "kind": "variable", + "def": { + "tsType": { + "repr": "a", "kind": "literal", - "literal": { - "kind": "number", - "number": 2.0 + "value": { + "kind": "string", + "string": "a" } }, - "location": { - "filename": "file:///mod.ts", - "line": 9, - "col": 8, - "byteIndex": 189 - } + "kind": "const" + } + } + ] + }, + { + "name": "NestedNs", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 5, + "col": 4, + "byteIndex": 114 }, - { - "name": "c", - "init": { - "repr": "3", - "kind": "literal", - "literal": { - "kind": "number", - "number": 3.0 + "declarationKind": "export", + "jsDoc": { + "doc": "Nested namespace JSDoc" + }, + "kind": "namespace", + "def": { + "elements": [ + { + "name": "Foo", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 6, + "col": 6, + "byteIndex": 148 + }, + "declarationKind": "export", + "kind": "enum", + "def": { + "members": [ + { + "name": "a", + "init": { + "repr": "1", + "kind": "literal", + "value": { + "kind": "number", + "number": 1.0 + } + }, + "location": { + "filename": "file:///mod.ts", + "line": 7, + "col": 8, + "byteIndex": 174 + } + }, + { + "name": "b", + "init": { + "repr": "2", + "kind": "literal", + "value": { + "kind": "number", + "number": 2.0 + } + }, + "location": { + "filename": "file:///mod.ts", + "line": 8, + "col": 8, + "byteIndex": 189 + } + }, + { + "name": "c", + "init": { + "repr": "3", + "kind": "literal", + "value": { + "kind": "number", + "number": 3.0 + } + }, + "location": { + "filename": "file:///mod.ts", + "line": 9, + "col": 8, + "byteIndex": 204 + } + } + ] + } + } + ] } - }, - "location": { - "filename": "file:///mod.ts", - "line": 10, - "col": 8, - "byteIndex": 204 - } + ] } - ] - } - } - ] - } - }, - { - "name": "OtherNs", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 15, - "col": 24, - "byteIndex": 252 - }, - "declarationKind": "export", - "kind": "namespace", - "namespaceDef": { - "elements": [ + } + ] + }, { - "name": "Other", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 16, - "col": 2, - "byteIndex": 264 - }, - "declarationKind": "export", - "kind": "class", - "classDef": { - "isAbstract": false, - "constructors": [], - "properties": [], - "indexSignatures": [], - "methods": [], - "extends": null, - "implements": [], - "typeParams": [], - "superTypeParams": [] - } + "name": "OtherNs", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 14, + "col": 24, + "byteIndex": 252 + }, + "declarationKind": "export", + "kind": "namespace", + "def": { + "elements": [ + { + "name": "Other", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 15, + "col": 2, + "byteIndex": 264 + }, + "declarationKind": "export", + "kind": "class", + "def": {} + } + ] + } + ] + } + } + ] } ] } } ] } - } -] + ] +} diff --git a/tests/specs/indented_with_tabs.txt b/tests/specs/indented_with_tabs.txt index 10bb32d4b..16086fcaa 100644 --- a/tests/specs/indented_with_tabs.txt +++ b/tests/specs/indented_with_tabs.txt @@ -70,7 +70,7 @@ namespace Tabs "location": { "filename": "file:///mod.ts", "line": 15, - "col": 2, + "col": 1, "byteIndex": 126 }, "declarationKind": "export", @@ -88,7 +88,7 @@ namespace Tabs "location": { "filename": "file:///mod.ts", "line": 23, - "col": 4, + "col": 2, "byteIndex": 212 }, "tsType": { diff --git a/tests/specs/infer_object_literal.txt b/tests/specs/infer_object_literal.txt index e3401680d..b466ae4f3 100644 --- a/tests/specs/infer_object_literal.txt +++ b/tests/specs/infer_object_literal.txt @@ -27,308 +27,268 @@ error[missing-jsdoc]: exported symbol is missing JSDoc documentation | ^ # output.txt -Defined in file:///mod.ts:4:14 +Defined in file:///mod.ts:3:14 const a: { d(e: string): void; h(): string; h(value: string); [t](u: string): void; a: string; b: Map; c: { d: string; }; f: (g: string) => void; [s]: (number | string)[]; } # output.json -[ - { - "name": "a", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 4, - "col": 13, - "byteIndex": 84 - }, - "declarationKind": "export", - "kind": "variable", - "variableDef": { - "tsType": { - "repr": "", - "kind": "typeLiteral", - "typeLiteral": { - "constructors": [], - "methods": [ - { - "name": "d", - "kind": "method", - "location": { - "filename": "file:///mod.ts", - "line": 9, - "col": 2, - "byteIndex": 166 - }, - "params": [ - { - "kind": "identifier", - "name": "e", - "optional": false, - "tsType": { - "repr": "string", - "kind": "keyword", - "keyword": "string" - } - } - ], - "optional": false, - "returnType": { - "repr": "void", - "kind": "keyword", - "keyword": "void" - }, - "typeParams": [] - }, - { - "name": "h", - "kind": "getter", - "location": { - "filename": "file:///mod.ts", - "line": 11, - "col": 2, - "byteIndex": 221 - }, - "params": [], - "optional": false, - "returnType": { - "repr": "string", - "kind": "keyword", - "keyword": "string" - }, - "typeParams": [] - }, - { - "name": "h", - "kind": "setter", - "location": { - "filename": "file:///mod.ts", - "line": 14, - "col": 2, - "byteIndex": 262 - }, - "params": [ - { - "kind": "identifier", - "name": "value", - "optional": false, - "tsType": { - "repr": "string", - "kind": "keyword", - "keyword": "string" - } - } - ], - "optional": false, - "returnType": null, - "typeParams": [] - }, - { - "name": "t", - "kind": "method", - "location": { - "filename": "file:///mod.ts", - "line": 18, - "col": 2, - "byteIndex": 316 - }, - "params": [ - { - "kind": "identifier", - "name": "u", - "optional": false, - "tsType": { - "repr": "string", - "kind": "keyword", - "keyword": "string" - } - } - ], - "computed": true, - "optional": false, - "returnType": { - "repr": "void", - "kind": "keyword", - "keyword": "void" - }, - "typeParams": [] - } - ], - "properties": [ - { - "name": "a", - "jsDoc": { - "doc": "JSDoc" - }, - "location": { - "filename": "file:///mod.ts", - "line": 6, - "col": 2, - "byteIndex": 107 - }, - "params": [], - "computed": false, - "optional": false, - "tsType": { - "repr": "string", - "kind": "keyword", - "keyword": "string" - }, - "typeParams": [] - }, - { - "name": "b", - "location": { - "filename": "file:///mod.ts", - "line": 7, - "col": 2, - "byteIndex": 117 - }, - "params": [], - "computed": false, - "optional": false, - "tsType": { - "repr": "Map", - "kind": "typeRef", - "typeRef": { - "typeParams": [ - { - "repr": "string", - "kind": "keyword", - "keyword": "string" +{ + "symbols": [ + { + "name": "a", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 3, + "col": 13, + "byteIndex": 84 + }, + "declarationKind": "export", + "kind": "variable", + "def": { + "tsType": { + "kind": "typeLiteral", + "value": { + "methods": [ + { + "name": "d", + "kind": "method", + "location": { + "filename": "file:///mod.ts", + "line": 8, + "col": 2, + "byteIndex": 166 }, - { - "repr": "number", + "params": [ + { + "kind": "identifier", + "name": "e", + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "value": "string" + } + } + ], + "returnType": { + "repr": "void", "kind": "keyword", - "keyword": "number" + "value": "void" } - ], - "typeName": "Map" - } - }, - "typeParams": [] - }, - { - "name": "c", - "location": { - "filename": "file:///mod.ts", - "line": 8, - "col": 2, - "byteIndex": 149 - }, - "params": [], - "computed": false, - "optional": false, - "tsType": { - "repr": "", - "kind": "typeLiteral", - "typeLiteral": { - "constructors": [], - "methods": [], - "properties": [ - { - "name": "d", - "location": { - "filename": "file:///mod.ts", - "line": 8, - "col": 7, - "byteIndex": 154 - }, - "params": [], - "computed": false, - "optional": false, - "tsType": { - "repr": "string", - "kind": "keyword", - "keyword": "string" - }, - "typeParams": [] + }, + { + "name": "h", + "kind": "getter", + "location": { + "filename": "file:///mod.ts", + "line": 10, + "col": 2, + "byteIndex": 221 + }, + "params": [], + "returnType": { + "repr": "string", + "kind": "keyword", + "value": "string" } - ], - "callSignatures": [], - "indexSignatures": [] - } - }, - "typeParams": [] - }, - { - "name": "f", - "location": { - "filename": "file:///mod.ts", - "line": 10, - "col": 2, - "byteIndex": 191 - }, - "params": [], - "computed": false, - "optional": false, - "tsType": { - "repr": "", - "kind": "fnOrConstructor", - "fnOrConstructor": { - "constructor": false, - "tsType": { - "repr": "void", - "kind": "keyword", - "keyword": "void" }, - "params": [ - { - "kind": "identifier", - "name": "g", - "optional": false, - "tsType": { - "repr": "string", - "kind": "keyword", - "keyword": "string" + { + "name": "h", + "kind": "setter", + "location": { + "filename": "file:///mod.ts", + "line": 13, + "col": 2, + "byteIndex": 262 + }, + "params": [ + { + "kind": "identifier", + "name": "value", + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "value": "string" + } } - } - ], - "typeParams": [] - } - }, - "typeParams": [] - }, - { - "name": "s", - "location": { - "filename": "file:///mod.ts", - "line": 17, - "col": 2, - "byteIndex": 293 - }, - "params": [], - "computed": true, - "optional": false, - "tsType": { - "repr": "", - "kind": "array", - "array": { - "repr": "", - "kind": "union", - "union": [ - { - "repr": "number", + ] + }, + { + "name": "t", + "kind": "method", + "location": { + "filename": "file:///mod.ts", + "line": 17, + "col": 2, + "byteIndex": 316 + }, + "params": [ + { + "kind": "identifier", + "name": "u", + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "value": "string" + } + } + ], + "computed": true, + "returnType": { + "repr": "void", "kind": "keyword", - "keyword": "number" + "value": "void" + } + } + ], + "properties": [ + { + "name": "a", + "jsDoc": { + "doc": "JSDoc" + }, + "location": { + "filename": "file:///mod.ts", + "line": 5, + "col": 2, + "byteIndex": 107 }, - { + "tsType": { "repr": "string", "kind": "keyword", - "keyword": "string" + "value": "string" + } + }, + { + "name": "b", + "location": { + "filename": "file:///mod.ts", + "line": 6, + "col": 2, + "byteIndex": 117 + }, + "tsType": { + "repr": "Map", + "kind": "typeRef", + "value": { + "typeParams": [ + { + "repr": "string", + "kind": "keyword", + "value": "string" + }, + { + "repr": "number", + "kind": "keyword", + "value": "number" + } + ], + "typeName": "Map" + } + } + }, + { + "name": "c", + "location": { + "filename": "file:///mod.ts", + "line": 7, + "col": 2, + "byteIndex": 149 + }, + "tsType": { + "kind": "typeLiteral", + "value": { + "properties": [ + { + "name": "d", + "location": { + "filename": "file:///mod.ts", + "line": 7, + "col": 7, + "byteIndex": 154 + }, + "tsType": { + "repr": "string", + "kind": "keyword", + "value": "string" + } + } + ] + } } - ] - } - }, - "typeParams": [] - } - ], - "callSignatures": [], - "indexSignatures": [] + }, + { + "name": "f", + "location": { + "filename": "file:///mod.ts", + "line": 9, + "col": 2, + "byteIndex": 191 + }, + "tsType": { + "kind": "fnOrConstructor", + "value": { + "constructor": false, + "tsType": { + "repr": "void", + "kind": "keyword", + "value": "void" + }, + "params": [ + { + "kind": "identifier", + "name": "g", + "optional": false, + "tsType": { + "repr": "string", + "kind": "keyword", + "value": "string" + } + } + ] + } + } + }, + { + "name": "s", + "location": { + "filename": "file:///mod.ts", + "line": 16, + "col": 2, + "byteIndex": 293 + }, + "computed": true, + "tsType": { + "kind": "array", + "value": { + "kind": "union", + "value": [ + { + "repr": "number", + "kind": "keyword", + "value": "number" + }, + { + "repr": "string", + "kind": "keyword", + "value": "string" + } + ] + } + } + } + ] + } + }, + "kind": "const" + } } - }, - "kind": "const" + ] } - } -] + ] +} diff --git a/tests/specs/jsdoc_types.txt b/tests/specs/jsdoc_types.txt index 0ec1ec4b7..fb2cf08b3 100644 --- a/tests/specs/jsdoc_types.txt +++ b/tests/specs/jsdoc_types.txt @@ -205,17 +205,11 @@ class StringList "value": "number" } ], - "typeName": "Set", - "resolution": { - "kind": "typeParam" - } + "typeName": "Set" } } ], - "typeName": "Map", - "resolution": { - "kind": "typeParam" - } + "typeName": "Map" } }, "doc": "the lookup map" @@ -320,10 +314,7 @@ class StringList "value": "unknown" } ], - "typeName": "Record", - "resolution": { - "kind": "typeParam" - } + "typeName": "Record" } }, "doc": "an object" @@ -346,17 +337,11 @@ class StringList "value": "string" } ], - "typeName": "Array", - "resolution": { - "kind": "typeParam" - } + "typeName": "Array" } } ], - "typeName": "Promise", - "resolution": { - "kind": "typeParam" - } + "typeName": "Promise" } }, "doc": "the results" @@ -367,10 +352,7 @@ class StringList "repr": "RangeError", "kind": "typeRef", "value": { - "typeName": "RangeError", - "resolution": { - "kind": "typeParam" - } + "typeName": "RangeError" } }, "doc": "if out of range" @@ -381,10 +363,7 @@ class StringList "repr": "TypeError", "kind": "typeRef", "value": { - "typeName": "TypeError", - "resolution": { - "kind": "typeParam" - } + "typeName": "TypeError" } }, "doc": "if wrong type" @@ -584,10 +563,7 @@ class StringList "value": "string" } ], - "typeName": "ReadonlyArray", - "resolution": { - "kind": "typeParam" - } + "typeName": "ReadonlyArray" } } } @@ -663,10 +639,7 @@ class StringList "repr": "HTMLElement", "kind": "typeRef", "value": { - "typeName": "HTMLElement", - "resolution": { - "kind": "typeParam" - } + "typeName": "HTMLElement" } } } @@ -711,10 +684,7 @@ class StringList "value": "string" } ], - "typeName": "Array", - "resolution": { - "kind": "typeParam" - } + "typeName": "Array" } } } diff --git a/tests/specs/mapped_types.txt b/tests/specs/mapped_types.txt index 654b3476b..66a665ad4 100644 --- a/tests/specs/mapped_types.txt +++ b/tests/specs/mapped_types.txt @@ -84,10 +84,7 @@ type MappedTypeWithNewProperties = readonly [Properties in keyof Type as N "repr": "Properties", "kind": "typeRef", "value": { - "typeName": "Properties", - "resolution": { - "kind": "typeParam" - } + "typeName": "Properties" } } } diff --git a/tests/specs/namespace_exports_self.txt b/tests/specs/namespace_exports_self.txt index 8a7c08c58..22cc40e03 100644 --- a/tests/specs/namespace_exports_self.txt +++ b/tests/specs/namespace_exports_self.txt @@ -41,7 +41,7 @@ Defined in file:///mod.ts:1:1 namespace a Description. - private const a: string + const a: string Description. Defined in file:///mod.ts:8:1 @@ -88,7 +88,7 @@ namespace f "col": 0, "byteIndex": 20 }, - "declarationKind": "private", + "declarationKind": "export", "jsDoc": { "doc": "Description." }, diff --git a/tests/specs/private_type_class_property.txt b/tests/specs/private_type_class_property.txt index 9d894825c..4717af2d5 100644 --- a/tests/specs/private_type_class_property.txt +++ b/tests/specs/private_type_class_property.txt @@ -51,51 +51,58 @@ error[missing-jsdoc]: exported symbol is missing JSDoc documentation | ^ # output.txt -Defined in file:///mod.ts:1:1 +Defined in file:///mod.ts:0:1 type PrivatePropThroughNamespaceRef = typeof MyNamespace.Export.someProp -Defined in file:///mod.ts:3:1 +Defined in file:///mod.ts:2:1 private namespace MyNamespace # output.json -[ - { - "name": "PrivatePropThroughNamespaceRef", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 1, - "col": 0, - "byteIndex": 0 +{ + "symbols": [ + { + "name": "PrivatePropThroughNamespaceRef", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 0, + "col": 0, + "byteIndex": 0 + }, + "declarationKind": "export", + "kind": "typeAlias", + "def": { + "tsType": { + "repr": "MyNamespace.Export.someProp", + "kind": "typeQuery", + "value": "MyNamespace.Export.someProp" + } + } + } + ] }, - "declarationKind": "export", - "kind": "typeAlias", - "typeAliasDef": { - "tsType": { - "repr": "MyNamespace.Export.someProp", - "kind": "typeQuery", - "typeQuery": "MyNamespace.Export.someProp" - }, - "typeParams": [] + { + "name": "MyNamespace", + "declarations": [ + { + "location": { + "filename": "file:///mod.ts", + "line": 2, + "col": 0, + "byteIndex": 82 + }, + "declarationKind": "private", + "kind": "namespace", + "def": { + "elements": [] + } + } + ] } - }, - { - "name": "MyNamespace", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 3, - "col": 0, - "byteIndex": 82 - }, - "declarationKind": "private", - "kind": "namespace", - "namespaceDef": { - "elements": [] - } - } -] + ] +} diff --git a/tests/specs/re_export_all_as_with_jsdoc.txt b/tests/specs/re_export_all_as_with_jsdoc.txt index 99d8a3573..9ba35bac1 100644 --- a/tests/specs/re_export_all_as_with_jsdoc.txt +++ b/tests/specs/re_export_all_as_with_jsdoc.txt @@ -7,7 +7,7 @@ export function foo(): void {} export * as other from "./other.ts"; # output.txt -Defined in file:///mod.ts:2:1 +Defined in file:///mod.ts:1:1 namespace other Re-exports of other. @@ -17,51 +17,56 @@ namespace other # output.json -[ - { - "name": "other", - "isDefault": false, - "location": { - "filename": "file:///mod.ts", - "line": 2, - "col": 0, - "byteIndex": 28 - }, - "declarationKind": "export", - "jsDoc": { - "doc": "Re-exports of other." - }, - "kind": "namespace", - "namespaceDef": { - "elements": [ +{ + "symbols": [ + { + "name": "other", + "declarations": [ { - "name": "foo", - "isDefault": false, "location": { - "filename": "file:///other.ts", - "line": 2, + "filename": "file:///mod.ts", + "line": 1, "col": 0, - "byteIndex": 18 + "byteIndex": 28 }, "declarationKind": "export", "jsDoc": { - "doc": "a function" + "doc": "Re-exports of other." }, - "kind": "function", - "functionDef": { - "params": [], - "returnType": { - "repr": "void", - "kind": "keyword", - "keyword": "void" - }, - "hasBody": true, - "isAsync": false, - "isGenerator": false, - "typeParams": [] + "kind": "namespace", + "def": { + "elements": [ + { + "name": "foo", + "declarations": [ + { + "location": { + "filename": "file:///other.ts", + "line": 1, + "col": 0, + "byteIndex": 18 + }, + "declarationKind": "export", + "jsDoc": { + "doc": "a function" + }, + "kind": "function", + "def": { + "params": [], + "returnType": { + "repr": "void", + "kind": "keyword", + "value": "void" + }, + "hasBody": true + } + } + ] + } + ] } } ] } - } -] + ] +} diff --git a/tests/specs/structured_jsdoc.txt b/tests/specs/structured_jsdoc.txt index 04f08fa7d..ab7469908 100644 --- a/tests/specs/structured_jsdoc.txt +++ b/tests/specs/structured_jsdoc.txt @@ -184,10 +184,7 @@ class A "value": "void" } ], - "typeName": "Promise", - "resolution": { - "kind": "typeParam" - } + "typeName": "Promise" } } } diff --git a/tests/specs/type_literal_mapped_type.txt b/tests/specs/type_literal_mapped_type.txt index 9fc6d5609..9a6ddd2d8 100644 --- a/tests/specs/type_literal_mapped_type.txt +++ b/tests/specs/type_literal_mapped_type.txt @@ -81,10 +81,7 @@ type T = readonly [P in keyof Type as NewType]: Type[P] "repr": "P", "kind": "typeRef", "value": { - "typeName": "P", - "resolution": { - "kind": "typeParam" - } + "typeName": "P" } } } From 6ff6fa1b3fedaf0c5a2dc260529e8e72ee37da0e Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 2 Jun 2026 13:54:45 -0700 Subject: [PATCH 4/4] use git deno_graph --- Cargo.lock | 4 ++- Cargo.toml | 5 +--- examples/ddoc/main.rs | 4 +-- src/html/mod.rs | 4 +-- src/parser.rs | 67 +++++++++++++++++++++---------------------- 5 files changed, 41 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bbe45084b..a28ea8f17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -618,6 +618,7 @@ checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" [[package]] name = "deno_ast" version = "0.53.2" +source = "git+https://github.com/nathanwhit/deno_ast?branch=oxc-port#adc326fa89885400fc7d7baeb007b833138f5aff" dependencies = [ "base64", "capacity_builder", @@ -717,6 +718,7 @@ dependencies = [ [[package]] name = "deno_graph" version = "0.108.2" +source = "git+https://github.com/nathanwhit/deno_graph?branch=oxc-port#7f786030d26b7aca8937c362436d56e1145168d8" dependencies = [ "async-trait", "boxed_error", @@ -2879,7 +2881,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cfbddcc50..ce97fd0cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/denoland/deno_doc" members = ["lib"] [workspace.dependencies] -deno_graph = { path = "../deno_graph", default-features = false, features = [ +deno_graph = { git = "https://github.com/nathanwhit/deno_graph", branch = "oxc-port", default-features = false, features = [ "swc", "symbols", ] } @@ -20,9 +20,6 @@ import_map = "0.25.0" serde = { version = "1.0.204", features = ["derive"] } serde_json = { version = "1.0.122", features = ["preserve_order"] } -[patch."https://github.com/nathanwhit/deno_ast"] -deno_ast = { path = "../deno_ast" } - [lib] name = "deno_doc" diff --git a/examples/ddoc/main.rs b/examples/ddoc/main.rs index 06ac4aafd..e051ff97c 100644 --- a/examples/ddoc/main.rs +++ b/examples/ddoc/main.rs @@ -259,13 +259,13 @@ async fn run() -> anyhow::Result<()> { // This allows comparing renamed modules. let old_by_original = old_specifiers .iter() - .zip(old_docs.into_iter()) + .zip(old_docs) .map(|(orig, (_, nodes))| (orig.clone(), nodes)) .collect::>(); let new_by_original = new_specifiers .iter() - .zip(new_docs.into_iter()) + .zip(new_docs) .map(|(orig, (_, nodes))| (orig.clone(), nodes)) .collect::>(); diff --git a/src/html/mod.rs b/src/html/mod.rs index c23f47c48..fc1f72b39 100644 --- a/src/html/mod.rs +++ b/src/html/mod.rs @@ -10,6 +10,7 @@ use serde::Serialize; use std::borrow::Cow; use std::cmp::Ordering; use std::collections::HashMap; +use std::path::Path; use std::path::PathBuf; use std::sync::Arc; @@ -1766,8 +1767,7 @@ pub fn find_common_ancestor<'a>( } } - if common_ancestor.as_os_str().is_empty() - || common_ancestor == PathBuf::from("/") + if common_ancestor.as_os_str().is_empty() || common_ancestor == Path::new("/") { None } else { diff --git a/src/parser.rs b/src/parser.rs index c32f1240b..0694ae819 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -565,41 +565,40 @@ impl<'a> DocParser<'a> { for stmt in module_info.statements() { if let Statement::ImportDeclaration(import_decl) = stmt && let Some(js_doc) = js_doc_for_range(module_info, import_decl.span) + && let Some(specifiers) = &import_decl.specifiers { - if let Some(specifiers) = &import_decl.specifiers { - for specifier in specifiers { - let (imported_name, original_name, src) = match specifier { - ImportDeclarationSpecifier::ImportSpecifier(named_specifier) => ( - named_specifier.local.name.to_string(), - Some(module_export_name_value(&named_specifier.imported)), - &import_decl.source.value, - ), - ImportDeclarationSpecifier::ImportDefaultSpecifier( - default_specifier, - ) => ( - default_specifier.local.name.to_string(), - Some("default".to_string()), - &import_decl.source.value, - ), - ImportDeclarationSpecifier::ImportNamespaceSpecifier( - namespace_specifier, - ) => ( - namespace_specifier.local.name.to_string(), - None, - &import_decl.source.value, - ), - }; - - let resolved_specifier = - self.resolve_dependency(&src.to_string(), referrer)?; - - imports.push(Import { - imported_name: imported_name.into_boxed_str(), - js_doc: js_doc.clone(), - src: resolved_specifier.to_string(), - original_name, - }); - } + for specifier in specifiers { + let (imported_name, original_name, src) = match specifier { + ImportDeclarationSpecifier::ImportSpecifier(named_specifier) => ( + named_specifier.local.name.to_string(), + Some(module_export_name_value(&named_specifier.imported)), + &import_decl.source.value, + ), + ImportDeclarationSpecifier::ImportDefaultSpecifier( + default_specifier, + ) => ( + default_specifier.local.name.to_string(), + Some("default".to_string()), + &import_decl.source.value, + ), + ImportDeclarationSpecifier::ImportNamespaceSpecifier( + namespace_specifier, + ) => ( + namespace_specifier.local.name.to_string(), + None, + &import_decl.source.value, + ), + }; + + let resolved_specifier = + self.resolve_dependency(src.as_ref(), referrer)?; + + imports.push(Import { + imported_name: imported_name.into_boxed_str(), + js_doc: js_doc.clone(), + src: resolved_specifier.to_string(), + original_name, + }); } } }