diff --git a/src/commands/commandUtils.ml b/src/commands/commandUtils.ml index 6012439052d..131c152fd01 100644 --- a/src/commands/commandUtils.ml +++ b/src/commands/commandUtils.ml @@ -678,6 +678,7 @@ let file_options = module_file_exts = FlowConfig.module_file_exts flowconfig; module_resource_exts = FlowConfig.module_resource_exts flowconfig; node_resolver_dirnames = FlowConfig.node_resolver_dirnames flowconfig; + node_resolver_aliases = FlowConfig.node_resolver_aliases flowconfig; } let ignore_flag prev = diff --git a/src/commands/config/flowConfig.ml b/src/commands/config/flowConfig.ml index 806e3245f79..d07c2c5ffab 100644 --- a/src/commands/config/flowConfig.ml +++ b/src/commands/config/flowConfig.ml @@ -93,6 +93,7 @@ module Opts = struct no_flowlib: bool; node_resolver_allow_root_relative: bool; node_resolver_dirnames: string list; + node_resolver_aliases: string list; node_resolver_root_relative_dirnames: string list; recursion_limit: int; root_name: string option; @@ -192,6 +193,7 @@ module Opts = struct no_flowlib = false; node_resolver_allow_root_relative = false; node_resolver_dirnames = ["node_modules"]; + node_resolver_aliases = []; node_resolver_root_relative_dirnames = [""]; recursion_limit = 10000; root_name = None; @@ -472,6 +474,13 @@ module Opts = struct else let node_resolver_dirnames = v :: opts.node_resolver_dirnames in Ok { opts with node_resolver_dirnames }) ); + ( "module.system.node.resolve_alias", + string + ~init:(fun opts -> { opts with node_resolver_aliases = [] }) + ~multiple:true + (fun opts v -> + let node_resolver_aliases = v :: opts.node_resolver_aliases in + Ok { opts with node_resolver_aliases }) ); ( "module.system.node.root_relative_dirname", string ~init:(fun opts -> { opts with node_resolver_root_relative_dirnames = [] }) @@ -1008,7 +1017,7 @@ let is_not_comment = (* Line starts with ; *) Str.regexp_string "\240\159\146\169"; (* Line starts with poop emoji *) - + ] in fun (_, line) -> @@ -1200,6 +1209,8 @@ let node_resolver_allow_root_relative c = c.options.Opts.node_resolver_allow_roo let node_resolver_dirnames c = c.options.Opts.node_resolver_dirnames +let node_resolver_aliases c = c.options.Opts.node_resolver_aliases + let node_resolver_root_relative_dirnames c = c.options.Opts.node_resolver_root_relative_dirnames let recursion_limit c = c.options.Opts.recursion_limit diff --git a/src/commands/config/flowConfig.mli b/src/commands/config/flowConfig.mli index 06920e8805a..54f876b1340 100644 --- a/src/commands/config/flowConfig.mli +++ b/src/commands/config/flowConfig.mli @@ -142,6 +142,8 @@ val node_resolver_allow_root_relative : config -> bool val node_resolver_dirnames : config -> string list +val node_resolver_aliases: config -> string list + val node_resolver_root_relative_dirnames : config -> string list val required_version : config -> string option diff --git a/src/common/files.ml b/src/common/files.ml index 77c4ea7b240..b114b0d32af 100644 --- a/src/common/files.ml +++ b/src/common/files.ml @@ -17,6 +17,7 @@ type options = { module_file_exts: SSet.t; module_resource_exts: SSet.t; node_resolver_dirnames: string list; + node_resolver_aliases: string list; } let default_lib_dir options = options.default_lib_dir @@ -37,6 +38,8 @@ let module_resource_exts options = options.module_resource_exts let node_resolver_dirnames options = options.node_resolver_dirnames +let node_resolver_aliases options = options.node_resolver_aliases + (* During node module resolution, we need to look for node_modules/ directories * as we walk up the path. But checking each directory for them would be expensive. * So instead we memorize which directories contain node_modules/ directories. @@ -114,6 +117,8 @@ let is_valid_path = let is_node_module options path = List.mem (Filename.basename path) options.node_resolver_dirnames +let is_module_alias options path = List.mem (Filename.basename path) options.node_resolver_aliases + let is_flow_file ~options = let is_valid_path = is_valid_path ~options in (fun path -> is_valid_path path && not (is_directory path)) @@ -193,7 +198,7 @@ let max_files = 1000 If kind_of_path fails, then we only emit a warning if error_filter passes *) let make_next_files_and_symlinks - ~node_module_filter ~path_filter ~realpath_filter ~error_filter paths = + ~node_module_filter ~module_alias_filter ~path_filter ~realpath_filter ~error_filter paths = let prefix_checkers = Base.List.map ~f:is_prefix paths in let rec process sz (acc, symlinks) files dir stack = if sz >= max_files then @@ -215,7 +220,7 @@ let make_next_files_and_symlinks else process sz (acc, symlinks) files dir stack | Dir (path, is_symlink) -> - if node_module_filter file then + if node_module_filter file || module_alias_filter file then node_modules_containers := SMap.add ~combine:SSet.union @@ -256,12 +261,13 @@ let make_next_files_and_symlinks and including any directories that are symlinked to even if they are outside of `paths`. *) let make_next_files_following_symlinks - ~node_module_filter ~path_filter ~realpath_filter ~error_filter paths = + ~node_module_filter ~module_alias_filter ~path_filter ~realpath_filter ~error_filter paths = let paths = Base.List.map ~f:Path.to_string paths in let cb = ref (make_next_files_and_symlinks ~node_module_filter + ~module_alias_filter ~path_filter ~realpath_filter ~error_filter @@ -294,6 +300,7 @@ let make_next_files_following_symlinks cb := make_next_files_and_symlinks ~node_module_filter + ~module_alias_filter ~path_filter:realpath_filter ~realpath_filter ~error_filter @@ -315,6 +322,7 @@ let get_all = let init ?(flowlibs_only = false) (options : options) = let node_module_filter = is_node_module options in + let module_alias_filter = is_module_alias options in let libs = if flowlibs_only then [] @@ -341,6 +349,7 @@ let init ?(flowlibs_only = false) (options : options) = let filter' path = (path = lib_str || filter path) && not (is_json_file path) in make_next_files_following_symlinks ~node_module_filter + ~module_alias_filter ~path_filter:filter' ~realpath_filter:filter' ~error_filter:(fun _ -> true) @@ -416,6 +425,7 @@ let watched_paths options = Path_matcher.stems options.includes *) let make_next_files ~root ~all ~subdir ~options ~libs = let node_module_filter = is_node_module options in + let module_alias_filter = is_module_alias options in let filter = if all then fun _ -> @@ -454,6 +464,7 @@ let make_next_files ~root ~all ~subdir ~options ~libs = in make_next_files_following_symlinks ~node_module_filter + ~module_alias_filter ~path_filter ~realpath_filter ~error_filter:filter @@ -585,6 +596,14 @@ let is_within_node_modules ~root ~options path = let node_resolver_dirnames = node_resolver_dirnames options |> SSet.of_list in not (SSet.inter directories node_resolver_dirnames |> SSet.is_empty) +(* Given a path, we want to know if it's a resolve alias. *) +let is_within_alias_directory ~root ~options path = + (* We use paths that are relative to the root, so that we ignore ancestor directories *) + let path = relative_path (Path.to_string root) path in + let directories = Str.split dir_sep path |> SSet.of_list in + let node_resolver_aliases = node_resolver_aliases options |> SSet.of_list in + not (SSet.inter directories node_resolver_aliases |> SSet.is_empty) + (* realpath doesn't work for non-existent paths. So let's find the longest existent prefix, run * realpath on that, and then append the rest to it *) diff --git a/src/common/files.mli b/src/common/files.mli index f81fa2c29bb..d05abf447f5 100644 --- a/src/common/files.mli +++ b/src/common/files.mli @@ -17,6 +17,7 @@ type options = { module_file_exts: SSet.t; module_resource_exts: SSet.t; node_resolver_dirnames: string list; + node_resolver_aliases: string list; } val default_lib_dir : options -> Path.t option @@ -37,6 +38,8 @@ val module_resource_exts : options -> SSet.t val node_resolver_dirnames : options -> string list +val node_resolver_aliases : options -> string list + val node_modules_containers : SSet.t SMap.t ref val global_file_name : string @@ -124,6 +127,8 @@ val mkdirp : string -> Unix.file_perm -> unit val is_within_node_modules : root:Path.t -> options:options -> string -> bool +val is_within_alias_directory : root:Path.t -> options:options -> string -> bool + val imaginary_realpath : string -> string val canonicalize_filenames : diff --git a/src/services/inference/module/module_js.ml b/src/services/inference/module/module_js.ml index 5ad17dd9d51..4428f1d77bf 100644 --- a/src/services/inference/module/module_js.ml +++ b/src/services/inference/module/module_js.ml @@ -61,6 +61,9 @@ let choose_provider_and_warn_about_duplicates = in (defn, errmap) +let get_root ~options = + Options.root options |> Path.to_string |> Sys_utils.normalize_filename_dir_sep + (** * A set of module.name_mapper config entry allows users to specify regexp * matcher strings each with a template string in order to map the names of a @@ -74,7 +77,7 @@ let choose_provider_and_warn_about_duplicates = let module_name_candidates ~options = Module_hashtables.memoize_with_module_name_candidates_cache ~f:(fun name -> let mappers = Options.module_name_mappers options in - let root = Options.root options |> Path.to_string |> Sys_utils.normalize_filename_dir_sep in + let root = get_root options in let map_name mapped_names (regexp, template) = let new_name = name @@ -318,26 +321,47 @@ module Node = struct let rec node_module ~options ~reader node_modules_containers file loc resolution_acc dir r = let file_options = Options.file_options options in + let root = get_root options in lazy_seq [ lazy (match SMap.get dir node_modules_containers with | Some existing_node_modules_dirs -> lazy_seq - ( Files.node_resolver_dirnames file_options - |> Base.List.map ~f:(fun dirname -> - lazy - ( if SSet.mem dirname existing_node_modules_dirs then - resolve_relative - ~options - ~reader - loc - ?resolution_acc - dir - (spf "%s%s%s" dirname Filename.dir_sep r) - else - None )) ) - | None -> None); + [ + lazy + (lazy_seq + ( Files.node_resolver_aliases file_options + |> Base.List.map ~f:(fun dirname -> + let modified_dirname = + dirname + |> Str.split_delim Files.project_root_token + |> String.concat root + in + lazy + (resolve_relative + ~options + ~reader + loc + ?resolution_acc + dir + (spf "%s%s%s" modified_dirname Filename.dir_sep r))) )); + lazy + (lazy_seq + ( Files.node_resolver_dirnames file_options + |> Base.List.map ~f:(fun dirname -> + lazy + ( if SSet.mem dirname existing_node_modules_dirs then + resolve_relative + ~options + ~reader + loc + ?resolution_acc + dir + (spf "%s%s%s" dirname Filename.dir_sep r))) )); + ] + else + None ); lazy (let parent_dir = Filename.dirname dir in if dir = parent_dir then diff --git a/tests/config_module_system_node_resolve_alias/.flowconfig b/tests/config_module_system_node_resolve_alias/.flowconfig new file mode 100644 index 00000000000..1beb8c31031 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/.flowconfig @@ -0,0 +1,5 @@ +[options] +module.system.node.resolve_dirname=node_modules +module.system.node.resolve_dirname=custom_node_modules +module.system.node.resolve_alias=custom_resolve_dir +module.system.node.resolve_alias=/root_resolve_dir diff --git a/tests/config_module_system_node_resolve_alias/.testconfig b/tests/config_module_system_node_resolve_alias/.testconfig new file mode 100644 index 00000000000..70d0dd9761a --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/.testconfig @@ -0,0 +1 @@ +shell: test.sh \ No newline at end of file diff --git a/tests/config_module_system_node_resolve_alias/config_module_system_node_resolve_alias.exp b/tests/config_module_system_node_resolve_alias/config_module_system_node_resolve_alias.exp new file mode 100644 index 00000000000..048605368c5 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/config_module_system_node_resolve_alias.exp @@ -0,0 +1,231 @@ + +Should have all expected errors +Error ------------------------------------------------------------------------------------------ subdir/sublevel.js:18:2 + +Cannot cast `two` to string literal `custom_resolve_dir/testproj2` because string literal +`subdir/custom_resolve_dir/testproj2` [1] is incompatible with string literal `custom_resolve_dir/testproj2` [2]. + + subdir/sublevel.js:18:2 + 18| (two: "custom_resolve_dir/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^ + +References: + subdir/custom_resolve_dir/testproj2/index.js:3:18 + 3| export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + subdir/sublevel.js:18:7 + 18| (two: "custom_resolve_dir/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------ subdir/sublevel.js:19:2 + +Cannot cast `two` to string literal `node_modules/testproj2` because string literal +`subdir/custom_resolve_dir/testproj2` [1] is incompatible with string literal `node_modules/testproj2` [2]. + + subdir/sublevel.js:19:2 + 19| (two: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^ + +References: + subdir/custom_resolve_dir/testproj2/index.js:3:18 + 3| export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + subdir/sublevel.js:19:7 + 19| (two: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------ subdir/sublevel.js:45:2 + +Cannot cast `incrementalRoot` to string literal `root_resolve_dir/incrementalRoot` because string literal +`subdir/custom_resolve_dir/incrementalRoot` [1] is incompatible with string literal +`root_resolve_dir/incrementalRoot` [2]. + + subdir/sublevel.js:45:2 + 45| (incrementalRoot: "root_resolve_dir/incrementalRoot"); + ^^^^^^^^^^^^^^^ + +References: + subdir/custom_resolve_dir/incrementalRoot/index.js:3:18 + 3| export var name: "subdir/custom_resolve_dir/incrementalRoot" = "subdir/custom_resolve_dir/incrementalRoot"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + subdir/sublevel.js:45:19 + 45| (incrementalRoot: "root_resolve_dir/incrementalRoot"); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error -------------------------------------------------------------------------------------------------- toplevel.js:8:2 + +Cannot cast `one` to string literal `node_modules/testproj` because string literal `custom_resolve_dir/testproj` [1] is +incompatible with string literal `node_modules/testproj` [2]. + + toplevel.js:8:2 + 8| (one: "node_modules/testproj"); // Error: Resolve from resolve_alias first! + ^^^ + +References: + custom_resolve_dir/testproj/index.js:3:18 + 3| export var name: "custom_resolve_dir/testproj" = "custom_resolve_dir/testproj"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + toplevel.js:8:7 + 8| (one: "node_modules/testproj"); // Error: Resolve from resolve_alias first! + ^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------------- toplevel.js:15:2 + +Cannot cast `incrementalNodeModules` to string literal `node_modules/incrementalNodeModules` because string literal +`custom_resolve_dir/incrementalNodeModules` [1] is incompatible with string literal +`node_modules/incrementalNodeModules` [2]. + + toplevel.js:15:2 + 15| (incrementalNodeModules: "node_modules/incrementalNodeModules"); + ^^^^^^^^^^^^^^^^^^^^^^ + +References: + custom_resolve_dir/incrementalNodeModules/index.js:3:18 + 3| export var name: "custom_resolve_dir/incrementalNodeModules" = "custom_resolve_dir/incrementalNodeModules"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + toplevel.js:15:26 + 15| (incrementalNodeModules: "node_modules/incrementalNodeModules"); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + + +Found 5 errors + +Should fix incrementalRoot +Error ------------------------------------------------------------------------------------------ subdir/sublevel.js:18:2 + +Cannot cast `two` to string literal `custom_resolve_dir/testproj2` because string literal +`subdir/custom_resolve_dir/testproj2` [1] is incompatible with string literal `custom_resolve_dir/testproj2` [2]. + + subdir/sublevel.js:18:2 + 18| (two: "custom_resolve_dir/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^ + +References: + subdir/custom_resolve_dir/testproj2/index.js:3:18 + 3| export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + subdir/sublevel.js:18:7 + 18| (two: "custom_resolve_dir/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------ subdir/sublevel.js:19:2 + +Cannot cast `two` to string literal `node_modules/testproj2` because string literal +`subdir/custom_resolve_dir/testproj2` [1] is incompatible with string literal `node_modules/testproj2` [2]. + + subdir/sublevel.js:19:2 + 19| (two: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^ + +References: + subdir/custom_resolve_dir/testproj2/index.js:3:18 + 3| export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + subdir/sublevel.js:19:7 + 19| (two: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error -------------------------------------------------------------------------------------------------- toplevel.js:8:2 + +Cannot cast `one` to string literal `node_modules/testproj` because string literal `custom_resolve_dir/testproj` [1] is +incompatible with string literal `node_modules/testproj` [2]. + + toplevel.js:8:2 + 8| (one: "node_modules/testproj"); // Error: Resolve from resolve_alias first! + ^^^ + +References: + custom_resolve_dir/testproj/index.js:3:18 + 3| export var name: "custom_resolve_dir/testproj" = "custom_resolve_dir/testproj"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + toplevel.js:8:7 + 8| (one: "node_modules/testproj"); // Error: Resolve from resolve_alias first! + ^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------------- toplevel.js:15:2 + +Cannot cast `incrementalNodeModules` to string literal `node_modules/incrementalNodeModules` because string literal +`custom_resolve_dir/incrementalNodeModules` [1] is incompatible with string literal +`node_modules/incrementalNodeModules` [2]. + + toplevel.js:15:2 + 15| (incrementalNodeModules: "node_modules/incrementalNodeModules"); + ^^^^^^^^^^^^^^^^^^^^^^ + +References: + custom_resolve_dir/incrementalNodeModules/index.js:3:18 + 3| export var name: "custom_resolve_dir/incrementalNodeModules" = "custom_resolve_dir/incrementalNodeModules"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + toplevel.js:15:26 + 15| (incrementalNodeModules: "node_modules/incrementalNodeModules"); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + + +Found 4 errors + +Should fix incrementalNodeModules +Error ------------------------------------------------------------------------------------------ subdir/sublevel.js:18:2 + +Cannot cast `two` to string literal `custom_resolve_dir/testproj2` because string literal +`subdir/custom_resolve_dir/testproj2` [1] is incompatible with string literal `custom_resolve_dir/testproj2` [2]. + + subdir/sublevel.js:18:2 + 18| (two: "custom_resolve_dir/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^ + +References: + subdir/custom_resolve_dir/testproj2/index.js:3:18 + 3| export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + subdir/sublevel.js:18:7 + 18| (two: "custom_resolve_dir/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------ subdir/sublevel.js:19:2 + +Cannot cast `two` to string literal `node_modules/testproj2` because string literal +`subdir/custom_resolve_dir/testproj2` [1] is incompatible with string literal `node_modules/testproj2` [2]. + + subdir/sublevel.js:19:2 + 19| (two: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^ + +References: + subdir/custom_resolve_dir/testproj2/index.js:3:18 + 3| export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + subdir/sublevel.js:19:7 + 19| (two: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + ^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error -------------------------------------------------------------------------------------------------- toplevel.js:8:2 + +Cannot cast `one` to string literal `node_modules/testproj` because string literal `custom_resolve_dir/testproj` [1] is +incompatible with string literal `node_modules/testproj` [2]. + + toplevel.js:8:2 + 8| (one: "node_modules/testproj"); // Error: Resolve from resolve_alias first! + ^^^ + +References: + custom_resolve_dir/testproj/index.js:3:18 + 3| export var name: "custom_resolve_dir/testproj" = "custom_resolve_dir/testproj"; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + toplevel.js:8:7 + 8| (one: "node_modules/testproj"); // Error: Resolve from resolve_alias first! + ^^^^^^^^^^^^^^^^^^^^^^^ [2] + + + +Found 3 errors diff --git a/tests/config_module_system_node_resolve_alias/custom_node_modules/incremental/index.js b/tests/config_module_system_node_resolve_alias/custom_node_modules/incremental/index.js new file mode 100644 index 00000000000..1c9bf0a126a --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/custom_node_modules/incremental/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "custom_node_modules/incremental" = "custom_node_modules/incremental"; diff --git a/tests/config_module_system_node_resolve_alias/custom_node_modules/testproj4/index.js b/tests/config_module_system_node_resolve_alias/custom_node_modules/testproj4/index.js new file mode 100644 index 00000000000..bc4d5706e49 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/custom_node_modules/testproj4/index.js @@ -0,0 +1,4 @@ +// @flow + +export var name: "custom_node_modules/testproj4" = + "custom_node_modules/testproj4"; diff --git a/tests/config_module_system_node_resolve_alias/custom_resolve_dir/incrementalNodeModules/index.js b/tests/config_module_system_node_resolve_alias/custom_resolve_dir/incrementalNodeModules/index.js new file mode 100644 index 00000000000..398a6397e57 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/custom_resolve_dir/incrementalNodeModules/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "custom_resolve_dir/incrementalNodeModules" = "custom_resolve_dir/incrementalNodeModules"; diff --git a/tests/config_module_system_node_resolve_alias/custom_resolve_dir/testproj/index.js b/tests/config_module_system_node_resolve_alias/custom_resolve_dir/testproj/index.js new file mode 100644 index 00000000000..124474deaaf --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/custom_resolve_dir/testproj/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "custom_resolve_dir/testproj" = "custom_resolve_dir/testproj"; diff --git a/tests/config_module_system_node_resolve_alias/custom_resolve_dir/testproj2/index.js b/tests/config_module_system_node_resolve_alias/custom_resolve_dir/testproj2/index.js new file mode 100644 index 00000000000..620347ab2f1 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/custom_resolve_dir/testproj2/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "custom_resolve_dir/testproj2" = "custom_resolve_dir/testproj2"; diff --git a/tests/config_module_system_node_resolve_alias/node_modules/incrementalNodeModules/index.js b/tests/config_module_system_node_resolve_alias/node_modules/incrementalNodeModules/index.js new file mode 100644 index 00000000000..a06529ae6fa --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/node_modules/incrementalNodeModules/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "node_modules/incrementalNodeModules" = "node_modules/incrementalNodeModules"; diff --git a/tests/config_module_system_node_resolve_alias/node_modules/testproj/index.js b/tests/config_module_system_node_resolve_alias/node_modules/testproj/index.js new file mode 100644 index 00000000000..04064ab9e18 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/node_modules/testproj/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "node_modules/testproj" = "node_modules/testproj"; diff --git a/tests/config_module_system_node_resolve_alias/node_modules/testproj2/index.js b/tests/config_module_system_node_resolve_alias/node_modules/testproj2/index.js new file mode 100644 index 00000000000..592604c3880 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/node_modules/testproj2/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "node_modules/testproj2" = "node_modules/testproj2"; diff --git a/tests/config_module_system_node_resolve_alias/node_modules/testproj2/subfile.js b/tests/config_module_system_node_resolve_alias/node_modules/testproj2/subfile.js new file mode 100644 index 00000000000..86e2965c7ac --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/node_modules/testproj2/subfile.js @@ -0,0 +1,3 @@ +// @flow +export var name: "node_modules/testproj2/subfile" = + "node_modules/testproj2/subfile"; diff --git a/tests/config_module_system_node_resolve_alias/node_modules/testproj3/index.js b/tests/config_module_system_node_resolve_alias/node_modules/testproj3/index.js new file mode 100644 index 00000000000..5c439a350d5 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/node_modules/testproj3/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "node_modules/testproj3" = "node_modules/testproj3"; diff --git a/tests/config_module_system_node_resolve_alias/root_resolve_dir/incrementalRoot/index.js b/tests/config_module_system_node_resolve_alias/root_resolve_dir/incrementalRoot/index.js new file mode 100644 index 00000000000..3e8e4357bec --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/root_resolve_dir/incrementalRoot/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "root_resolve_dir/incrementalRoot" = "root_resolve_dir/incrementalRoot"; diff --git a/tests/config_module_system_node_resolve_alias/root_resolve_dir/testproj6/index.js b/tests/config_module_system_node_resolve_alias/root_resolve_dir/testproj6/index.js new file mode 100644 index 00000000000..7499d5fcf0a --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/root_resolve_dir/testproj6/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "root_resolve_dir/testproj6" = "root_resolve_dir/testproj6"; diff --git a/tests/config_module_system_node_resolve_alias/subdir/custom_resolve_dir/incrementalRoot/index.js b/tests/config_module_system_node_resolve_alias/subdir/custom_resolve_dir/incrementalRoot/index.js new file mode 100644 index 00000000000..354ae0a1982 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/subdir/custom_resolve_dir/incrementalRoot/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "subdir/custom_resolve_dir/incrementalRoot" = "subdir/custom_resolve_dir/incrementalRoot"; diff --git a/tests/config_module_system_node_resolve_alias/subdir/custom_resolve_dir/testproj2/index.js b/tests/config_module_system_node_resolve_alias/subdir/custom_resolve_dir/testproj2/index.js new file mode 100644 index 00000000000..af4294a36c2 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/subdir/custom_resolve_dir/testproj2/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2"; diff --git a/tests/config_module_system_node_resolve_alias/subdir/custom_resolve_dir/testproj5/index.js b/tests/config_module_system_node_resolve_alias/subdir/custom_resolve_dir/testproj5/index.js new file mode 100644 index 00000000000..40e5d9afa37 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/subdir/custom_resolve_dir/testproj5/index.js @@ -0,0 +1,4 @@ +// @flow + +export var name: "subdir/custom_resolve_dir/testproj5" = + "subdir/custom_resolve_dir/testproj5"; diff --git a/tests/config_module_system_node_resolve_alias/subdir/root_resolve_dir/testproj6/index.js b/tests/config_module_system_node_resolve_alias/subdir/root_resolve_dir/testproj6/index.js new file mode 100644 index 00000000000..e666bbcd3e8 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/subdir/root_resolve_dir/testproj6/index.js @@ -0,0 +1,4 @@ +// @flow + +export var name: "subdir/root_resolve_dir/testproj6" = + "subdir/root_resolve_dir/testproj6"; diff --git a/tests/config_module_system_node_resolve_alias/subdir/sublevel.js b/tests/config_module_system_node_resolve_alias/subdir/sublevel.js new file mode 100644 index 00000000000..ce3bba44c70 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/subdir/sublevel.js @@ -0,0 +1,45 @@ +// @flow +import { name as one } from "testproj"; +import { name as two } from "testproj2"; +import { name as three } from "testproj2/subfile"; + +import { name as four } from "testproj3"; +import { name as five } from "testproj4"; + +import { name as six } from "testproj5"; + +import { name as seven } from "testproj6"; + +import { name as incrementalRoot } from "incrementalRoot"; + +(one: "custom_resolve_dir/testproj"); + +(two: "subdir/custom_resolve_dir/testproj2"); +(two: "custom_resolve_dir/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! +(two: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! + +// if we fail to resolve in custom_resolve_dir +// then we should still resolve node_modules if +// possible. +// +// this tends to bring up the possibility of +// confusing bugs but it is consistent with +// the behavior of the webpack/babel features +// they are based upon. +// +// personally can see a flow lint warning +// as an option here if a conflict of folders +// is detected between aliases and/or node_modules +(three: "node_modules/testproj2/subfile"); + +// should still resolve node_modules +(four: "node_modules/testproj3"); + +// should still resolve custom_node_modules +(five: "custom_node_modules/testproj4"); + +// Should not resolve to the subdir +(seven: "root_resolve_dir/testproj6"); + +// should resolve to the subdirectory, and then get fixed +(incrementalRoot: "root_resolve_dir/incrementalRoot"); diff --git a/tests/config_module_system_node_resolve_alias/test.sh b/tests/config_module_system_node_resolve_alias/test.sh new file mode 100755 index 00000000000..7d0018c358d --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/test.sh @@ -0,0 +1,10 @@ +#!/bin/bash +. ../fs.sh +printf "\nShould have all expected errors\n" +assert_errors "$FLOW" status . +printf "\nShould fix incrementalRoot\n" +remove subdir/custom_resolve_dir/incrementalRoot/index.js +assert_errors "$FLOW" status . +printf "\nShould fix incrementalNodeModules\n" +remove custom_resolve_dir/incrementalNodeModules/index.js +assert_errors "$FLOW" status . diff --git a/tests/config_module_system_node_resolve_alias/toplevel.js b/tests/config_module_system_node_resolve_alias/toplevel.js new file mode 100644 index 00000000000..524389e49d1 --- /dev/null +++ b/tests/config_module_system_node_resolve_alias/toplevel.js @@ -0,0 +1,15 @@ +// @flow + +import { name as one } from "testproj"; +import { name as two } from "testproj2"; +import { name as incrementalNodeModules } from "incrementalNodeModules"; + +(one: "custom_resolve_dir/testproj"); +(one: "node_modules/testproj"); // Error: Resolve from resolve_alias first! + +// at base level we resolve local testproj2 +// as opposed to the local custom_resolve_dir +// in the subdir test +(two: "custom_resolve_dir/testproj2"); + +(incrementalNodeModules: "node_modules/incrementalNodeModules");