Skip to content

Commit

Permalink
commit resolve_alias feature
Browse files Browse the repository at this point in the history
add tests for resolve_alias
  • Loading branch information
bradennapier committed Feb 5, 2019
1 parent 306096a commit 15e9328
Show file tree
Hide file tree
Showing 15 changed files with 141 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/commands/commandUtils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,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 = CommandSpec.ArgSpec.(
Expand Down
12 changes: 12 additions & 0 deletions src/commands/config/flowConfig.ml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ module Opts = struct
munge_underscores: bool;
no_flowlib: bool;
node_resolver_dirnames: string list;
node_resolver_aliases: string list;
root_name: string option;
saved_state_fetcher: Options.saved_state_fetcher;
shm_dep_table_pow: int;
Expand Down Expand Up @@ -155,6 +156,7 @@ module Opts = struct
munge_underscores = false;
no_flowlib = false;
node_resolver_dirnames = ["node_modules"];
node_resolver_aliases = [];
root_name = None;
saved_state_fetcher = Options.Dummy_fetcher;
shm_dep_table_pow = 17;
Expand Down Expand Up @@ -486,6 +488,15 @@ module Opts = struct
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.use_strict",
boolean (fun opts v -> Ok { opts with modules_are_use_strict = v });
Expand Down Expand Up @@ -991,6 +1002,7 @@ let modules_are_use_strict c = c.options.Opts.modules_are_use_strict
let munge_underscores c = c.options.Opts.munge_underscores
let no_flowlib c = c.options.Opts.no_flowlib
let node_resolver_dirnames c = c.options.Opts.node_resolver_dirnames
let node_resolver_aliases c = c.options.Opts.node_resolver_aliases
let root_name c = c.options.Opts.root_name
let saved_state_fetcher c = c.options.Opts.saved_state_fetcher
let shm_dep_table_pow c = c.options.Opts.shm_dep_table_pow
Expand Down
1 change: 1 addition & 0 deletions src/commands/config/flowConfig.mli
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ val modules_are_use_strict: config -> bool
val munge_underscores: config -> bool
val no_flowlib: config -> bool
val node_resolver_dirnames: config -> string list
val node_resolver_aliases: config -> string list
val required_version: config -> string option
val root_name: config -> string option
val saved_state_fetcher: config -> Options.saved_state_fetcher
Expand Down
27 changes: 22 additions & 5 deletions src/common/files.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -28,6 +29,7 @@ let lib_paths options = options.lib_paths
let module_file_exts options = options.module_file_exts
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

let node_modules_containers = ref SSet.empty

Expand Down Expand Up @@ -104,6 +106,9 @@ 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)
Expand Down Expand Up @@ -177,7 +182,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 = Core_list.map ~f:is_prefix paths in
let rec process sz (acc, symlinks) files dir stack =
if sz >= max_files then
Expand All @@ -193,7 +198,7 @@ let make_next_files_and_symlinks
then process (sz+1) (real :: acc, symlinks) files dir stack
else process sz (acc, symlinks) files dir stack
| Dir (path, is_symlink) ->
if node_module_filter file
if node_module_filter file || module_alias_filter file
then node_modules_containers := SSet.add (Filename.dirname file) !node_modules_containers;
let dirfiles = Array.to_list @@ try_readdir path in
let symlinks =
Expand Down Expand Up @@ -229,13 +234,14 @@ let make_next_files_and_symlinks
of `paths`. *)
let make_next_files_following_symlinks
~node_module_filter
~module_alias_filter
~path_filter
~realpath_filter
~error_filter
paths =
let paths = Core_list.map ~f:Path.to_string paths in
let cb = ref (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
) in
let symlinks = ref SSet.empty in
let seen_symlinks = ref SSet.empty in
Expand All @@ -254,7 +260,7 @@ let make_next_files_following_symlinks
symlinks := SSet.empty;
(* since we're following a symlink, use realpath_filter for both *)
cb := make_next_files_and_symlinks
~node_module_filter ~path_filter:realpath_filter ~realpath_filter ~error_filter paths;
~node_module_filter ~module_alias_filter ~path_filter:realpath_filter ~realpath_filter ~error_filter paths;
rec_cb ()
end
in
Expand All @@ -273,6 +279,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 [] else options.lib_paths in
let libs, filter = match options.default_lib_dir with
| None -> libs, is_valid_path ~options
Expand All @@ -291,6 +298,7 @@ let init ?(flowlibs_only=false) (options: options) =
let filter' path = path = lib_str || filter path in
make_next_files_following_symlinks
~node_module_filter
~module_alias_filter
~path_filter:filter'
~realpath_filter:filter'
~error_filter:(fun _ -> true)
Expand Down Expand Up @@ -364,6 +372,7 @@ let watched_paths options =
*)
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 _ -> true else wanted ~options libs in

