From 855dc9d75b91527f412516e0683adabdfc647c7f Mon Sep 17 00:00:00 2001 From: RumovZ Date: Tue, 7 Feb 2023 02:56:14 +0100 Subject: [PATCH] Add Rust bin to deprecate unused ftl entries (#2364) * Add Rust bin to deprecate unused ftl entries * Align function names with bin names * Support passing in multiple ftl roots * Use source instead of jsons for deprecating * Fix CargoRun not working more than once (dae) * Add ftl:deprecate (dae) * Deprecate some strings (dae) This is not all of the strings that are currently unused * Check json files before deprecating; add allowlist (dae) The scheduler messages we'll probably want to reuse for the v2->v3 transition, so I'd prefer to keep them undeprecated for now. * Deprecate old bury options (dae) * Support gathering usages from Kotlin files for AnkiDroid (dae) * Update json scripts (dae) * Remove old deprecation headers * Parameterize JSON roots to keep * Tweak deprecation message (dae) --- build/configure/src/rust.rs | 10 ++ build/ninja_gen/src/cargo.rs | 2 +- ftl/.gitignore | 4 +- ftl/core/browsing.ftl | 11 +- ftl/core/custom-study.ftl | 2 +- ftl/core/deck-config.ftl | 26 +-- ftl/core/errors.ftl | 7 +- ftl/core/importing.ftl | 7 +- ftl/core/preferences.ftl | 9 +- ftl/update-ankidroid-usage.sh | 3 + ftl/update-ankimobile-usage.sh | 11 +- ftl/update-desktop-usage.sh | 9 - ftl/usage/no-deprecate.json | 4 + .../src/bin/deprecate_ftl_entries.rs | 49 ++++++ .../src/bin/garbage_collect_ftl_entries.rs | 6 +- rslib/i18n_helpers/src/bin/write_ftl_json.rs | 2 +- rslib/i18n_helpers/src/garbage_collection.rs | 165 +++++++++++++----- 17 files changed, 231 insertions(+), 96 deletions(-) create mode 100755 ftl/update-ankidroid-usage.sh delete mode 100755 ftl/update-desktop-usage.sh create mode 100644 ftl/usage/no-deprecate.json create mode 100644 rslib/i18n_helpers/src/bin/deprecate_ftl_entries.rs diff --git a/build/configure/src/rust.rs b/build/configure/src/rust.rs index 92f79cc64..3ad59564a 100644 --- a/build/configure/src/rust.rs +++ b/build/configure/src/rust.rs @@ -65,6 +65,16 @@ fn prepare_translations(build: &mut Build) -> Result<()> { }, )?; + build.add( + "ftl:deprecate", + CargoRun { + binary_name: "deprecate_ftl_entries", + cargo_args: "-p anki_i18n_helpers", + bin_args: "ftl/core ftl/qt -- pylib qt rslib ts --keep ftl/usage", + deps: inputs!["ftl/core", "ftl/qt", "pylib", "qt", "rslib", "ts"], + }, + )?; + Ok(()) } diff --git a/build/ninja_gen/src/cargo.rs b/build/ninja_gen/src/cargo.rs index c5620292e..a782155b4 100644 --- a/build/ninja_gen/src/cargo.rs +++ b/build/ninja_gen/src/cargo.rs @@ -239,6 +239,6 @@ impl BuildAction for CargoRun { build.add_variable("binary", self.binary_name); build.add_variable("cargo_args", self.cargo_args); build.add_variable("bin_args", self.bin_args); - build.add_outputs("", vec!["phony"]); + build.add_outputs("", vec![format!("phony-{}", self.binary_name)]); } } diff --git a/ftl/.gitignore b/ftl/.gitignore index 738260199..78c0fe481 100644 --- a/ftl/.gitignore +++ b/ftl/.gitignore @@ -1,2 +1,2 @@ -usage - +usage/* +!usage/no-deprecate.json diff --git a/ftl/core/browsing.ftl b/ftl/core/browsing.ftl index b7564d79d..1aac56835 100644 --- a/ftl/core/browsing.ftl +++ b/ftl/core/browsing.ftl @@ -13,8 +13,6 @@ browsing-browser-options = Browser Options browsing-buried = Buried browsing-card = Card browsing-cards = Cards -# Exactly one character representing 'Cards'; should differ from browsing-note-initial. -browsing-card-initial = C browsing-card-list = Card List browsing-cards-cant-be-manually-moved-into = Cards can't be manually moved into a filtered deck. browsing-cards-deleted = @@ -61,8 +59,6 @@ browsing-no-flag = No Flag browsing-no-selection = No cards or notes selected. browsing-note = Note browsing-notes = Notes -# Exactly one character representing 'Notes'; should differ from browsing-card-initial. -browsing-note-initial = N browsing-optional-filter = Optional filter: browsing-override-back-template = Override back template: browsing-override-font = Override font: @@ -168,5 +164,10 @@ browsing-reparented-decks = *[other] Renamed { $count } decks. } -## obsolete; no need to translate +## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future. + +# Exactly one character representing 'Cards'; should differ from browsing-note-initial. +browsing-card-initial = C +# Exactly one character representing 'Notes'; should differ from browsing-card-initial. +browsing-note-initial = N diff --git a/ftl/core/custom-study.ftl b/ftl/core/custom-study.ftl index fd46d72c2..ac2b65257 100644 --- a/ftl/core/custom-study.ftl +++ b/ftl/core/custom-study.ftl @@ -28,7 +28,7 @@ custom-study-available-new-cards-2 = Available new cards: { $countString } custom-study-available-review-cards-2 = Available review cards: { $countString } custom-study-available-child-count = ({ $count } in subdecks) -## DEPRECATED - you do not need to translate these. +## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future. custom-study-available-new-cards = Available new cards: { $count } custom-study-available-review-cards = Available review cards: { $count } diff --git a/ftl/core/deck-config.ftl b/ftl/core/deck-config.ftl index 95e262661..acda67440 100644 --- a/ftl/core/deck-config.ftl +++ b/ftl/core/deck-config.ftl @@ -98,17 +98,6 @@ deck-config-leech-action-tooltip = ## Burying section deck-config-bury-title = Burying -deck-config-bury-new-siblings = Bury new siblings -deck-config-bury-review-siblings = Bury review siblings -deck-config-bury-interday-learning-siblings = Bury interday learning siblings -deck-config-bury-new-tooltip = - Whether other `new` cards of the same note (eg reverse cards, adjacent cloze deletions) - will be delayed until the next day. -deck-config-bury-review-tooltip = Whether other `review` cards of the same note will be delayed until the next day. -deck-config-bury-interday-learning-tooltip = - Whether other `learning` cards of the same note with intervals > 1 day - will be delayed until the next day. - deck-config-bury-siblings = Bury siblings deck-config-do-not-bury = Do not bury siblings deck-config-bury-if-new = Bury if new @@ -122,7 +111,7 @@ deck-config-bury-tooltip = day. When enabled, Anki will automatically *bury* siblings, hiding them until the next day. This option allows you to choose which kinds of cards may be buried when you answer one of their siblings. - + When using the V3 scheduler, interday learning cards can also be buried. Interday learning cards are cards with a current learning step of one or more days. @@ -306,5 +295,16 @@ deck-config-maximum-answer-secs-above-recommended = Anki can schedule your revie deck-config-which-deck = Which deck would you like? -## NO NEED TO TRANSLATE. These strings have been replaced with new versions, and will be removed in the future. +## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future. + +deck-config-bury-new-siblings = Bury new siblings +deck-config-bury-review-siblings = Bury review siblings +deck-config-bury-interday-learning-siblings = Bury interday learning siblings +deck-config-bury-new-tooltip = + Whether other `new` cards of the same note (eg reverse cards, adjacent cloze deletions) + will be delayed until the next day. +deck-config-bury-review-tooltip = Whether other `review` cards of the same note will be delayed until the next day. +deck-config-bury-interday-learning-tooltip = + Whether other `learning` cards of the same note with intervals > 1 day + will be delayed until the next day. diff --git a/ftl/core/errors.ftl b/ftl/core/errors.ftl index 4f53f8579..c3f5a3b18 100644 --- a/ftl/core/errors.ftl +++ b/ftl/core/errors.ftl @@ -1,5 +1,3 @@ -errors-invalid-input-empty = Invalid input. -errors-invalid-input-details = Invalid input: { $details } errors-parse-number-fail = A number was invalid or out of range. errors-filtered-parent-deck = Filtered decks can not have child decks. errors-filtered-deck-required = This action can only be used on a filtered deck. @@ -18,3 +16,8 @@ errors-inconsistent-db-state = Your database appears to be in an inconsistent st errors-bad-directive = Error in directive '{ $directive }': { $error } errors-option-not-set = '{ $option }' not set + +## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future. + +errors-invalid-input-empty = Invalid input. +errors-invalid-input-details = Invalid input: { $details } diff --git a/ftl/core/importing.ftl b/ftl/core/importing.ftl index fd3788175..c895fad1e 100644 --- a/ftl/core/importing.ftl +++ b/ftl/core/importing.ftl @@ -82,7 +82,6 @@ importing-processed-media-file = [one] Imported { $count } media file *[other] Imported { $count } media files } -importing-importing-collection = Importing collection... importing-importing-file = Importing file... importing-extracting = Extracting data... importing-gathering = Gathering data... @@ -97,7 +96,6 @@ importing-processed-cards = [one] Processed { $count } card... *[other] Processed { $count } cards... } -importing-unable-to-import-filename = Unable to import { $filename }: file type not supported importing-existing-notes = Existing notes # "Existing notes: Duplicate" (verb) importing-duplicate = Duplicate @@ -108,3 +106,8 @@ importing-update = Update importing-tag-all-notes = Tag all notes importing-tag-updated-notes = Tag updated notes importing-file = File + +## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future. + +importing-importing-collection = Importing collection... +importing-unable-to-import-filename = Unable to import { $filename }: file type not supported diff --git a/ftl/core/preferences.ftl b/ftl/core/preferences.ftl index d6b159abd..cac8b9360 100644 --- a/ftl/core/preferences.ftl +++ b/ftl/core/preferences.ftl @@ -1,6 +1,5 @@ preferences-automatically-sync-on-profile-openclose = Automatically sync on profile open/close preferences-backups = Backups -preferences-basic = Basic preferences-change-deck-depending-on-note-type = Change deck depending on note type preferences-changes-will-take-effect-when-you = Changes will take effect when you restart Anki. preferences-hours-past-midnight = hours past midnight @@ -58,15 +57,19 @@ preferences-appearance = Appearance preferences-general = General preferences-style = Style preferences-review = Review -preferences-reviewer = Reviewer preferences-distractions = Distractions preferences-minimalist-mode = Minimalist mode preferences-editing = Editing preferences-browsing = Browsing preferences-default-deck = Default deck preferences-account = AnkiWeb Account -preferences-media = Media preferences-note = Note preferences-scheduler = Scheduler preferences-user-interface = User Interface preferences-import-export = Import/Export + +## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future. + +preferences-basic = Basic +preferences-reviewer = Reviewer +preferences-media = Media diff --git a/ftl/update-ankidroid-usage.sh b/ftl/update-ankidroid-usage.sh new file mode 100755 index 000000000..efce07cc4 --- /dev/null +++ b/ftl/update-ankidroid-usage.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +cargo run --bin write_ftl_json ftl/usage/ankidroid.json ~/Local/droid/Anki-Android diff --git a/ftl/update-ankimobile-usage.sh b/ftl/update-ankimobile-usage.sh index e68620f04..da31a11da 100755 --- a/ftl/update-ankimobile-usage.sh +++ b/ftl/update-ankimobile-usage.sh @@ -1,13 +1,4 @@ #!/bin/bash -# # This script can only be run by Damien, as it requires a copy of AnkiMobile's sources. -# A similar script could be added for AnkiDroid in the future. -# -set -e - -scriptRoot=$(realpath $(dirname $0)/..) -sourceRoot=$(realpath $scriptRoot/../../mobile/ankimobile/src) - -bazel run //rslib/i18n_helpers:write_ftl_json $scriptRoot/ftl/usage/ankimobile.json \ - $sourceRoot +cargo run --bin write_ftl_json ftl/usage/ankimobile.json ../../mobile/ankimobile/src diff --git a/ftl/update-desktop-usage.sh b/ftl/update-desktop-usage.sh deleted file mode 100755 index 92c8a395e..000000000 --- a/ftl/update-desktop-usage.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -set -e - -version=$1 -root=$(realpath $(dirname $0)/..) - -bazel run //rslib/i18n_helpers:write_ftl_json $root/ftl/usage/desktop-$version.json \ - $root/{rslib,ts,pylib,qt} diff --git a/ftl/usage/no-deprecate.json b/ftl/usage/no-deprecate.json new file mode 100644 index 000000000..d0bb64c56 --- /dev/null +++ b/ftl/usage/no-deprecate.json @@ -0,0 +1,4 @@ +[ + "scheduling-update-soon", + "scheduling-update-later-button" +] diff --git a/rslib/i18n_helpers/src/bin/deprecate_ftl_entries.rs b/rslib/i18n_helpers/src/bin/deprecate_ftl_entries.rs new file mode 100644 index 000000000..3b4081a27 --- /dev/null +++ b/rslib/i18n_helpers/src/bin/deprecate_ftl_entries.rs @@ -0,0 +1,49 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +/// Deprecate unused ftl entries by moving them to the bottom of the file and +/// adding a deprecation warning. An entry is considered unused if cannot be +/// found in a source or JSON file. +/// Arguments before `--` are roots of ftl files, arguments after that are +/// source roots. JSON roots must be preceded by `--keep` or `-k`. +fn main() { + let args = Arguments::new(); + anki_i18n_helpers::garbage_collection::deprecate_ftl_entries( + &args.ftl_roots, + &args.source_roots, + &args.json_roots, + ); +} + +#[derive(Default)] +struct Arguments { + ftl_roots: Vec, + source_roots: Vec, + json_roots: Vec, +} + +impl Arguments { + fn new() -> Self { + let mut args = Self::default(); + let mut past_separator = false; + let mut keep_flag = false; + for arg in std::env::args() { + match arg.as_str() { + "--" => { + past_separator = true; + } + "--keep" | "-k" => { + keep_flag = true; + } + _ if keep_flag => { + keep_flag = false; + args.json_roots.push(arg) + } + _ if past_separator => args.source_roots.push(arg), + _ => args.ftl_roots.push(arg), + }; + } + + args + } +} diff --git a/rslib/i18n_helpers/src/bin/garbage_collect_ftl_entries.rs b/rslib/i18n_helpers/src/bin/garbage_collect_ftl_entries.rs index 03b9922fb..bfdf21588 100644 --- a/rslib/i18n_helpers/src/bin/garbage_collect_ftl_entries.rs +++ b/rslib/i18n_helpers/src/bin/garbage_collect_ftl_entries.rs @@ -3,9 +3,9 @@ /// Delete every entry in the ftl files that is not mentioned in another message /// or a given json. -/// First argument is the root of the ftl files, second one is the root of the -/// json files. +/// First argument is the root of the json files, following are the roots of the +/// ftl files. fn main() { let args: Vec = std::env::args().collect(); - anki_i18n_helpers::garbage_collection::remove_unused_ftl_messages(&args[1], &args[2]); + anki_i18n_helpers::garbage_collection::garbage_collect_ftl_entries(&args[2..], &args[1]); } diff --git a/rslib/i18n_helpers/src/bin/write_ftl_json.rs b/rslib/i18n_helpers/src/bin/write_ftl_json.rs index 457009a8e..1a88abab7 100644 --- a/rslib/i18n_helpers/src/bin/write_ftl_json.rs +++ b/rslib/i18n_helpers/src/bin/write_ftl_json.rs @@ -7,5 +7,5 @@ /// First argument is the target file name, following are source roots. fn main() { let args: Vec = std::env::args().collect(); - anki_i18n_helpers::garbage_collection::extract_ftl_references(&args[2..], &args[1]); + anki_i18n_helpers::garbage_collection::write_ftl_json(&args[2..], &args[1]); } diff --git a/rslib/i18n_helpers/src/garbage_collection.rs b/rslib/i18n_helpers/src/garbage_collection.rs index 423428ee7..e51e993c1 100644 --- a/rslib/i18n_helpers/src/garbage_collection.rs +++ b/rslib/i18n_helpers/src/garbage_collection.rs @@ -7,6 +7,7 @@ use std::io::BufReader; use std::iter::FromIterator; use fluent_syntax::ast; +use fluent_syntax::ast::Resource; use fluent_syntax::parser; use lazy_static::lazy_static; use regex::Regex; @@ -16,16 +17,14 @@ use walkdir::WalkDir; use crate::serialize; -/// Extract references from all Rust, Python, TS, Svelte, Swift and Designer -/// files in the `roots`, convert them to kebab case and write them as a json to -/// the target file. -pub fn extract_ftl_references, S2: AsRef>(roots: &[S1], target: S2) { - let mut refs = HashSet::new(); - for root in roots { - for_files_with_ending(root.as_ref(), "", |entry| { - extract_references_from_file(&mut refs, &entry) - }) - } +const DEPCRATION_WARNING: &str = + "NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future."; + +/// Extract references from all Rust, Python, TS, Svelte, Swift, Kotlin and +/// Designer files in the `roots`, convert them to kebab case and write them as +/// a json to the target file. +pub fn write_ftl_json, S2: AsRef>(roots: &[S1], target: S2) { + let refs = gather_ftl_references(roots); let mut refs = Vec::from_iter(refs); refs.sort(); serde_json::to_writer_pretty( @@ -37,42 +36,95 @@ pub fn extract_ftl_references, S2: AsRef>(roots: &[S1], targ /// Delete every entry in `ftl_root` that is not mentioned in another message /// or any json in `json_root`. -pub fn remove_unused_ftl_messages>(ftl_root: S, json_root: S) { - let mut used_ftls = HashSet::new(); - import_used_messages(json_root.as_ref(), &mut used_ftls); - extract_nested_messages_and_terms(ftl_root.as_ref(), &mut used_ftls); - strip_unused_ftl_messages_and_terms(ftl_root.as_ref(), &used_ftls); +pub fn garbage_collect_ftl_entries(ftl_roots: &[impl AsRef], json_root: impl AsRef) { + let used_ftls = get_all_used_messages_and_terms(json_root.as_ref(), ftl_roots); + strip_unused_ftl_messages_and_terms(ftl_roots, &used_ftls); } -fn for_files_with_ending(root: &str, file_ending: &str, mut op: impl FnMut(DirEntry)) { - for res in WalkDir::new(root) { - let entry = res.expect("failed to visit dir"); - if entry.file_type().is_file() - && entry - .file_name() - .to_str() - .expect("non-unicode filename") - .ends_with(file_ending) - { - op(entry); +/// Moves every entry in `ftl_roots` that is not mentioned in another message, a +/// source file or any json in `json_roots` to the bottom of its file below a +/// deprecation warning. +pub fn deprecate_ftl_entries( + ftl_roots: &[impl AsRef], + source_roots: &[impl AsRef], + json_roots: &[impl AsRef], +) { + let mut used_ftls = gather_ftl_references(source_roots); + import_messages_from_json(json_roots, &mut used_ftls); + extract_nested_messages_and_terms(ftl_roots, &mut used_ftls); + deprecate_unused_ftl_messages_and_terms(ftl_roots, &used_ftls); +} + +fn get_all_used_messages_and_terms( + json_root: &str, + ftl_roots: &[impl AsRef], +) -> HashSet { + let mut used_ftls = HashSet::new(); + import_messages_from_json(&[json_root], &mut used_ftls); + extract_nested_messages_and_terms(ftl_roots, &mut used_ftls); + used_ftls +} + +fn for_files_with_ending( + roots: &[impl AsRef], + file_ending: &str, + mut op: impl FnMut(DirEntry), +) { + for root in roots { + for res in WalkDir::new(root.as_ref()) { + let entry = res.expect("failed to visit dir"); + if entry.file_type().is_file() + && entry + .file_name() + .to_str() + .expect("non-unicode filename") + .ends_with(file_ending) + { + op(entry); + } } } } -fn import_used_messages(json_root: &str, used_ftls: &mut HashSet) { - for_files_with_ending(json_root, ".json", |entry| { +fn gather_ftl_references(roots: &[impl AsRef]) -> HashSet { + let mut refs = HashSet::new(); + for_files_with_ending(roots, "", |entry| { + extract_references_from_file(&mut refs, &entry) + }); + refs +} + +/// Iterates over all .ftl files in `root`, parses them and rewrites the file if +/// `op` decides to return a new AST. +fn rewrite_ftl_files( + roots: &[impl AsRef], + mut op: impl FnMut(Resource<&str>) -> Option>, +) { + for_files_with_ending(roots, ".ftl", |entry| { + let ftl = fs::read_to_string(entry.path()).expect("failed to open file"); + let ast = parser::parse(ftl.as_str()).expect("failed to parse ftl"); + if let Some(ast) = op(ast) { + fs::write(entry.path(), serialize::serialize(&ast)).expect("failed to write file"); + } + }); +} + +fn import_messages_from_json(json_roots: &[impl AsRef], entries: &mut HashSet) { + for_files_with_ending(json_roots, ".json", |entry| { let buffer = BufReader::new(fs::File::open(entry.path()).expect("failed to open file")); let refs: Vec = serde_json::from_reader(buffer).expect("failed to parse json"); - used_ftls.extend(refs); + entries.extend(refs); }) } -fn extract_nested_messages_and_terms(ftl_root: &str, used_ftls: &mut HashSet) { +fn extract_nested_messages_and_terms( + ftl_roots: &[impl AsRef], + used_ftls: &mut HashSet, +) { lazy_static! { static ref REFERENCE: Regex = Regex::new(r"\{\s*-?([-0-9a-z]+)\s*\}").unwrap(); } - - for_files_with_ending(ftl_root, ".ftl", |entry| { + for_files_with_ending(ftl_roots, ".ftl", |entry| { let source = fs::read_to_string(entry.path()).expect("file not readable"); for caps in REFERENCE.captures_iter(&source) { used_ftls.insert(caps[1].to_string()); @@ -80,24 +132,48 @@ fn extract_nested_messages_and_terms(ftl_root: &str, used_ftls: &mut HashSet) { - for_files_with_ending(ftl_root, ".ftl", |entry| { - let ftl = fs::read_to_string(entry.path()).expect("failed to open file"); - let mut ast = parser::parse(ftl.as_str()).expect("failed to parse ftl"); +fn strip_unused_ftl_messages_and_terms(roots: &[impl AsRef], used_ftls: &HashSet) { + rewrite_ftl_files(roots, |mut ast| { let num_entries = ast.body.len(); + ast.body.retain(entry_use_check(used_ftls)); + (ast.body.len() < num_entries).then_some(ast) + }); +} - ast.body.retain(|entry| match entry { - ast::Entry::Message(msg) => used_ftls.contains(msg.id.name), - ast::Entry::Term(term) => used_ftls.contains(term.id.name), - _ => true, - }); - - if ast.body.len() < num_entries { - fs::write(entry.path(), serialize::serialize(&ast)).expect("failed to write file"); +fn deprecate_unused_ftl_messages_and_terms(roots: &[impl AsRef], used_ftls: &HashSet) { + rewrite_ftl_files(roots, |ast| { + let (mut used, mut unused): (Vec<_>, Vec<_>) = + ast.body.into_iter().partition(entry_use_check(used_ftls)); + if unused.is_empty() { + None + } else { + append_deprecation_warning(&mut used); + used.append(&mut unused); + Some(Resource { body: used }) } }); } +fn append_deprecation_warning(entries: &mut Vec>) { + entries.retain(|entry| match entry { + ast::Entry::GroupComment(ast::Comment { content }) => { + !matches!(content.first(), Some(&DEPCRATION_WARNING)) + } + _ => true, + }); + entries.push(ast::Entry::GroupComment(ast::Comment { + content: vec![DEPCRATION_WARNING], + })); +} + +fn entry_use_check(used_ftls: &HashSet) -> impl Fn(&ast::Entry<&str>) -> bool + '_ { + |entry: &ast::Entry<&str>| match entry { + ast::Entry::Message(msg) => used_ftls.contains(msg.id.name), + ast::Entry::Term(term) => used_ftls.contains(term.id.name), + _ => true, + } +} + fn extract_references_from_file(refs: &mut HashSet, entry: &DirEntry) { lazy_static! { static ref SNAKECASE_TR: Regex = Regex::new(r"\Wtr\s*\.([0-9a-z_]+)\W").unwrap(); @@ -113,6 +189,7 @@ fn extract_references_from_file(refs: &mut HashSet, entry: &DirEntry) { } else if file_name.ends_with(".ts") || file_name.ends_with(".svelte") || file_name.ends_with(".swift") + || file_name.ends_with(".kt") { (&CAMELCASE_TR, camel_to_kebab_case) } else if file_name.ends_with(".ui") {