diff --git a/Cargo.lock b/Cargo.lock index 3c7904aa7..1a4ca96ab 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" @@ -111,9 +99,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "arrayvec" @@ -121,23 +109,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 2.0.106", -] - [[package]] name = "async-trait" version = "0.1.89" @@ -164,7 +135,7 @@ dependencies = [ "addr2line", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.8.9", "object", "rustc-demangle", "windows-targets 0.52.6", @@ -176,6 +147,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "base64-simd" version = "0.8.0" @@ -186,32 +163,11 @@ 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 = "2.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" - -[[package]] -name = "bitvec" -version = "1.0.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "block-buffer" @@ -237,25 +193,18 @@ name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" -dependencies = [ - "allocator-api2", -] [[package]] -name = "bytes" -version = "1.12.1" +name = "bytecount" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] -name = "bytes-str" -version = "0.2.7" +name = "bytes" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c60b5ce37e0b883c37eb89f79a1e26fbe9c1081945d024eee93e8d91a7e18b3" -dependencies = [ - "bytes", - "serde", -] +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "capacity_builder" @@ -305,10 +254,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.34" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" +checksum = "86e055fa6e3e40ad6187ba25b6855eeb635d5271f8e0f0e1e9a5826b8d75bea0" dependencies = [ + "find-msvc-tools", "shlex", ] @@ -395,6 +345,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" @@ -403,15 +362,15 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "compact_str" -version = "0.7.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +checksum = "79fcda08c33bb58b97008b2cdada6622500e949e060f5913361763121abd2416" dependencies = [ "castaway", "cfg-if", "itoa", - "ryu", "static_assertions", + "zmij", ] [[package]] @@ -463,6 +422,12 @@ dependencies = [ "vte", ] +[[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" @@ -485,7 +450,7 @@ dependencies = [ "clap", "criterion-plot", "futures", - "itertools", + "itertools 0.13.0", "num-traits", "oorandom", "page_size", @@ -505,7 +470,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" dependencies = [ "cast", - "itertools", + "itertools 0.13.0", ] [[package]] @@ -593,58 +558,25 @@ dependencies = [ "syn 2.0.106", ] -[[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" +version = "0.53.3" +source = "git+https://github.com/nathanwhit/deno_ast?branch=oxc-port#a12e82c25d4851b6bd34270bd17e4c992ca7e082" dependencies = [ - "base64", + "base64 0.22.1", "capacity_builder", "deno_error", "deno_media_type", "deno_terminal", - "dprint-swc-ext", + "oxc", "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", "url", @@ -734,9 +666,8 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.111.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d39f55639b6bffe4e886d2ea33724606729d3ec9c8e05a48952a56c1cef961" +version = "0.111.1" +source = "git+https://github.com/nathanwhit/deno_graph?branch=oxc-port#962071922301d16dff79e3ee485482025dd3a0dc" dependencies = [ "async-trait", "boxed_error", @@ -792,9 +723,9 @@ dependencies = [ [[package]] name = "deno_semver" -version = "0.10.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff487e9bf55c39bfbc47418a009a0de0988c4fea5e48e8ca787fa7dbff8056cc" +checksum = "147261611819fb4dfe339b53e3b45d6704c7e32c86ce33a88511d5bcebebaaa3" dependencies = [ "capacity_builder", "deno_error", @@ -887,20 +818,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" @@ -917,6 +838,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" @@ -946,9 +879,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "fastrand" -version = "2.5.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fearless_simd" @@ -964,7 +897,7 @@ checksum = "3e91d94c6885390b81782d7ee60fd6583b33907333a8b340de25ccf468353315" dependencies = [ "proc-macro2", "quote", - "syn 3.0.7", + "syn 3.0.9", ] [[package]] @@ -981,6 +914,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" + [[package]] name = "finl_unicode" version = "1.5.0" @@ -1002,22 +941,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 2.0.106", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - [[package]] name = "futf" version = "0.1.5" @@ -1162,32 +1085,19 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ - "ahash", "allocator-api2", ] -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[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" @@ -1200,18 +1110,10 @@ dependencies = [ ] [[package]] -name = "hstr" -version = "3.0.3" +name = "hmac-sha1-compact" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c43c0a9e8fbdb3bb9dc8eee85e1e2ac81605418b4c83b6b7413cbf14d56ca5c" -dependencies = [ - "hashbrown 0.14.5", - "new_debug_unreachable", - "once_cell", - "rustc-hash", - "serde", - "triomphe", -] +checksum = "7ed9b23855291da44e7e84616e19dc0d969c3580e14ffa6b759f28775e26afc1" [[package]] name = "html-escape" @@ -1349,12 +1251,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" @@ -1374,12 +1270,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.14.0" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", - "hashbrown 0.17.1", + "hashbrown", "serde", "serde_core", ] @@ -1407,18 +1303,6 @@ dependencies = [ "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 2.0.106", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1434,11 +1318,20 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" @@ -1450,6 +1343,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" @@ -1518,15 +1417,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memchr-n" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1805571b8e7b1284ad43f27c88477840c1c0e5807c150021ac83d2228806540e" +checksum = "f48c6352cc1185740af256ccc396af598d2366bfd90a34f5afe48744bf06a5b5" dependencies = [ "fearless_simd", "fearless_simd_macros", @@ -1541,6 +1440,15 @@ dependencies = [ "adler2", ] +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.0.4" @@ -1564,15 +1472,20 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nonmax" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" + [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "93e7820bc0a80a0238e650327316f929ba18d5be054b647490a3a6a339f3e7c0" dependencies = [ "num-integer", "num-traits", - "serde", ] [[package]] @@ -1608,16 +1521,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", - "libc", -] - [[package]] name = "object" version = "0.36.7" @@ -1652,135 +1555,500 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] -name = "page_size" -version = "0.6.0" +name = "oxc" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +checksum = "d6e790cd34b555e135d0d656139676ae62a50ef9a6829f9aacf9602b7525c501" dependencies = [ - "libc", - "winapi", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_codegen", + "oxc_diagnostics", + "oxc_parser", + "oxc_regular_expression", + "oxc_semantic", + "oxc_span", + "oxc_str", + "oxc_syntax", + "oxc_transformer", + "oxc_transformer_plugins", ] [[package]] -name = "par-core" -version = "2.0.0" +name = "oxc-browserslist" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96cbd21255b7fb29a5d51ef38a779b517a91abd59e2756c039583f43ef4c90f" +checksum = "456720daa870e4f69f8d29fded1c8deea82da4780a6b8553baa160eb0cd8d864" dependencies = [ - "once_cell", + "js-sys", + "libc", + "miniz_oxide 0.9.1", + "postcard", + "rustc-hash", + "serde", + "thiserror", ] [[package]] -name = "parking_lot" -version = "0.12.4" +name = "oxc_allocator" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "45c8f46c8923b4afb4dd588d4684d5dd32332f1341225c066cc6af31094e7e3d" dependencies = [ - "lock_api", - "parking_lot_core", + "allocator-api2", + "hashbrown", + "oxc_data_structures", + "rustc-hash", ] [[package]] -name = "parking_lot_core" -version = "0.9.11" +name = "oxc_ast" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "35465751cfc99739fee42d8345b57d5b5087b462bea7bc5bb17d1f248e1efa22" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", + "bitflags", + "oxc_allocator", + "oxc_ast_macros", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_estree", + "oxc_regular_expression", + "oxc_span", + "oxc_str", + "oxc_syntax", ] [[package]] -name = "pathdiff" -version = "0.2.3" +name = "oxc_ast_macros" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +checksum = "e78e5d50ecf9fbf6c00afb29dbd670784b2ac407fd676f625d1f3515a1a2d577" +dependencies = [ + "phf 0.14.0", + "proc-macro2", + "quote", + "syn 3.0.9", +] [[package]] -name = "percent-encoding" -version = "2.3.2" +name = "oxc_ast_visit" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +checksum = "6836d2fde033c44eae57ab1be3fcc7bd6a57465783bdfce654ca28064a334dbe" +dependencies = [ + "oxc_allocator", + "oxc_ast", + "oxc_span", + "oxc_syntax", +] [[package]] -name = "pest" -version = "2.8.1" +name = "oxc_codegen" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +checksum = "75db0d260bb5493e31be0ab17651d428da5cd8c49ec2cf78d857e605d66385dd" dependencies = [ - "memchr", - "thiserror", - "ucd-trie", + "bitflags", + "cow-utils", + "oxc_allocator", + "oxc_ast", + "oxc_data_structures", + "oxc_ecmascript", + "oxc_index", + "oxc_semantic", + "oxc_sourcemap", + "oxc_span", + "oxc_str", + "oxc_syntax", + "rustc-hash", + "smallvec", ] [[package]] -name = "pest_derive" -version = "2.8.1" +name = "oxc_compat" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" +checksum = "90809c31d39f49d2023b090ffcfd13b5f2e07b156abde430f1b1454ceef51bb1" dependencies = [ - "pest", - "pest_generator", + "cow-utils", + "oxc-browserslist", + "oxc_syntax", + "rustc-hash", + "serde", ] [[package]] -name = "pest_generator" -version = "2.8.1" +name = "oxc_data_structures" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" +checksum = "a46b759a8cb13a1111649370f1d769322b082edabd625466254f238818bdc9e9" dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.106", + "ropey", ] [[package]] -name = "pest_meta" -version = "2.8.1" +name = "oxc_diagnostics" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" +checksum = "5b80f4b05a80879518ebe85a8df9368758ebc1e176327b659e1e97389f8561c7" dependencies = [ - "pest", - "sha2", + "bytecount", + "cow-utils", + "itoa", + "memchr", + "oxc_span", + "percent-encoding", + "smallvec", + "textwrap", + "unicode-segmentation", + "unicode-width 0.2.1", ] [[package]] -name = "phf" -version = "0.11.3" +name = "oxc_ecmascript" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +checksum = "f8c634665e0be5dde95549146734ab4939b8d1b5d2e7cc006d38b9f5d17a58a2" dependencies = [ - "phf_macros", - "phf_shared 0.11.3", + "dragonbox_ecma", + "itoa", + "num-bigint", + "num-traits", + "oxc_ast", + "oxc_data_structures", + "oxc_span", + "oxc_str", + "oxc_syntax", ] [[package]] -name = "phf" -version = "0.14.0" +name = "oxc_estree" +version = "0.155.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6" -dependencies = [ - "phf_shared 0.14.0", - "serde", -] +checksum = "5dcdd8235762cc9305d619842b73c1e89a0ebec8ccf2f27142ef597521443c1f" [[package]] -name = "phf_codegen" -version = "0.11.3" +name = "oxc_index" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +checksum = "191884bee6c3744909a51acc7d78d4ae370d817b25875b10642f632327b6296e" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", + "nonmax", + "serde", ] [[package]] -name = "phf_codegen" +name = "oxc_parser" +version = "0.155.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "635c4e1bb876a9d4ee0e338fa68547a1d75add58637e5c3921fb81ae10a60439" +dependencies = [ + "bitflags", + "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.155.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae3f2c42773d16336a75d5c61dae45a34aea399f0b5399a7a25c8509d79662f" +dependencies = [ + "bitflags", + "oxc_allocator", + "oxc_ast_macros", + "oxc_diagnostics", + "oxc_span", + "oxc_str", + "phf 0.14.0", + "rustc-hash", + "unicode-id-start", +] + +[[package]] +name = "oxc_semantic" +version = "0.155.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b24ee2095e2ddac60c2063b59693bbf2b80936c8a9e036463b153a203857831b" +dependencies = [ + "itertools 0.15.0", + "memchr", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_index", + "oxc_span", + "oxc_str", + "oxc_syntax", + "rustc-hash", + "self_cell", + "smallvec", +] + +[[package]] +name = "oxc_sourcemap" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1133371a5fadc14b9f66a8fec14be3564a77647c7ab21b1ef0ec973bd82613ce" +dependencies = [ + "base64-simd", + "json-escape-simd", + "rustc-hash", + "serde", + "serde_json", +] + +[[package]] +name = "oxc_span" +version = "0.155.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb5bee6f7a9829ddc4d8c05102fe1aa7e2ca31c7ff0bcfbb7069ca977334840" +dependencies = [ + "compact_str", + "oxc_allocator", + "oxc_ast_macros", + "oxc_estree", + "oxc_str", +] + +[[package]] +name = "oxc_str" +version = "0.155.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c04d966af690d3b780ee4c47436174e558750eed6ca40b07d695fa4910ad8e33" +dependencies = [ + "compact_str", + "hashbrown", + "memchr", + "oxc_allocator", + "oxc_estree", +] + +[[package]] +name = "oxc_syntax" +version = "0.155.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684d5f6db25b6e3d026582b3926166c80eeda9aac8a879782292c6a33b7d13a0" +dependencies = [ + "bitflags", + "cow-utils", + "dragonbox_ecma", + "nonmax", + "oxc_allocator", + "oxc_ast_macros", + "oxc_estree", + "oxc_index", + "oxc_span", + "oxc_str", + "phf 0.14.0", + "unicode-id-start", +] + +[[package]] +name = "oxc_transformer" +version = "0.155.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fec592c64f6455678cbdb76635144f76825fcaf85f9509d814bd6a9e2bfde160" +dependencies = [ + "base64 0.23.1", + "compact_str", + "hmac-sha1-compact", + "indexmap", + "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", +] + +[[package]] +name = "oxc_transformer_plugins" +version = "0.155.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2470e565dc13884f9a1e1c08d8eaad3c927e807d867a118c0f0287534971327f" +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.155.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ba98ff0dc34cb2e45bcbe3cee395e792298fad77ca63c574766571f859cc56" +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 = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + +[[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" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "pest_meta" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" +dependencies = [ + "pest", + "sha2", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared 0.11.3", +] + +[[package]] +name = "phf" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6" +dependencies = [ + "phf_macros", + "phf_shared 0.14.0", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_codegen" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41b585a510fb76fdebead6897982ef2a03a21d8e6cbcca904999742a4afc6ffe" @@ -1811,12 +2079,12 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +checksum = "5fa8d0ca26d424d27630da600c6624696e7dec8bf7b3b492b383c5dc49e5e085" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", + "phf_generator 0.14.0", + "phf_shared 0.14.0", "proc-macro2", "quote", "syn 2.0.106", @@ -1828,7 +2096,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher 1.0.1", + "siphasher", ] [[package]] @@ -1837,7 +2105,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89" dependencies = [ - "siphasher 1.0.1", + "siphasher", ] [[package]] @@ -1880,6 +2148,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" @@ -1914,15 +2194,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" @@ -1932,12 +2203,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.6" @@ -2011,6 +2276,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" @@ -2035,12 +2310,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" @@ -2050,18 +2319,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" @@ -2155,9 +2424,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook-registry" @@ -2174,12 +2443,6 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "siphasher" version = "1.0.1" @@ -2194,20 +2457,18 @@ checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "d0d5d4b1981b8bbbb7aed204cae5726d683d5d6ac7e74ec54122ea28f315e7c8" +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" @@ -2231,25 +2492,18 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "str_indices" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6" + [[package]] name = "string_cache" version = "0.8.9" @@ -2275,293 +2529,12 @@ dependencies = [ "quote", ] -[[package]] -name = "string_enum" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae36a4951ca7bd1cfd991c241584a9824a70f6aff1e7d4f693fb3f2465e4030e" -dependencies = [ - "quote", - "swc_macros_common", - "syn 2.0.106", -] - [[package]] name = "strsim" 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", - "is-macro", - "num-bigint", - "once_cell", - "phf 0.11.3", - "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 2.0.106", -] - -[[package]] -name = "swc_ecma_lexer" -version = "26.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e82f7747e052c6ff6e111fa4adeb14e33b46ee6e94fe5ef717601f651db48fc" -dependencies = [ - "bitflags", - "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", - "either", - "num-bigint", - "phf 0.11.3", - "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", - "once_cell", - "par-core", - "phf 0.11.3", - "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", - "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 2.0.106", -] - -[[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 2.0.106", -] - -[[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" @@ -2575,9 +2548,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.7" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d62a2e0561533f2ca2561d0cf27fd9fedb640a1bf2616ff5d5c80d99017faadc" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -2615,12 +2588,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "tendril" version = "0.4.3" @@ -2642,12 +2609,14 @@ dependencies = [ ] [[package]] -name = "text_lines" -version = "0.6.0" +name = "textwrap" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd5828de7deaa782e1dd713006ae96b3bee32d3279b79eb67ecf8072c059bcf" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" dependencies = [ - "serde", + "smawk", + "unicode-linebreak", + "unicode-width 0.2.1", ] [[package]] @@ -2736,47 +2705,6 @@ dependencies = [ "syn 2.0.106", ] -[[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 2.0.106", -] - -[[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" @@ -2785,9 +2713,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" @@ -2807,6 +2735,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" @@ -2816,6 +2750,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + [[package]] name = "unicode-width" version = "0.1.14" @@ -2864,12 +2804,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" @@ -3188,15 +3122,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 = "xml5ever" version = "0.18.1" @@ -3238,26 +3163,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 2.0.106", -] - [[package]] name = "zerofrom" version = "0.1.6" @@ -3311,3 +3216,9 @@ dependencies = [ "quote", "syn 2.0.106", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/Cargo.toml b/Cargo.toml index cdab2bf20..0821f985b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,11 +11,11 @@ repository = "https://github.com/denoland/deno_doc" members = ["lib"] [workspace.dependencies] -deno_graph = { version = "0.111.0", default-features = false, features = [ +deno_graph = { git = "https://github.com/nathanwhit/deno_graph", branch = "oxc-port", default-features = false, features = [ "swc", "symbols", ] } -deno_ast = { version = "0.53.2" } +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/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 475e3163a..8bca70453 100644 --- a/examples/ddoc/main.rs +++ b/examples/ddoc/main.rs @@ -160,9 +160,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, @@ -256,13 +258,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/lib/lib.rs b/lib/lib.rs index a25406035..c0623dff6 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..2c202d45e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.89.0" +channel = "1.97.0" components = ["rustfmt", "clippy"] diff --git a/src/class.rs b/src/class.rs index 801fd5d00..8bd5acd11 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); @@ -282,10 +287,9 @@ pub fn class_to_class_def( } } - let extends: Option> = match &class.super_class { - Some(boxed) => { - let expr: &Expr = boxed; - walk_class_extends(expr).map(|s| s.into_boxed_str()) + let extends: Option> = match &class.heritage { + Some(heritage) => { + walk_class_extends(&heritage.expression).map(|s| s.into_boxed_str()) } None => None, }; @@ -293,94 +297,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 +399,47 @@ 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); + { + let param = &ts_index_sig.parameter; + 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,21 @@ 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 + .heritage + .as_ref() + .and_then(|heritage| heritage.type_arguments.as_deref()), ); let decorators = decorators_to_defs(module_info, &class.decorators); @@ -457,7 +470,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 +478,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 +495,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 af5b8db35..620d4b34f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -13,10 +13,10 @@ use crate::util::ignore_directives::parse_ignore_directives; 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; @@ -26,7 +26,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; @@ -406,8 +406,7 @@ fn identifier_location( let Some(offset) = identifier_offset(text, location.byte_index, name) else { return location.clone(); }; - let pos = text_info.range().start + offset; - get_text_info_location(&location.filename, text_info, pos) + get_text_info_location(&location.filename, text_info, offset as u32) } pub struct DiagnosticsCollector<'a> { @@ -435,7 +434,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 1147298c9..d216fa67d 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; @@ -604,7 +604,7 @@ impl MethodsDiff { #[serde(rename_all = "camelCase")] pub struct MethodDiff { pub name: Box, - pub kind: deno_ast::swc::ast::MethodKind, + pub kind: crate::util::types::MethodKind, #[serde(skip_serializing_if = "Option::is_none")] pub name_change: Option>>, #[serde(skip_serializing_if = "Option::is_none")] diff --git a/src/diff/interface.rs b/src/diff/interface.rs index 5ead4010f..c5d2515cf 100644 --- a/src/diff/interface.rs +++ b/src/diff/interface.rs @@ -431,7 +431,7 @@ impl InterfaceMethodsDiff { #[serde(rename_all = "camelCase")] pub struct InterfaceMethodDiff { pub name: String, - pub kind: deno_ast::swc::ast::MethodKind, + pub kind: crate::util::types::MethodKind, #[serde(skip_serializing_if = "Option::is_none")] pub name_change: Option>, #[serde(skip_serializing_if = "Option::is_none")] 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 4d0670ef1..bab3090cd 100644 --- a/src/display.rs +++ b/src/display.rs @@ -53,30 +53,32 @@ pub(crate) fn display_readonly(is_readonly: bool) -> impl Display { } pub(crate) fn display_method( - method: deno_ast::swc::ast::MethodKind, + method: crate::util::types::MethodKind, ) -> impl Display { colors::magenta(match method { - deno_ast::swc::ast::MethodKind::Getter => "get ", - deno_ast::swc::ast::MethodKind::Setter => "set ", - _ => "", + crate::util::types::MethodKind::Getter => "get ", + crate::util::types::MethodKind::Setter => "set ", + crate::util::types::MethodKind::Method => "", }) } cfg_if! { if #[cfg(feature = "rust")] { + use crate::util::types::Accessibility; + 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 ", }, ) } diff --git a/src/enum.rs b/src/enum.rs index cd6090064..1cdd724de 100644 --- a/src/enum.rs +++ b/src/enum.rs @@ -1,6 +1,8 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_ast::SourceRangedForSpanned; +use deno_ast::JSStrExt; +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 +33,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_lossy(); + let init = if let Some(expr) = &enum_member.initializer { infer_ts_type_from_expr(module_info, expr, true) } else { None @@ -53,7 +50,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 0c6ded46b..8db223751 100644 --- a/src/function.rs +++ b/src/function.rs @@ -2,15 +2,15 @@ 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::BlockStmtOrExpr; -use deno_ast::swc::ast::ReturnStmt; -use deno_ast::swc::ast::Stmt; +use deno_ast::oxc::ast::ast::ArrowFunctionBody; +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; @@ -38,47 +38,54 @@ 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(); + .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_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() => - { - Some(inferred_void_return_type(function.is_async)) - } - None => None, - }; + 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() => + { + Some(inferred_void_return_type(function.r#async)) + } + 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, } @@ -86,37 +93,42 @@ 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(); - - let maybe_return_type = match arrow - .return_type - .as_deref() - .map(|return_type| TsTypeDef::new(module_info, &return_type.type_ann)) - { + .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 = match arrow.return_type.as_ref().map(|return_type| { + TsTypeDef::new(module_info, &return_type.type_annotation) + }) { Some(return_type) => Some(return_type), // An arrow with a block body that has no value-returning `return` // statement implicitly returns `void` (or `Promise` when async), // matching the inference done for function expressions. Expression-bodied // arrows always return their expression, so no return type is inferred. None - if !arrow.is_generator - && matches!(&*arrow.body, BlockStmtOrExpr::BlockStmt(block) - if get_return_stmt_with_arg_from_stmts(&block.stmts).is_none()) => + if matches!(&arrow.body, ArrowFunctionBody::FunctionBody(block) + if get_return_stmt_with_arg_from_stmts(&block.statements).is_none()) => { - Some(inferred_void_return_type(arrow.is_async)) + Some(inferred_void_return_type(arrow.r#async)) } None => None, }; let type_params = maybe_type_param_decl_to_type_param_defs( module_info, - arrow.type_params.as_deref(), + arrow.type_parameters.as_deref(), ); FunctionDef { @@ -124,8 +136,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([]), } @@ -152,21 +164,23 @@ fn inferred_void_return_type(is_async: bool) -> TsTypeDef { 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); @@ -176,49 +190,61 @@ 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).or_else(|| { - n.alt - .as_deref() - .and_then(get_return_stmt_with_arg_from_stmt) - }), - Stmt::Switch(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 + Statement::LabeledStatement(n) => { + get_return_stmt_with_arg_from_stmt(&n.body) + } + Statement::IfStatement(n) => { + get_return_stmt_with_arg_from_stmt(&n.consequent).or_else(|| { + n.alternate .as_ref() - .and_then(|h| get_return_stmt_with_arg_from_stmts(&h.body.stmts)) + .and_then(get_return_stmt_with_arg_from_stmt) }) - .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, + } + Statement::SwitchStatement(n) => n + .cases + .iter() + .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/comrak.rs b/src/html/comrak.rs index 8a887405e..19aa50e6a 100644 --- a/src/html/comrak.rs +++ b/src/html/comrak.rs @@ -149,10 +149,9 @@ pub fn create_renderer( if title_only { walk_node_title(root); - if let Some(child) = root.first_child() { + { + let child = root.first_child()?; render_node(child, &options, &plugins) - } else { - return None; } } else { if let Some(node_hook) = &node_hook { diff --git a/src/html/mod.rs b/src/html/mod.rs index 39cbf1837..6de671b07 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; @@ -968,12 +969,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, } } } @@ -1095,7 +1096,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 = @@ -1116,7 +1117,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( @@ -1257,10 +1258,10 @@ impl DocNodeWithContext { // so they must not get drilldown pages or listing/search entries // either let is_private = - |accessibility: &Option| { + |accessibility: &Option| { matches!( accessibility, - Some(deno_ast::swc::ast::Accessibility::Private) + Some(crate::util::types::Accessibility::Private) ) }; @@ -1897,8 +1898,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/html/symbols/class.rs b/src/html/symbols/class.rs index 099ae32fa..18fb53b75 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/interface.rs b/src/html/symbols/interface.rs index eb36c3012..6e59af93c 100644 --- a/src/html/symbols/interface.rs +++ b/src/html/symbols/interface.rs @@ -6,7 +6,7 @@ use crate::html::render_context::RenderContext; use crate::html::types::render_type_def_colon; use crate::html::types::type_params_summary; use crate::html::util::*; -use deno_ast::swc::ast::MethodKind; +use crate::util::types::MethodKind; use indexmap::IndexMap; pub(crate) fn render_interface( diff --git a/src/html/symbols/mod.rs b/src/html/symbols/mod.rs index 6485b42ba..e15d0f08f 100644 --- a/src/html/symbols/mod.rs +++ b/src/html/symbols/mod.rs @@ -712,7 +712,7 @@ pub(crate) fn render_accessor_type( 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 0f4cf63b1..3c305072c 100644 --- a/src/html/symbols/namespace.rs +++ b/src/html/symbols/namespace.rs @@ -496,7 +496,7 @@ fn get_subitem_diff_status( DeclarationDefDiff::Class(class_diff) => match kind { DrilldownKind::Method(method_kind) => { let mc = class_diff.method_changes.as_ref()?; - let matches = |m_name: &str, m_kind: deno_ast::swc::ast::MethodKind| { + let matches = |m_name: &str, m_kind: crate::util::types::MethodKind| { m_name == name && crate::html::MethodKind::from(m_kind) == *method_kind }; @@ -539,7 +539,7 @@ fn get_subitem_diff_status( DeclarationDefDiff::Interface(iface_diff) => match kind { DrilldownKind::Method(method_kind) => { let mc = iface_diff.method_changes.as_ref()?; - let matches = |m_name: &str, m_kind: deno_ast::swc::ast::MethodKind| { + let matches = |m_name: &str, m_kind: crate::util::types::MethodKind| { m_name == name && crate::html::MethodKind::from(m_kind) == *method_kind }; @@ -597,14 +597,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) @@ -643,7 +643,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; } @@ -676,8 +676,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 596102962..c1b9710c4 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; @@ -88,7 +88,7 @@ pub(crate) fn render_type_def( && let Some(href) = ctx .ctx .href_resolver - .resolve_global_symbol(&[keyword.to_owned()]) + .resolve_global_symbol(std::slice::from_ref(keyword)) { format!( r#"{keyword}"#, @@ -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/html/util.rs b/src/html/util.rs index cd390757a..474390deb 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(); @@ -1011,8 +1011,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..479122390 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -1,11 +1,16 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_ast::SourceRangedForSpanned; +use deno_ast::JSStrExt; +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 +21,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 +45,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_lossy(), + 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.as_js_str().to_string_lossy(); + } + // 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_lossy(), + 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 +111,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 +145,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 +161,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 +172,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 +198,34 @@ 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.parameter] + .into_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 23686d2b7..3fd928f20 100644 --- a/src/js_doc.rs +++ b/src/js_doc.rs @@ -86,47 +86,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 } @@ -609,7 +594,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, @@ -619,6 +606,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..64ae16023 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; @@ -206,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); } } @@ -312,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/params.rs b/src/params.rs index 457f55288..671f0bae7 100644 --- a/src/params.rs +++ b/src/params.rs @@ -5,11 +5,19 @@ use crate::decorators::decorators_to_defs; use crate::display::SliceDisplayer; use crate::display::display_optional; use crate::ts_type::TsTypeDef; +use deno_ast::JSStrExt; -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 +92,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 +137,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 +149,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 +250,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 +293,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 +319,111 @@ 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_lossy(), + 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) + } + // computed keys: the source text of the key including its brackets + // (swc's `ComputedPropName` span covered the brackets) + _ => { + let span = prop_key.span(); + let text = + &module_info.source_text()[span.start as usize..span.end as usize]; + format!("[{}]", text) + } } } diff --git a/src/parser.rs b/src/parser.rs index 4f394d45f..77f572541 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,26 +1,34 @@ // 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::JSStrExt; +use deno_ast::oxc::ast::ast::BindingIdentifier; +use deno_ast::oxc::ast::ast::BindingIdentifier as Ident; +use deno_ast::oxc::ast::ast::BindingPattern; +use deno_ast::oxc::ast::ast::Class; +use deno_ast::oxc::ast::ast::ClassElement; +use deno_ast::oxc::ast::ast::Declaration as OxcDeclaration; +use deno_ast::oxc::ast::ast::ExportDeclaration; +use deno_ast::oxc::ast::ast::ExportDefaultDeclaration; +use deno_ast::oxc::ast::ast::ExportDefaultDeclarationKind; +use deno_ast::oxc::ast::ast::Expression; +use deno_ast::oxc::ast::ast::Function as FnDecl; +use deno_ast::oxc::ast::ast::IdentifierReference; +use deno_ast::oxc::ast::ast::ImportDeclarationSpecifier; +use deno_ast::oxc::ast::ast::MethodDefinitionKind; +use deno_ast::oxc::ast::ast::ModuleExportName; +use deno_ast::oxc::ast::ast::PropertyKey; +use deno_ast::oxc::ast::ast::Statement; +use deno_ast::oxc::ast::ast::TSEnumDeclaration as TsEnumDecl; +use deno_ast::oxc::ast::ast::TSInterfaceDeclaration; +use deno_ast::oxc::ast::ast::TSInterfaceDeclaration as TsInterfaceDecl; +use deno_ast::oxc::ast::ast::TSNamespaceDeclaration as TsModuleDecl; +use deno_ast::oxc::ast::ast::TSSignature; +use deno_ast::oxc::ast::ast::TSTypeAliasDeclaration as TsTypeAliasDecl; +use deno_ast::oxc::ast::ast::TSTypeName; +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 +42,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::HashMap; use std::collections::HashSet; @@ -46,7 +53,7 @@ use std::sync::Arc; use crate::Location; use crate::diagnostics::DiagnosticsCollector; use crate::diagnostics::DocDiagnostic; -use crate::interface::expr_to_name; +use crate::interface::property_key_name; use crate::js_doc::JsDoc; use crate::node::DeclarationDef; use crate::node::DeclarationKind; @@ -54,10 +61,13 @@ use crate::node::Document; use crate::node::Import; use crate::node::NamespaceDef; use crate::node::ReferenceDef; +use crate::ts_type::Id; use crate::ts_type::PropertyDef; use crate::ts_type::TsTypeDef; use crate::ts_type::TsTypeDefKind; use crate::ts_type::TsTypeLiteralDef; +use crate::ts_type::binding_identifier_to_id; +use crate::ts_type::identifier_reference_to_id; use crate::ts_type::infer_simple_ts_type_from_init; use crate::util::graph::resolve_deno_graph_module; use crate::util::swc::get_location; @@ -66,10 +76,39 @@ 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::MethodKind; +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), @@ -123,11 +162,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 { @@ -485,18 +526,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; } } } @@ -551,38 +589,36 @@ impl<'a> DocParser<'a> { } } - /// Resolves a heritage clause expression (`implements Foo`, + /// Resolves a heritage clause type name (`implements Foo`, /// `implements ns.Foo`) to the interface declarations it refers to, /// following imports and re-exports. fn resolve_heritage_interfaces<'b>( &'b self, module_info: &'b EsModuleInfo, - expr: &deno_ast::swc::ast::Expr, - ) -> Vec<(ModuleInfoRef<'b>, &'b TsInterfaceDecl)> { - use deno_ast::swc::ast::Expr; - + type_name: &TSTypeName, + ) -> Vec<(ModuleInfoRef<'b>, &'b TSInterfaceDeclaration<'b>)> { // splits `a.b.c` into the root identifier and the member path - fn split_expr<'e>( - expr: &'e Expr, + fn split_type_name<'e>( + type_name: &'e TSTypeName<'e>, parts: &mut Vec, - ) -> Option<&'e Ident> { - match expr { - Expr::Ident(ident) => Some(ident), - Expr::Member(member_expr) => { - let root = split_expr(&member_expr.obj, parts)?; - let ident = member_expr.prop.as_ident()?; - parts.push(ident.sym.to_string()); + ) -> Option<&'e IdentifierReference<'e>> { + match type_name { + TSTypeName::IdentifierReference(ident) => Some(ident), + TSTypeName::QualifiedName(qualified_name) => { + let root = split_type_name(&qualified_name.left, parts)?; + parts.push(qualified_name.right.name.to_string()); Some(root) } - _ => None, + TSTypeName::ThisExpression(_) => None, } } let mut parts = Vec::new(); - let Some(root_ident) = split_expr(expr, &mut parts) else { + let Some(root_ident) = split_type_name(type_name, &mut parts) else { return Vec::new(); }; - let Some(symbol) = module_info.symbol_from_swc(&root_ident.to_id()) else { + let root_id = identifier_reference_to_id(module_info, root_ident); + let Some(symbol) = module_info.symbol_from_swc(&root_id) else { return Vec::new(); }; @@ -596,10 +632,7 @@ impl<'a> DocParser<'a> { .root_symbol .resolve_symbol_dep( ModuleInfoRef::Esm(module_info), - &deno_graph::symbols::SymbolNodeDep::QualifiedId( - root_ident.to_id(), - parts, - ), + &deno_graph::symbols::SymbolNodeDep::QualifiedId(root_id, parts), ) .into_iter() .filter_map(|entry| match entry { @@ -618,8 +651,8 @@ impl<'a> DocParser<'a> { let interface_decl = match definition.symbol_decl.maybe_node()? { SymbolNodeRef::TsInterface(n) => n, SymbolNodeRef::ExportDecl(_, ExportDeclRef::TsInterface(n)) => n, - SymbolNodeRef::ExportDefaultDecl(n) => match &n.decl { - DefaultDecl::TsInterfaceDecl(n) => n, + SymbolNodeRef::ExportDefaultDecl(n) => match &n.declaration { + ExportDefaultDeclarationKind::TSInterfaceDeclaration(n) => &**n, _ => return None, }, _ => return None, @@ -635,12 +668,9 @@ impl<'a> DocParser<'a> { fn apply_heritage_member_docs( &self, module_info: &EsModuleInfo, - class: &deno_ast::swc::ast::Class, + class: &Class, class_def: &mut crate::class::ClassDef, ) { - use deno_ast::swc::ast::MethodKind; - use deno_ast::swc::ast::TsTypeElement; - if class.implements.is_empty() { return; } @@ -687,12 +717,11 @@ impl<'a> DocParser<'a> { // base's. for type_ref in class.implements.iter() { let mut stack = - self.resolve_heritage_interfaces(module_info, &type_ref.expr); + self.resolve_heritage_interfaces(module_info, &type_ref.expression); stack.reverse(); while let Some((interface_module, interface_decl)) = stack.pop() { - if !visited - .insert((interface_module.module_id(), interface_decl.range())) + if !visited.insert((interface_module.module_id(), interface_decl.span)) { continue; } @@ -702,29 +731,23 @@ impl<'a> DocParser<'a> { for member in &interface_decl.body.body { let (key, kind) = match member { - TsTypeElement::TsMethodSignature(sig) => { - (&sig.key, Some(MethodKind::Method)) - } - TsTypeElement::TsGetterSignature(sig) => { - (&sig.key, Some(MethodKind::Getter)) + TSSignature::TSMethodSignature(sig) => { + (&sig.key, Some(MethodKind::from(sig.kind))) } - TsTypeElement::TsSetterSignature(sig) => { - (&sig.key, Some(MethodKind::Setter)) - } - TsTypeElement::TsPropertySignature(sig) => (&sig.key, None), - TsTypeElement::TsCallSignatureDecl(_) - | TsTypeElement::TsConstructSignatureDecl(_) - | TsTypeElement::TsIndexSignature(_) => continue, + TSSignature::TSPropertySignature(sig) => (&sig.key, None), + TSSignature::TSCallSignatureDeclaration(_) + | TSSignature::TSConstructSignatureDeclaration(_) + | TSSignature::TSIndexSignature(_) => continue, }; let Some(js_doc) = - js_doc_for_range(interface_module_info, &member.range()) + js_doc_for_range(interface_module_info, member.span()) else { continue; }; if js_doc.is_empty() { continue; } - let name = expr_to_name(key); + let name = property_key_name(key); match kind { Some(kind) => { method_docs.entry((name, kind)).or_insert(js_doc); @@ -738,10 +761,10 @@ impl<'a> DocParser<'a> { let mut parents = interface_decl .extends .iter() - .flat_map(|type_ref| { + .flat_map(|heritage| { self.resolve_heritage_interfaces( interface_module_info, - &type_ref.expr, + &heritage.type_name, ) }) .collect::>(); @@ -784,42 +807,39 @@ 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) + && let Some(specifiers) = &import_decl.specifiers { - for specifier in &import_decl.specifiers { - use deno_ast::swc::ast::ImportSpecifier::*; - + for specifier in specifiers { 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, + ImportDeclarationSpecifier::ImportSpecifier(named_specifier) => ( + named_specifier.local.name.to_string(), + Some(module_export_name_value(&named_specifier.imported)), + &import_decl.source.value, ), - Default(default_specifier) => ( - default_specifier.local.sym.to_string(), + ImportDeclarationSpecifier::ImportDefaultSpecifier( + default_specifier, + ) => ( + default_specifier.local.name.to_string(), Some("default".to_string()), - &import_decl.src.value, + &import_decl.source.value, ), - Namespace(namespace_specifier) => ( - namespace_specifier.local.sym.to_string(), + ImportDeclarationSpecifier::ImportNamespaceSpecifier( + namespace_specifier, + ) => ( + namespace_specifier.local.name.to_string(), None, - &import_decl.src.value, + &import_decl.source.value, ), }; let resolved_specifier = - self.resolve_dependency(&src.to_string_lossy(), referrer)?; + self.resolve_dependency(&src.to_str_lossy(), referrer)?; imports.push(Import { imported_name: imported_name.into_boxed_str(), @@ -840,9 +860,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(self, module_info, init, location, js_doc)) @@ -854,24 +873,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(self, module_info, init, location, js_doc)); } @@ -891,9 +910,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) }) } @@ -901,24 +920,20 @@ 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 (mut class_def, _) = super::class::get_doc_for_class_decl(module_info, class_decl); - self.apply_heritage_member_docs( - module_info, - &class_decl.class, - &mut class_def, - ); + self.apply_heritage_member_docs(module_info, class_decl, &mut class_def); let location = get_location(module_info, full_range.start); Some(Declaration::class( location, @@ -932,7 +947,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 = @@ -950,7 +965,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( @@ -971,7 +986,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( @@ -991,7 +1006,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 = @@ -1010,7 +1025,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, @@ -1032,13 +1047,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 { + OxcDeclaration::TSNamespaceDeclaration(n) => Some(&**n), + _ => None, + } + } SymbolNodeRef::TsNamespace(n) => Some(n), _ => None, }) @@ -1049,10 +1063,6 @@ impl<'a> DocParser<'a> { return None; // we already analyzed this module } - let _namespace_name = match &ts_module.id { - TsModuleName::Ident(ident) => ident.sym.to_string(), - TsModuleName::Str(str_) => str_.value.to_string_lossy().into_owned(), - }; let mut elements = Vec::new(); let mut handled_symbols = HashSet::new(); @@ -1176,18 +1186,17 @@ 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::TsNamespace(n) => match &n.id { - TsModuleName::Ident(ident) => Some(ident.sym.to_string()), - TsModuleName::Str(s) => { - Some(s.value.to_string_lossy().into_owned()) - } - }, - SymbolNodeRef::Var(_, _, ident) => Some(ident.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) => Some(n.id.name.to_string()), + SymbolNodeRef::Var(_, _, ident) => Some(ident.name.to_string()), SymbolNodeRef::ExportDefaultDecl(_) => { Some("default".to_string()) } @@ -1216,27 +1225,19 @@ 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()); + .map(|ident| ident.name.to_string().into_boxed_str()); let (mut class_def, decorator_js_doc) = - crate::class::class_to_class_def( - module_info, - &class_expr.class, - default_name, - ); - self.apply_heritage_member_docs( - module_info, - &class_expr.class, - &mut class_def, - ); + crate::class::class_to_class_def(module_info, class, default_name); + self.apply_heritage_member_docs(module_info, class, &mut class_def); let js_doc = if js_doc.is_empty() { decorator_js_doc } else { @@ -1244,12 +1245,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( @@ -1259,8 +1260,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, @@ -1273,6 +1274,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) @@ -1281,11 +1290,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( @@ -1303,7 +1314,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, ), }, @@ -1319,7 +1330,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()); @@ -1396,7 +1407,7 @@ impl<'a> DocParser<'a> { .filter_map(|node| { let specifier = self .resolve_dependency( - &node.src.value.to_string_lossy(), + &node.source.value.to_string_lossy(), module_info.specifier(), ) .ok()?; @@ -1782,7 +1793,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) @@ -1791,22 +1802,44 @@ 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, 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) => { - 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()) + // a nested namespace (`namespace A.B {}`) node starts at its own + // identifier, but its declaration is located at the outer `namespace` + // keyword, so prefer the symbol declaration's range + let full_range = symbol + .decls() + .iter() + .find(|decl| { + matches!( + decl.maybe_node(), + Some(SymbolNodeRef::TsNamespace(decl_node)) if std::ptr::eq(decl_node, n) + ) + }) + .map(|decl| decl.range) + .unwrap_or(n.range()); + self.get_decl_for_ts_namespace(module_info, symbol, n, full_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( @@ -1814,7 +1847,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 @@ -1822,25 +1855,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( @@ -1848,7 +1881,7 @@ impl<'a> DocParser<'a> { var_decl, var_declarator, ident, - &export_decl.range(), + export_decl.range(), ), }, SymbolNodeRef::Module(_) @@ -1873,7 +1906,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, @@ -1903,17 +1938,31 @@ 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 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: &ExportDeclaration, + ) -> bool { + export_decl.declaration.declare() } fn resolve_dependency( @@ -1935,7 +1984,7 @@ impl<'a> DocParser<'a> { enum ShadowedExportTarget { /// A local declaration or an aliased export targeting a local symbol. - SwcId(deno_ast::swc::ast::Id), + SwcId(Id), /// An aliased re-export (`export { foo as Bar } from "..."`), identified /// by the range of its export specifier. Range(SourceRange), @@ -1952,65 +2001,75 @@ enum ShadowedExportTarget { fn collect_shadowed_export_targets( module_info: &EsModuleInfo, ) -> IndexMap> { - use deno_ast::swc::ast::ExportSpecifier; - use deno_ast::swc::ast::ModuleExportName; - use deno_ast::swc::ast::Pat; - let mut targets: IndexMap> = IndexMap::new(); - for item in module_info.source().program_ref().body() { - let ModuleItemRef::ModuleDecl(module_decl) = item else { - continue; - }; - match module_decl { - ModuleDecl::ExportDecl(export_decl) => { - let mut add_ident = |ident: &Ident| { + for stmt in &module_info.program().body { + match stmt { + Statement::ExportDeclaration(export_decl) => { + let mut add_ident = |ident: &BindingIdentifier| { targets - .entry(ident.sym.to_string()) + .entry(ident.name.to_string()) .or_default() - .push(ShadowedExportTarget::SwcId(ident.to_id())); + .push(ShadowedExportTarget::SwcId(binding_identifier_to_id(ident))); }; - match &export_decl.decl { - Decl::Class(class_decl) => add_ident(&class_decl.ident), - Decl::Fn(fn_decl) => add_ident(&fn_decl.ident), - Decl::TsInterface(interface_decl) => add_ident(&interface_decl.id), - Decl::TsTypeAlias(type_alias) => add_ident(&type_alias.id), - Decl::TsEnum(enum_decl) => add_ident(&enum_decl.id), - Decl::TsModule(ts_module_decl) => { - if let TsModuleName::Ident(ident) = &ts_module_decl.id { + match &export_decl.declaration { + OxcDeclaration::ClassDeclaration(class_decl) => { + if let Some(ident) = &class_decl.id { add_ident(ident); } } - Decl::Var(var_decl) => { - for declarator in &var_decl.decls { - if let Pat::Ident(ident) = &declarator.name { - add_ident(&ident.id); + OxcDeclaration::FunctionDeclaration(fn_decl) => { + if let Some(ident) = &fn_decl.id { + add_ident(ident); + } + } + OxcDeclaration::TSInterfaceDeclaration(interface_decl) => { + add_ident(&interface_decl.id) + } + OxcDeclaration::TSTypeAliasDeclaration(type_alias) => { + add_ident(&type_alias.id) + } + OxcDeclaration::TSEnumDeclaration(enum_decl) => { + add_ident(&enum_decl.id) + } + OxcDeclaration::TSNamespaceDeclaration(ts_module_decl) => { + add_ident(&ts_module_decl.id) + } + OxcDeclaration::VariableDeclaration(var_decl) => { + for declarator in &var_decl.declarations { + if let BindingPattern::BindingIdentifier(ident) = &declarator.id { + add_ident(ident); } } } - Decl::Using(_) => {} + OxcDeclaration::TSExternalModuleDeclaration(_) + | OxcDeclaration::TSGlobalDeclaration(_) + | OxcDeclaration::TSImportEqualsDeclaration(_) => {} } } - ModuleDecl::ExportNamed(named_export) => { + Statement::ExportNamedDeclaration(named_export) => { for specifier in &named_export.specifiers { - let ExportSpecifier::Named(named_specifier) = specifier else { + let export_name = module_export_name_value(&specifier.exported); + let ModuleExportName::IdentifierReference(orig) = &specifier.local + else { continue; }; - let export_name = module_export_name_value( - named_specifier - .exported - .as_ref() - .unwrap_or(&named_specifier.orig), + targets.entry(export_name).or_default().push( + ShadowedExportTarget::SwcId(identifier_reference_to_id( + module_info, + orig, + )), ); - let target = if named_export.src.is_some() { - ShadowedExportTarget::Range(named_specifier.range()) - } else if let ModuleExportName::Ident(orig) = &named_specifier.orig { - ShadowedExportTarget::SwcId(orig.to_id()) - } else { - continue; - }; - targets.entry(export_name).or_default().push(target); + } + } + Statement::ExportFromDeclaration(named_export) => { + for specifier in &named_export.specifiers { + let export_name = module_export_name_value(&specifier.exported); + targets + .entry(export_name) + .or_default() + .push(ShadowedExportTarget::Range(specifier.span)); } } _ => {} @@ -2031,8 +2090,8 @@ impl DocParser<'_> { fn decl_from_init_alias( &self, module_info: &EsModuleInfo, - init: &deno_ast::swc::ast::Expr, - ident: &Ident, + init: &Expression, + ident: &BindingIdentifier, js_doc: &JsDoc, ) -> Option { /// The alias's own JSDoc wins; an undocumented alias inherits the @@ -2043,17 +2102,19 @@ impl DocParser<'_> { target_range: SourceRange, ) -> JsDoc { if js_doc.is_empty() { - js_doc_for_range(module_info, &target_range).unwrap_or_default() + js_doc_for_range(module_info, target_range).unwrap_or_default() } else { js_doc.clone() } } - let location = get_location(module_info, ident.start()); + let location = get_location(module_info, ident.span.start); match init { - deno_ast::swc::ast::Expr::Ident(init_ident) => { - let symbol = module_info.symbol_from_swc(&init_ident.to_id())?; + Expression::Identifier(init_ident) => { + let symbol = module_info.symbol_from_swc( + &identifier_reference_to_id(module_info, init_ident), + )?; for decl in symbol.decls() { let Some(node) = decl.maybe_node() else { continue; @@ -2074,18 +2135,14 @@ impl DocParser<'_> { // no `def_name`: the alias has a name of its own, and // `def_name` would override it everywhere the symbol is // rendered - crate::class::class_to_class_def( - module_info, - &class_decl.class, - None, - ); + crate::class::class_to_class_def(module_info, class_decl, None); self.apply_heritage_member_docs( module_info, - &class_decl.class, + class_decl, &mut class_def, ); let js_doc = if js_doc.is_empty() && decorator_js_doc.is_empty() { - js_doc_or_target(module_info, js_doc, class_decl.range()) + js_doc_or_target(module_info, js_doc, class_decl.span) } else if js_doc.is_empty() { decorator_js_doc } else { @@ -2101,11 +2158,10 @@ impl DocParser<'_> { SymbolNodeRef::FnDecl(fn_decl) => { let function_def = crate::function::function_to_function_def( module_info, - &fn_decl.function, + fn_decl, None, ); - let js_doc = - js_doc_or_target(module_info, js_doc, fn_decl.range()); + let js_doc = js_doc_or_target(module_info, js_doc, fn_decl.span); return Some(Declaration::function( location, DeclarationKind::Declare, @@ -2118,42 +2174,36 @@ impl DocParser<'_> { } None } - deno_ast::swc::ast::Expr::Member(member) => { + Expression::StaticMemberExpression(member) => { // `const baz = Foo.bar` where `bar` is a static method of a class - let obj_ident = member.obj.as_ident()?; - let prop_name = match &member.prop { - deno_ast::swc::ast::MemberProp::Ident(prop) => prop.sym.as_str(), - _ => return None, + let Expression::Identifier(obj_ident) = &member.object else { + return None; }; - let symbol = module_info.symbol_from_swc(&obj_ident.to_id())?; + let prop_name = member.property.name.as_str(); + let symbol = module_info.symbol_from_swc( + &identifier_reference_to_id(module_info, obj_ident), + )?; for decl in symbol.decls() { let Some(node) = decl.maybe_node() else { continue; }; let class = match node { - SymbolNodeRef::ClassDecl(class_decl) => &class_decl.class, + SymbolNodeRef::ClassDecl(class_decl) => class_decl, SymbolNodeRef::ExportDecl(_, ExportDeclRef::Class(class_decl)) => { - &class_decl.class + class_decl } _ => continue, }; - for class_member in &class.body { - let deno_ast::swc::ast::ClassMember::Method(method) = class_member - else { + for class_member in &class.body.body { + let ClassElement::MethodDefinition(method) = class_member else { continue; }; - if !method.is_static - || method.kind != deno_ast::swc::ast::MethodKind::Method - { + if !method.r#static || method.kind != MethodDefinitionKind::Method { continue; } let name_matches = match &method.key { - deno_ast::swc::ast::PropName::Ident(key) => { - key.sym.as_str() == prop_name - } - deno_ast::swc::ast::PropName::Str(key) => { - key.value.as_str() == Some(prop_name) - } + PropertyKey::StaticIdentifier(key) => key.name == prop_name, + PropertyKey::StringLiteral(key) => key.value == prop_name, _ => false, }; if !name_matches { @@ -2161,10 +2211,10 @@ impl DocParser<'_> { } let function_def = crate::function::function_to_function_def( module_info, - &method.function, + &method.value, None, ); - let js_doc = js_doc_or_target(module_info, js_doc, method.range()); + let js_doc = js_doc_or_target(module_info, js_doc, method.span); return Some(Declaration::function( location, DeclarationKind::Declare, @@ -2183,24 +2233,21 @@ impl DocParser<'_> { fn decl_from_expr( parser: &DocParser, 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 (mut 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 (mut class_def, decorator_js_doc) = + crate::class::class_to_class_def(module_info, class_expr, def_name); parser.apply_heritage_member_docs( module_info, - &class_expr.class, + class_expr, &mut class_def, ); let js_doc = if js_doc.is_empty() { @@ -2210,11 +2257,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( @@ -2224,7 +2271,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( @@ -2320,12 +2367,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 8145ef56d..b88cc9c44 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -505,8 +505,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)?; @@ -521,8 +521,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 @@ -893,9 +893,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 924e18cc3..54d205b57 100644 --- a/src/ts_type.rs +++ b/src/ts_type.rs @@ -7,24 +7,26 @@ use crate::display::display_computed; use crate::display::display_method; 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 deno_ast::JSStrExt; 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_graph::symbols::ExportDeclRef; use deno_graph::symbols::SymbolNodeRef; @@ -35,26 +37,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_lossy()) + } + 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)), @@ -62,11 +145,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 { @@ -75,69 +158,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, }; @@ -149,9 +210,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)), @@ -159,8 +220,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)), @@ -170,9 +231,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)), @@ -180,7 +241,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, @@ -189,15 +250,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 { @@ -217,15 +278,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(), @@ -233,10 +287,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() @@ -248,8 +302,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(), @@ -263,34 +317,49 @@ impl TsTypeDef { pub fn ts_expr_with_type_args( module_info: &EsModuleInfo, - other: &TsExprWithTypeArgs, + other: &TSClassImplements, ) -> Self { - // `expr_to_name` formats member expressions as computed keys - // (`[Symbol.iterator]`); heritage clauses like - // `implements ns.Interface` are plain qualified names instead. - fn expr_to_qualified_name( - expr: &deno_ast::swc::ast::Expr, - ) -> Option { - use deno_ast::swc::ast::Expr; - use deno_ast::swc::ast::MemberProp; - - match expr { - Expr::Ident(ident) => Some(ident.sym.to_string()), - Expr::Member(member_expr) => { - let left = expr_to_qualified_name(&member_expr.obj)?; - let MemberProp::Ident(ident) = &member_expr.prop else { - return None; - }; - Some(format!("{left}.{}", ident.sym)) - } - _ => None, - } + 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, + }), } + } - let type_name = expr_to_qualified_name(&other.expr) - .unwrap_or_else(|| expr_to_name(&other.expr)); + pub fn ts_class_implements( + module_info: &EsModuleInfo, + other: &TSClassImplements, + ) -> Self { + 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 = ts_type_name_to_name(&other.type_name); + + let type_params = if let Some(type_params_inst) = &other.type_arguments { let ts_type_defs = type_params_inst .params .iter() @@ -302,7 +371,7 @@ impl TsTypeDef { None }; - let resolution = expr_root_ident(&other.expr) + let resolution = ts_type_name_root_ident(&other.type_name) .and_then(|i| resolve_type_ref(module_info, i)); TsTypeDef { @@ -317,11 +386,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)), }; @@ -331,17 +400,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))), }; @@ -352,7 +425,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![]; @@ -360,33 +433,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.as_js_str().to_string_lossy()) + .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, @@ -396,64 +468,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.as_js_str().to_string_lossy()) + .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, @@ -467,26 +498,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, @@ -496,21 +524,33 @@ 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 - .iter() - .map(|param| ts_fn_param_to_param_def(module_info, param)) + let params = [&ts_index_sig.parameter] + .into_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 = 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, @@ -520,26 +560,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, @@ -569,7 +606,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)), @@ -584,9 +621,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 { @@ -595,8 +635,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() @@ -609,8 +649,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_lossy(), + qualifier: other + .qualifier + .as_ref() + .map(ts_import_type_qualifier_to_name), type_params, }; @@ -620,50 +663,52 @@ 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_parameters.as_deref(), + ); - 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 fn_def = TsFnOrConstructorDef { + constructor: false, + ts_type: TsTypeDef::new( + module_info, + &ts_fn_type.return_type.type_annotation, + ), + params, + type_params, + }; - 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, - } - } + TsTypeDef { + kind: TsTypeDefKind::FnOrConstructor(Box::new(fn_def)), + repr: String::new(), + } + } + + 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 { @@ -672,313 +717,493 @@ impl TsTypeDef { } } - pub fn new(module_info: &EsModuleInfo, other: &TsType) -> Self { - use deno_ast::swc::ast::TsType::*; + 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) } - TsTypeRef(type_ref) => TsTypeDef::ts_type_ref(module_info, type_ref), - TsTypeQuery(type_query) => TsTypeDef::ts_type_query(type_query), - TsTypeLit(type_literal) => { + TSType::TSConstructorType(ctor_type) => { + TsTypeDef::ts_constructor_type(module_info, ctor_type) + } + TSType::TSTypeReference(type_ref) => { + TsTypeDef::ts_type_ref(module_info, type_ref) + } + 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::*; +pub(crate) type Id = (String, usize); + +pub(crate) fn binding_identifier_to_id(ident: &BindingIdentifier) -> Id { + let ctxt = ident + .symbol_id + .get() + .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(); +pub(crate) 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) +} + +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 expr_root_ident(expr: &Expr) -> Option<&Ident> { - match expr { - Expr::Ident(ident) => Some(ident), - Expr::Member(member_expr) => expr_root_ident(&member_expr.obj), - _ => 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_lossy() + } + 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 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 resolve_type_ref( module_info: &EsModuleInfo, - ident: &Ident, + ident: &IdentifierReference, ) -> Option { - if let Some(symbol) = module_info.symbol_from_swc(&ident.to_id()) { - if let Some(file_dep) = symbol.file_dep() { + let id = identifier_reference_to_id(module_info, ident); + if let Some(symbol) = module_info.symbol_from_swc(&id) { + return if let Some(file_dep) = symbol.file_dep() { Some(TypeRefResolution::Import { specifier: file_dep.specifier.clone(), name: file_dep.name.maybe_name().map(|s| s.to_string()), }) } 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()); - Some(TypeRefResolution::TypeParam { - declaring_name: origin.as_ref().map(|o| o.0.clone()), - declaring_kind: origin.as_ref().map(|o| o.1.clone()), - }) - } else { - // Unresolved identifier — a global type (Promise, Array, etc.) - // or truly unresolvable. - None + }; } + // A reference that semantic analysis resolved to nothing is an unresolved + // identifier: a global type (Promise, Array, etc.) or truly unresolvable. + let reference_symbol_id = + match (ident.reference_id.get(), module_info.scoping()) { + (Some(reference_id), Some(scoping)) => { + match scoping.get_reference(reference_id).symbol_id() { + // swc's resolver did not bind `infer X` type parameters, so a + // reference to one was unresolved + Some(symbol_id) + if is_infer_type_param(module_info, scoping, symbol_id) => + { + return None; + } + Some(symbol_id) => Some(symbol_id), + None => return None, + } + } + // not semantically analyzed (e.g. a type parsed from a JSDoc tag) + _ => None, + }; + // The identifier resolved to a binding that is not a module-level symbol: + // it's a type parameter or other locally-scoped binding. + let origin = 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: origin.as_ref().and_then(|o| o.0.clone()), + declaring_kind: origin.as_ref().and_then(|o| o.1.clone()), + }) } -/// Walks the module AST to find which declaration owns a type parameter. -fn find_type_param_origin( +/// Whether the symbol is a type parameter introduced by an `infer X` type. +fn is_infer_type_param( module_info: &EsModuleInfo, - target_id: &Id, -) -> Option<(String, TypeParamDeclaringKind)> { - use deno_ast::ModuleItemRef; - - let program = module_info.source().program_ref(); + scoping: &deno_ast::oxc::semantic::Scoping, + symbol_id: deno_ast::oxc::semantic::SymbolId, +) -> bool { + let span = scoping.symbol_span(symbol_id); + module_info + .source_text() + .get(..span.start as usize) + .is_some_and(|text| text.trim_end().ends_with("infer")) +} - 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); - } +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, + ) } - ModuleItemRef::Stmt(Stmt::Decl(decl)) => { - if let Some(origin) = find_type_param_in_decl(decl, target_id) { - return Some(origin); - } + 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, + ) } - 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); - } - } - } + 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::ExportDeclaration(export) => { + declaration_type_param_declaring_info( + &export.declaration, + 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 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, +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, ), - 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 - } - } - 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 - } - } - 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 + 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 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)); +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, } - - 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)); - } - } - _ => {} - } - } - - 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 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 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 simple_expr_name(expr: &Expr) -> String { - match expr { - Expr::Ident(ident) => ident.sym.to_string(), - _ => "[computed]".to_string(), - } +fn span_contains(container: Span, span: Span) -> bool { + container.start <= span.start && span.end <= container.end } -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)) +fn ts_tuple_element_to_ts_type_def( + module_info: &EsModuleInfo, + elem: &TSTupleElement, +) -> TsTypeDef { + match elem { + TSTupleElement::TSOptionalType(opt) => { + TsTypeDef::ts_optional_type(module_info, opt) + } + TSTupleElement::TSRestType(rest) => { + TsTypeDef::ts_rest_type(module_info, rest) + } + 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) + } + TSTupleElement::TSTypeReference(t) => { + TsTypeDef::ts_type_ref(module_info, t) + } + 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) + } + 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"), + } } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] @@ -1075,20 +1300,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 { @@ -1099,22 +1325,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 { @@ -1482,18 +1704,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 { ... } /// ^^^^^^^ ^^^^^ ^^^^^^^^ @@ -1533,7 +1743,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) } @@ -1549,8 +1759,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_lossy()) } pub fn string_value(value: String) -> Self { @@ -1565,7 +1775,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); @@ -1573,7 +1786,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, @@ -1607,7 +1820,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) } @@ -1623,12 +1836,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, }; @@ -1694,86 +1914,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")) + } } - Expr::New(expr) => { + 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())) + } + 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)) - } - Expr::TsAs(as_expr) => { - // e.g.) export const foo = 1 as string; - Some(TsTypeDef::new(module_info, &as_expr.type_ann)) + Some(TsTypeDef::new(module_info, &assertion.type_annotation)) } - 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 @@ -1803,63 +2057,66 @@ 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::ImportMeta(_) + | Expression::NewTarget(_) + | 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 { @@ -1871,43 +2128,50 @@ 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); + for elem in &arr_lit.elements { + match elem { + ArrayExpressionElement::SpreadElement(spread) => { + // e.g.) const foo = [...bar, "baz"] as const; + if let Some(element_types) = infer_ts_types_from_spread_expr( + module_info, + &spread.argument, + is_const, + ) { + for ts_type in element_types { + if !defs.contains(&ts_type) { + defs.push(ts_type); + } + } + } else { + // the type of the spread element cannot be inferred and so will + // infer an any array. + return Some(TsTypeDef { + repr: "any[]".to_string(), + kind: TsTypeDefKind::Array(Box::new(TsTypeDef::keyword("any"))), + }); } - } 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"))), - }); } - } else { - // e.g.) const foo = [...bar, "baz"] as const; - if let Some(element_types) = - infer_ts_types_from_spread_expr(module_info, &expr.expr, is_const) - { - for ts_type in element_types { + 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"))), + }); } - } else { - // the type of the spread element cannot be inferred and so will - // infer an any array. - return Some(TsTypeDef { - repr: "any[]".to_string(), - kind: TsTypeDefKind::Array(Box::new(TsTypeDef::keyword("any"))), - }); } } } @@ -1954,15 +2218,13 @@ fn infer_ts_type_from_spread_ident( ) => (var_decl, var_declarator), _ => return None, }; - if let Pat::Ident(ident) = &var_declarator.name - && let Some(type_ann) = &ident.type_ann - { - return Some(TsTypeDef::new(module_info, &type_ann.type_ann)); + if let Some(type_ann) = &var_declarator.type_annotation { + return Some(TsTypeDef::new(module_info, &type_ann.type_annotation)); } infer_ts_type_from_expr( module_info, - var_declarator.init.as_deref()?, - var_decl.kind == VarDeclKind::Const, + var_declarator.init.as_ref()?, + var_decl.kind == VariableDeclarationKind::Const, ) }) } @@ -1972,14 +2234,14 @@ fn infer_ts_type_from_spread_ident( /// spread expression and unwrapping its array or tuple element types. fn infer_ts_types_from_spread_expr( module_info: &EsModuleInfo, - expr: &Expr, + expr: &Expression, is_const: bool, ) -> Option> { let ts_type = match expr { - Expr::Ident(ident) => { + Expression::Identifier(ident) => { // e.g.) const foo = ["a", "b"] as const; // const bar = [...foo, "c"] as const; - let id = ident.to_id(); + let id = identifier_reference_to_id(module_info, ident); let already_seen = SEEN_SPREAD_IDENTS.with(|seen| { let mut seen = seen.borrow_mut(); if seen.contains(&id) { @@ -2013,7 +2275,7 @@ fn infer_ts_types_from_spread_expr( fn infer_ts_type_from_arrow_expr( module_info: &EsModuleInfo, - expr: &ArrowExpr, + expr: &ArrowFunctionExpression, ) -> Option { Some(TsTypeDef { kind: TsTypeDefKind::FnOrConstructor(Box::new( @@ -2025,7 +2287,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( @@ -2035,67 +2297,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), }), }), @@ -2103,33 +2324,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() { @@ -2141,24 +2356,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.as_js_str().to_string_lossy()) + .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, @@ -2166,89 +2384,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); @@ -2262,11 +2479,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::>>(); @@ -2295,11 +2512,11 @@ impl Display for TsTypeDef { write!( f, "{} {} {} ? {} : {}", - &*conditional.check_type, + *conditional.check_type, colors::magenta("extends"), - &*conditional.extends_type, - &*conditional.true_type, - &*conditional.false_type + *conditional.extends_type, + *conditional.true_type, + *conditional.false_type ) } TsTypeDefKind::Infer(infer) => { @@ -2325,14 +2542,14 @@ impl Display for TsTypeDef { "" }), SliceDisplayer::new(&fn_or_constructor.params, ", ", false), - &fn_or_constructor.ts_type, + fn_or_constructor.ts_type, ) } TsTypeDefKind::IndexedAccess(indexed_access) => { write!( f, "{}[{}]", - &*indexed_access.obj_type, &*indexed_access.index_type + *indexed_access.obj_type, *indexed_access.index_type ) } TsTypeDefKind::Intersection(intersection) => { @@ -2443,7 +2660,7 @@ impl Display for TsTypeDef { ) } TsTypeDefKind::TypeOperator(type_operator) => { - write!(f, "{} {}", type_operator.operator, &type_operator.ts_type) + write!(f, "{} {}", type_operator.operator, type_operator.ts_type) } TsTypeDefKind::TypeQuery(type_query) => { write!(f, "typeof {}", type_query) @@ -2470,7 +2687,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/ignore_directives.rs b/src/util/ignore_directives.rs index 8e3af0b45..536497e9d 100644 --- a/src/util/ignore_directives.rs +++ b/src/util/ignore_directives.rs @@ -3,10 +3,8 @@ use std::collections::HashMap; use std::collections::HashSet; -use deno_ast::SourceRange; -use deno_ast::SourceRangedForSpanned; use deno_ast::SourceTextInfo; -use deno_ast::swc::common::comments::CommentKind; +use deno_ast::oxc::span::Span; use deno_graph::symbols::EsModuleInfo; /// Ignores the diagnostics on the next line of code. @@ -97,27 +95,29 @@ impl IgnoreDirectives { } pub fn parse_ignore_directives(module_info: &EsModuleInfo) -> IgnoreDirectives { - let text_info = module_info.source().text_info_lazy(); - let comments = module_info.source().comments().get_vec(); + let text_info = module_info.source_text_info(); + let source_text = module_info.source_text(); + let comments = module_info.comments(); let mut directives = IgnoreDirectives::default(); - for comment in &comments { - for line_index in comment_only_lines(text_info, comment.range()) { + for comment in comments { + for line_index in comment_only_lines(text_info, comment.span) { directives.comment_lines.insert(line_index); } } - for comment in &comments { - if comment.kind != CommentKind::Line { + for comment in comments { + if !comment.is_line() { continue; } - let line_index = text_info.line_index(comment.start()); + let line_index = text_info.line_index(comment.span.start as usize); if !directives.comment_lines.contains(&line_index) { continue; // trailing comment on a line of code } + let comment_text = comment.content_span().source_text(source_text); if let Some(codes) = - parse_directive_codes(&comment.text, IGNORE_FILE_DIRECTIVE) + parse_directive_codes(comment_text, IGNORE_FILE_DIRECTIVE) { // only recognize a file directive at the top of the file if (0..line_index).all(|line_index| { @@ -127,7 +127,7 @@ pub fn parse_ignore_directives(module_info: &EsModuleInfo) -> IgnoreDirectives { directives.file = Some(codes); } } else if let Some(codes) = - parse_directive_codes(&comment.text, IGNORE_DIRECTIVE) + parse_directive_codes(comment_text, IGNORE_DIRECTIVE) { directives.lines.insert(line_index, codes); } @@ -139,19 +139,18 @@ pub fn parse_ignore_directives(module_info: &EsModuleInfo) -> IgnoreDirectives { /// The 0-indexed lines of a comment that contain no code. fn comment_only_lines( text_info: &SourceTextInfo, - range: SourceRange, + span: Span, ) -> std::ops::RangeInclusive { - let start_line = text_info.line_index(range.start); - let end_line = text_info.line_index(range.end); + let start = span.start as usize; + let end = span.end as usize; + let start_line = text_info.line_index(start); + let end_line = text_info.line_index(end); let has_code_before = !text_info - .range_text(&SourceRange::new( - text_info.line_start(start_line), - range.start, - )) + .range_text(text_info.line_start(start_line), start) .trim() .is_empty(); let has_code_after = !text_info - .range_text(&SourceRange::new(range.end, text_info.line_end(end_line))) + .range_text(end, text_info.line_end(end_line)) .trim() .is_empty(); diff --git a/src/util/mod.rs b/src/util/mod.rs index 4476133e2..0a9b22a91 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -5,3 +5,4 @@ pub mod graph; pub mod ignore_directives; pub mod swc; pub mod symbol; +pub mod types; diff --git a/src/util/swc.rs b/src/util/swc.rs index cb49aecc2..f32fc4271 100644 --- a/src/util/swc.rs +++ b/src/util/swc.rs @@ -1,12 +1,10 @@ // 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::JSStrExt; 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 +20,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 +43,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 +66,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 +81,37 @@ 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(); + + 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); } - }) + 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,11 +119,14 @@ 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 byte_index = pos as usize; + let text = text_info.text(); + let lookup_byte_index = byte_index.min(text.len()); 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); + text_info.line_and_column_display_with_indent_width(lookup_byte_index, 2); + Location { filename: specifier.into(), line: line_and_column_index.line_number - 1, @@ -126,8 +139,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_lossy(), } } 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..03ee50d54 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,48 @@ 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: the explicit annotation, the type of a referenced + // variable or the type inferred from the initializer. + 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 = + crate::ts_type::identifier_reference_to_id(module_info, ref_ident); + 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); + // only the explicit type annotation of the referenced variable + // is used; its initializer is not inferred from + if let Some(type_ann) = &ref_var_declarator.type_annotation { + return Some(TsTypeDef::new( + module_info, + &type_ann.type_annotation, + )); + } } } None @@ -73,192 +76,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, + kind, maybe_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, + kind, maybe_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 922189f4c..98372306d 100644 --- a/src/visibility.rs +++ b/src/visibility.rs @@ -5,8 +5,8 @@ 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::swc::ast::TsType; +use deno_ast::oxc::ast::ast::TSType; +use deno_ast::oxc::span::Span; use deno_graph::ModuleGraph; use deno_graph::symbols::DefinitionPathNode; use deno_graph::symbols::DefinitionPathNodeResolved; @@ -25,7 +25,7 @@ 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, @@ -37,7 +37,7 @@ pub struct SymbolDeclDeps { } #[derive(Default, Debug)] -pub struct SymbolDeps(IndexMap>); +pub struct SymbolDeps(IndexMap>); impl SymbolDeps { pub fn is_empty(&self) -> bool { @@ -100,7 +100,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)) }) @@ -118,7 +118,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)) }) @@ -222,7 +222,7 @@ fn decl_is_pure_type_alias(decl: &SymbolDecl) -> bool { _ => None, }; type_alias.is_some_and( - |n| matches!(&*n.type_ann, TsType::TsTypeRef(r) if r.type_params.is_none()), + |n| matches!(&n.type_annotation, TSType::TSTypeReference(r) if r.type_arguments.is_none()), ) } 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 3523a73e2..920e23a74 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, @@ -386,9 +388,11 @@ async fn html_doc_import_linking_internal_file() { ) .await; + let allocator = deno_ast::oxc::allocator::Allocator::default(); let parse_output = DocParser::new( &graph, &analyzer, + &allocator, &source_files, DocParserOptions { diagnostics: false, @@ -1250,9 +1254,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, @@ -1299,9 +1305,11 @@ async fn parse_sources_multi(sources: &[(&str, &str)]) -> ParseOutput { ) .await; + let allocator = deno_ast::oxc::allocator::Allocator::default(); DocParser::new( &graph, &analyzer, + &allocator, &roots, DocParserOptions { private: false, diff --git a/tests/snapshots/html_test__html_doc_files_multiple-39.snap b/tests/snapshots/html_test__html_doc_files_multiple-39.snap index 2bebe8505..c33c1d6dc 100644 --- a/tests/snapshots/html_test__html_doc_files_multiple-39.snap +++ b/tests/snapshots/html_test__html_doc_files_multiple-39.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 f97d3e36c..1fc344891 100644 --- a/tests/snapshots/html_test__symbol_group.snap +++ b/tests/snapshots/html_test__symbol_group.snap @@ -8412,7 +8412,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": "", @@ -8434,7 +8434,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" },