(* The directories from which we start our search *)
Expand Down Expand Up @@ -399,7 +408,7 @@ let make_next_files ~root ~all ~subdir ~options ~libs =
)
in
make_next_files_following_symlinks
~node_module_filter ~path_filter ~realpath_filter ~error_filter:filter starting_points
~node_module_filter ~module_alias_filter ~path_filter ~realpath_filter ~error_filter:filter starting_points

let is_windows_root root =
Sys.win32 &&
Expand Down Expand Up @@ -527,6 +536,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
*)
Expand Down
3 changes: 3 additions & 0 deletions src/common/files.mli
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -28,6 +29,7 @@ val lib_paths: options -> Path.t list
val module_file_exts: options -> SSet.t
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 ref

Expand Down Expand Up @@ -106,6 +108,7 @@ val filename_from_string: options: options -> string -> File_key.t
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:
Expand Down
24 changes: 18 additions & 6 deletions src/services/inference/module/module_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -407,12 +407,24 @@ module Node = struct
lazy_seq [
lazy (
if SSet.mem dir node_modules_containers then
lazy_seq (Files.node_resolver_dirnames file_options |> Core_list.map ~f:(fun dirname ->
lazy (resolve_relative
~options ~reader
loc ?resolution_acc dir (spf "%s%s%s" dirname Filename.dir_sep r)
)
))
lazy_seq([
lazy (
lazy_seq (Files.node_resolver_aliases file_options |> Core_list.map ~f:(fun dirname ->
lazy (resolve_relative
~options
loc ?resolution_acc dir (spf "%s%s%s" dirname Filename.dir_sep r)
)
))
);
lazy (
lazy_seq (Files.node_resolver_dirnames file_options |> Core_list.map ~f:(fun dirname ->
lazy (resolve_relative
~options ~reader
loc ?resolution_acc dir (spf "%s%s%s" dirname Filename.dir_sep r)
)
))
);
])
else None
);

Expand Down
3 changes: 3 additions & 0 deletions tests/config_module_system_node_resolve_alias/.flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[options]
module.system.node.resolve_dirname=node_modules
module.system.node.resolve_alias=custom_resolve_dir
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ subdir/sublevel.js:6:2

Cannot cast name 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
3│ import {name} from "testproj2";
4│
5│ (name: "subdir/custom_resolve_dir/testproj2");
[2] 6│ (name: "custom_resolve_dir/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first!
7│ (name: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first!
8│

subdir/custom_resolve_dir/testproj2/index.js
[1] 3│ export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2";


Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ subdir/sublevel.js:7:2

Cannot cast name 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
4│
5│ (name: "subdir/custom_resolve_dir/testproj2");
6│ (name: "custom_resolve_dir/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first!
[2] 7│ (name: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first!
8│

subdir/custom_resolve_dir/testproj2/index.js
[1] 3│ export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2";


Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ toplevel.js:6:2

Cannot cast name 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
3│ import {name} from "testproj";
4│
5│ (name: "custom_resolve_dir/testproj");
[2] 6│ (name: "node_modules/testproj"); // Error: Resolve from resolve_alias first!

custom_resolve_dir/testproj/index.js
[1] 3│ export var name: "custom_resolve_dir/testproj" = "custom_resolve_dir/testproj";



Found 3 errors
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @flow

export var name: "custom_resolve_dir/testproj" = "custom_resolve_dir/testproj";
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @flow

export var name: "custom_resolve_dir/testproj2" = "custom_resolve_dir/testproj2";

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @flow

export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2";
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @flow

import {name} from "testproj2";

(name: "subdir/custom_resolve_dir/testproj2");
(name: "custom_resolve_dir/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first!
(name: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first!
6 changes: 6 additions & 0 deletions tests/config_module_system_node_resolve_alias/toplevel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @flow

import {name} from "testproj";

(name: "custom_resolve_dir/testproj");
(name: "node_modules/testproj"); // Error: Resolve from resolve_alias first!

0 comments on commit 15e9328

Please sign in to comment.