Skip to content

Commit

Permalink
feat(core): make processing typescript dependencies in rust the defau…
Browse files Browse the repository at this point in the history
…lt (#18398)
  • Loading branch information
FrozenPandaz committed Aug 1, 2023
1 parent 3ae657c commit 842cf7a
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 170 deletions.
1 change: 0 additions & 1 deletion e2e/nx-run/src/affected-graph.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,6 @@ describe('Nx Affected and Graph Tests', () => {
target: mylib,
type: 'static',
},
{ source: myapp, target: mylib2, type: 'dynamic' },
],
[myappE2e]: [
{
Expand Down
136 changes: 99 additions & 37 deletions packages/nx/src/native/plugins/js/ts_import_locators.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use std::path::Path;
use std::rc::Rc;
use std::sync::Arc;
use std::time::Instant;

use rayon::prelude::*;
use tracing::debug;
use tracing::trace;

use swc_common::{BytePos, SourceFile, SourceMap, Spanned};
use swc_common::comments::SingleThreadedComments;
use swc_common::{BytePos, SourceMap, Spanned};
use swc_ecma_ast::EsVersion::EsNext;
use swc_ecma_parser::error::Error;
use swc_ecma_parser::lexer::Lexer;
Expand Down Expand Up @@ -449,6 +449,8 @@ fn process_file((source_project, file_path): (&String, &String)) -> Option<Impor
.load_file(Path::new(file_path))
.unwrap();

let comments = SingleThreadedComments::default();

let tsx = file_path.ends_with(".tsx") || file_path.ends_with(".jsx");
let lexer = Lexer::new(
Syntax::Typescript(TsConfig {
Expand All @@ -460,14 +462,14 @@ fn process_file((source_project, file_path): (&String, &String)) -> Option<Impor
}),
EsNext,
(&*cm).into(),
None,
Some(&comments),
);

// State
let mut state = State::new(lexer);

let mut static_import_expressions: Vec<String> = vec![];
let mut dynamic_import_expressions: Vec<String> = vec![];
let mut static_import_expressions: Vec<(String, BytePos)> = vec![];
let mut dynamic_import_expressions: Vec<(String, BytePos)> = vec![];

loop {
let current_token = state.next();
Expand All @@ -477,6 +479,8 @@ fn process_file((source_project, file_path): (&String, &String)) -> Option<Impor
break;
}

let mut pos: Option<BytePos> = None;

if let Some(current) = &current_token {
let word = match &current.token {
Token::Word(w) => w,
Expand All @@ -487,35 +491,29 @@ fn process_file((source_project, file_path): (&String, &String)) -> Option<Impor
let import = match word {
// This is an import keyword
Keyword(keyword) if *keyword == Import => {
if is_code_ignored(&cm, current.span.lo) {
continue;
}

pos = Some(current.span.lo);
find_specifier_in_import(&mut state)
}
Keyword(keyword) if *keyword == Export => {
if is_code_ignored(&cm, current.span.lo) {
continue;
}
pos = Some(current.span.lo);

find_specifier_in_export(&mut state)
}
Ident(ident) if ident == "require" => {
if is_code_ignored(&cm, current.span.lo) {
continue;
}
pos = Some(current.span.lo);
find_specifier_in_require(&mut state)
}
_ => None,
};

if let Some((specifier, import_type)) = import {
let pos = pos.expect("Always exists when there is an import");
match import_type {
ImportType::Static => {
static_import_expressions.push(specifier);
static_import_expressions.push((specifier, pos));
}
ImportType::Dynamic => {
dynamic_import_expressions.push(specifier);
dynamic_import_expressions.push((specifier, pos));
}
}
}
Expand All @@ -539,11 +537,42 @@ fn process_file((source_project, file_path): (&String, &String)) -> Option<Impor
errs.clear();
}

if file_path == "nx-dev/ui-markdoc/src/lib/tags/graph.component.tsx" {
trace!("{:?}", static_import_expressions);
trace!("{:?}", dynamic_import_expressions);
// Create a HashMap of comments by the lines where they end
let (leading_comments, _) = comments.take_all();
let mut lines_with_nx_ignore_comments: HashSet<usize> = HashSet::new();
let leading_comments = leading_comments.borrow();
for (_, comments) in leading_comments.iter() {
for comment in comments {
let comment_text = comment.text.trim();

if comment_text.contains("nx-ignore-next-line") {
let line_where_comment_ends = cm
.lookup_line(comment.span.hi)
.expect("Comments end on a line");

lines_with_nx_ignore_comments.insert(line_where_comment_ends);
}
}
}

let code_is_not_ignored = |(specifier, pos): (String, BytePos)| {
let line_with_code = cm.lookup_line(pos).expect("All code is on a line");
if lines_with_nx_ignore_comments.contains(&(line_with_code - 1)) {
None
} else {
Some(specifier)
}
};

let static_import_expressions = static_import_expressions
.into_iter()
.filter_map(code_is_not_ignored)
.collect();
let dynamic_import_expressions = dynamic_import_expressions
.into_iter()
.filter_map(code_is_not_ignored)
.collect();

Some(ImportResult {
file: file_path.clone(),
source_project: source_project.clone(),
Expand All @@ -552,22 +581,6 @@ fn process_file((source_project, file_path): (&String, &String)) -> Option<Impor
})
}

fn is_code_ignored(cm: &Rc<SourceFile>, pos: BytePos) -> bool {
let line_with_dep = cm.lookup_line(pos).expect("The dep is on a line");

if line_with_dep == 0 {
return false;
}

if let Some(line_before_dep) = cm.get_line(line_with_dep - 1) {
let trimmed_line = line_before_dep.trim();
if trimmed_line == "// nx-ignore-next-line" || trimmed_line == "/* nx-ignore-next-line */" {
return true;
}
}
false
}

#[napi]
fn find_imports(project_file_map: HashMap<String, Vec<String>>) -> Vec<ImportResult> {
enable_logger();
Expand All @@ -589,6 +602,55 @@ mod find_imports {
use assert_fs::TempDir;
use swc_common::comments::NoopComments;

#[test]
fn should_not_include_ignored_imports() {
let temp_dir = TempDir::new().unwrap();
temp_dir
.child("test.ts")
.write_str(
r#"
// nx-ignore-next-line
import 'a';
/* nx-ignore-next-line */
import 'a1';
/* nx-ignore-next-line */
import 'a2';
/**
* nx-ignore-next-line
*/
import 'a3';
/*
nx-ignore-next-line
*/
import 'a4'; import 'a5';
/* prettier-ignore */ /* nx-ignore-next-line */
import 'a4'; import 'a5';
/* nx-ignore-next-line */ /* prettier-ignore */
import 'a4'; import 'a5';
"#,
)
.unwrap();

let test_file_path = temp_dir.display().to_string() + "/test.ts";

let results = find_imports(HashMap::from([(
String::from("a"),
vec![test_file_path.clone()],
)]));

let result = results.get(0).unwrap();

assert!(result.static_import_expressions.is_empty());
assert!(result.dynamic_import_expressions.is_empty());
}

#[test]
fn should_find_imports() {
let temp_dir = TempDir::new().unwrap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ export function buildExplicitDependencies(
// to be able to use at least 2 workers (1 worker per CPU and
// 1 CPU for the main thread)
if (
(process.env.NX_NATIVE_TS_DEPS &&
process.env.NX_NATIVE_TS_DEPS !== 'false') ||
process.env.NX_NATIVE_TS_DEPS !== 'false' ||
jsPluginConfig.analyzeSourceFiles === false ||
totalNumOfFilesToProcess < 100 ||
getNumberOfWorkers() <= 2
Expand Down

1 comment on commit 842cf7a

@vercel
Copy link

@vercel vercel bot commented on 842cf7a Aug 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-nrwl.vercel.app
nx-five.vercel.app
nx-dev-git-master-nrwl.vercel.app
nx.dev

Please sign in to comment.